vendor/gedmo/doctrine-extensions/src/Translatable/Mapping/Driver/Attribute.php line 52

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Doctrine Behavioral Extensions package.
  4. * (c) Gediminas Morkevicius <gediminas.morkevicius@gmail.com> http://www.gediminasm.org
  5. * For the full copyright and license information, please view the LICENSE
  6. * file that was distributed with this source code.
  7. */
  8. namespace Gedmo\Translatable\Mapping\Driver;
  9. use Gedmo\Exception\InvalidMappingException;
  10. use Gedmo\Mapping\Annotation\Language;
  11. use Gedmo\Mapping\Annotation\Locale;
  12. use Gedmo\Mapping\Annotation\Translatable;
  13. use Gedmo\Mapping\Annotation\TranslationEntity;
  14. use Gedmo\Mapping\Driver\AbstractAnnotationDriver;
  15. /**
  16. * Mapping driver for the translatable extension which reads extended metadata from annotations on a translatable class.
  17. *
  18. * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  19. *
  20. * @internal
  21. */
  22. class Attribute extends AbstractAnnotationDriver
  23. {
  24. /**
  25. * Mapping object to configure the translation model for a translatable class.
  26. */
  27. public const ENTITY_CLASS = TranslationEntity::class;
  28. /**
  29. * Mapping object to identify a field as translatable in a translatable class.
  30. */
  31. public const TRANSLATABLE = Translatable::class;
  32. /**
  33. * Mapping object to identify the field which stores the locale or language for the translation.
  34. *
  35. * This object is an alias of {@see self::LANGUAGE}
  36. */
  37. public const LOCALE = Locale::class;
  38. /**
  39. * Mapping object to identify the field which stores the locale or language for the translation.
  40. *
  41. * This object is an alias of {@see self::LOCALE}
  42. */
  43. public const LANGUAGE = Language::class;
  44. public function readExtendedMetadata($meta, array &$config)
  45. {
  46. $class = $this->getMetaReflectionClass($meta);
  47. // class annotations
  48. if ($annot = $this->reader->getClassAnnotation($class, self::ENTITY_CLASS)) {
  49. \assert($annot instanceof TranslationEntity);
  50. if (!$cl = $this->getRelatedClassName($meta, $annot->class)) {
  51. throw new InvalidMappingException("Translation class: {$annot->class} does not exist.");
  52. }
  53. $config['translationClass'] = $cl;
  54. }
  55. // property annotations
  56. foreach ($class->getProperties() as $property) {
  57. if ($meta->isMappedSuperclass && !$property->isPrivate()
  58. || $meta->isInheritedField($property->name)
  59. || isset($meta->associationMappings[$property->name]['inherited'])
  60. ) {
  61. continue;
  62. }
  63. // translatable property
  64. if ($translatable = $this->reader->getPropertyAnnotation($property, self::TRANSLATABLE)) {
  65. \assert($translatable instanceof Translatable);
  66. $field = $property->getName();
  67. if (!$meta->hasField($field)) {
  68. throw new InvalidMappingException("Unable to find translatable [{$field}] as mapped property in entity - {$meta->getName()}");
  69. }
  70. // fields cannot be overrided and throws mapping exception
  71. $config['fields'][] = $field;
  72. if (isset($translatable->fallback)) {
  73. $config['fallback'][$field] = $translatable->fallback;
  74. }
  75. }
  76. // locale property
  77. if ($this->reader->getPropertyAnnotation($property, self::LOCALE)) {
  78. $field = $property->getName();
  79. if ($meta->hasField($field)) {
  80. throw new InvalidMappingException("Locale field [{$field}] should not be mapped as column property in entity - {$meta->getName()}, since it makes no sense");
  81. }
  82. $config['locale'] = $field;
  83. } elseif ($this->reader->getPropertyAnnotation($property, self::LANGUAGE)) {
  84. $field = $property->getName();
  85. if ($meta->hasField($field)) {
  86. throw new InvalidMappingException("Language field [{$field}] should not be mapped as column property in entity - {$meta->getName()}, since it makes no sense");
  87. }
  88. $config['locale'] = $field;
  89. }
  90. }
  91. // Embedded entity
  92. if (property_exists($meta, 'embeddedClasses') && $meta->embeddedClasses) {
  93. foreach ($meta->embeddedClasses as $propertyName => $embeddedClassInfo) {
  94. if ($meta->isInheritedEmbeddedClass($propertyName)) {
  95. continue;
  96. }
  97. $embeddedClass = new \ReflectionClass($embeddedClassInfo['class']);
  98. foreach ($embeddedClass->getProperties() as $embeddedProperty) {
  99. if ($translatable = $this->reader->getPropertyAnnotation($embeddedProperty, self::TRANSLATABLE)) {
  100. \assert($translatable instanceof Translatable);
  101. $field = $propertyName.'.'.$embeddedProperty->getName();
  102. $config['fields'][] = $field;
  103. if (isset($translatable->fallback)) {
  104. $config['fallback'][$field] = $translatable->fallback;
  105. }
  106. }
  107. }
  108. }
  109. }
  110. if (!$meta->isMappedSuperclass && $config) {
  111. if (is_array($meta->getIdentifier()) && count($meta->getIdentifier()) > 1) {
  112. throw new InvalidMappingException("Translatable does not support composite identifiers in class - {$meta->getName()}");
  113. }
  114. }
  115. return $config;
  116. }
  117. }