vendor/ibexa/taxonomy/src/lib/Event/Subscriber/ContentTypeEventsSubscriber.php line 63

Open in your IDE?
  1. <?php
  2. /**
  3. * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4. * @license For full copyright and license information view LICENSE file distributed with this source code.
  5. */
  6. declare(strict_types=1);
  7. namespace Ibexa\Taxonomy\Event\Subscriber;
  8. use Ibexa\Contracts\Core\Repository\Events\ContentType\BeforeRemoveFieldDefinitionEvent;
  9. use Ibexa\Contracts\Core\Repository\Events\ContentType\BeforeUpdateFieldDefinitionEvent;
  10. use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeDraft;
  11. use Ibexa\Core\Base\Exceptions\InvalidArgumentException;
  12. use Ibexa\Taxonomy\Service\TaxonomyConfiguration;
  13. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  14. /**
  15. * Throws validation errors when Taxonomy fieldtypes are removed from content type.
  16. *
  17. * This prevents system from becoming corrupted due to broken Taxonomy content type.
  18. *
  19. * @internal
  20. */
  21. final class ContentTypeEventsSubscriber implements EventSubscriberInterface
  22. {
  23. private TaxonomyConfiguration $taxonomyConfiguration;
  24. public function __construct(
  25. TaxonomyConfiguration $taxonomyConfiguration
  26. ) {
  27. $this->taxonomyConfiguration = $taxonomyConfiguration;
  28. }
  29. public static function getSubscribedEvents(): array
  30. {
  31. return [
  32. BeforeRemoveFieldDefinitionEvent::class => 'onRemoveFieldDefinition',
  33. BeforeUpdateFieldDefinitionEvent::class => 'onUpdateFieldDefinition',
  34. ];
  35. }
  36. public function onRemoveFieldDefinition(BeforeRemoveFieldDefinitionEvent $event): void
  37. {
  38. $taxonomy = $this->getTaxonomy($event->getContentTypeDraft());
  39. if (null === $taxonomy) {
  40. return;
  41. }
  42. $fieldMappings = $this->taxonomyConfiguration->getFieldMappings($taxonomy);
  43. $fieldDefinition = $event->getFieldDefinition();
  44. if (!in_array($fieldDefinition->identifier, $fieldMappings, true)) {
  45. return;
  46. }
  47. throw new InvalidArgumentException(
  48. '$fieldDefinition',
  49. 'Cannot remove field definitions used by Taxonomy content type',
  50. );
  51. }
  52. public function onUpdateFieldDefinition(BeforeUpdateFieldDefinitionEvent $event): void
  53. {
  54. $taxonomy = $this->getTaxonomy($event->getContentTypeDraft());
  55. if (null === $taxonomy) {
  56. return;
  57. }
  58. $fieldMappings = $this->taxonomyConfiguration->getFieldMappings($taxonomy);
  59. $fieldDefinition = $event->getFieldDefinition();
  60. if (!in_array($fieldDefinition->identifier, $fieldMappings, true)) {
  61. return;
  62. }
  63. $fieldDefinitionUpdateStruct = $event->getFieldDefinitionUpdateStruct();
  64. if (
  65. null !== $fieldDefinitionUpdateStruct->identifier
  66. && $fieldDefinitionUpdateStruct->identifier !== $fieldDefinition->identifier
  67. ) {
  68. throw new InvalidArgumentException(
  69. '$fieldDefinition',
  70. 'Cannot change field definition identifier used by Taxonomy content type',
  71. );
  72. }
  73. // additional validation for identifier and parent
  74. if (
  75. $fieldDefinition->identifier === $fieldMappings['identifier']
  76. || $fieldDefinition->identifier === $fieldMappings['parent']
  77. ) {
  78. if (
  79. null !== $fieldDefinitionUpdateStruct->isRequired
  80. && $fieldDefinition->isRequired !== $fieldDefinitionUpdateStruct->isRequired
  81. ) {
  82. throw new InvalidArgumentException(
  83. '$fieldDefinition',
  84. 'Cannot change isRequired flag on field definition used by Taxonomy content type',
  85. );
  86. }
  87. if ($fieldDefinitionUpdateStruct->isTranslatable === true) {
  88. throw new InvalidArgumentException(
  89. '$fieldDefinition',
  90. 'Cannot change isTranslatable flag on field definition used by Taxonomy content type',
  91. );
  92. }
  93. }
  94. }
  95. private function getTaxonomy(ContentTypeDraft $contentTypeDraft): ?string
  96. {
  97. if (!$this->taxonomyConfiguration->isContentTypeAssociatedWithTaxonomy($contentTypeDraft)) {
  98. return null;
  99. }
  100. return $this->taxonomyConfiguration->getTaxonomyForContentType($contentTypeDraft);
  101. }
  102. }