diff --git a/config/services.yaml b/config/services.yaml index 8390dfb10..cfe7636d1 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -60,6 +60,10 @@ services: tags: - { name: doctrine.event_listener, event: loadClassMetadata } + Bolt\Event\Listener\TaxonomyFillListener: + tags: + - { name: doctrine.event_listener, event: postLoad } + Bolt\Extension\RoutesLoader: tags: [routing.loader] diff --git a/src/Configuration/Content/TaxonomyType.php b/src/Configuration/Content/TaxonomyType.php new file mode 100644 index 000000000..54cfba798 --- /dev/null +++ b/src/Configuration/Content/TaxonomyType.php @@ -0,0 +1,50 @@ +get($name); + } + + public static function factory(?string $name, Collection $taxonomyTypesConfig): self + { + if ($taxonomyTypesConfig->has($name)) { + return new self($taxonomyTypesConfig->get($name)); + } + + $taxonomyType = $taxonomyTypesConfig + ->filter(function (Collection $taxonomyTypeConfig) use ($name): bool { + return $taxonomyTypeConfig['singular_slug'] === $name; + }) + ->map(function (Collection $taxonomyTypeConfig): self { + return new self($taxonomyTypeConfig); + }) + ->first(); + + if ($taxonomyType) { + return $taxonomyType; + } + + return new self([ + 'name' => $name, + 'slug' => $name, + 'singular_slug' => $name, + 'singular_name' => $name, + // when it is created on the fly + 'virtual' => true, + ]); + } + + public function getSlug(): string + { + return $this->get('slug'); + } +} diff --git a/src/Entity/Taxonomy.php b/src/Entity/Taxonomy.php index 90a677c00..1467f900a 100644 --- a/src/Entity/Taxonomy.php +++ b/src/Entity/Taxonomy.php @@ -5,10 +5,12 @@ namespace Bolt\Entity; use Bolt\Common\Str; +use Bolt\Configuration\Content\TaxonomyType; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; +use Tightenco\Collect\Support\Collection as LaravelCollection; /** * @ORM\Entity(repositoryClass="Bolt\Repository\TaxonomyRepository") @@ -50,9 +52,17 @@ class Taxonomy */ private $sortorder = 0; - public function __construct() + /** @var TaxonomyType|null */ + private $taxonomyTypeDefinition = null; + + public function __construct(?TaxonomyType $taxonomyTypeDefinition = null) { $this->content = new ArrayCollection(); + + if ($taxonomyTypeDefinition) { + $this->setType($taxonomyTypeDefinition->getSlug()); + $this->setDefinition($taxonomyTypeDefinition); + } } public function getId(): ?int @@ -60,6 +70,14 @@ public function getId(): ?int return $this->id; } + /** + * @see \Bolt\Event\Listener\TaxonomyFillListener + */ + public function setDefinitionFromTaxonomyTypesConfig(LaravelCollection $taxonomyTypesConfig): void + { + $this->taxonomyTypeDefinition = TaxonomyType::factory($this->type, $taxonomyTypesConfig); + } + /** * @return Collection|Content[] */ @@ -86,6 +104,24 @@ public function removeContent(Content $content): self return $this; } + public function getTaxonomyTypeSlug(): string + { + if ($this->getDefinition() === null) { + throw new \RuntimeException('Taxonomy not fully initialized'); + } + + return $this->getDefinition()->get('slug'); + } + + public function getTaxonomyTypeSingularSlug(): string + { + if ($this->getDefinition() === null) { + throw new \RuntimeException('Taxonomy not fully initialized'); + } + + return $this->getDefinition()->get('singular_slug'); + } + public function getType(): ?string { return $this->type; @@ -133,4 +169,17 @@ public function setSortorder(int $sortorder): self return $this; } + + public function setDefinition(TaxonomyType $taxonomyType): void + { + $this->taxonomyTypeDefinition = $taxonomyType; + } + + /** + * @Groups("get_definition") + */ + public function getDefinition(): ?TaxonomyType + { + return $this->taxonomyTypeDefinition; + } } diff --git a/src/Event/Listener/TaxonomyFillListener.php b/src/Event/Listener/TaxonomyFillListener.php new file mode 100644 index 000000000..4d8b07aad --- /dev/null +++ b/src/Event/Listener/TaxonomyFillListener.php @@ -0,0 +1,34 @@ +config = $config; + } + + public function postLoad(LifecycleEventArgs $args): void + { + $entity = $args->getEntity(); + + if ($entity instanceof Taxonomy) { + $this->fillTaxonomy($entity); + } + } + + public function fillTaxonomy(Taxonomy $entity): void + { + $entity->setDefinitionFromTaxonomyTypesConfig($this->config->get('taxonomies')); + } +} diff --git a/src/Twig/ContentExtension.php b/src/Twig/ContentExtension.php index 5be1c0028..43f366bba 100644 --- a/src/Twig/ContentExtension.php +++ b/src/Twig/ContentExtension.php @@ -384,7 +384,7 @@ public function getLink($contentOrTaxonomy, bool $canonical = false, ?string $lo if ($contentOrTaxonomy instanceof Taxonomy) { return $this->urlGenerator->generate('taxonomy', [ - 'taxonomyslug' => $contentOrTaxonomy->getType(), + 'taxonomyslug' => $contentOrTaxonomy->getTaxonomyTypeSingularSlug(), 'slug' => $contentOrTaxonomy->getSlug(), ]); } diff --git a/src/Twig/TextExtension.php b/src/Twig/TextExtension.php index 1dbd57afb..1f2df8389 100644 --- a/src/Twig/TextExtension.php +++ b/src/Twig/TextExtension.php @@ -97,7 +97,7 @@ public function urlDecode(string $string) foreach (explode('&', $string) as $chunk) { $param = explode('=', $chunk); - if ($param) { + if (! empty($param)) { $params[urldecode($param[0])] = urldecode($param[1]); } }