protected static function visitEntity(IEntity $entity, IModel $model, $withCascade = true) { $entityHash = spl_object_hash($entity); if (isset(self::$outputQueue[$entityHash])) { if (self::$outputQueue[$entityHash] === true) { $cycle = []; $bt = debug_backtrace(); foreach ($bt as $item) { if ($item['function'] === 'getCascadeQueue') { break; } elseif ($item['function'] === 'addRelationshipToQueue') { $cycle[] = get_class($item['args'][0]) . '::$' . $item['args'][1]->name; } } throw new InvalidStateException('Persist cycle detected in ' . implode(' - ', $cycle) . '. Use manual two phase persist.'); } return; } $repository = $model->getRepositoryForEntity($entity); $repository->attach($entity); $repository->doFireEvent($entity, 'onBeforePersist'); if ($withCascade) { self::$outputQueue[$entityHash] = true; foreach ($entity->getMetadata()->getProperties() as $propertyMeta) { if ($propertyMeta->relationship !== null && $propertyMeta->relationship->cascade['persist']) { self::addRelationshipToQueue($entity, $propertyMeta, $model); } } unset(self::$outputQueue[$entityHash]); // reenqueue } self::$outputQueue[$entityHash] = $entity; }
public static function getCascadeQueue($entity, IModel $model, &$queue = []) { $entityHash = spl_object_hash($entity); if (isset($queue[$entityHash])) { return; } $repository = $model->getRepositoryForEntity($entity); $repository->attach($entity); $repository->doFireEvent($entity, 'onBeforePersist'); list($pre, $post) = static::getLoadedRelationships($entity); foreach ($pre as $value) { if ($value instanceof IEntity) { static::getCascadeQueue($value, $model, $queue); } elseif ($value instanceof IRelationshipCollection) { foreach ($value->getEntitiesForPersistance() as $subValue) { static::getCascadeQueue($subValue, $model, $queue); } $queue[spl_object_hash($value)] = $value; } } $queue[$entityHash] = $entity; foreach ($post as $value) { if ($value instanceof IEntity) { static::getCascadeQueue($value, $model, $queue); } elseif ($value instanceof IRelationshipCollection) { foreach ($value->getEntitiesForPersistance() as $subValue) { static::getCascadeQueue($subValue, $model, $queue); } $queue[spl_object_hash($value)] = $value; } } }
protected function random(PropertyMetadata $property) { if (in_array($property->relationshipType, [PropertyMetadata::RELATIONSHIP_MANY_HAS_ONE, PropertyMetadata::RELATIONSHIP_ONE_HAS_ONE, PropertyMetadata::RELATIONSHIP_ONE_HAS_ONE_DIRECTED])) { $entityClass = $this->model->getRepository($property->relationshipRepository)->getEntityClassNames()[0]; return $this->create($entityClass); } $possibilities = []; if ($property->enum) { $possibilities = $property->enum; } else { foreach (array_keys($property->types) as $type) { switch ($type) { case 'datetime': $possibilities[] = new DateTime($this->randomInt(2010, 2020) . '-' . $this->randomInt(1, 12) . '-' . $this->randomInt(1, 31)); break; case 'string': $possibilities[] = $this->randomWords(20, 50); break; case 'int': $possibilities[] = $this->randomInt(0, 100); break; case 'float': $possibilities[] = $this->randomInt(0, 100) + $this->randomInt(0, 100) / 100; break; case 'bool': $possibilities[] = (bool) $this->randomInt(0, 1); break; } } } if (!$possibilities) { return NULL; } return $possibilities[array_rand($possibilities)]; }
protected function createComponent($name) { if ($name instanceof Nextras\Orm\Entity\IEntity) { $class = rtrim($name->getMetadata()->getClassName(), 'a..zA..Z') . 'Form\\Container'; return new $class($name, $this->model->getRepositoryForEntity($name)); } return parent::createComponent($name); }
public function create($entity, array $params = []) { $entity = new $entity(); $repository = $this->model->getRepositoryForEntity($entity); $repository->attach($entity); $this->fill($entity, $params); return $entity; }
public function persist(IEntity $entity, $recursive = TRUE) { $this->identityMap->check($entity); if (isset($this->isPersisting[spl_object_hash($entity)])) { return $entity; } $this->isPersisting[spl_object_hash($entity)] = TRUE; $this->attach($entity); $relationships = []; if ($recursive) { foreach ($entity->toArray(IEntity::TO_ARRAY_LOADED_RELATIONSHIP_AS_IS) as $k => $v) { if ($v instanceof IEntity) { $this->model->getRepositoryForEntity($v)->persist($v); } elseif ($v instanceof IRelationshipCollection) { $relationships[] = $v; } } } if ($entity->isModified()) { $id = $this->mapper->persist($entity); $entity->fireEvent('onPersist', [$id]); } foreach ($relationships as $relationship) { $relationship->persist($recursive); } unset($this->isPersisting[spl_object_hash($entity)]); return $entity; }
private function parseCondition(array $levels, IMapper $mapper) { /** @var IDbStorageReflection $reflection */ $reflection = $mapper->getStorageReflection(); $expression = ''; $column = array_pop($levels); $entityMD = $this->metadataStorage->get($mapper->getRepository()->getEntityClassNames()[0]); foreach ($levels as $level) { if (!$entityMD->hasProperty($level)) { throw new InvalidArgumentException("Undefined property {$entityMD->className}::\${$level}."); } $propertyMD = $entityMD->getProperty($level); if (!$propertyMD->relationshipRepository) { throw new InvalidArgumentException("Entity {$entityMD->className}::\${$level} does not contain a relationship."); } $targetMapper = $this->model->getRepository($propertyMD->relationshipRepository)->getMapper(); $targetReflection = $targetMapper->getStorageReflection(); if ($propertyMD->relationshipType === PropertyMetadata::RELATIONSHIP_ONE_HAS_MANY) { $table = $targetReflection->getStorageName(); $joinColumn = $targetReflection->convertEntityToStorageKey($propertyMD->relationshipProperty); $expression .= ":{$table}({$joinColumn})"; } elseif ($propertyMD->relationshipType === PropertyMetadata::RELATIONSHIP_MANY_HAS_MANY) { if ($propertyMD->relationshipIsMain) { $expression .= ':' . $reflection->getManyHasManyStorageName($targetMapper); $expression .= '.' . $reflection->getManyHasManyStoragePrimaryKeys($targetMapper)[1]; } else { $expression .= ':' . $targetReflection->getManyHasManyStorageName($mapper); $expression .= '.' . $targetReflection->getManyHasManyStoragePrimaryKeys($mapper)[0]; } } else { $expression .= '.' . $reflection->convertEntityToStorageKey($level); } $mapper = $targetMapper; $reflection = $targetReflection; $entityMD = $this->metadataStorage->get($mapper->getRepository()->getEntityClassNames()[0]); } // check if property exists $entityMD->getProperty($column); $column = $reflection->convertEntityToStorageKey($column); return "{$expression}.{$column}"; }
protected function createComponentTranslates(Nextras\Orm\Entity\Reflection\PropertyMetadata $metadata) : Nette\Forms\Container { $translates = $this->addContainer($metadata->name); $localeRepository = $this->model->getRepositoryForEntity(Ytnuk\Translation\Locale\Entity::class); self::$locales ?: (self::$locales = $localeRepository->findAll()->fetchPairs(current($localeRepository->getEntityMetadata()->getPrimaryKey()))); $collection = array_combine(array_map(function (Ytnuk\Translation\Translate\Entity $entity) { return $entity->getRawValue('locale'); }, $collection = iterator_to_array($this->entity->getValue($metadata->name))), $collection); array_walk(self::$locales, function (Ytnuk\Translation\Locale\Entity $locale) use($translates, $collection) { $translate = $collection[$locale->id] ?? new Ytnuk\Translation\Translate\Entity(); $translates->addComponent($component = $this->form->createComponent($translate), $locale->id); if ($component instanceof Nette\Forms\Container) { $component->setCurrentGroup($translates->getCurrentGroup()); $value = $component['value']; if ($value instanceof Nette\Forms\Controls\BaseControl) { $value->caption = NULL; $value->setRequired(FALSE); } unset($component['locale']); $component->addHidden('locale', $locale->id)->setOption('entity', $locale); } }); $parent = $this->lookup(parent::class, FALSE); if ($parent instanceof parent) { $translates->getCurrentGroup()->setOption('label', $parent->formatPropertyLabel($parent->getMetadata()->getProperty($this->getName()))); if (!$parent->getMetadata()->getProperty($this->name)->isNullable && ($containers = iterator_to_array($translates->getComponents(FALSE, Nette\Forms\Container::class)))) { foreach ($containers as $key => $container) { $value = $container['value'] ?? NULL; if ($value instanceof Nette\Forms\Controls\BaseControl) { foreach (array_diff_key($containers, array_flip([$key])) as $sibling) { $value = $value->addConditionOn($sibling['value'], ~Nette\Forms\Form::FILLED); } $value->setRequired(); } } } } return $translates; }
/** * @param EntityMetadata[] $metadata * @param IModel $model */ public function validate(array $metadata, IModel $model) { $pairs = [PropertyMetadata::RELATIONSHIP_MANY_HAS_MANY => PropertyMetadata::RELATIONSHIP_MANY_HAS_MANY, PropertyMetadata::RELATIONSHIP_MANY_HAS_ONE => PropertyMetadata::RELATIONSHIP_ONE_HAS_MANY, PropertyMetadata::RELATIONSHIP_ONE_HAS_MANY => PropertyMetadata::RELATIONSHIP_MANY_HAS_ONE, PropertyMetadata::RELATIONSHIP_ONE_HAS_ONE => PropertyMetadata::RELATIONSHIP_ONE_HAS_ONE, PropertyMetadata::RELATIONSHIP_ONE_HAS_ONE_DIRECTED => PropertyMetadata::RELATIONSHIP_ONE_HAS_ONE_DIRECTED]; foreach ($metadata as $entityMeta) { foreach ($entityMeta->getProperties() as $propertyMeta) { if (!$propertyMeta->relationshipType) { continue; } $repositoryName = $propertyMeta->relationshipRepository; if (!$model->hasRepository($repositoryName)) { throw new InvalidStateException("{$entityMeta->className}::\${$propertyMeta->name} points to unknown '{$propertyMeta->relationshipRepository}' repository."); } $symetricEntityMeta = $metadata[$repositoryName::getEntityClassNames()[0]]; if (!$symetricEntityMeta->hasProperty($propertyMeta->relationshipProperty)) { throw new InvalidStateException("{$entityMeta->className}::\${$propertyMeta->name} has not defined a symetric relationship in {$symetricEntityMeta->className}::\${$propertyMeta->relationshipProperty}."); } /** @var PropertyMetadata $symetricPropertyMeta */ $symetricPropertyMeta = $symetricEntityMeta->getProperty($propertyMeta->relationshipProperty); if ($propertyMeta->name !== $symetricPropertyMeta->relationshipProperty) { throw new InvalidStateException("{$entityMeta->className}::\${$propertyMeta->name} relationship with {$symetricEntityMeta->className}::\${$propertyMeta->relationshipProperty} is not transitive."); } if ($symetricPropertyMeta->relationshipType === NULL) { throw new InvalidStateException("{$entityMeta->className}::\${$propertyMeta->name} has not defined a symetric relationship in {$symetricEntityMeta->className}::\${$propertyMeta->relationshipProperty}."); } if ($symetricPropertyMeta->relationshipType !== $pairs[$propertyMeta->relationshipType]) { throw new InvalidStateException("{$entityMeta->className}::\${$propertyMeta->name} has not defined a propper reverse relationship type in {$symetricEntityMeta->className}::\${$propertyMeta->relationshipProperty}."); } if ($propertyMeta->relationshipType === PropertyMetadata::RELATIONSHIP_MANY_HAS_MANY || $propertyMeta->relationshipType === PropertyMetadata::RELATIONSHIP_ONE_HAS_ONE_DIRECTED) { if ($propertyMeta->relationshipIsMain && $symetricPropertyMeta->relationshipIsMain) { throw new InvalidStateException("Only one side of relationship {$entityMeta->className}::\${$propertyMeta->name} × {$symetricEntityMeta->className}::\${$propertyMeta->relationshipProperty} could be defined as a primary."); } elseif (!$propertyMeta->relationshipIsMain && !$symetricPropertyMeta->relationshipIsMain) { throw new InvalidStateException("At least one side of relationship {$entityMeta->className}::\${$propertyMeta->name} × {$symetricEntityMeta->className}::\${$propertyMeta->relationshipProperty} has to be defined as a primary."); } } } } }
/** @inheritdoc */ public function remove($entity, $recursive = FALSE) { $entity = $entity instanceof IEntity ? $entity : $this->getById($entity); $this->identityMap->check($entity); if (isset($this->isProcessing[spl_object_hash($entity)])) { return $entity; } $this->isProcessing[spl_object_hash($entity)] = TRUE; $this->fireEvent($entity, 'onBeforeRemove'); foreach ($entity->getMetadata()->getProperties() as $property) { if ($property->relationship !== NULL) { if (in_array($property->relationship->type, [PropertyRelationshipMetadata::MANY_HAS_ONE, PropertyRelationshipMetadata::ONE_HAS_ONE, PropertyRelationshipMetadata::ONE_HAS_ONE_DIRECTED])) { $entity->getProperty($property->name)->set(NULL, TRUE); } elseif ($property->relationship->type === PropertyRelationshipMetadata::MANY_HAS_MANY) { $entity->getValue($property->name)->set([]); } else { $reverseRepository = $this->model->getRepository($property->relationship->repository); $reverseProperty = $reverseRepository->getEntityMetadata()->getProperty($property->relationship->property); if ($reverseProperty->isNullable || !$recursive) { $entity->getValue($property->name)->set([]); } else { foreach ($entity->getValue($property->name) as $reverseEntity) { $reverseRepository->remove($reverseEntity, $recursive); } } } } } if ($entity->isPersisted()) { $this->mapper->remove($entity); $this->identityMap->remove($entity->getPersistedId()); $this->entitiesToFlush[1][] = $entity; } $this->detach($entity); $this->fireEvent($entity, 'onAfterRemove'); unset($this->isProcessing[spl_object_hash($entity)]); return $entity; }
/** @inheritdoc */ public function remove($entity, $withCascade = true) { $entity = $entity instanceof IEntity ? $entity : $this->getById($entity); $this->identityMap->check($entity); return $this->model->remove($entity, $withCascade); }
protected function createComponentOneHasMany(Nextras\Orm\Entity\Reflection\PropertyMetadata $metadata, int $forceDefault = 0) : Kdyby\Replicator\Container { $repository = $this->model->getRepository($metadata->relationship->repository); $collection = $this->entity->getValue($metadata->name)->get()->fetchPairs(current($repository->getEntityMetadata()->getPrimaryKey())); $replicator = new Kdyby\Replicator\Container(function (Nette\Forms\Container $container) use($metadata, $repository, $collection) { $replicator = $container->parent; $name = $container->getName(); unset($container->parent[$name]); if (!($entity = $collection[$name] ?? NULL)) { $entityClassName = $repository->getEntityMetadata()->getClassName(); $entity = new $entityClassName(); } $replicator->addComponent($container = $this->form->createComponent($entity), $name); if ($container instanceof Nette\Forms\Container) { call_user_func([$container->addSubmit('delete', $this->formatPropertyAction($metadata, 'delete')), 'addRemoveOnClick'], function (Kdyby\Replicator\Container $replicator, self $container) { $container->removeEntity(TRUE); }); } }); $add = $replicator->addSubmit('add', $this->formatPropertyAction($metadata, 'add')); call_user_func([$add, 'addCreateOnClick']); $add->setValidationScope([$replicator]); $replicator->setCurrentGroup($this->getForm()->addGroup($this->prefixPropertyGroup($metadata), FALSE)->add($add)); $this[$metadata->name] = $replicator; if ($createDefault = max(count($collection), $forceDefault)) { if (!$this->getForm()->isSubmitted()) { $count = 0; while ($count++ < $createDefault) { $replicator->createOne(key($collection)); next($collection); } } elseif ($forceDefault) { while (iterator_count($replicator->getContainers()) < $createDefault) { $replicator->createOne(); } } } if ($add->isSubmittedBy()) { $isValid = TRUE; if ($scope = $add->getValidationScope()) { $isValid = !array_filter($scope, function (Nette\Forms\Container $container) { return !$container->isValid(); }); } if ($isValid) { $add->setValidationScope(FALSE); } $add->click(); $add->onClick = []; } $containers = []; foreach ($replicator->getContainers() as $container) { $delete = $container['delete'] ?? NULL; if ($delete instanceof Nette\Forms\Controls\SubmitButton && !$delete->isSubmittedBy()) { $containers[$container->name] = $container; } } if (count($containers) <= $forceDefault) { array_map(function (self $container) { unset($container['delete']); }, $containers); } else { $persistedContainers = array_filter($containers, function (self $container) { return $container->getEntity()->isPersisted(); }); if (count($persistedContainers) <= $forceDefault) { array_map(function (self $container) { unset($container['delete']); }, $persistedContainers); } } foreach ($containers as $key => $container) { if ($container instanceof Nette\ComponentModel\IContainer) { foreach ($container->getComponents(FALSE, Nette\Forms\Controls\BaseControl::class) as $control) { if ($control instanceof Nette\Forms\Controls\BaseControl && ($unique = $control->getOption('unique'))) { foreach (array_diff_key($containers, [$key => $container]) as $sibling) { $condition = $control->addCondition(Nette\Forms\Form::FILLED); if (is_string($unique) && isset($sibling[$unique]) && ($uniqueControl = $container[$unique] ?? NULL)) { if ($uniqueControl instanceof Nette\Forms\IControl) { $condition = $condition->addConditionOn($uniqueControl, Nette\Forms\Form::EQUAL, $sibling[$unique]); } } $condition->addRule(Nette\Forms\Form::NOT_EQUAL, NULL, $sibling[$control->name]); } } } } } return $replicator; }
private function normalizeAndAddJoins(array $levels, $sourceEntity, QueryBuilder $builder, &$distinctNeeded = false, &$value = null, &$modifier = '%any') { $column = array_pop($levels); $sourceMapper = $this->mapper; $sourceAlias = $builder->getFromAlias(); $sourceReflection = $sourceMapper->getStorageReflection(); $sourceEntityMeta = $this->metadataStorage->get($sourceEntity ?: $sourceMapper->getRepository()->getEntityClassNames()[0]); foreach ($levels as $levelIndex => $level) { $property = $sourceEntityMeta->getProperty($level); if ($property->relationship === null) { throw new InvalidArgumentException("Entity {$sourceEntityMeta->className}::\${$level} does not contain a relationship."); } $targetMapper = $this->model->getRepository($property->relationship->repository)->getMapper(); $targetReflection = $targetMapper->getStorageReflection(); $targetEntityMetadata = $this->metadataStorage->get($property->relationship->entity); $relType = $property->relationship->type; if ($relType === Relationship::ONE_HAS_MANY || $relType === Relationship::ONE_HAS_ONE && !$property->relationship->isMain) { $targetColumn = $targetReflection->convertEntityToStorageKey($property->relationship->property); $sourceColumn = $sourceReflection->getStoragePrimaryKey()[0]; $distinctNeeded = $relType === Relationship::ONE_HAS_MANY; } elseif ($relType === Relationship::MANY_HAS_MANY) { if ($property->relationship->isMain) { list($joinTable, list($inColumn, $outColumn)) = $sourceMapper->getManyHasManyParameters($property, $targetMapper); } else { $sourceProperty = $targetEntityMetadata->getProperty($property->relationship->property); list($joinTable, list($outColumn, $inColumn)) = $targetMapper->getManyHasManyParameters($sourceProperty, $sourceMapper); } $sourceColumn = $sourceReflection->getStoragePrimaryKey()[0]; $builder->leftJoin($sourceAlias, $joinTable, self::getAlias($joinTable), "[{$sourceAlias}.{$sourceColumn}] = [{$joinTable}.{$inColumn}]"); $sourceAlias = $joinTable; $sourceColumn = $outColumn; $targetColumn = $targetReflection->getStoragePrimaryKey()[0]; $distinctNeeded = true; } else { $targetColumn = $targetReflection->getStoragePrimaryKey()[0]; $sourceColumn = $sourceReflection->convertEntityToStorageKey($level); } $targetTable = $targetMapper->getTableName(); $targetAlias = $level . str_repeat('_', $levelIndex); $builder->leftJoin($sourceAlias, $targetTable, $targetAlias, "[{$sourceAlias}.{$sourceColumn}] = [{$targetAlias}.{$targetColumn}]"); $sourceAlias = $targetAlias; $sourceMapper = $targetMapper; $sourceReflection = $targetReflection; $sourceEntityMeta = $targetEntityMetadata; } $targetProperty = $sourceEntityMeta->getProperty($column); if ($targetProperty->isPrimary && $targetProperty->isVirtual) { // primary-proxy $primaryKey = $sourceEntityMeta->getPrimaryKey(); if (count($primaryKey) > 1) { // composite primary key $modifier = '%any'; list($expression, $value) = $this->processMultiColumn($sourceReflection, $primaryKey, $value, $sourceAlias); return $expression; } else { $column = reset($primaryKey); } } list($expression, $modifier, $value) = $this->processColumn($sourceReflection, $column, $value, $sourceAlias); return $expression; }
private function normalizeAndAddJoins(array $levels, $sourceEntity, QueryBuilder $builder, &$distinctNeeded = FALSE, &$value = NULL) { $column = array_pop($levels); $sourceMapper = $this->mapper; $sourceAlias = $builder->getFromAlias(); $sourceReflection = $sourceMapper->getStorageReflection(); $sourceEntityMeta = $this->metadataStorage->get($sourceEntity ?: $sourceMapper->getRepository()->getEntityClassNames()[0]); foreach ($levels as $levelIndex => $level) { $property = $sourceEntityMeta->getProperty($level); if ($property->relationship === NULL) { throw new InvalidArgumentException("Entity {$sourceEntityMeta->className}::\${$level} does not contain a relationship."); } $targetMapper = $this->model->getRepository($property->relationship->repository)->getMapper(); $targetReflection = $targetMapper->getStorageReflection(); $targetEntityMetadata = $this->metadataStorage->get($property->relationship->entity); $relType = $property->relationship->type; if ($relType === Relationship::ONE_HAS_MANY || $relType === Relationship::ONE_HAS_ONE_DIRECTED && !$property->relationship->isMain) { $targetColumn = $targetReflection->convertEntityToStorageKey($property->relationship->property); $sourceColumn = $sourceReflection->getStoragePrimaryKey()[0]; $distinctNeeded = TRUE; } elseif ($relType === Relationship::MANY_HAS_MANY) { if ($property->relationship->isMain) { list($joinTable, list($inColumn, $outColumn)) = $sourceMapper->getManyHasManyParameters($property, $targetMapper); } else { $sourceProperty = $targetEntityMetadata->getProperty($property->relationship->property); list($joinTable, list($outColumn, $inColumn)) = $targetMapper->getManyHasManyParameters($sourceProperty, $sourceMapper); } $sourceColumn = $sourceReflection->getStoragePrimaryKey()[0]; $builder->leftJoin($sourceAlias, $joinTable, self::getAlias($joinTable), "[{$sourceAlias}.{$sourceColumn}] = [{$joinTable}.{$inColumn}]"); $sourceAlias = $joinTable; $sourceColumn = $outColumn; $targetColumn = $targetReflection->getStoragePrimaryKey()[0]; $distinctNeeded = TRUE; } else { $targetColumn = $targetReflection->getStoragePrimaryKey()[0]; $sourceColumn = $sourceReflection->convertEntityToStorageKey($level); } $targetTable = $targetMapper->getTableName(); $targetAlias = $level . str_repeat('_', $levelIndex); $builder->leftJoin($sourceAlias, $targetTable, $targetAlias, "[{$sourceAlias}.{$sourceColumn}] = [{$targetAlias}.{$targetColumn}]"); $sourceAlias = $targetAlias; $sourceMapper = $targetMapper; $sourceReflection = $targetReflection; $sourceEntityMeta = $targetEntityMetadata; } $sourceEntityMeta->getProperty($column); // check if property exists if ($column === 'id' && count($sourceEntityMeta->getPrimaryKey()) > 1) { $pair = []; foreach ($sourceEntityMeta->getPrimaryKey() as $column) { $column = $sourceReflection->convertEntityToStorageKey($column); $pair[] = "{$sourceAlias}.{$column}"; } if (!isset($value[0][0])) { $value = [$value]; } return '(' . implode(', ', $pair) . ')'; } else { $column = $sourceReflection->convertEntityToStorageKey($column); return "{$sourceAlias}.{$column}"; } }
/** * @param IEntity $entity * @param PropertyMetadata[] $metadata * @parma IModel $model * @param array $pre */ private static function setNulls($entity, array $metadata, IModel $model, array &$pre) { foreach ($metadata as $propertyMeta) { $type = $propertyMeta->relationship->type; $name = $propertyMeta->name; $reverseRepository = $model->getRepository($propertyMeta->relationship->repository); $reverseProperty = $propertyMeta->relationship->property ? $reverseRepository->getEntityMetadata()->getProperty($propertyMeta->relationship->property) : null; if ($type === Relationship::MANY_HAS_MANY) { /** @var ManyHasMany $property */ $property = $entity->getProperty($name); $pre[] = $property; if ($reverseProperty !== null) { foreach ($property as $reverseEntity) { $pre[] = $reverseEntity->getProperty($reverseProperty->name); } } $entity->setValue($name, []); } elseif ($type === Relationship::MANY_HAS_ONE || $type === Relationship::ONE_HAS_ONE && $propertyMeta->relationship->isMain) { /** @var ManyHasOne|OneHasOne $property */ $property = $entity->getProperty($name); if ($reverseProperty !== null && $entity->hasValue($name)) { $pre[] = $entity->getValue($name)->getProperty($reverseProperty->name); } $property->set(null, true); } else { // $type === Relationship::ONE_HAS_MANY or // $type === Relationship::ONE_HAS_ONE && !$isMain if (!$entity->hasValue($name) || $reverseProperty === null) { continue; } if ($reverseProperty->isNullable) { if ($type === Relationship::ONE_HAS_MANY) { foreach ($entity->getValue($name) as $subValue) { $pre[] = $subValue; } $entity->setValue($name, []); } else { $pre[] = $entity->getValue($name); $entity->getProperty($name)->set(null, true); } } else { if ($type === Relationship::ONE_HAS_MANY && $entity->getValue($name)->count() === 0) { continue; } $entityClass = get_class($entity); $reverseEntityClass = $propertyMeta->relationship->entity; $primaryValue = $entity->getValue('id'); $primaryValue = is_array($primaryValue) ? '[' . implode(', ', $primaryValue) . ']' : $primaryValue; throw new InvalidStateException("Cannot remove {$entityClass}::\$id={$primaryValue} because {$reverseEntityClass}::\${$reverseProperty->name} cannot be a null."); } } } }
public function __construct(IModel $model, IMapper $mapper) { $this->model = $model; $this->mapper = $mapper; $this->metadataStorage = $model->getMetadataStorage(); }
/** * @param IEntity $entity * @param PropertyMetadata[] $metadata * @parma IModel $model * @param array $pre */ private static function setNulls($entity, array $metadata, IModel $model, array &$pre) { foreach ($metadata as $propertyMeta) { $type = $propertyMeta->relationship->type; $name = $propertyMeta->name; if ($type === Relationship::MANY_HAS_MANY) { $entity->setValue($name, []); } elseif ($type === Relationship::MANY_HAS_ONE || $type === Relationship::ONE_HAS_ONE && $propertyMeta->relationship->isMain) { $entity->getProperty($name)->set(NULL, TRUE); } else { // $type === Relationship::ONE_HAS_MANY or // $type === Relationship::ONE_HAS_ONE && !$isPrimary $reverseRepository = $model->getRepository($propertyMeta->relationship->repository); $reverseProperty = $reverseRepository->getEntityMetadata()->getProperty($propertyMeta->relationship->property); if ($reverseProperty->isNullable) { if ($entity->hasValue($name)) { if ($type === Relationship::ONE_HAS_MANY) { foreach ($entity->getValue($name) as $subValue) { $pre[] = $subValue; } $entity->getValue($name)->set([]); } else { $pre[] = $entity->getValue($name); $entity->setValue($name, NULL); } } } else { $entityClass = get_class($entity); $reverseEntityClass = $propertyMeta->relationship->entity; $primaryValue = $entity->getValue('id'); $primaryValue = is_array($primaryValue) ? '[' . implode(', ', $primaryValue) . ']' : $primaryValue; throw new InvalidStateException("Cannot remove {$entityClass}::\$id={$primaryValue} because {$reverseEntityClass}::\${$reverseProperty->name} cannot be a null."); } } } }