/** * Checks if the specified class and method matches against the filter * * @param string $className Name of the class to check against * @param string $methodName Name of the method to check against * @param string $methodDeclaringClassName Name of the class the method was originally declared in * @param mixed $pointcutQueryIdentifier Some identifier for this query - must at least differ from a previous identifier. Used for circular reference detection. * @return boolean true if the class / method match, otherwise false */ public function matches($className, $methodName, $methodDeclaringClassName, $pointcutQueryIdentifier) { $valueObjectAnnotation = $this->reflectionService->getClassAnnotation($className, Flow\ValueObject::class); if ($valueObjectAnnotation !== null && $valueObjectAnnotation->embedded === true) { return true; } return false; }
protected function initializeObject() { /** @var Table $table */ $table = $this->reflectionService->getClassAnnotation($this->projectionClassName, Table::class); if ($table !== NULL) { $this->tableName = $table->name; } }
/** * Returns a proxy class object for the specified original class. * * If no such proxy class has been created yet by this renderer, * this function will create one and register it for later use. * * If the class is not proxable, FALSE will be returned * * @param string $fullClassName Name of the original class * @return \TYPO3\Flow\Object\Proxy\ProxyClass|boolean */ public function getProxyClass($fullClassName) { if (interface_exists($fullClassName) || in_array('TYPO3\\Flow\\Tests\\BaseTestCase', class_parents($fullClassName))) { return FALSE; } if (class_exists($fullClassName) === FALSE) { return FALSE; } $classReflection = new \ReflectionClass($fullClassName); if ($classReflection->isInternal() === TRUE) { return FALSE; } $proxyAnnotation = $this->reflectionService->getClassAnnotation($fullClassName, 'TYPO3\\Flow\\Annotations\\Proxy'); if ($proxyAnnotation !== NULL && $proxyAnnotation->enabled === FALSE) { return FALSE; } if (in_array(substr($fullClassName, 0, 14), $this->blacklistedSubPackages)) { return FALSE; } if (!isset($this->proxyClasses[$fullClassName])) { $this->proxyClasses[$fullClassName] = new ProxyClass($fullClassName); $this->proxyClasses[$fullClassName]->injectReflectionService($this->reflectionService); } return $this->proxyClasses[$fullClassName]; }
/** * Returns a proxy class object for the specified original class. * * If no such proxy class has been created yet by this renderer, * this function will create one and register it for later use. * * If the class is not proxable, FALSE will be returned * * @param string $fullClassName Name of the original class * @return \TYPO3\Flow\Object\Proxy\ProxyClass|boolean */ public function getProxyClass($fullClassName) { if (interface_exists($fullClassName) || in_array(\TYPO3\Flow\Tests\BaseTestCase::class, class_parents($fullClassName))) { return false; } if (class_exists($fullClassName) === false) { return false; } $classReflection = new \ReflectionClass($fullClassName); if ($classReflection->isInternal() === true) { return false; } $proxyAnnotation = $this->reflectionService->getClassAnnotation($fullClassName, \TYPO3\Flow\Annotations\Proxy::class); if ($proxyAnnotation !== null && $proxyAnnotation->enabled === false) { return false; } if (in_array(substr($fullClassName, 0, 14), $this->blacklistedSubPackages)) { return false; } // Annotation classes (like \TYPO3\Flow\Annotations\Entity) must never be proxied because that would break the Doctrine AnnotationParser if ($classReflection->isFinal() && preg_match('/^\\s?\\*\\s?\\@Annotation\\s/m', $classReflection->getDocComment()) === 1) { return false; } if (!isset($this->proxyClasses[$fullClassName])) { $this->proxyClasses[$fullClassName] = new ProxyClass($fullClassName); $this->proxyClasses[$fullClassName]->injectReflectionService($this->reflectionService); } return $this->proxyClasses[$fullClassName]; }
/** * @param string $className * @return string */ protected function createTableDefinitionQueryForClassName($className) { /** @var Table $table */ $table = $this->reflectionService->getClassAnnotation($className, Table::class); $columns = $this->reflectionService->getPropertyNamesByAnnotation($className, Column::class); $columnDefinitions = []; foreach ($columns as $columnName) { /** @var Column $column */ $column = $this->reflectionService->getPropertyAnnotation($className, $columnName, Column::class); $columnDefinitions[] = '`' . $columnName . '` ' . $column->definition; } if ($table->indexes !== NULL) { $columnDefinitions[] = $table->indexes; } return 'CREATE TABLE ' . $table->name . ' (' . implode(', ', $columnDefinitions) . ') ENGINE = InnoDB'; }
/** * Returns a proxy class object for the specified original class. * * If no such proxy class has been created yet by this renderer, * this function will create one and register it for later use. * * If the class is not proxable, FALSE will be returned * * @param string $fullClassName Name of the original class * @return \TYPO3\Flow\Object\Proxy\ProxyClass|boolean */ public function getProxyClass($fullClassName) { if (interface_exists($fullClassName) || in_array(\TYPO3\Flow\Tests\BaseTestCase::class, class_parents($fullClassName))) { return false; } if (class_exists($fullClassName) === false) { return false; } $classReflection = new \ReflectionClass($fullClassName); if ($classReflection->isInternal() === true) { return false; } $proxyAnnotation = $this->reflectionService->getClassAnnotation($fullClassName, \TYPO3\Flow\Annotations\Proxy::class); if ($proxyAnnotation !== null && $proxyAnnotation->enabled === false) { return false; } if (in_array(substr($fullClassName, 0, 14), $this->blacklistedSubPackages)) { return false; } if (!isset($this->proxyClasses[$fullClassName])) { $this->proxyClasses[$fullClassName] = new ProxyClass($fullClassName); $this->proxyClasses[$fullClassName]->injectReflectionService($this->reflectionService); } return $this->proxyClasses[$fullClassName]; }
/** * @param string $model * @param object $context an arbitrary object which is available in all actions and nested functionality * @return array * @throws MissingModelTypeException * @throws \Exception */ protected function getProperties($model, $context = null) { if ($model === NULL) { throw new MissingModelTypeException('The "model" property has not been specified as parameter to the ViewHelper ' . get_class($this) . '.', 1452715128); } $classSchema = $this->reflectionService->getClassSchema($model); if ($classSchema === NULL) { throw new MissingModelTypeException('No class schema could be resolved for model ' . $model . '.', 1452715183); } $classSchema->getProperties(); $fields = []; foreach ($classSchema->getProperties() as $propertyName => $propertyDefinition) { if ($propertyName === 'Persistence_Object_Identifier') { continue; } /* @var $formFieldAnnotation FormField */ $formFieldAnnotation = $this->reflectionService->getPropertyAnnotation($model, $propertyName, FormField::class); $fields[$propertyName] = []; if ($formFieldAnnotation) { $fields[$propertyName] = get_object_vars($formFieldAnnotation); } $this->addDefaultsToFields($fields, $propertyName); } foreach (get_class_methods($model) as $methodName) { if (substr($methodName, 0, 3) === 'get') { $methodAnnotation = $this->reflectionService->getMethodAnnotation($model, $methodName, FormField::class); if ($methodAnnotation) { $propertyName = lcfirst(substr($methodName, 3)); $fields[$propertyName] = get_object_vars($methodAnnotation); $this->addDefaultsToFields($fields, $propertyName); } } } $generatorAnnotation = $this->reflectionService->getClassAnnotation($model, FieldGenerator::class); if ($generatorAnnotation !== NULL) { $generator = $this->objectManager->get($generatorAnnotation->className); if (!$generator instanceof FieldGeneratorInterface) { throw new \Exception('TODO: generator must implement FieldGeneratorInterface, ' . get_class($generator) . ' given.'); } foreach ($generator->generate($context) as $propertyName => $annotation) { $fields[$propertyName] = get_object_vars($annotation); $this->addDefaultsToFields($fields, $propertyName); } } return (new PositionalArraySorter($fields))->toArray(); }
/** * Builds a raw configuration array by parsing possible scope and autowiring * annotations from the given class or interface. * * @param string $className * @param array $rawObjectConfiguration * @return array */ protected function enhanceRawConfigurationWithAnnotationOptions($className, array $rawObjectConfiguration) { if ($this->reflectionService->isClassAnnotatedWith($className, 'TYPO3\\Flow\\Annotations\\Scope')) { $rawObjectConfiguration['scope'] = $this->reflectionService->getClassAnnotation($className, 'TYPO3\\Flow\\Annotations\\Scope')->value; } if ($this->reflectionService->isClassAnnotatedWith($className, 'TYPO3\\Flow\\Annotations\\Autowiring')) { $rawObjectConfiguration['autowiring'] = $this->reflectionService->getClassAnnotation($className, 'TYPO3\\Flow\\Annotations\\Autowiring')->enabled; } return $rawObjectConfiguration; }
/** * Intercept flush event * * @param \Doctrine\ORM\Event\OnFlushEventArgs $eventArgs * * @throws \CDSRC\Libraries\SoftDeletable\Exceptions\PropertyNotFoundException */ public function onFlush(OnFlushEventArgs $eventArgs) { $entityManager = $eventArgs->getEntityManager(); $unitOfWork = $entityManager->getUnitOfWork(); $properties = array(); foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) { $className = get_class($entity); $annotation = $this->reflectionService->getClassAnnotation($className, SoftDeletable::class); if ($annotation !== null) { if (!isset($properties[$className])) { $existingProperties = $this->reflectionService->getClassPropertyNames($className); if (!in_array($annotation->deleteProperty, $existingProperties)) { throw new PropertyNotFoundException("Property '" . $annotation->deleteProperty . "' not found for '" . $className . "'", 1439207432); } $reflectionClass = new \ReflectionClass($className); $properties[$className] = array(); if (strlen($annotation->hardDeleteProperty) > 0) { if (!in_array($annotation->hardDeleteProperty, $existingProperties)) { throw new PropertyNotFoundException("Property '" . $annotation->hardDeleteProperty . "' not found for '" . $className . "'", 1439207431); } $properties[$className]['h'] = $reflectionClass->getProperty($annotation->hardDeleteProperty); $properties[$className]['h']->setAccessible(true); } $properties[$className]['p'] = $reflectionClass->getProperty($annotation->deleteProperty); $properties[$className]['p']->setAccessible(true); } if (isset($properties[$className]['h']) && $properties[$className]['h']->getValue($entity)) { continue; } $oldValue = $properties[$className]['p']->getValue($entity); $date = new \DateTime(); $properties[$className]['p']->setValue($entity, $date); $entityManager->persist($entity); $unitOfWork->propertyChanged($entity, $annotation->deleteProperty, $oldValue, $date); $unitOfWork->scheduleExtraUpdate($entity, array($annotation->deleteProperty => array($oldValue, $date))); } } }
/** * Returns Mapper-Service configured for CAS Provider. * * @param string $providerName provider name to fetch a mapper from. * * @throws \RafaelKa\JasigPhpCas\Exception\InvalidConfigurationException * @throws \RafaelKa\JasigPhpCas\Exception\InvalidClassDefinitionForMapperException * * @return \RafaelKa\JasigPhpCas\Service\MapperInterface */ private function getMapperByProviderName($providerName) { if (!empty($this->providerMappers[$providerName])) { return $this->providerMappers[$providerName]; } $mapperClassName = $this->configurationManager->getConfiguration(\TYPO3\Flow\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'TYPO3.Flow.security.authentication.providers.' . $providerName . 'Mapping.MapperClass'); if (empty($mapperClassName)) { $mapperClassName = self::DEFAULT_CAS_MAPPER; } else { if (!class_exists($mapperClassName)) { throw new \RafaelKa\JasigPhpCas\Exception\InvalidConfigurationException(sprintf('Class "%s" configured in Settings.yaml at "TYPO3.Flow.security.authentication.providers.%s.Mapping.MapperClass" does not exists.', $mapperClassName, $providerName), 1370983932); } if (!$this->reflectionService->isClassImplementationOf($mapperClassName, 'RafaelKa\\JasigPhpCas\\Service\\MapperInterface')) { throw new \RafaelKa\JasigPhpCas\Exception\InvalidClassDefinitionForMapperException(sprintf('Class "%s" configured in Settings.yaml at "TYPO3.Flow.security.authentication.providers.%s.MapperClass" is not implementation of "RafaelKa\\JasigPhpCas\\Service\\MapperInterface". Please rediclare "%s" as "\\TYPO3\\Flow\\Security\\Authentication\\TokenInterface" adapter Class.', $mapperClassName, $providerName, $mapperClassName), 1370981664); } if (!$this->reflectionService->getClassAnnotation($mapperClassName, 'TYPO3\\Flow\\Annotations\\Scope')->value !== 'singleton') { throw new \RafaelKa\JasigPhpCas\Exception\InvalidClassDefinitionForMapperException(sprintf('Class "%s" configured in Settings.yaml at "TYPO3.Flow.security.authentication.providers.%s.MapperClass" is not a singleton. Please declare "%s" as "@Flow\\Scope("singleton")" Class.', $mapperClassName, $providerName, $mapperClassName), 1371036890); } } $this->providerMappers[$providerName] = $this->objectManager->get($mapperClassName); return $this->providerMappers[$providerName]; }
/** * Creates and returns an aspect from the annotations found in a class which * is tagged as an aspect. The object acting as an advice will already be * fetched (and therefore instantiated if necessary). * * @param string $aspectClassName Name of the class which forms the aspect, contains advices etc. * @return mixed The aspect container containing one or more advisors or FALSE if no container could be built * @throws \TYPO3\Flow\Aop\Exception */ protected function buildAspectContainer($aspectClassName) { $aspectContainer = new \TYPO3\Flow\Aop\AspectContainer($aspectClassName); $methodNames = get_class_methods($aspectClassName); foreach ($methodNames as $methodName) { foreach ($this->reflectionService->getMethodAnnotations($aspectClassName, $methodName) as $annotation) { $annotationClass = get_class($annotation); switch ($annotationClass) { case \TYPO3\Flow\Annotations\Around::class: $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\Flow\Aop\Advice\AroundAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case \TYPO3\Flow\Annotations\Before::class: $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\Flow\Aop\Advice\BeforeAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case \TYPO3\Flow\Annotations\AfterReturning::class: $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\Flow\Aop\Advice\AfterReturningAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case \TYPO3\Flow\Annotations\AfterThrowing::class: $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\Flow\Aop\Advice\AfterThrowingAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case \TYPO3\Flow\Annotations\After::class: $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\Flow\Aop\Advice\AfterAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case \TYPO3\Flow\Annotations\Pointcut::class: $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->expression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->expression, $pointcutFilterComposite, $aspectClassName, $methodName); $aspectContainer->addPointcut($pointcut); break; } } } $introduceAnnotation = $this->reflectionService->getClassAnnotation($aspectClassName, \TYPO3\Flow\Annotations\Introduce::class); if ($introduceAnnotation !== null) { if ($introduceAnnotation->interfaceName === null && $introduceAnnotation->traitName === null) { throw new \TYPO3\Flow\Aop\Exception('The introduction in class "' . $aspectClassName . '" does neither contain an interface name nor a trait name, at least one is required.', 1172694761); } $pointcutFilterComposite = $this->pointcutExpressionParser->parse($introduceAnnotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $introduceAnnotation->interfaceName, \TYPO3\Flow\Annotations\Introduce::class)); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($introduceAnnotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); if ($introduceAnnotation->interfaceName !== null) { $introduction = new \TYPO3\Flow\Aop\InterfaceIntroduction($aspectClassName, $introduceAnnotation->interfaceName, $pointcut); $aspectContainer->addInterfaceIntroduction($introduction); } if ($introduceAnnotation->traitName !== null) { $introduction = new \TYPO3\Flow\Aop\TraitIntroduction($aspectClassName, $introduceAnnotation->traitName, $pointcut); $aspectContainer->addTraitIntroduction($introduction); } } foreach ($this->reflectionService->getClassPropertyNames($aspectClassName) as $propertyName) { $introduceAnnotation = $this->reflectionService->getPropertyAnnotation($aspectClassName, $propertyName, \TYPO3\Flow\Annotations\Introduce::class); if ($introduceAnnotation !== null) { $pointcutFilterComposite = $this->pointcutExpressionParser->parse($introduceAnnotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $propertyName, \TYPO3\Flow\Annotations\Introduce::class)); $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($introduceAnnotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $introduction = new PropertyIntroduction($aspectClassName, $propertyName, $pointcut); $aspectContainer->addPropertyIntroduction($introduction); } } if (count($aspectContainer->getAdvisors()) < 1 && count($aspectContainer->getPointcuts()) < 1 && count($aspectContainer->getInterfaceIntroductions()) < 1 && count($aspectContainer->getTraitIntroductions()) < 1 && count($aspectContainer->getPropertyIntroductions()) < 1) { throw new \TYPO3\Flow\Aop\Exception('The class "' . $aspectClassName . '" is tagged to be an aspect but doesn\'t contain advices nor pointcut or introduction declarations.', 1169124534); } return $aspectContainer; }
/** * Evaluate the property annotations and amend the metadata accordingly. * * @param ORM\ClassMetadataInfo $metadata * @return void * @throws ORM\MappingException */ protected function evaluatePropertyAnnotations(ORM\ClassMetadataInfo $metadata) { $className = $metadata->name; $class = $metadata->getReflectionClass(); $classSchema = $this->getClassSchema($className); foreach ($class->getProperties() as $property) { if (!$classSchema->hasProperty($property->getName()) || $classSchema->isPropertyTransient($property->getName()) || $metadata->isMappedSuperclass && !$property->isPrivate() || $metadata->isInheritedField($property->getName()) || $metadata->isInheritedAssociation($property->getName()) || $metadata->isInheritedEmbeddedClass($property->getName())) { continue; } $propertyMetaData = $classSchema->getProperty($property->getName()); $mapping = []; $mapping['fieldName'] = $property->getName(); $mapping['columnName'] = strtolower($property->getName()); $mapping['targetEntity'] = $propertyMetaData['type']; $joinColumns = $this->evaluateJoinColumnAnnotations($property); // Field can only be annotated with one of: // @OneToOne, @OneToMany, @ManyToOne, @ManyToMany, @Column (optional) if ($oneToOneAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OneToOne::class)) { if ($this->reader->getPropertyAnnotation($property, ORM\Id::class) !== null) { $mapping['id'] = true; } if ($oneToOneAnnotation->targetEntity) { $mapping['targetEntity'] = $oneToOneAnnotation->targetEntity; } if ($oneToOneAnnotation->inversedBy !== null || $oneToOneAnnotation->mappedBy === null) { $mapping['joinColumns'] = $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property); } $mapping['mappedBy'] = $oneToOneAnnotation->mappedBy; $mapping['inversedBy'] = $oneToOneAnnotation->inversedBy; if ($oneToOneAnnotation->cascade) { $mapping['cascade'] = $oneToOneAnnotation->cascade; } elseif ($this->isValueObject($mapping['targetEntity'], $className)) { $mapping['cascade'] = ['persist']; } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) { $mapping['cascade'] = ['all']; } if ($oneToOneAnnotation->orphanRemoval) { $mapping['orphanRemoval'] = $oneToOneAnnotation->orphanRemoval; } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false && $this->isValueObject($mapping['targetEntity'], $className) === false) { $mapping['orphanRemoval'] = true; } $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnotation->fetch); $metadata->mapOneToOne($mapping); } elseif ($oneToManyAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OneToMany::class)) { $mapping['mappedBy'] = $oneToManyAnnotation->mappedBy; if ($oneToManyAnnotation->targetEntity) { $mapping['targetEntity'] = $oneToManyAnnotation->targetEntity; } elseif (isset($propertyMetaData['elementType'])) { $mapping['targetEntity'] = $propertyMetaData['elementType']; } if ($oneToManyAnnotation->cascade) { $mapping['cascade'] = $oneToManyAnnotation->cascade; } elseif ($this->isValueObject($mapping['targetEntity'], $className)) { $mapping['cascade'] = ['persist']; } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) { $mapping['cascade'] = ['all']; } $mapping['indexBy'] = $oneToManyAnnotation->indexBy; if ($oneToManyAnnotation->orphanRemoval) { $mapping['orphanRemoval'] = $oneToManyAnnotation->orphanRemoval; } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false && $this->isValueObject($mapping['targetEntity'], $className) === false) { $mapping['orphanRemoval'] = true; } $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnotation->fetch); if ($orderByAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OrderBy::class)) { $mapping['orderBy'] = $orderByAnnotation->value; } $metadata->mapOneToMany($mapping); } elseif ($manyToOneAnnotation = $this->reader->getPropertyAnnotation($property, ORM\ManyToOne::class)) { if ($this->reader->getPropertyAnnotation($property, ORM\Id::class) !== null) { $mapping['id'] = true; } if ($manyToOneAnnotation->targetEntity) { $mapping['targetEntity'] = $manyToOneAnnotation->targetEntity; } $mapping['joinColumns'] = $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property); if ($manyToOneAnnotation->cascade) { $mapping['cascade'] = $manyToOneAnnotation->cascade; } elseif ($this->isValueObject($mapping['targetEntity'], $className)) { $mapping['cascade'] = ['persist']; } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) { $mapping['cascade'] = ['all']; } $mapping['inversedBy'] = $manyToOneAnnotation->inversedBy; $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnotation->fetch); $metadata->mapManyToOne($mapping); } elseif ($manyToManyAnnotation = $this->reader->getPropertyAnnotation($property, ORM\ManyToMany::class)) { if ($manyToManyAnnotation->targetEntity) { $mapping['targetEntity'] = $manyToManyAnnotation->targetEntity; } elseif (isset($propertyMetaData['elementType'])) { $mapping['targetEntity'] = $propertyMetaData['elementType']; } /** @var ORM\JoinTable $joinTableAnnotation */ if ($joinTableAnnotation = $this->reader->getPropertyAnnotation($property, ORM\JoinTable::class)) { $joinTable = $this->evaluateJoinTableAnnotation($joinTableAnnotation, $property, $className, $mapping); } else { $joinColumns = [['name' => null, 'referencedColumnName' => null]]; $joinTable = ['name' => $this->inferJoinTableNameFromClassAndPropertyName($className, $property->getName()), 'joinColumns' => $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property, self::MAPPING_MM_REGULAR), 'inverseJoinColumns' => $this->buildJoinColumnsIfNeeded($joinColumns, $mapping, $property)]; } $mapping['joinTable'] = $joinTable; $mapping['mappedBy'] = $manyToManyAnnotation->mappedBy; $mapping['inversedBy'] = $manyToManyAnnotation->inversedBy; if ($manyToManyAnnotation->cascade) { $mapping['cascade'] = $manyToManyAnnotation->cascade; } elseif ($this->isValueObject($mapping['targetEntity'], $className)) { $mapping['cascade'] = ['persist']; } elseif ($this->isAggregateRoot($mapping['targetEntity'], $className) === false) { $mapping['cascade'] = ['all']; } $mapping['indexBy'] = $manyToManyAnnotation->indexBy; $mapping['orphanRemoval'] = $manyToManyAnnotation->orphanRemoval; $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnotation->fetch); if ($orderByAnnotation = $this->reader->getPropertyAnnotation($property, ORM\OrderBy::class)) { $mapping['orderBy'] = $orderByAnnotation->value; } $metadata->mapManyToMany($mapping); } elseif ($embeddedAnnotation = $this->reader->getPropertyAnnotation($property, ORM\Embedded::class)) { if ($embeddedAnnotation->class) { $mapping['class'] = $embeddedAnnotation->class; } else { // This will not happen currently, because "class" argument is required. It would be nice if that could be changed though. $mapping['class'] = $mapping['targetEntity']; } $mapping['columnPrefix'] = $embeddedAnnotation->columnPrefix; $metadata->mapEmbedded($mapping); } else { $mapping['nullable'] = false; /** @var ORM\Column $columnAnnotation */ if ($columnAnnotation = $this->reader->getPropertyAnnotation($property, ORM\Column::class)) { $mapping = $this->addColumnToMappingArray($columnAnnotation, $mapping); } if (!isset($mapping['type'])) { switch ($propertyMetaData['type']) { case 'DateTime': $mapping['type'] = 'datetime'; break; case 'string': case 'integer': case 'boolean': case 'float': case 'array': $mapping['type'] = $propertyMetaData['type']; break; default: if (strpos($propertyMetaData['type'], '\\') !== false) { if ($this->reflectionService->isClassAnnotatedWith($propertyMetaData['type'], Flow\ValueObject::class)) { $valueObjectAnnotation = $this->reflectionService->getClassAnnotation($propertyMetaData['type'], Flow\ValueObject::class); if ($valueObjectAnnotation->embedded === true) { $mapping['class'] = $propertyMetaData['type']; $mapping['columnPrefix'] = $mapping['columnName']; $metadata->mapEmbedded($mapping); // Leave switch and continue with next property continue 2; } $mapping['type'] = 'object'; } elseif (class_exists($propertyMetaData['type'])) { throw ORM\MappingException::missingRequiredOption($property->getName(), 'OneToOne', sprintf('The property "%s" in class "%s" has a non standard data type and doesn\'t define the type of the relation. You have to use one of these annotations: @OneToOne, @OneToMany, @ManyToOne, @ManyToMany', $property->getName(), $className)); } } else { throw ORM\MappingException::propertyTypeIsRequired($className, $property->getName()); } } } if ($this->reader->getPropertyAnnotation($property, ORM\Id::class) !== null) { $mapping['id'] = true; } if ($generatedValueAnnotation = $this->reader->getPropertyAnnotation($property, ORM\GeneratedValue::class)) { $metadata->setIdGeneratorType(constant('Doctrine\\ORM\\Mapping\\ClassMetadata::GENERATOR_TYPE_' . strtoupper($generatedValueAnnotation->strategy))); } if ($this->reflectionService->isPropertyAnnotatedWith($className, $property->getName(), ORM\Version::class)) { $metadata->setVersionMapping($mapping); } $metadata->mapField($mapping); // Check for SequenceGenerator/TableGenerator definition if ($seqGeneratorAnnotation = $this->reader->getPropertyAnnotation($property, ORM\SequenceGenerator::class)) { $metadata->setSequenceGeneratorDefinition(['sequenceName' => $seqGeneratorAnnotation->sequenceName, 'allocationSize' => $seqGeneratorAnnotation->allocationSize, 'initialValue' => $seqGeneratorAnnotation->initialValue]); } elseif ($this->reader->getPropertyAnnotation($property, ORM\TableGenerator::class) !== null) { throw ORM\MappingException::tableIdGeneratorNotImplemented($className); } elseif ($customGeneratorAnnotation = $this->reader->getPropertyAnnotation($property, ORM\CustomIdGenerator::class)) { $metadata->setCustomGeneratorDefinition(['class' => $customGeneratorAnnotation->class]); } } // Evaluate @Cache annotation if (($cacheAnnotation = $this->reader->getPropertyAnnotation($property, ORM\Cache::class)) !== null) { $metadata->enableAssociationCache($mapping['fieldName'], array('usage' => constant('Doctrine\\ORM\\Mapping\\ClassMetadata::CACHE_USAGE_' . $cacheAnnotation->usage), 'region' => $cacheAnnotation->region)); } } }