/** * Save related entities * * @param EntityInterface $entity Entity to save relation from * @param string $relationName Name of the relation to save * @param array $options Options to pass to the mappers * @return boolean */ public function save(EntityInterface $entity, $relationName, $options = []) { $lastResult = false; $relatedEntity = $entity->relation($relationName); $relatedMapper = $this->mapper()->getMapper($this->entityName()); //Autoloaded relation, no need to save if ($relatedEntity instanceof HasOne) { return 0; } if ($relatedEntity === false || $relatedEntity->get($this->foreignKey()) !== $entity->primaryKey()) { if ($relatedMapper->entityManager()->fields()[$this->foreignKey()]['notnull']) { $relatedMapper->delete([$this->foreignKey() => $entity->primaryKey()]); } else { $relatedMapper->queryBuilder()->builder()->update($relatedMapper->table())->set($this->foreignKey(), null)->where([$this->foreignKey() => $entity->primaryKey()]); } if ($relatedEntity instanceof EntityInterface) { //Update the foreign key to match the main entity primary key $relatedEntity->set($this->foreignKey(), $entity->primaryKey()); } } if ($relatedEntity instanceof EntityInterface && ($relatedEntity->isNew() || $relatedEntity->isModified())) { $lastResult = $relatedMapper->save($relatedEntity, $options); } return $lastResult; }
/** * Save related entities * * @param ntityInterface $entity Entity to save relation from * @param string $relationName Name of the relation to save * @param array $options Options to pass to the mappers * @return boolean */ public function save(EntityInterface $entity, $relationName, $options = []) { $lastResult = 0; $relatedEntity = $entity->relation($relationName); if ($relatedEntity instanceof EntityInterface) { if ($relatedEntity->isNew() || $relatedEntity->isModified()) { $relatedMapper = $this->mapper()->getMapper($this->entityName()); $lastResult = $relatedMapper->save($relatedEntity, $options); //Update the local key to match the related entity primary key if ($entity->get($this->localKey()) !== $relatedEntity->primaryKey()) { $relatedRelations = $entity->relations($relatedMapper, $relatedEntity); //Check if it was a hasOne or a hasMany relation, //if hasOne, we must unset old value foreach ($relatedRelations as $relatedRelation) { if ($relatedRelation instanceof Relation\HasOne && $relatedRelation->foreignKey() === $this->localKey()) { if ($relatedMapper->entityManager()->fields()[$relatedRelation->foreignKey()]['notnull']) { $lastResult = $relatedMapper->delete([$relatedRelation->foreignKey() => $entity->get($relatedRelation->foreignKey())]); } else { $lastResult = $relatedMapper->queryBuilder()->builder()->update($relatedMapper->table())->set($relatedRelation->foreignKey(), null)->where([$relatedRelation->foreignKey() => $entity->get($relatedRelation->foreignKey())]); } } } $entity->set($this->localKey(), $relatedEntity->primaryKey()); } } } return $lastResult; }
/** * Run set validation rules on fields */ public function validate(EntityInterface $entity) { $v = new \Valitron\Validator($entity->data()); // Run beforeValidate to know whether or not we can continue if (false === $this->eventEmitter()->emit('beforeValidate', [$entity, $this, $v])) { return false; } // Check validation rules on each feild $uniqueWhere = []; foreach ($this->fields() as $field => $fieldAttrs) { // Required field if (isset($fieldAttrs['required']) && true === $fieldAttrs['required'] || $fieldAttrs['primary'] === true && $fieldAttrs['autoincrement'] === false) { $v->rule('required', $field); } // Unique field if ($entity->isNew() && isset($fieldAttrs['unique']) && !empty($fieldAttrs['unique']) && $entity->{$field} !== null) { if (is_string($fieldAttrs['unique'])) { // Named group $fieldKeyName = $fieldAttrs['unique']; $uniqueWhere[$fieldKeyName][$field] = $entity->{$field}; } else { $uniqueWhere[$field] = $entity->{$field}; } } // Run only if field required if ($entity->{$field} !== null && $fieldAttrs['required'] === true) { // Field with 'options' if (isset($fieldAttrs['options']) && is_array($fieldAttrs['options'])) { $v->rule('in', $field, $fieldAttrs['options']); } // Valitron validation rules if (isset($fieldAttrs['validation']) && is_array($fieldAttrs['validation'])) { foreach ($fieldAttrs['validation'] as $rule => $ruleName) { $params = []; if (is_string($rule)) { $params = (array) $ruleName; $ruleName = $rule; } $params = array_merge([$ruleName, $field], $params); call_user_func_array([$v, 'rule'], $params); } } } } // Unique validation if (!empty($uniqueWhere)) { foreach ($uniqueWhere as $field => $value) { if (!is_array($value)) { $value = [$field => $entity->{$field}]; } if (!in_array(null, $value, true) && $this->first($value) !== false) { $entity->error($field, "" . ucwords(str_replace('_', ' ', $field)) . " '" . implode('-', $value) . "' is already taken."); } } } if (!$v->validate()) { $entity->errors($v->errors(), false); } // Run afterValidate to run additional/custom validations if (false === $this->eventEmitter()->emit('afterValidate', [$entity, $this, $v])) { return false; } // Return error result return !$entity->hasErrors(); }
/** * Save related entities * * @param EntityInterface $entity Entity to save relation from * @param string $relationName Name of the relation to save * @param array $options Options to pass to the mappers * @return boolean */ public function save(EntityInterface $entity, $relationName, $options = []) { $relatedEntities = $entity->relation($relationName); $deletedIds = []; $lastResult = false; $relatedMapper = $this->mapper()->getMapper($this->entityName()); if (is_array($relatedEntities) || $relatedEntities instanceof Entity\Collection) { $oldEntities = $this->execute(); $relatedIds = []; foreach ($relatedEntities as $related) { if ($related->isNew() || $related->isModified() || $related->get($this->foreignKey()) !== $entity->primaryKey()) { //Update the foreign key to match the main entity primary key $related->set($this->foreignKey(), $entity->primaryKey()); $lastResult = $relatedMapper->save($related, $options); } $relatedIds[] = $related->id; } foreach ($oldEntities as $oldRelatedEntity) { if (!in_array($oldRelatedEntity, $relatedIds)) { $deletedIds[] = $oldRelatedEntity->primaryKey(); } } } if (count($deletedIds) || $relatedEntities === false) { $conditions = [$this->foreignKey() => $entity->primaryKey()]; if (count($deletedIds)) { $conditions[$this->localKey() . ' :in'] = $deletedIds; } if ($relatedMapper->entityManager()->fields()[$this->foreignKey()]['notnull']) { $relatedMapper->delete($conditions); } else { $relatedMapper->queryBuilder()->builder()->update($relatedMapper->table())->set($this->foreignKey(), null)->where($conditions); } } return $lastResult; }
/** * Save related entities * * @param EntityInterface $entity Entity to save relation from * @param string $relationName Name of the relation to save * @param array $options Options to pass to the mappers * @return boolean */ public function save(EntityInterface $entity, $relationName, $options = []) { $deletedIds = []; $lastResult = false; $relatedMapper = $this->mapper()->getMapper($this->entityName()); $relatedEntities = $entity->relation($relationName); $oldEntities = $this->execute(); if (is_array($relatedEntities) || $relatedEntities instanceof Entity\Collection) { $throughMapper = $this->mapper()->getMapper($this->throughEntityName()); $relatedMapper = $this->mapper()->getMapper($this->entityName()); $relatedIds = []; foreach ($relatedEntities as $related) { if ($related->isNew() || $related->isModified()) { $lastResult = $relatedMapper->save($related, $options); } $relatedIds[] = $related->primaryKey(); if (!count($throughMapper->where([$this->localKey() => $entity->primaryKey(), $this->foreignKey() => $related->primaryKey()]))) { $lastResult = $throughMapper->create([$this->localKey() => $entity->primaryKey(), $this->foreignKey() => $related->primaryKey()]); } } $deletedIds = []; foreach ($oldEntities as $oldRelatedEntity) { if (!in_array($oldRelatedEntity->primaryKey(), $relatedIds)) { $deletedIds[] = $oldRelatedEntity->primaryKey(); } } if (!empty($deletedIds)) { $throughMapper->delete([$this->localKey() => $entity->primaryKey(), $this->foreignKey() . ' :in' => $deletedIds]); } } else { if ($relatedEntities === false) { //Relation was deleted, remove all $throughMapper = $this->mapper()->getMapper($this->throughEntityName()); $throughMapper->delete([$this->localKey() => $entity->primaryKey()]); } } return $lastResult; }
/** * Validate related entity if it is new or modified only * @param \Spot\EntityInterface $relatedEntity * @param \Spot\EntityInterface $entity * @param \Spot\Relation\RelationAbstract $relation * @return array Related entity errors */ protected function validateRelatedEntity(EntityInterface $relatedEntity, EntityInterface $entity, \Spot\Relation\RelationAbstract $relation) { $tainted = $relatedEntity->isNew() || $relatedEntity->isModified(); $errorsRelated = []; if ($tainted && !$this->getMapper(get_class($relatedEntity))->validate($relatedEntity)) { $errorsRelated = $relatedEntity->errors(); //Disable validation on foreign key field it will be filled up later on when the new entity is persisted if (($relation instanceof Relation\HasMany || $relation instanceof Relation\HasOne) && $relatedEntity->isNew()) { unset($errorsRelated[$relation->foreignKey()]); } $relatedEntity->errors($errorsRelated); } if ($relation instanceof Relation\BelongsTo && $entity->isNew()) { $errors = $entity->errors(); unset($errors[$relation->localKey()]); $entity->errors($errors); } return $errorsRelated; }