vendor/sonata-project/admin-bundle/src/Command/GenerateAdminCommand.php line 35

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of the Sonata Project package.
  5.  *
  6.  * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Sonata\AdminBundle\Command;
  12. use Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle;
  13. use Sonata\AdminBundle\Controller\CRUDController;
  14. use Sonata\AdminBundle\Generator\AdminGenerator;
  15. use Sonata\AdminBundle\Generator\ControllerGenerator;
  16. use Sonata\AdminBundle\Manipulator\ServicesManipulator;
  17. use Sonata\AdminBundle\Model\ModelManagerInterface;
  18. use Symfony\Bundle\FrameworkBundle\Console\Application;
  19. use Symfony\Component\Console\Input\InputArgument;
  20. use Symfony\Component\Console\Input\InputInterface;
  21. use Symfony\Component\Console\Input\InputOption;
  22. use Symfony\Component\Console\Output\OutputInterface;
  23. use Symfony\Component\DependencyInjection\Container;
  24. use Symfony\Component\HttpKernel\Bundle\BundleInterface;
  25. use Symfony\Component\HttpKernel\KernelInterface;
  26. /**
  27.  * @author Marek Stipek <mario.dweller@seznam.cz>
  28.  * @author Simon Cosandey <simon.cosandey@simseo.ch>
  29.  */
  30. class GenerateAdminCommand extends QuestionableCommand
  31. {
  32.     /**
  33.      * @var string[]
  34.      */
  35.     private $managerTypes;
  36.     public function configure()
  37.     {
  38.         $this
  39.             ->setName('sonata:admin:generate')
  40.             ->setDescription('Generates an admin class based on the given model class')
  41.             ->addArgument('model'InputArgument::REQUIRED'The fully qualified model class')
  42.             ->addOption('bundle''b'InputOption::VALUE_OPTIONAL'The bundle name')
  43.             ->addOption('admin''a'InputOption::VALUE_OPTIONAL'The admin class basename')
  44.             ->addOption('controller''c'InputOption::VALUE_OPTIONAL'The controller class basename')
  45.             ->addOption('manager''m'InputOption::VALUE_OPTIONAL'The model manager type')
  46.             ->addOption('services''y'InputOption::VALUE_OPTIONAL'The services YAML file''services.yml')
  47.             ->addOption('id''i'InputOption::VALUE_OPTIONAL'The admin service ID')
  48.         ;
  49.     }
  50.     public function isEnabled()
  51.     {
  52.         return class_exists(SensioGeneratorBundle::class);
  53.     }
  54.     /**
  55.      * @param string $managerType
  56.      *
  57.      * @throws \InvalidArgumentException
  58.      *
  59.      * @return string
  60.      */
  61.     public function validateManagerType($managerType)
  62.     {
  63.         $managerTypes $this->getAvailableManagerTypes();
  64.         if (!isset($managerTypes[$managerType])) {
  65.             throw new \InvalidArgumentException(sprintf(
  66.                 'Invalid manager type "%s". Available manager types are "%s".',
  67.                 $managerType,
  68.                 implode('", "'$managerTypes)
  69.             ));
  70.         }
  71.         return $managerType;
  72.     }
  73.     protected function execute(InputInterface $inputOutputInterface $output)
  74.     {
  75.         $modelClass Validators::validateClass($input->getArgument('model'));
  76.         $modelClassBasename current(\array_slice(explode('\\'$modelClass), -1));
  77.         $bundle $this->getBundle($input->getOption('bundle') ?: $this->getBundleNameFromClass($modelClass));
  78.         $adminClassBasename $input->getOption('admin') ?: $modelClassBasename.'Admin';
  79.         $adminClassBasename Validators::validateAdminClassBasename($adminClassBasename);
  80.         $managerType $input->getOption('manager') ?: $this->getDefaultManagerType();
  81.         $modelManager $this->getModelManager($managerType);
  82.         $skeletonDirectory __DIR__.'/../Resources/skeleton';
  83.         $adminGenerator = new AdminGenerator($modelManager$skeletonDirectory);
  84.         try {
  85.             $adminGenerator->generate($bundle$adminClassBasename$modelClass);
  86.             $output->writeln(sprintf(
  87.                 '%sThe admin class "<info>%s</info>" has been generated under the file "<info>%s</info>".',
  88.                 PHP_EOL,
  89.                 $adminGenerator->getClass(),
  90.                 realpath($adminGenerator->getFile())
  91.             ));
  92.         } catch (\Exception $e) {
  93.             $this->writeError($output$e->getMessage());
  94.         }
  95.         if ($controllerClassBasename $input->getOption('controller')) {
  96.             $controllerClassBasename Validators::validateControllerClassBasename($controllerClassBasename);
  97.             $controllerGenerator = new ControllerGenerator($skeletonDirectory);
  98.             try {
  99.                 $controllerGenerator->generate($bundle$controllerClassBasename);
  100.                 $output->writeln(sprintf(
  101.                     '%sThe controller class "<info>%s</info>" has been generated under the file "<info>%s</info>".',
  102.                     PHP_EOL,
  103.                     $controllerGenerator->getClass(),
  104.                     realpath($controllerGenerator->getFile())
  105.                 ));
  106.             } catch (\Exception $e) {
  107.                 $this->writeError($output$e->getMessage());
  108.             }
  109.         }
  110.         if ($servicesFile $input->getOption('services')) {
  111.             $adminClass $adminGenerator->getClass();
  112.             $file sprintf('%s/Resources/config/%s'$bundle->getPath(), $servicesFile);
  113.             $servicesManipulator = new ServicesManipulator($file);
  114.             $controllerName $controllerClassBasename
  115.                 sprintf('%s:%s'$bundle->getName(), substr($controllerClassBasename0, -10))
  116.                 : CRUDController::class
  117.             ;
  118.             try {
  119.                 $id $input->getOption('id') ?: $this->getAdminServiceId($bundle->getName(), $adminClassBasename);
  120.                 $servicesManipulator->addResource($id$modelClass$adminClass$controllerName$managerType);
  121.                 $output->writeln(sprintf(
  122.                     '%sThe service "<info>%s</info>" has been appended to the file <info>"%s</info>".',
  123.                     PHP_EOL,
  124.                     $id,
  125.                     realpath($file)
  126.                 ));
  127.             } catch (\Exception $e) {
  128.                 $this->writeError($output$e->getMessage());
  129.             }
  130.         }
  131.         return 0;
  132.     }
  133.     protected function interact(InputInterface $inputOutputInterface $output)
  134.     {
  135.         $questionHelper $this->getQuestionHelper();
  136.         $questionHelper->writeSection($output'Welcome to the Sonata admin generator');
  137.         $modelClass $this->askAndValidate(
  138.             $input,
  139.             $output,
  140.             'The fully qualified model class',
  141.             $input->getArgument('model'),
  142.             'Sonata\AdminBundle\Command\Validators::validateClass'
  143.         );
  144.         $modelClassBasename current(\array_slice(explode('\\'$modelClass), -1));
  145.         $bundleName $this->askAndValidate(
  146.             $input,
  147.             $output,
  148.             'The bundle name',
  149.             $input->getOption('bundle') ?: $this->getBundleNameFromClass($modelClass),
  150.             'Sensio\Bundle\GeneratorBundle\Command\Validators::validateBundleName'
  151.         );
  152.         $adminClassBasename $this->askAndValidate(
  153.             $input,
  154.             $output,
  155.             'The admin class basename',
  156.             $input->getOption('admin') ?: $modelClassBasename.'Admin',
  157.             'Sonata\AdminBundle\Command\Validators::validateAdminClassBasename'
  158.         );
  159.         if (\count($this->getAvailableManagerTypes()) > 1) {
  160.             $managerType $this->askAndValidate(
  161.                 $input,
  162.                 $output,
  163.                 'The manager type',
  164.                 $input->getOption('manager') ?: $this->getDefaultManagerType(),
  165.                 [$this'validateManagerType']
  166.             );
  167.             $input->setOption('manager'$managerType);
  168.         }
  169.         if ($this->askConfirmation($input$output'Do you want to generate a controller''no''?')) {
  170.             $controllerClassBasename $this->askAndValidate(
  171.                 $input,
  172.                 $output,
  173.                 'The controller class basename',
  174.                 $input->getOption('controller') ?: $modelClassBasename.'AdminController',
  175.                 'Sonata\AdminBundle\Command\Validators::validateControllerClassBasename'
  176.             );
  177.             $input->setOption('controller'$controllerClassBasename);
  178.         }
  179.         if ($this->askConfirmation($input$output'Do you want to update the services YAML configuration file''yes''?')) {
  180.             $path $this->getBundle($bundleName)->getPath().'/Resources/config/';
  181.             $servicesFile $this->askAndValidate(
  182.                 $input,
  183.                 $output,
  184.                 'The services YAML configuration file',
  185.                 is_file($path.'admin.yml') ? 'admin.yml' 'services.yml',
  186.                 'Sonata\AdminBundle\Command\Validators::validateServicesFile'
  187.             );
  188.             $id $this->askAndValidate(
  189.                 $input,
  190.                 $output,
  191.                 'The admin service ID',
  192.                 $this->getAdminServiceId($bundleName$adminClassBasename),
  193.                 'Sonata\AdminBundle\Command\Validators::validateServiceId'
  194.             );
  195.             $input->setOption('services'$servicesFile);
  196.             $input->setOption('id'$id);
  197.         } else {
  198.             $input->setOption('services'false);
  199.         }
  200.         $input->setArgument('model'$modelClass);
  201.         $input->setOption('admin'$adminClassBasename);
  202.         $input->setOption('bundle'$bundleName);
  203.     }
  204.     /**
  205.      * @throws \InvalidArgumentException
  206.      */
  207.     private function getBundleNameFromClass(string $class): ?string
  208.     {
  209.         $application $this->getApplication();
  210.         /* @var $application Application */
  211.         foreach ($application->getKernel()->getBundles() as $bundle) {
  212.             if (=== strpos($class$bundle->getNamespace().'\\')) {
  213.                 return $bundle->getName();
  214.             }
  215.         }
  216.         return null;
  217.     }
  218.     private function getBundle(string $name): BundleInterface
  219.     {
  220.         return $this->getKernel()->getBundle($name);
  221.     }
  222.     private function writeError(OutputInterface $outputstring $message): void
  223.     {
  224.         $output->writeln(sprintf("\n<error>%s</error>"$message));
  225.     }
  226.     /**
  227.      * @throws \RuntimeException
  228.      */
  229.     private function getDefaultManagerType(): string
  230.     {
  231.         if (!$managerTypes $this->getAvailableManagerTypes()) {
  232.             throw new \RuntimeException('There are no model managers registered.');
  233.         }
  234.         return current($managerTypes);
  235.     }
  236.     private function getModelManager(string $managerType): ModelManagerInterface
  237.     {
  238.         $modelManager $this->getContainer()->get('sonata.admin.manager.'.$managerType);
  239.         \assert($modelManager instanceof ModelManagerInterface);
  240.         return $modelManager;
  241.     }
  242.     private function getAdminServiceId(string $bundleNamestring $adminClassBasename): string
  243.     {
  244.         $prefix 'Bundle' === substr($bundleName, -6) ? substr($bundleName0, -6) : $bundleName;
  245.         $suffix 'Admin' === substr($adminClassBasename, -5) ? substr($adminClassBasename0, -5) : $adminClassBasename;
  246.         $suffix str_replace('\\''.'$suffix);
  247.         return Container::underscore(sprintf(
  248.             '%s.admin.%s',
  249.             $prefix,
  250.             $suffix
  251.         ));
  252.     }
  253.     /**
  254.      * @return string[]
  255.      */
  256.     private function getAvailableManagerTypes(): array
  257.     {
  258.         $container $this->getContainer();
  259.         if (!$container instanceof Container) {
  260.             return [];
  261.         }
  262.         if (null === $this->managerTypes) {
  263.             $this->managerTypes = [];
  264.             foreach ($container->getServiceIds() as $id) {
  265.                 if (=== strpos($id'sonata.admin.manager.')) {
  266.                     $managerType substr($id21);
  267.                     $this->managerTypes[$managerType] = $managerType;
  268.                 }
  269.             }
  270.         }
  271.         return $this->managerTypes;
  272.     }
  273.     private function getKernel(): KernelInterface
  274.     {
  275.         /* @var $application Application */
  276.         $application $this->getApplication();
  277.         return $application->getKernel();
  278.     }
  279. }