301 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
		
		
			
		
	
	
			301 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
|  | .. raw:: pdf
 | ||
|  | 
 | ||
|  |    PageBreak titlePage
 | ||
|  | 
 | ||
|  | .. class:: centredtitle
 | ||
|  | 
 | ||
|  | Build Configs internals
 | ||
|  | 
 | ||
|  | .. raw:: pdf
 | ||
|  | 
 | ||
|  |    PageBreak standardPage
 | ||
|  | 
 | ||
|  | .. code-block::
 | ||
|  | 
 | ||
|  |    src/
 | ||
|  |        Action/
 | ||
|  |            CreateFinalConfigurationData.php
 | ||
|  |            CreateListOfFilesToGenerate.php
 | ||
|  |            GenerateConfigurationFiles.php
 | ||
|  |            ValidateConfigurationData.php
 | ||
|  |        Command/
 | ||
|  |            GenerateCommand.php
 | ||
|  |            InitCommand.php
 | ||
|  |        DataTransferObject/
 | ||
|  |            ConfigDto.php
 | ||
|  |            TemplateFile.php
 | ||
|  |        Enum/
 | ||
|  |            Language.php
 | ||
|  |            ProjectType.php
 | ||
|  |            WebServer.php
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    protected function configure(): void
 | ||
|  |        $this
 | ||
|  |            ->addOption(
 | ||
|  |                name: 'config-file',
 | ||
|  |                shortcut: ['c'],
 | ||
|  |                mode: InputOption::VALUE_REQUIRED,
 | ||
|  |                description: 'The path to the project\'s build.yaml file',
 | ||
|  |                default: 'build.yaml',
 | ||
|  |            )
 | ||
|  |            ->addOption(
 | ||
|  |                name: 'output-dir',
 | ||
|  |                shortcut: ['o'],
 | ||
|  |                mode: InputOption::VALUE_REQUIRED,
 | ||
|  |                description: 'The directory to create files in',
 | ||
|  |                default: '.',
 | ||
|  |            );
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    protected function execute(InputInterface $input, OutputInterface $output): int
 | ||
|  |    {
 | ||
|  |       $io = new SymfonyStyle($input, $output);
 | ||
|  | 
 | ||
|  |       $configFile = $input->getOption(name: 'config-file');
 | ||
|  |       $outputDir = $input->getOption(name: 'output-dir');
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. raw:: pdf
 | ||
|  | 
 | ||
|  |    PageBreak
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    protected function execute(InputInterface $input, OutputInterface $output): int
 | ||
|  |    {
 | ||
|  |       // ...
 | ||
|  | 
 | ||
|  |       $pipelines = [
 | ||
|  |           new CreateFinalConfigurationData(),
 | ||
|  |  
 | ||
|  |           new ValidateConfigurationData(),
 | ||
|  |  
 | ||
|  |           new CreateListOfFilesToGenerate(),
 | ||
|  |  
 | ||
|  |           new GenerateConfigurationFiles(
 | ||
|  |               $this->filesystem,
 | ||
|  |               $this->twig,
 | ||
|  |               $outputDir,
 | ||
|  |           ),
 | ||
|  |       ];
 | ||
|  |     }
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    protected function execute(InputInterface $input, OutputInterface $output): int
 | ||
|  |    {
 | ||
|  |        // ...
 | ||
|  | 
 | ||
|  |        /**
 | ||
|  |         * @var Collection<int,TemplateFile> $generatedFiles
 | ||
|  |         * @var ConfigDto $configurationData
 | ||
|  |         */
 | ||
|  |        [$configurationData, $generatedFiles] = (new Pipeline())
 | ||
|  |            ->send($configFile)
 | ||
|  |            ->through($pipelines)
 | ||
|  |            ->thenReturn();
 | ||
|  | 
 | ||
|  |        $io->info("Building configuration for {$configurationData->name}.");
 | ||
|  | 
 | ||
|  |        $io->write('Generated files:');
 | ||
|  |        $io->listing(static::getListOfFiles(filesToGenerate: $generatedFiles)->toArray());
 | ||
|  | 
 | ||
|  |        return Command::SUCCESS;
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    // CreateFinalConfigurationData.php
 | ||
|  | 
 | ||
|  |    public function handle(string $configFile, \Closure $next) {
 | ||
|  |    {
 | ||
|  |        $configurationData = Yaml::parseFile(filename: $configFile);
 | ||
|  | 
 | ||
|  |        $configurationData = array_replace_recursive(
 | ||
|  |            Yaml::parseFile(filename: __DIR__ . '/../../resources/build.defaults.yaml'),
 | ||
|  |            $configurationData,
 | ||
|  |        );
 | ||
|  | 
 | ||
|  |        // ...
 | ||
|  | 
 | ||
|  |        return $next($configurationData);
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. raw:: pdf
 | ||
|  | 
 | ||
|  |    PageBreak
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    // ValidateConfigurationData.php
 | ||
|  | 
 | ||
|  |    public function handle(array $configurationData, \Closure $next)
 | ||
|  |    {
 | ||
|  |        // Convert the input to a configuration data object.
 | ||
|  |        $normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter());
 | ||
|  |        $serializer = new Serializer([$normalizer], [new JsonEncoder()]);
 | ||
|  | 
 | ||
|  |        $configurationDataDto = $serializer->deserialize(
 | ||
|  |            json_encode($configurationData),
 | ||
|  |            ConfigDto::class,
 | ||
|  |            'json',
 | ||
|  |        );
 | ||
|  | 
 | ||
|  |        // ...
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. raw:: pdf
 | ||
|  | 
 | ||
|  |    PageBreak
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    // ValidateConfigurationData.php
 | ||
|  | 
 | ||
|  |    public function handle(array $configurationData, \Closure $next)
 | ||
|  |    {
 | ||
|  |        // ...
 | ||
|  | 
 | ||
|  |        $validator = Validation::createValidatorBuilder()
 | ||
|  |            ->enableAnnotationMapping()
 | ||
|  |            ->getValidator();
 | ||
|  |        $violations = $validator->validate($configurationDataDto);
 | ||
|  | 
 | ||
|  |        if (0 < $violations->count()) {
 | ||
|  |            throw new \RuntimeException('Configuration is invalid.');
 | ||
|  |        }
 | ||
|  | 
 | ||
|  |        return $next([$configurationData, $configurationDataDto]);
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    // ConfigDto.php
 | ||
|  | 
 | ||
|  |    #[Assert\Collection(
 | ||
|  |         allowExtraFields: false,
 | ||
|  |         fields: ['docroot' => new Assert\Choice([null, 'web', 'docroot'])],
 | ||
|  |     )]
 | ||
|  |     public array $drupal;
 | ||
|  | 
 | ||
|  |     #[Assert\Collection([
 | ||
|  |         'ignore' => new Assert\Optional([
 | ||
|  |             new Assert\All([
 | ||
|  |                 new Assert\Type('string'),
 | ||
|  |             ]),
 | ||
|  |         ]),
 | ||
|  |     ])]
 | ||
|  |     public array $git;
 | ||
|  | 
 | ||
|  |     #[Assert\Choice(choices: ['javascript', 'php', 'typescript'])]
 | ||
|  |     public string $language;
 | ||
|  | 
 | ||
|  |     #[Assert\NotBlank]
 | ||
|  |     #[Assert\Type('string')]
 | ||
|  |     public string $name;
 | ||
|  | 
 | ||
|  |     #[Assert\Type('string')]
 | ||
|  |     public string $projectRoot;
 | ||
|  | 
 | ||
|  |     #[Assert\Choice(choices: [
 | ||
|  |         'drupal',
 | ||
|  |         'fractal',
 | ||
|  |         'php-library',
 | ||
|  |         'symfony',
 | ||
|  |    ])]
 | ||
|  |    public string $type;
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :startinline: true
 | ||
|  |    :linenos: | ||
|  | 
 | ||
|  |    // CreateListOfFilesToGenerate.php
 | ||
|  | 
 | ||
|  |    public function handle(array $configurationDataAndDto, \Closure $next)
 | ||
|  |    {
 | ||
|  |        /**
 | ||
|  |          * @var ConfigDto $configDto,
 | ||
|  |          * @var array<string,mixed> $configurationData
 | ||
|  |          */
 | ||
|  |         [$configurationData, $configDto] = $configurationDataAndDto;
 | ||
|  | 
 | ||
|  |         /** @var Collection<int, TemplateFile> */
 | ||
|  |         $filesToGenerate = collect();
 | ||
|  | 
 | ||
|  |         // ...
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :startinline: true
 | ||
|  |    :linenos: | ||
|  | 
 | ||
|  |    // CreateListOfFilesToGenerate.php
 | ||
|  | 
 | ||
|  |    public function handle(array $configurationDataAndDto, \Closure $next)
 | ||
|  |    {
 | ||
|  |        // ...
 | ||
|  | 
 | ||
|  |        if (!isset($configDto->php['phpunit']) || $configDto->php['phpunit'] !== false) {
 | ||
|  | 
 | ||
|  |            $filesToGenerate->push(
 | ||
|  |                new TemplateFile(
 | ||
|  |                    data: 'drupal/phpunit.xml.dist',
 | ||
|  |                    name: 'phpunit.xml.dist',
 | ||
|  |                )
 | ||
|  |            );
 | ||
|  |        }
 | ||
|  | 
 | ||
|  |        // ...
 | ||
|  | 
 | ||
|  |        return $next([$configurationData, $configDto, $filesToGenerate]);
 | ||
|  |    }
 | ||
|  | 
 | ||
|  | .. code-block:: php
 | ||
|  |    :linenos: | ||
|  |    :startinline: true
 | ||
|  | 
 | ||
|  |    // GenerateConfigurationFiles.php
 | ||
|  | 
 | ||
|  |    public function handle(array $filesToGenerateAndConfigurationData, \Closure $next)
 | ||
|  |    {
 | ||
|  |        // ...
 | ||
|  | 
 | ||
|  |        $filesToGenerate->each(function(TemplateFile $templateFile) use ($configurationData): void {
 | ||
|  |            if ($templateFile->path !== null) {
 | ||
|  |                if (!$this->filesystem->exists($templateFile->path)) {
 | ||
|  |                    $this->filesystem->mkdir("{$this->outputDir}/{$templateFile->path}");
 | ||
|  |                }
 | ||
|  |            }
 | ||
|  | 
 | ||
|  |            $sourceFile = "{$templateFile->data}.twig";
 | ||
|  | 
 | ||
|  |            $outputFile = collect([$this->outputDir, $templateFile->path, $templateFile->name])
 | ||
|  |                ->filter()->implode('/');
 | ||
|  | 
 | ||
|  |            $this->filesystem->dumpFile($outputFile, $this->twig->render($sourceFile, $configurationData));
 | ||
|  |        });
 | ||
|  | 
 | ||
|  |        return $next([$configurationDataDto, $filesToGenerate]);
 | ||
|  |    }
 | ||
|  | 
 |