NotionCommotion
Members-
Posts
2,446 -
Joined
-
Last visited
-
Days Won
10
Everything posted by NotionCommotion
-
Uploading a file with JSON to a REST API
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Thanks for your help requinix and kicken. I feel good about my plan going forward. My consensus is: While there are some benefits of having the file and associated data in a single request, it is not worth doing so for the following reasons: Limits flexibillity for future changes. Base64 uses increases file size and utilizes more resources. Mixing fields and the file in a multipart form adds complexities and is harder to document and test. If the entity with the metadata has one and only one file associated with it, then the file should be uploaded first and the next request should create the entity along with the file location, and a cron process should delete any non-associated files. If the entity with the metadata can have multiple files associated with it, then the data should be uploaded first and the entity created, and the next request(s) should upload the files and associate them to the entity. If I am way off base, let me know, but if only a little, please let me happy in my ignorance -
Uploading a file with JSON to a REST API
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
If done correctly, a user wouldn't/shouldn't know. Yes, I knew that it was possible but the lack of others doing so made me feel that it might be a bad idea. Sorry, should have stated the question not whether it could be done but should be done. The eternal question! Will also need to consider the added client complexity of making multiple requests. If it is just me and it will be fairly easy to modify api-platform's upload solution to do both, I expect that would be easiest, but if most API client developers are accustom to making two requests, expect I should implement it that way. -
Uploading a file with JSON to a REST API
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
I've been going down the path to upload both the file and the metadata in the same request, but starting to doubt myself again and want to stop sooner than later if a bad decision. Evidently, YouTube sends the metadata first, persists an entity, returns the endpoint, and uploads the file using PUT (or maybe PATCH?). This post says basically there is no option to send the metadata and file in the same request unless the file is Base64 encoded (which evidently is bad). My interpretation of the general concusses is send the file first, store it in some tmp folder, and then upload the metadata, move the file, and and create the entity. My originally referenced documentation didn't make judgement but went out to say it isn't JSON which I maybe incorrectly interpret as saying don't do in a single request. It "seems" like it is possible using multipart to send both in the same request, but I've found nothing confirming this belief. Am I going down the wrong path trying to send a single request with both the file and metadata? -
Currently, no, but like life, that might change. I've seen mention of this but haven't looked into. On my list... Me too. Off topic. Tampa Bay or KC?
-
I am still on the fence whether I should have a single User class or two classes VenderUser and OwnerUser (really will call just Vendor and User) which each extend AbstractUser. If I go with just one class, I can add roles as necessary to control action. Sure, they might have different methods, but this can be controlled by roles. And each are intended to be joined to different tables (i.e. Project is owned by one OwnerUser and many VendorUsers are assigned to many Projects), but again this can be controlled by the assigned roles. Or is this "too" different, and I should have two classes? I believe doing so is more intuitive and less prone to a corrupt database. It also makes it easier to have one endpoint to retrieve a collection of Users and another to retrieve a collection of Vendors. But where do I stop? I expect you have a single User class and not separate StudentUser and ManagerUser classes, right? And surely I wouldn't want to create a OwnerUser and then an AdminUser because this truly conflicts with the "Symfony" way of doing it. So, it comes down to whether OwnerUser (which might or might not have some sort of higher admin role assigned) and VendorUser are fundamentally different enough to warrant separate classes. What do you think?
-
Stupid mistake with Doctrine entities and inheritance
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Thanks kicken. I half hearted tested your suggestion with no expectations, and behold you are absolutely correct! Then, I was more confused regarding why it worked, but then spotted my stupid mistake. Previously I've always manually created my Doctrine repositories and added a 'create()` method to each to create an entity. Symfony does almost the same but injects the class name of the to be created class in the constructor. Happy to find that it was nothing magical but just normal PHP. My final solution still extends AbstractUserRepository, but each entity has its own constructor. Thanks again! <?php namespace App\Repository; use App\Entity\Vendor; use Doctrine\Persistence\ManagerRegistry; class VendorRepository extends AbstractUserRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Vendor::class); } } -
Submitting forms with arrays as JSON
NotionCommotion replied to NotionCommotion's topic in Javascript Help
No, and I should make it able to do so... Eventually. But I haven't implemented the other content types yet and wish to at least get one thing working first. And while maybe I should always know the latest JS latest cool way for doing things, it annoys me sometimes having to learn them when I don't have time to do so. Can you be more specific regarding my very non-abstract question? -
Submitting forms with arrays as JSON
NotionCommotion replied to NotionCommotion's topic in Javascript Help
My hack which I would rather not use. function formDataToObj(formData) { var o={}; for (var [key, val] of formData.entries()) { if(key.slice(-2)==='[]') { key = key.substr(0, key.length-2); if (typeof o[key] === 'undefined') { o[key] = []; } o[key].push(val); } else { o[key] = val; } } return o; }, -
When submitting application/x-www-form-urlencoded data to PHP, using names such as roles[] does the trick. <form id="addRecordForm"> <input type="text" class="form-control" id="firstName" name="firstName" placeholder="John"> <input type="text" class="form-control" id="lastName" name="lastName" placeholder="Doe"> <input type="hidden" name="roles[]" value="ROLE_1"> <input type="hidden" name="roles[]" value="ROLE_2"> </form> However, I will be sending application/json;charset=UTF-8. To get the data, I typically using the following, but it will not work with inputs with array data and will only include the second ROLE_2. var data = Object.fromEntries(new FormData( form )); I can come up with a hack (i.e. explicitly get the content from FormData before executing Object.fromEntries()) to meet my immediate needs, but would rather standardize on a better solution. Any recommendations?
-
Stupid mistake with Doctrine entities and inheritance
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
I have no idea why this would make a different, but if I remove the repository declaration in the child entity, I now get the desired results. Of course, now I can't have separate repositories for each sub-class... Does not work: /** * @ORM\Entity * @ORM\Entity(repositoryClass=OwnerUserRepository::class) */ class OwnerUser extends AbstractUser { } Works: /** * @ORM\Entity */ class OwnerUser extends AbstractUser { } -
I am doing something stupid, and just can't see it and hoping someone has better eyes than mine. I have two Doctrine entities which extend another class using single class inheritance, but when retrieving the collection of either of the two child classes, I get the collection of the parent (i.e. combination of both child classes). I've experimented with making the parent abstract and not including it in the discriminator map but no change. In hopes to identifying my mistake, I created a new Symfony project with just the relevant classes and show all steps below. Initial install by running the following: symfony new test composer update composer require doctrine/orm composer require migrations composer require maker --dev composer require security Using "php bin/console make:user", I created three users: AbstractUser, OwnerUser, VendorUser. I then edited all three entities and the owner and vendor repositories as follows: <?php namespace App\Entity; use App\Repository\AbstractUserRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\UserInterface; /** * @ORM\Entity(repositoryClass=AbstractUserRepository::class) * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="discr", type="string") * @ORM\DiscriminatorMap({"owner" = "OwnerUser", "vendor" = "VendorUser", "abstract" = "AbstractUser"}) */ class AbstractUser implements UserInterface { // No changes made } <?php namespace App\Entity; use App\Repository\OwnerUserRepository; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass=OwnerUserRepository::class) */ class OwnerUser extends AbstractUser { } <?php namespace App\Entity; use App\Repository\VendorUserRepository; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass=VendorUserRepository::class) */ class VendorUser extends AbstractUser { } No change to AbstractUserRepository. <?php namespace App\Repository; class OwnerUserRepository extends AbstractUserRepository { } <?php namespace App\Repository; class VendorUserRepository extends AbstractUserRepository { } Then I migrated the DB. php bin/console doctrine:schema:drop --full-database --force rm migrations/* php bin/console make:migration php bin/console doctrine:migrations:migrate Next I created two OwnerUsers and one VendorUser using a command script I wrote shown at the end of this post. # php bin/console app:tester create OwnerUser roles=[] # php bin/console app:tester create OwnerUser roles=[] # php bin/console app:tester create VendorUser roles=[] Checked the PostSQL database. facdocs=> \d List of relations Schema | Name | Type | Owner --------+-----------------------------+----------+--------- public | abstract_user | table | facdocs public | abstract_user_id_seq | sequence | facdocs public | doctrine_migration_versions | table | facdocs (3 rows) facdocs=> select * from abstract_user; id | email | roles | password | discr ----+-------------+-------+----------------+-------- 1 | setEmail158 | [] | setPassword146 | owner 2 | setEmail87 | [] | setPassword101 | owner 3 | setEmail62 | [] | setPassword20 | vendor (3 rows) facdocs=> Next, I retrieved the entities using Doctrine along with the beforementioned test script. [michael@devserver test]$ php bin/console app:tester read VendorUser Test Entity Manager ============ command: read entity: VendorUser class: \App\Entity\VendorUser properties: [] array(3) { [0]=> object(stdClass)#293 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(1) ["email:App\Entity\AbstractUser:private"]=> string(11) "setEmail158" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword146" } [1]=> object(stdClass)#294 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(2) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail87" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword101" } [2]=> object(stdClass)#358 (5) { ["__CLASS__"]=> string(21) "App\Entity\VendorUser" ["id:App\Entity\AbstractUser:private"]=> int(3) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail62" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(13) "setPassword20" } } [michael@devserver test]$ [michael@devserver test]$ php bin/console app:tester read OwnerUser Test Entity Manager ============ command: read entity: OwnerUser class: \App\Entity\OwnerUser properties: [] array(3) { [0]=> object(stdClass)#293 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(1) ["email:App\Entity\AbstractUser:private"]=> string(11) "setEmail158" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword146" } [1]=> object(stdClass)#294 (5) { ["__CLASS__"]=> string(20) "App\Entity\OwnerUser" ["id:App\Entity\AbstractUser:private"]=> int(2) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail87" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(14) "setPassword101" } [2]=> object(stdClass)#358 (5) { ["__CLASS__"]=> string(21) "App\Entity\VendorUser" ["id:App\Entity\AbstractUser:private"]=> int(3) ["email:App\Entity\AbstractUser:private"]=> string(10) "setEmail62" ["roles:App\Entity\AbstractUser:private"]=> string(8) "Array(0)" ["password:App\Entity\AbstractUser:private"]=> string(13) "setPassword20" } } [michael@devserver test]$ As seen, when requesting a collection of either OwnerUsers or VendorUsers, I am retrieving the combination of both collections. I am sure it is totally user (i.e. me) error, but just don't see it. Are you able to see my stupid mistake? Thanks My test script is below: <?php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Common\Util\Debug; class Tester extends Command { // the name of the command (the part after "bin/console") protected static $defaultName = 'app:tester'; private $entityManager; public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; parent::__construct(); } protected function configure() { $this ->setDescription('Doctrine Object Tester. --help') ->setHelp('This command allows you to query a single entity...') ->addArgument('cmd', InputArgument::REQUIRED, 'The command name [create, read].') ->addArgument('entity', InputArgument::REQUIRED, 'The name of the entity.') ->addArgument('properties', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'properies (foo=foo bla=[]') ; } private function getProperties($input) { $properties=[]; foreach($input as $property) { $property=explode('=', $property); $name = trim($property[0]); $value = trim($property[1]); if($value === '[]') { $value = []; } elseif($value === 'null') { $value = null; } elseif(substr($value, 0, 1) === '/') { $value = explode('/', substr($value, 1)); $class = ucfirst(substr($value[0], 0, -1)); $class = '\App\Entity\\'.$class; if(count($value)===1) { $value = $this->entityManager->getRepository($class)->findAll(); } else { $value = $this->entityManager->getRepository($class)->find($value[1]); } } $properties[$name] = $value; } return $properties; } protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln([ 'Test Entity Manager', '============', '', ]); // retrieve the argument value using getArgument() $cmd = $input->getArgument('cmd'); $output->writeln('command: '.$cmd); $entity = $input->getArgument('entity'); $output->writeln('entity: '.$entity); $class = '\App\Entity\\'.$entity; $output->writeln('class: '.$class); $properties = $this->getProperties($input->getArgument('properties')); $output->writeln('properties: '.json_encode($properties)); switch($cmd) { case 'create': $entity = new $class; foreach(get_class_methods($entity) as $method) { if(substr($method, 0, 3)==='set') { $m = lcfirst(substr($method, 3)); $entity->$method(array_key_exists($m, $properties)?$properties[$m]:$method.rand(0,200)); } } $this->entityManager->persist($entity); $this->entityManager->flush(); $output->writeln('entity created'); break; case 'read': Debug::dump($this->entityManager->getRepository($class)->findAll()); break; default: $output->writeln('INVALID COMMAND: '.$cmd.'. Only create and read are supported.'); } return Command::SUCCESS; } }
-
Yes, everything often seems like a work in progress. I think I know the "best" way to do something, go down that path for a while, then learn something new which is "way better", and then get myself in a conundrum whether I continue with my previous approach or go forward with the new approach. And every time I naively believe that making the change will be easy... Glad I do, but never easy. Regarding retrieving a list of a given user type, I will use role the "symfony" way for access control and security purposes, but think extending the basic User class is best (whatever best means). My rational is only based on roles being stored as JSON in the user table. As always, appreciate your advice!
-
Thank you kicken, How long did it take you to get up to speed with Symfony? Any particular good resources you used? I've read about a couple philosophies one could take regarding roles, and was leaning in the direction of what you are doing. Now no longer leaning! Any thoughts how you would just return of your users which have been assigned the ROLE_DEVELOPER and similarly all the users who have not been assigned that role? I take it is_granted() is something one would on a web application and not just an API. Does it make sense to provide something in the JSON response so that similar functionality can still be performed?
-
While I am impressed with much of Symfony, the needing to know everything the "symfony way" is a little annoying. For an application, I will have several types of users: Admin Users. They can create a project, add new vendors, assign vendors to a given project, add new normal or admin users, etc. Vendors. They can view projects which they are assigned to and upload documents for that project. Normal Users. They will have the ability to view documents related to a given project which are submitted by vendors. Super Users. There will be multiple Accounts where all of the above user's will be assigned to a single, and they can only interact with others assigned to that same account. The super user can create an account and add the initial Admin User to that account. To expose the data, I am using api-platform. Currently, I am just trying to create endpoints to retrieve a list of vendors, normal users, etc. One possible solution I know how to accomplish but don't believe is the correct way is to create an AbstractUser and create VendorUser, NormalUser, etc which extend AbstractUser. Doing so will create routes for each of these user types and meet my immediate needs. Alternatively, I can create only a single User entity, and then assign roles such as ROLE_ADMIN, ROLE_VENDOR, ROLE_USER, or ROLE_SUPER. Ideally, I could then add new routes such as /vendors instead of making it /users?type=vendor. Or maybe I should be doing something totally different. If I was building this from scratch, I can definitely figure something out, however, would like to take advantage of symfony and do it their way. But I am a complete newbie when it comes to symfony, and don't even know where to start, and would appreciate a strategy to go which won't lead me down to bad of wrong path.
-
Interpreting/correcting code for api-platform and JWT
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Noticed I made a couple mistakes on my conversion of the argument approach, but corrected. This one, however, has got me stumped. Can't pass null as the 6th argument due to declaration not being ?ExternalDocumentation. Is their a workaround without using PHP8 other than creating an empty ExternalDocumentation and hope it doesn't cause issues? final class Operation { public function __construct( string $operationId = null, // pass 'postCredentialsItem' array $tags = [], // pass [] array $responses = [], // pass $responses string $summary = '', // pass 'Get JWT token to login.' string $description = '', // pass '' ExternalDocumentation $externalDocs = null, // HELP!!! array $parameters = [], // pass [] RequestBody $requestBody = null, // pass $requestBody \ArrayObject $callbacks = null, // All remaining are not provided as arguements bool $deprecated = false, ?array $security = null, ?array $servers = null ) {} -
Interpreting/correcting code for api-platform and JWT
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Thanks kicken! Thought I was going crazy. Looks like I had the constructor part right but wasn't close with the "other new feature". Guess it makes sense. One last item I didn't even mention was the lake of namespace on ArrayObject. Normally, I would have used it as \ArrayObject since without it would be \App\OpenApi\ArrayObject. Given that api-platform has been right so far, probably shouldn't assume it was a typo mistake on their part. Is this some new PHP8 change as well? $responses = [ '200' => [ 'description' => 'Get JWT token', 'content' => [ 'application/json' => [ 'schema' => [ '$ref' => '#/components/schemas/Token', ], ], ] ] ]; $content = new ArrayObject([ 'application/json' => [ 'schema' => [ '$ref' => '#/components/schemas/Credentials', ], ], ]); $requestBody = new Model\RequestBody('Generate new JWT Token', $content); $post = new Model\Operation('postCredentialsItem', null, $responses, 'Get JWT token to login.', $requestBody); $pathItem = new Model\PathItem('JWT Token', null, null, null, null, $post); -
The following script comes from create a decorator example. Please take a look at __construct() and $pathItem. Doesn't look like any PHP I've ever seen. Agree? I don't think it matters and just stating so to make sure, but I am not using a docket but have api-platform on the local server. I've gotten all to work until now. <?php // api/src/OpenApi/JwtDecorator.php declare(strict_types=1); namespace App\OpenApi; use ApiPlatform\Core\OpenApi\Factory\OpenApiFactoryInterface; use ApiPlatform\Core\OpenApi\OpenApi; use ApiPlatform\Core\OpenApi\Model; final class JwtDecorator implements OpenApiFactoryInterface { public function __construct( private OpenApiFactoryInterface $decorated ) {} public function __invoke(array $context = []): OpenApi { $openApi = ($this->decorated)($context); $schemas = $openApi->getComponents()->getSchemas(); $schemas['Token'] = new ArrayObject([ 'type' => 'object', 'properties' => [ 'token' => [ 'type' => 'string', 'readOnly' => true, ], ], ]); $schemas['Credentials'] = new ArrayObject([ 'type' => 'object', 'properties' => [ 'email' => [ 'type' => 'string', 'example' => 'johndoe@example.com', ], 'password' => [ 'type' => 'string', 'example' => 'apassword', ], ], ]); $pathItem = new Model\PathItem( ref: 'JWT Token', post: new Model\Operation( operationId: 'postCredentialsItem', responses: [ '200' => [ 'description' => 'Get JWT token', 'content' => [ 'application/json' => [ 'schema' => [ '$ref' => '#/components/schemas/Token', ], ], ], ], ], summary: 'Get JWT token to login.', requestBody: new Model\RequestBody( description: 'Generate new JWT Token', content: new ArrayObject([ 'application/json' => [ 'schema' => [ '$ref' => '#/components/schemas/Credentials', ], ], ]), ), ), ); $openApi->getPaths()->addPath('/authentication_token', $pathItem); return $openApi; } } I am thinking that maybe the constructor needs to be changed to: private $decorated; public function __construct(OpenApiFactoryInterface $decorated) { $this->decorated = $decorated; } Regarding $pathItem, Model\PathItem's constructor is as follows. Any thoughts on what they are suggesting? Thanks public function __construct( string $ref = null, string $summary = null, string $description = null, Operation $get = null, Operation $put = null, Operation $post = null, Operation $delete = null, Operation $options = null, Operation $head = null, Operation $patch = null, Operation $trace = null, ?array $servers = null, array $parameters = [] ) {/* ... */}
-
Uploading a file with JSON to a REST API
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Which would be fine. Will test, but not certain that is what they are saying. The reason I think so is it might not reflect a "pure" REST API. A request to create a file on the server should return the location of the file. A request to create an entity which includes some meta data as well as a file should return some representation of that entity. You know, I don't know what I am thinking and will test... -
I actually have two parts to this post. One which describes just my understanding on how a multipart request should look with a REST API and gives a little context, and the second how to actually implement it using Sympony and api-platform. Part 1 Looking to simultaneously upload a file, some file meta data, and identifier of the uploading user to a REST API, and will do so using a multipart request. Based on swagger, looks like the request should look something like the following: POST /upload HTTP/1.1 Content-Length: 428 Content-Type: multipart/form-data; boundary=abcde12345 --abcde12345 Content-Disposition: form-data; name="id" Content-Type: text/plain 123e4567-e89b-12d3-a456-426655440000 --abcde12345 Content-Disposition: form-data; name="address" Content-Type: application/json { "street": "3, Garden St", "city": "Hillsbery, UT" } --abcde12345 Content-Disposition: form-data; name="profileImage "; filename="image1.png" Content-Type: application/octet-stream {…file content…} --abcde12345-- Background noise... The above example shows three parts which include the text ID, JSON address and octet-stream file. Doing so doesn't make sense to me and I will probably just have two parts for the meta data JSON. Note that potentially, I will be removing the user from the JSON payload and including it in some JWT header. Also, showing resources as links such as /api/users/1 in the request and response JSON is new to me, but I guess makes sense. Regardless, my meta data JSON will look like: { "projectId": 1234, "documentDescription": "bla bla bla", "specification": "230903.2.4.D", "user": "/api/users/1" } and the response will look like: { "projectId": 1234, "documentDescription": "bla bla bla", "specification": "230903.2.4.D", "uploadAt": "2021-01-27 08:41:17", "fileName": "pressuresensor.pdf". "user": "/api/users/1". "file": "/api/uplodaed_files/1234" } Am I somewhat going down the right path? Part 2 Wow, should have looked into Sympony before now! Entities, validation, the API, etc were a breeze. Still confused with some of the "magic", but understanding what is under the hood more and more. As stated initially, I am utilizing api-platform and am looking at api-platform's file-upload. I guess the first question is whether my POST request with both the file and JSON meta data can be performed in a single request. Per making-a-request-to-the-media_objects-endpoint: What? Am I reading this correct? Do I first need to make a multipart requests using either a standard HTML form or a XMLHttpRequest which just sends the file, receive the document locator, and then send a second request with the location and my meta data? If so, I guess I have enough to go forward. I would rather, however, perform the work in a single request. My previous mentioned swagger multipart-requests shows both in the same request. symfonycasts's api-uploads also describes doing so, but not with api-platform. Is there a way to do so with api-platform? Does it make sense to use api-platform for all other routes but then make a custom route for document with meta data uploads? Any recommendations are much appreciated. Thanks
-
Composer with different versions of PHP
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Thanks kicken, Not sure if I really understood this part. If I have both a composer.json and composer.lock file, composer install appears to install based on composer.lock and ignores composer.json and the composer.lock file will not be modified. But then If I immediately afterwards perform a composer update, the dependencies "might" be changed resulting in a modified composer.lock file based on the PHP version. If I perform a composer install, and don't have a composer.lock file, then composer will first give me a warning and then create a composer.lock file and install dependencies based on the composer.json file. Seem accurate? I had messed around with composer's config.platform option, but gave up. Will look back into it. Regarding your simple wrapper, are you talking about just a bash script to execute the composer.phar file with the appropriate PHP version? If so, is this any different then editing the first line of the composer.phar file (i.e. #!/usr/bin/env php74 to #!/usr/bin/env php73) and making the file executable? -
Composer with different versions of PHP
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Use case is building a plugin for an existing CMS. The CMS and plugin are normally located remotely and the CMS "installs" the plugin. The plugin is fine with PHP7.4, but when it passes a given symfony/etc object to the CMS, I get undefined method or interface violation errors. I am uncertain whether the CMS uses the composer.json files directly and not just with composer. Your docker idea might make sense. Thanks -
Composer with different versions of PHP
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Yes, if true, it might be relevant here. If based on the given project, I need to use either PHP7.3 or PHP7.4 and either Composer 1 or Composer 2, then I need either: A composer1.phar and a composer2.phar and run them using either php (7.4) or php73. A composer 1 executable which uses PHP7.3, a composer 1 executable which uses PHP7.4, a composer 2 executable which uses PHP7.3, and a composer 2 executable which uses PHP7.4. I prefer the second approach with the executables located in /user/local/bin instead of crating around all these composer phar files. Am I missing something? -
Composer with different versions of PHP
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Guess I incorrectly thought the the composer.json file can contain logic which dictates which version of some package is installed based on the executing PHP version. Good to know it doesn't and I can remove that variable when troubleshooting why something isn't working the way I hoped. PS. https://github.com/concrete5/composer/issues/34#issuecomment-696401142 and similar statements are what maybe made me think so. -
Composer with different versions of PHP
NotionCommotion replied to NotionCommotion's topic in PHP Coding Help
Thanks requinix, I was pretty sure I sometime got quirky/different results when running as PHP7.3 or 7.4. Are you also saying that the following will make no difference? $ php composer.phar --update #php7.4 $ php73 composer.phar --update In hindsight, agree my proposed solution of executing composer-setup.php with different PHP versions probably made no sense. If executing the phar with different PHP versions does have an effect, maybe make to executables for each composer version #!/usr/bin/env php <?php /* * This file is part of Composer. * #!/usr/bin/env php73 <?php /* * This file is part of Composer. *