NotionCommotion Posted September 21, 2021 Share Posted September 21, 2021 A while back, I added a post which discussed how to validate PHP's scripts to ensure that all attributes had an available class. My reason for doing so is annotations will throw an error yet attributes will not work but will not provide a warning and are difficult to troubleshot. For example, I will get a warning for $propertyWithError but not for $propertyWithoutError. <?php namespace App\Entity; // use Symfony\Component\Validator\Constraints as Assert; class SomeEntity { /** * @Assert\NotBlank */ private string $propertyWithError; #[Assert\NotBlank] private string $propertyWithoutError; } I then created the a composer package which would parse all the PHP scripts and look for attributes without existing classes. I then created a Symfony command script (App\Command/AttributeValidator) which would use my package and at the CLI I could execute: bin/console app:attribute-validator <?php declare(strict_types=1); namespace App\Command; use Nette\Utils\Strings; use Nette\Utils\Json; use RuntimeException; use Exception; 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 Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use NotionCommotion\AttributeValidator\AttributeValidator as NotionCommotionAttributeValidator; use NotionCommotion\AttributeValidator\AttributeValidatorException; final class AttributeValidator extends Command { private const COMMANDS = ['validate', 'getClassesWithUndeclaredAttributes', 'getClassesWithoutUndeclaredAttributes', 'getSuspectClasses', 'getNotFoundClasses', 'getTraits', 'getInterfaces', 'getAbstracts', 'jsonSerialize', 'debugSuspectFiles', 'debugFile']; // the name of the command (the part after "bin/console") /** * @var string */ protected static $defaultName = 'app:attribute-validator'; protected function configure(): void { $this ->setDescription('Attribute Validator. --help') ->setHelp('This command allows you to check for PHP8 attributes without classes') ->addArgument('path', InputArgument::OPTIONAL, 'Path to check', 'src') ->addOption('command', null, InputOption::VALUE_REQUIRED, 'What command to run?', 'validate') ; } protected function execute(InputInterface $input, OutputInterface $output): int { $command = $input->getOption('command'); if(!in_array($command, self::COMMANDS)) { throw new \Exception(sprintf('Invalid command %s. Only %s are allowed', $command, implode(', ', self::COMMANDS))); } if($command==='validate') { return $this->$command($input, $output); } else { $output->writeln([ 'Attribute Validator', '============', '', ]); $output->writeln("Command: ".$command); $path = $input->getArgument('path'); $output->writeln("Path to check: ".$path); if($command==='debugFile'){ print_r(NotionCommotionAttributeValidator::debugFile($path)); } else{ print_r(NotionCommotionAttributeValidator::create($path)->$command()); } return Command::SUCCESS; } } private function validate(InputInterface $input, OutputInterface $output): int { $output->writeln([ 'Attribute Validator', '============', '', ]); $path = $input->getArgument('path'); $output->writeln("Path to check: ".$path); $helper = $this->getHelper('question'); /* $question = new ConfirmationQuestion('Continue with this action?', true); if (!$helper->ask($input, $output, $question)) { return Command::SUCCESS; } */ $validator = NotionCommotionAttributeValidator::create($path); $errors=0; foreach($validator->validate() as $type=>$errs) { $output->writeln($type.' errors'); switch($type) { case 'classesWithUndeclaredAttributes': foreach($errs as $e) { $output->writeln(sprintf(' %s: %s', $e['fqcn'], $e['filename'])); if(!empty($e['classAttributes'])) { $errors++; $output->writeln(sprintf(' classAttributes: %s', implode(', ', $e['classAttributes']))); } foreach(array_intersect_key($e, array_flip(['propertyAttributes', 'methodAttributes', 'parameterAttributes', 'classConstantAttributes'])) as $attrType=>$ar) { $a = []; foreach($ar as $class=>$t) { $errors++; $a[] = sprintf('%s: %s', $class, implode(', ', $t)); } if($a) { $output->writeln(sprintf(' %s: %s', $attrType, implode(', ', $a))); } } } break; case 'notFoundClasses': case 'suspectClasses': foreach($errs as $e) { $errors++; $a = []; foreach(['class', 'trait', 'interface', 'abstract'] as $t) { if($e[$t]) { $a[] = sprintf('%s: %s', $t, implode(', ', $e[$t])); } } $output->writeln(sprintf(' %s: %s %s', $e['filename'], $e['namespace'], implode(' | ', $a))); } break; default: throw new AttributeValidatorException('Invalid test: '.$type); } } $output->writeln('Error count: '.$errors); return Command::SUCCESS; } } It all works except I don't want to have to copy App\Command/AttributeValidator to each project and so created a second composer package to install it. When executing composer require notion-commotion/attribute-validator-command, this second package is installed but not any of its dependencies. What am I doing wrong? Also, off topic and my primary question is related to composer installing dependencies, however, if anyone knows the proper way to have composer install a symfony command, please let me know. Thanks! { "name": "notion-commotion/attribute-validator-command", "description": "Creates Symfony command to find attributes which do not have classes assigned.", "type": "library", "license": "MIT", "authors": [ { "name": "Michael Reed", "email": "xxx@gmail.com" } ], "require": { "php": ">=8", "symfony/console": "5.3.*", "nette/utils": "4", "notion-commotion/attribute-validator": "^1" }, "autoload": { "psr-4": { "NotionCommotion\\AttributeValidatorCommand\\": "src/" } }, "minimum-stability": "stable", "require": {} } 1 Quote Link to comment https://forums.phpfreaks.com/topic/313787-create-composer-package-which-requires-another-package/ Share on other sites More sharing options...
kicken Posted September 21, 2021 Share Posted September 21, 2021 Your composer.json file defines two require keys. The first one has your intended requirements, the second later on is empty. The empty one overrides your first one. 1 Quote Link to comment https://forums.phpfreaks.com/topic/313787-create-composer-package-which-requires-another-package/#findComment-1590218 Share on other sites More sharing options...
NotionCommotion Posted September 22, 2021 Author Share Posted September 22, 2021 29 minutes ago, kicken said: Your composer.json file defines two require keys. The first one has your intended requirements, the second later on is empty. The empty one overrides your first one. Well, I feel stupid. Potentially, I did not really do so but just did so when posting this question but hope that I really did so... Quote Link to comment https://forums.phpfreaks.com/topic/313787-create-composer-package-which-requires-another-package/#findComment-1590221 Share on other sites More sharing options...
NotionCommotion Posted September 22, 2021 Author Share Posted September 22, 2021 13 hours ago, kicken said: Your composer.json file defines two require keys. The first one has your intended requirements, the second later on is empty. The empty one overrides your first one. Thanks again kicken, Yes, you are 100% correct. I should have initially noticed my error but with multiple new concepts looked right past it. Made the corrections and initially no go because of tag issues but eventually worked. While I could go forward with having my new notion-commotion/attribute-validator-command along with its dependencies in the vendor directory, it will be a bit of a hack. I will then need to manually add a small script in App\Command which uses this new class. Know how to modify composer.json in order to make this automatic? Normally I add my custom command scripts to App\Command namespace but I am thinking doing so isn't right since composer probably should have the ability to modify anything in \src. True? If not, does it go in \bin? Quote Link to comment https://forums.phpfreaks.com/topic/313787-create-composer-package-which-requires-another-package/#findComment-1590226 Share on other sites More sharing options...
kicken Posted September 22, 2021 Share Posted September 22, 2021 Have a look at the composer's documentation for vendor binaries and maybe scripts. By adding a script to your project, you could run your command via something like composer attribute-validator. If you add the vendor/bin path to your PATH then you could just run attribute-validator directly. 1 Quote Link to comment https://forums.phpfreaks.com/topic/313787-create-composer-package-which-requires-another-package/#findComment-1590229 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.