コード例 #1
1
 /**
  * Updates counter cache for a single association
  *
  * @param \Cake\Event\Event $event Event instance.
  * @param \Cake\ORM\Entity $entity Entity
  * @param Association $assoc The association object
  * @param array $settings The settings for for counter cache for this association
  * @return void
  */
 protected function _processAssociation(Event $event, Entity $entity, Association $assoc, array $settings)
 {
     $foreignKeys = (array) $assoc->foreignKey();
     $primaryKeys = (array) $assoc->target()->primaryKey();
     $countConditions = $entity->extract($foreignKeys);
     $updateConditions = array_combine($primaryKeys, $countConditions);
     $countOriginalConditions = $entity->extractOriginal($foreignKeys);
     if ($countOriginalConditions !== []) {
         $updateOriginalConditions = array_combine($primaryKeys, $countOriginalConditions);
     }
     foreach ($settings as $field => $config) {
         if (is_int($field)) {
             $field = $config;
             $config = [];
         }
         if (!is_string($config) && is_callable($config)) {
             $count = $config($event, $entity, $this->_table, false);
         } else {
             $count = $this->_getCount($config, $countConditions);
         }
         $assoc->target()->updateAll([$field => $count], $updateConditions);
         if (isset($updateOriginalConditions)) {
             if (!is_string($config) && is_callable($config)) {
                 $count = $config($event, $entity, $this->_table, true);
             } else {
                 $count = $this->_getCount($config, $countOriginalConditions);
             }
             $assoc->target()->updateAll([$field => $count], $updateOriginalConditions);
         }
     }
 }
コード例 #2
0
ファイル: HasMany.php プロジェクト: ripzappa0924/carte0.0.1
 /**
  * Takes an entity from the source table and looks if there is a field
  * matching the property name for this association. The found entity will be
  * saved on the target table for this association by passing supplied
  * `$options`
  *
  * @param \Cake\ORM\Entity $entity an entity from the source table
  * @param array|\ArrayObject $options options to be passed to the save method in
  * the target table
  * @return bool|Entity false if $entity could not be saved, otherwise it returns
  * the saved entity
  * @see Table::save()
  * @throws \InvalidArgumentException when the association data cannot be traversed.
  */
 public function save(Entity $entity, array $options = [])
 {
     $targetEntities = $entity->get($this->property());
     if (empty($targetEntities)) {
         return $entity;
     }
     if (!is_array($targetEntities) && !$targetEntities instanceof \Traversable) {
         $name = $this->property();
         $message = sprintf('Could not save %s, it cannot be traversed', $name);
         throw new \InvalidArgumentException($message);
     }
     $properties = array_combine((array) $this->foreignKey(), $entity->extract((array) $this->source()->primaryKey()));
     $target = $this->target();
     $original = $targetEntities;
     foreach ($targetEntities as $k => $targetEntity) {
         if (!$targetEntity instanceof Entity) {
             break;
         }
         if (!empty($options['atomic'])) {
             $targetEntity = clone $targetEntity;
         }
         $targetEntity->set($properties, ['guard' => false]);
         if ($target->save($targetEntity, $options)) {
             $targetEntities[$k] = $targetEntity;
             continue;
         }
         if (!empty($options['atomic'])) {
             $original[$k]->errors($targetEntity->errors());
             $entity->set($this->property(), $original);
             return false;
         }
     }
     $entity->set($this->property(), $targetEntities);
     return $entity;
 }
コード例 #3
0
 /**
  * Cascade a delete to remove dependent records.
  *
  * This method does nothing if the association is not dependent.
  *
  * @param \Cake\ORM\Entity $entity The entity that started the cascaded delete.
  * @param array $options The options for the original delete.
  * @return bool Success.
  */
 public function cascadeDelete(Entity $entity, array $options = [])
 {
     if (!$this->dependent()) {
         return true;
     }
     $table = $this->target();
     $foreignKey = (array) $this->foreignKey();
     $primaryKey = (array) $this->source()->primaryKey();
     $conditions = array_combine($foreignKey, $entity->extract($primaryKey));
     if ($this->_cascadeCallbacks) {
         $query = $this->find('all')->where($conditions)->bufferResults(false);
         foreach ($query as $related) {
             $table->delete($related, $options);
         }
         return true;
     }
     $conditions = array_merge($conditions, $this->conditions());
     return $table->deleteAll($conditions);
 }
コード例 #4
0
 /**
  * Ensures that the provided entity contains non-empty values for the left and
  * right fields
  *
  * @param \Cake\ORM\Entity $entity The entity to ensure fields for
  * @return void
  */
 protected function _ensureFields($entity)
 {
     $config = $this->config();
     $fields = [$config['left'], $config['right']];
     $values = array_filter($entity->extract($fields));
     if (count($values) === count($fields)) {
         return;
     }
     $fresh = $this->_table->get($entity->get($this->_getPrimaryKey()), $fields);
     $entity->set($fresh->extract($fields), ['guard' => false]);
     foreach ($fields as $field) {
         $entity->dirty($field, false);
     }
 }
コード例 #5
0
ファイル: EntityTest.php プロジェクト: jeremyheaton/ultiswap
 /**
  * Tests extract only dirty properties
  *
  * @return void
  */
 public function testExtractDirty()
 {
     $entity = new Entity(['id' => 1, 'title' => 'Foo', 'author_id' => 3]);
     $entity->dirty('id', false);
     $entity->dirty('title', false);
     $expected = ['author_id' => 3];
     $result = $entity->extract(['id', 'title', 'author_id'], true);
     $this->assertEquals($expected, $result);
 }
コード例 #6
0
 /**
  * Sets entity's order and updates order of other records when necessary.
  *
  * @param \Cake\Event\Event $event The beforeSave event that was fired.
  * @param \Cake\ORM\Entity $entity The entity that is going to be saved.
  * @param \ArrayObject $options The options passed to the save method.
  *
  * @return void
  */
 public function beforeSave(Event $event, Entity $entity, ArrayObject $options)
 {
     $config = $this->config();
     $newOrder = null;
     $newScope = [];
     // If scope are specified and data for all scope fields is not
     // provided we cannot calculate new order
     if ($config['scope']) {
         $newScope = $entity->extract($config['scope']);
         if (count($newScope) !== count($config['scope'])) {
             return;
         }
         // Modify where clauses when NULL values are used
         foreach ($newScope as $field => $value) {
             if (is_null($value)) {
                 $newScope[$field . ' IS'] = $value;
                 unset($newScope[$field]);
             }
         }
     }
     $orderField = $config['order'];
     $newOrder = $entity->get($orderField);
     // Adding
     if ($entity->isNew()) {
         // Order not specified
         if ($newOrder === null) {
             // Insert at end of list
             $entity->set($orderField, $this->_getHighestOrder($newScope) + 1);
             // Order specified
         } else {
             // Increment order of records it's inserted before
             $this->_sync([$orderField => $this->_getUpdateExpression('+')], [$orderField . ' >=' => $newOrder], $newScope);
         }
         // Editing
     } else {
         // No action if no new order or scope specified
         if ($newOrder === null && !$newScope) {
             return;
         }
         list($oldOrder, $oldScope) = $this->_getOldValues($entity);
         // No action if new and old scope and order same
         if ($newOrder == $oldOrder && $newScope == $oldScope) {
             return;
         }
         // If changing scope
         if ($newScope && $newScope != $oldScope) {
             // Decrement records in old scope with higher order than moved record old order
             $this->_sync([$orderField => $this->_getUpdateExpression('-')], [$orderField . ' >' => $oldOrder], $oldScope);
             // Order not specified
             if ($newOrder === null) {
                 // Insert at end of new scope
                 $entity->set($orderField, $this->_getHighestOrder($newScope) + 1);
                 // Order specified
             } else {
                 // Increment records in new scope with higher order than moved record new order
                 $this->_sync([$orderField => $this->_getUpdateExpression('+')], [$orderField . ' >=' => $newOrder], $newScope);
             }
             // Same scope
         } else {
             // If moving up
             if ($newOrder < $oldOrder) {
                 // Increment order of those in between
                 $this->_sync([$orderField => $this->_getUpdateExpression('+')], [$orderField . ' >=' => $newOrder, $orderField . ' <' => $oldOrder], $newScope);
                 // Moving down
             } else {
                 // Decrement order of those in between
                 $this->_sync([$orderField => $this->_getUpdateExpression('-')], [$orderField . ' >' => $oldOrder, $orderField . ' <=' => $newOrder], $newScope);
             }
         }
     }
 }
コード例 #7
0
ファイル: BelongsToMany.php プロジェクト: maitrepylos/nazeweb
 /**
  * Returns the list of joint entities that exist between the source entity
  * and each of the passed target entities
  *
  * @param \Cake\ORM\Entity $sourceEntity The row belonging to the source side
  *   of this association.
  * @param array $targetEntities The rows belonging to the target side of this
  *   association.
  * @throws \InvalidArgumentException if any of the entities is lacking a primary
  *   key value
  * @return array
  */
 protected function _collectJointEntities($sourceEntity, $targetEntities)
 {
     $target = $this->target();
     $source = $this->source();
     $junction = $this->junction();
     $jointProperty = $this->_junctionProperty;
     $primary = (array) $target->primaryKey();
     $result = [];
     $missing = [];
     foreach ($targetEntities as $entity) {
         $joint = $entity->get($jointProperty);
         if (!$joint) {
             $missing[] = $entity->extract($primary);
             continue;
         }
         $result[] = $joint;
     }
     if (empty($missing)) {
         return $result;
     }
     $belongsTo = $junction->association($target->alias());
     $hasMany = $source->association($junction->alias());
     $foreignKey = (array) $this->foreignKey();
     $assocForeignKey = (array) $belongsTo->foreignKey();
     $sourceKey = $sourceEntity->extract((array) $source->primaryKey());
     foreach ($missing as $key) {
         $unions[] = $hasMany->find('all')->where(array_combine($foreignKey, $sourceKey))->andWhere(array_combine($assocForeignKey, $key));
     }
     $query = array_shift($unions);
     foreach ($unions as $q) {
         $query->union($q);
     }
     return array_merge($result, $query->toArray());
 }
コード例 #8
0
ファイル: Table.php プロジェクト: nrother/cakephp
 /**
  * Validator method used to check the uniqueness of a value for a column.
  * This is meant to be used with the validation API and not to be called
  * directly.
  *
  * ### Example:
  *
  * ```
  * $validator->add('email', [
  *  'unique' => ['rule' => 'validateUnique', 'provider' => 'table']
  * ])
  * ```
  *
  * Unique validation can be scoped to the value of another column:
  *
  * ```
  * $validator->add('email', [
  *  'unique' => [
  *      'rule' => ['validateUnique', ['scope' => 'site_id']],
  *      'provider' => 'table'
  *  ]
  * ]);
  * ```
  *
  * In the above example, the email uniqueness will be scoped to only rows having
  * the same site_id. Scoping will only be used if the scoping field is present in
  * the data to be validated.
  *
  * @param mixed $value The value of column to be checked for uniqueness
  * @param array $options The options array, optionally containing the 'scope' key.
  *   May also be the validation context if there are no options.
  * @param array|null $context Either the validation context or null.
  * @return bool true if the value is unique
  */
 public function validateUnique($value, array $options, array $context = null)
 {
     if ($context === null) {
         $context = $options;
     }
     $entity = new Entity($context['data'], ['useSetters' => false, 'markNew' => $context['newRecord'], 'source' => $this->registryAlias()]);
     $fields = array_merge([$context['field']], isset($options['scope']) ? (array) $options['scope'] : []);
     $values = $entity->extract($fields);
     foreach ($values as $field) {
         if ($field !== null && !is_scalar($field)) {
             return false;
         }
     }
     $rule = new IsUnique($fields);
     return $rule($entity, ['repository' => $this]);
 }
コード例 #9
0
 /**
  * Modifies the entity before it is saved so that versioned fields are persisted
  * in the database too.
  *
  * @param \Cake\Event\Event $event The beforeSave event that was fired
  * @param \Cake\ORM\Entity $entity The entity that is going to be saved
  * @param \ArrayObject $options the options passed to the save method
  * @return void
  */
 public function beforeSave(Event $event, Entity $entity, ArrayObject $options)
 {
     $association = $this->versionAssociation();
     $name = $association->name();
     $newOptions = [$name => ['validate' => false]];
     $options['associated'] = $newOptions + $options['associated'];
     $fields = $this->_fields();
     $values = $entity->extract($fields, $this->_config['onlyDirty']);
     $model = $this->_config['referenceName'];
     $primaryKey = (array) $this->_table->primaryKey();
     $foreignKey = $this->_extractForeignKey($entity);
     $versionField = $this->_config['versionField'];
     if (isset($options['versionId'])) {
         $versionId = $options['versionId'];
     } else {
         $table = TableRegistry::get($this->_config['versionTable']);
         $preexistent = $table->find()->select(['version_id'])->where(['model' => $model] + $foreignKey)->order(['id desc'])->limit(1)->hydrate(false)->toArray();
         $versionId = Hash::get($preexistent, '0.version_id', 0) + 1;
     }
     $created = new DateTime();
     $new = [];
     foreach ($values as $field => $content) {
         if (in_array($field, $primaryKey) || $field == $versionField) {
             continue;
         }
         $data = ['version_id' => $versionId, 'model' => $model, 'field' => $field, 'content' => $content, 'created' => $created] + $foreignKey;
         $event = new Event('Model.Version.beforeSave', $this, $options);
         $userData = EventManager::instance()->dispatch($event);
         if (isset($userData->result) && is_array($userData->result)) {
             $data = array_merge($data, $userData->result);
         }
         $entityClass = $table->entityClass();
         $new[$field] = new $entityClass($data, ['useSetters' => false, 'markNew' => true]);
     }
     $entity->set($association->property(), $new);
     if (!empty($versionField) && in_array($versionField, $this->_table->schema()->columns())) {
         $entity->set($this->_config['versionField'], $versionId);
     }
 }
コード例 #10
0
ファイル: HasOne.php プロジェクト: ripzappa0924/carte0.0.1
 /**
  * Takes an entity from the source table and looks if there is a field
  * matching the property name for this association. The found entity will be
  * saved on the target table for this association by passing supplied
  * `$options`
  *
  * @param \Cake\ORM\Entity $entity an entity from the source table
  * @param array|\ArrayObject $options options to be passed to the save method in
  * the target table
  * @return bool|Entity false if $entity could not be saved, otherwise it returns
  * the saved entity
  * @see Table::save()
  */
 public function save(Entity $entity, array $options = [])
 {
     $targetEntity = $entity->get($this->property());
     if (empty($targetEntity) || !$targetEntity instanceof Entity) {
         return $entity;
     }
     $properties = array_combine((array) $this->foreignKey(), $entity->extract((array) $this->source()->primaryKey()));
     $targetEntity->set($properties, ['guard' => false]);
     if (!$this->target()->save($targetEntity, $options)) {
         $targetEntity->unsetProperty(array_keys($properties));
         return false;
     }
     return $entity;
 }
コード例 #11
0
 /**
  * Modifies the entity before it is saved so that versioned fields are persisted
  * in the database too.
  *
  * @param \Cake\Event\Event $event The beforeSave event that was fired
  * @param \Cake\ORM\Entity $entity The entity that is going to be saved
  * @param \ArrayObject $options the options passed to the save method
  * @return void
  */
 public function beforeSave(Event $event, Entity $entity, ArrayObject $options)
 {
     $table = $this->_config['versionTable'];
     $newOptions = [$table => ['validate' => false]];
     $options['associated'] = $newOptions + $options['associated'];
     $fields = $this->_fields();
     $values = $entity->extract($fields);
     $model = $this->_table->alias();
     $primaryKey = (array) $this->_table->primaryKey();
     $primaryKey = current($primaryKey);
     $foreignKey = $entity->get($primaryKey);
     $versionField = $this->_config['versionField'];
     $preexistent = TableRegistry::get($table)->find()->select(['version_id'])->where(compact('foreign_key', 'model'))->order(['id desc'])->limit(1)->hydrate(false)->toArray();
     $versionId = Hash::get($preexistent, '0.version_id', 0) + 1;
     $created = new Time();
     foreach ($values as $field => $content) {
         if ($field == $primaryKey || $field == $versionField) {
             continue;
         }
         $data = ['version_id' => $versionId, 'model' => $model, 'foreign_key' => $foreignKey, 'field' => $field, 'content' => $content, 'created' => $created];
         $new[$field] = new Entity($data, ['useSetters' => false, 'markNew' => true]);
     }
     $entity->set('__version', $new);
     if (!empty($versionField) && in_array($versionField, $fields)) {
         $entity->set($this->_config['versionField'], $versionId);
     }
 }