diff --git a/CHANGELOG.md b/CHANGELOG.md index 594ff2f6..77853766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * fix: PropertyAccessor `UninitializedPropertyException` error now is regarded as null. * fix: Transformer `SearchResult` was not properly ordered. +* feat: `TryProperty` command, or `rekalogika:mapper:tryproperty` in console. ## 0.5.7 diff --git a/src/Command/TryPropertyCommand.php b/src/Command/TryPropertyCommand.php new file mode 100644 index 00000000..27858412 --- /dev/null +++ b/src/Command/TryPropertyCommand.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Command; + +use Rekalogika\Mapper\Transformer\Contracts\MixedType; +use Rekalogika\Mapper\TransformerRegistry\TransformerRegistryInterface; +use Rekalogika\Mapper\TypeResolver\TypeResolverInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; + +#[AsCommand(name: 'rekalogika:mapper:tryproperty', description: 'Gets the mapping result by providing the class and property name of the source and target.')] +class TryPropertyCommand extends Command +{ + public function __construct( + private TransformerRegistryInterface $transformerRegistry, + private TypeResolverInterface $typeResolver, + private PropertyInfoExtractorInterface $propertyInfoExtractor, + ) { + parent::__construct(); + } + + protected function configure(): void + { + $this + ->addArgument('sourceClass', InputArgument::REQUIRED, 'The source class') + ->addArgument('sourceProperty', InputArgument::REQUIRED, 'The source property') + ->addArgument('targetClass', InputArgument::REQUIRED, 'The target class') + ->addArgument('targetProperty', InputArgument::REQUIRED, 'The target property') + ->setHelp("The %command.name% displays the mapping result by providing the class and property name of the source and target."); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $rows = []; + + // + // source type + // + + /** @var string */ + $sourceClass = $input->getArgument('sourceClass'); + /** @var string */ + $sourceProperty = $input->getArgument('sourceProperty'); + /** @var string */ + $targetClass = $input->getArgument('targetClass'); + /** @var string */ + $targetProperty = $input->getArgument('targetProperty'); + + $sourceTypes = $this->propertyInfoExtractor + ->getTypes($sourceClass, $sourceProperty); + + if ($sourceTypes === null || count($sourceTypes) === 0) { + $sourceTypes = [MixedType::instance()]; + } + + $targetTypes = $this->propertyInfoExtractor + ->getTypes($targetClass, $targetProperty); + + if ($targetTypes === null || count($targetTypes) === 0) { + $targetTypes = [MixedType::instance()]; + } + + + $results = $this->transformerRegistry + ->findBySourceAndTargetTypes($sourceTypes, $targetTypes); + + foreach ($results as $result) { + $rows[] = [ + $result->getMappingOrder(), + $this->typeResolver->getTypeString($result->getSourceType()), + $this->typeResolver->getTypeString($result->getTargetType()), + $result->getTransformer()::class, + ]; + } + + // + // render + // + + $io->section('Applicable Transformers'); + + if (count($rows) === 0) { + $io->error('No applicable transformers found.'); + + return Command::SUCCESS; + } + + $table = new Table($output); + $table->setVertical(); + $table->setHeaders(['Mapping Order', 'Source Type', 'Target Type', 'Transformer']); + $table->setStyle('box'); + $table->setRows($rows); + $table->render(); + + return Command::SUCCESS; + } +} diff --git a/src/MapperFactory/MapperFactory.php b/src/MapperFactory/MapperFactory.php index 681b1a99..8c8331dc 100644 --- a/src/MapperFactory/MapperFactory.php +++ b/src/MapperFactory/MapperFactory.php @@ -17,6 +17,7 @@ use Psr\Container\ContainerInterface; use Rekalogika\Mapper\Command\MappingCommand; use Rekalogika\Mapper\Command\TryCommand; +use Rekalogika\Mapper\Command\TryPropertyCommand; use Rekalogika\Mapper\MainTransformer\MainTransformer; use Rekalogika\Mapper\Mapper; use Rekalogika\Mapper\MapperInterface; @@ -102,6 +103,7 @@ class MapperFactory private ?MappingCommand $mappingCommand = null; private ?TryCommand $tryCommand = null; + private ?TryPropertyCommand $tryPropertyCommand = null; private ?Application $application = null; /** @@ -527,12 +529,26 @@ protected function getTryCommand(): TryCommand return $this->tryCommand; } + protected function getTryPropertyCommand(): TryPropertyCommand + { + if (null === $this->tryPropertyCommand) { + $this->tryPropertyCommand = new TryPropertyCommand( + $this->getTransformerRegistry(), + $this->getTypeResolver(), + $this->getPropertyInfoExtractor(), + ); + } + + return $this->tryPropertyCommand; + } + public function getApplication(): Application { if (null === $this->application) { $this->application = new Application(); $this->application->add($this->getMappingCommand()); $this->application->add($this->getTryCommand()); + $this->application->add($this->getTryPropertyCommand()); } return $this->application;