From 1c0726275a92cfff91a1edce5780f875c78cceed Mon Sep 17 00:00:00 2001 From: Benjamin Kott Date: Mon, 25 Nov 2024 08:14:29 +0100 Subject: [PATCH] [WIP][TASK] Detect basepackages @todo add validation @check endpoints --- composer.json | 1 + composer.lock | 26 ++-- phpstan-baseline.neon | 6 + .../packages/bootstrap_package/config.yaml | 1 + .../packages/fluid_styled_content/config.yaml | 1 + src/Command/BasepackagesCommand.php | 67 +++++++++ src/Entity/Sitepackage/Basepackage.php | 93 +++++++++++++ src/Entity/Sitepackage/BasepackageVersion.php | 41 ++++++ src/Form/SitepackageType.php | 27 ++-- src/Service/SitepackageBaseService.php | 131 ++++++++++++++++++ 10 files changed, 371 insertions(+), 23 deletions(-) create mode 100644 resources/packages/bootstrap_package/config.yaml create mode 100644 resources/packages/fluid_styled_content/config.yaml create mode 100644 src/Command/BasepackagesCommand.php create mode 100644 src/Entity/Sitepackage/Basepackage.php create mode 100644 src/Entity/Sitepackage/BasepackageVersion.php create mode 100644 src/Service/SitepackageBaseService.php diff --git a/composer.json b/composer.json index 403004e7..6e700082 100644 --- a/composer.json +++ b/composer.json @@ -67,6 +67,7 @@ "symfony/dependency-injection": "^6.2", "symfony/dotenv": "^6.2", "symfony/expression-language": "^6.2", + "symfony/finder": "^6.2", "symfony/flex": "^2.2", "symfony/form": "^6.2", "symfony/framework-bundle": "^6.2", diff --git a/composer.lock b/composer.lock index 21fb583a..224c3795 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7339b545be1829fa90a1f0746acd4204", + "content-hash": "ad17535462042e65c82825143926935c", "packages": [ { "name": "composer/ca-bundle", @@ -5084,16 +5084,16 @@ }, { "name": "symfony/finder", - "version": "v6.4.7", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "511c48990be17358c23bf45c5d71ab85d40fb764" + "reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/511c48990be17358c23bf45c5d71ab85d40fb764", - "reference": "511c48990be17358c23bf45c5d71ab85d40fb764", + "url": "https://api.github.com/repos/symfony/finder/zipball/daea9eca0b08d0ed1dc9ab702a46128fd1be4958", + "reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958", "shasum": "" }, "require": { @@ -5128,7 +5128,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.7" + "source": "https://github.com/symfony/finder/tree/v6.4.13" }, "funding": [ { @@ -5144,7 +5144,7 @@ "type": "tidelift" } ], - "time": "2024-04-23T10:36:43+00:00" + "time": "2024-10-01T08:30:56+00:00" }, { "name": "symfony/flex", @@ -8515,16 +8515,16 @@ }, { "name": "symfony/yaml", - "version": "v6.4.7", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "53e8b1ef30a65f78eac60fddc5ee7ebbbdb1dee0" + "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/53e8b1ef30a65f78eac60fddc5ee7ebbbdb1dee0", - "reference": "53e8b1ef30a65f78eac60fddc5ee7ebbbdb1dee0", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e99b4e94d124b29ee4cf3140e1b537d2dad8cec9", + "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9", "shasum": "" }, "require": { @@ -8567,7 +8567,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.7" + "source": "https://github.com/symfony/yaml/tree/v6.4.13" }, "funding": [ { @@ -8583,7 +8583,7 @@ "type": "tidelift" } ], - "time": "2024-04-28T10:28:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "t3g/symfony-template-bundle", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index b5f24234..d75dff7f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -294,6 +294,12 @@ parameters: count: 1 path: src/Service/ComposerPackagesService.php + - + message: '#^Method App\\Service\\SitepackageBaseService\:\:getBasepackageVersionChoices\(\) should return array\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Service/SitepackageBaseService.php + - message: '#^Parameter \#1 \$releases of method App\\Twig\\Filter\\SortByVersion\:\:sort\(\) expects Doctrine\\Common\\Collections\\Collection\, mixed given\.$#' identifier: argument.type diff --git a/resources/packages/bootstrap_package/config.yaml b/resources/packages/bootstrap_package/config.yaml new file mode 100644 index 00000000..1f337636 --- /dev/null +++ b/resources/packages/bootstrap_package/config.yaml @@ -0,0 +1 @@ +label: Bootstrap Package diff --git a/resources/packages/fluid_styled_content/config.yaml b/resources/packages/fluid_styled_content/config.yaml new file mode 100644 index 00000000..84c5a0ce --- /dev/null +++ b/resources/packages/fluid_styled_content/config.yaml @@ -0,0 +1 @@ +label: Fluid Styled Content diff --git a/src/Command/BasepackagesCommand.php b/src/Command/BasepackagesCommand.php new file mode 100644 index 00000000..c4878ad7 --- /dev/null +++ b/src/Command/BasepackagesCommand.php @@ -0,0 +1,67 @@ +setDescription('Display all available Basepackages.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $packages = $this->sitepackageBaseService->getPackages(); + + $rows = []; + foreach ($packages as $package) { + $rows[] = [ + $package->getIdentifier(), + $package->getLabel(), + implode(', ', array_map(static fn(BasepackageVersion $version): float => $version->getVersion(), $package->getVersions()->toArray())), + ]; + } + + $table = new Table($output); + $table->setHeaders(['Identifier', 'Label', 'Versions']); + $table->setRows($rows); + $table->render(); + + return self::SUCCESS; + } +} diff --git a/src/Entity/Sitepackage/Basepackage.php b/src/Entity/Sitepackage/Basepackage.php new file mode 100644 index 00000000..4ded9dc6 --- /dev/null +++ b/src/Entity/Sitepackage/Basepackage.php @@ -0,0 +1,93 @@ + + */ + protected ArrayCollection $versions; + + public function __construct() + { + $this->versions = new ArrayCollection(); + } + + public function getIdentifier(): string + { + return $this->identifier; + } + + public function setIdentifier(string $identifier): self + { + $this->identifier = $identifier; + + return $this; + } + + public function getLabel(): string + { + return $this->label; + } + + public function setLabel(string $label): self + { + $this->label = $label; + + return $this; + } + + /** + * @return ArrayCollection + */ + public function getVersions(): ArrayCollection + { + return $this->versions->matching(new Criteria(null, ['version' => Criteria::DESC])); + } + + public function addVersion(BasepackageVersion $version): self + { + if (!$this->versions->contains($version)) { + $this->versions[] = $version; + } + + return $this; + } + + public function removeVersion(BasepackageVersion $version): static + { + if ($this->versions->contains($version)) { + $this->versions->removeElement($version); + } + + return $this; + } +} diff --git a/src/Entity/Sitepackage/BasepackageVersion.php b/src/Entity/Sitepackage/BasepackageVersion.php new file mode 100644 index 00000000..92fa17b6 --- /dev/null +++ b/src/Entity/Sitepackage/BasepackageVersion.php @@ -0,0 +1,41 @@ +version; + } + + public function setVersion(float $version): self + { + $this->version = $version; + + return $this; + } +} diff --git a/src/Form/SitepackageType.php b/src/Form/SitepackageType.php index 3c5bf884..6a9b0396 100644 --- a/src/Form/SitepackageType.php +++ b/src/Form/SitepackageType.php @@ -24,7 +24,9 @@ namespace App\Form; use App\Entity\Sitepackage; +use App\Service\SitepackageBaseService; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -33,29 +35,34 @@ class SitepackageType extends AbstractType { + private SitepackageBaseService $sitepackageBaseService; + + public function __construct(SitepackageBaseService $sitepackageBaseService) + { + $this->sitepackageBaseService = $sitepackageBaseService; + } + /** * @param array $options */ public function buildForm(FormBuilderInterface $builder, array $options): void { + $sitepackageBaseService = $this->sitepackageBaseService; + $builder ->setAction($options['action']) ->add('basePackage', ChoiceType::class, [ 'label' => 'Base Package', - 'choices' => [ - 'Bootstrap Package' => 'bootstrap_package', - 'Fluid Styled Content' => 'fluid_styled_content', - ], + 'choice_loader' => new CallbackChoiceLoader(static function () use ($sitepackageBaseService): array { + return $sitepackageBaseService->getBasepackageChoices(); + }), 'expanded' => true, ]) ->add('typo3Version', ChoiceType::class, [ 'label' => 'TYPO3 Version', - 'choices' => [ - '13.4 (Beta)' => 13.4, - '12.4' => 12.4, - '11.5' => 11.5, - '10.4' => 10.4, - ], + 'choice_loader' => new CallbackChoiceLoader(static function () use ($sitepackageBaseService): array { + return $sitepackageBaseService->getBasepackageVersionChoices(); + }), 'expanded' => true, ]) ->add('title', TextType::class, [ diff --git a/src/Service/SitepackageBaseService.php b/src/Service/SitepackageBaseService.php new file mode 100644 index 00000000..293ef8f4 --- /dev/null +++ b/src/Service/SitepackageBaseService.php @@ -0,0 +1,131 @@ +kernel = $kernel; + $this->cache = $cache; + } + + /** + * @return ArrayCollection + */ + public function getPackages(): ArrayCollection + { + $cache = $this->cache->getItem('sitepackagegenerator.basepackages'); + if (!$cache->isHit()) { + $cache->set($this->generatePackages()); + } + + /** @var ArrayCollection $data */ + $data = $cache->get(); + + return $data; + } + + /** + * @return array + */ + public function getBasepackageChoices(): array + { + $choices = []; + foreach ($this->getPackages() as $package) { + $choices[$package->getLabel()] = $package->getIdentifier(); + } + + /** @var array $choices */ + return $choices; + } + + /** + * @return array + */ + public function getBasepackageVersionChoices(): array + { + /** @var array $choices */ + $choices = []; + + /** @var Basepackage $package */ + foreach ($this->getPackages() as $package) { + /** @var BasepackageVersion $version */ + foreach ($package->getVersions() as $version) { + $choices[(string)$version->getVersion()] = $version->getVersion(); + } + } + krsort($choices); + + return $choices; + } + + /** + * @return ArrayCollection + */ + protected function generatePackages(): ArrayCollection + { + $finder = new Finder(); + $finder->directories()->in($this->kernel->getProjectDir() . '/resources/packages')->depth('== 0'); + + $collection = new ArrayCollection(); + foreach ($finder as $folder) { + $identifier = $folder->getFilename(); + $path = $folder->getPathname(); + $configFile = $path . '/config.yaml'; + + if (file_exists($configFile)) { + /** @var array{'label': string} $config */ + $config = Yaml::parseFile($configFile); + + $basepackage = new Basepackage(); + $basepackage->setIdentifier($identifier); + $basepackage->setLabel($config['label'] ?? $identifier); + + $versionFinder = new Finder(); + $versionFinder->directories()->in($folder->getPathname())->depth('== 0'); + foreach ($versionFinder as $versionFolder) { + $versionNumber = (float)($versionFolder->getFilename()); + $basepackageVersion = new BasepackageVersion(); + $basepackageVersion->setVersion($versionNumber); + $basepackage->addVersion($basepackageVersion); + } + $collection->add($basepackage); + } + } + + return $collection; + } +}