Пример #1
0
 public function beforeSave(Event $event, EntityInterface $entity)
 {
     if ($entity === null) {
         return true;
     }
     $isNew = $entity->isNew();
     $fields = $this->config('fields');
     $ip = self::$_request->clientIp();
     foreach ($fields as $field => $when) {
         $when = strtolower($when);
         if (!in_array($when, ['always', 'new'])) {
             throw new UnexpectedValueException(sprintf('"When" should be one of "always", "new". The passed value "%s" is invalid', $when));
         }
         switch ($when) {
             case 'always':
                 $entity->set($field, $ip);
                 continue;
                 break;
             case 'new':
                 if ($isNew) {
                     $entity->set($field, $ip);
                     continue;
                 }
                 break;
         }
     }
     return true;
 }
 /**
  * Generates IDs for an entity before it is saved to the database.
  *
  * @param Event $event Instance of save event
  * @param EntityInterface $entity Entity being saved
  */
 public function beforeSave(Event $event, EntityInterface $entity)
 {
     // Check if entity is being created in database
     // If so, update appropriate ID fields if present
     if ($entity->isNew()) {
         $entity->set($this->config('base64.field'), $this->generateBase64Id());
         $entity->set($this->config('uuid.field'), $this->generateUuid());
     }
 }
Пример #3
0
 /**
  * Event listener to encrypt data.
  *
  * @param \Cake\Event\Event $event Event.
  * @param \Cake\Datasource\EntityInterface $entity Entity.
  * @return void
  */
 public function beforeSave(Event $event, EntityInterface $entity)
 {
     $driver = $this->_table->connection()->driver();
     foreach ($this->config('fields') as $field => $type) {
         if (!$entity->has($field)) {
             continue;
         }
         $raw = $entity->get($field);
         $plain = Type::build($type)->toDatabase($raw, $driver);
         $entity->set($field, $this->encrypt($plain));
     }
 }
 /**
  * Save also related model data
  *
  * @param \Cake\Event\Event
  * @param \Cake\ORM\Entity;
  * @return void
  */
 public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $options)
 {
     foreach ($this->config('fields') as $field => $mapped) {
         list($mappedTable, $mappedField) = explode('.', $mapped);
         if (!isset($this->_table->{$mappedTable}) || $this->_table->{$mappedTable}->isOwningSide($this->_table)) {
             throw new Exception(sprintf('Incorrect definition of related data to persist for %s', $mapped));
         }
         $foreign = $entity->get($this->_table->{$mappedTable}->foreignKey());
         if (!is_null($foreign)) {
             // get related entity
             $related = $this->_table->{$mappedTable}->get($foreign);
             // set field value
             $entity->set($field, $related->get($mappedField));
         }
     }
 }
 /**
  * Save also related model data
  *
  * @param \Cake\Event\Event
  * @param \Cake\ORM\Entity;
  * @return void
  */
 public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $options)
 {
     $relatedEntities = [];
     foreach ($this->config('fields') as $field => $mapped) {
         list($mappedTable, $mappedField) = explode('.', $mapped);
         if (!isset($this->_table->{$mappedTable}) || $this->_table->{$mappedTable}->isOwningSide($this->_table)) {
             throw new Exception(sprintf('Incorrect definition of related data to persist for %s', $mapped));
         }
         $foreignKeys = $entity->extract((array) $this->_table->{$mappedTable}->foreignKey());
         $dirtyForeignKeys = $entity->extract((array) $this->_table->{$mappedTable}->foreignKey(), true);
         if (!empty($dirtyForeignKeys)) {
             // get related entity
             if (empty($relatedEntities[$mappedTable])) {
                 $relatedEntities[$mappedTable] = $this->_table->{$mappedTable}->get($foreignKeys);
             }
             // set field value
             $entity->set($field, $relatedEntities[$mappedTable]->get($mappedField));
         }
     }
 }
 /**
  * Helper method used to generated multiple translated field entities
  * out of the data found in the `_translations` property in the passed
  * entity. The result will be put into its `_i18n` property
  *
  * @param \Cake\Datasource\EntityInterface $entity Entity
  * @return void
  */
 protected function _bundleTranslatedFields($entity)
 {
     $translations = (array) $entity->get('_translations');
     if (empty($translations) && !$entity->dirty('_translations')) {
         return;
     }
     $primaryKey = (array) $this->_table->primaryKey();
     $key = $entity->get(current($primaryKey));
     foreach ($translations as $lang => $translation) {
         if (!$translation->id) {
             $update = ['id' => $key, 'locale' => $lang];
             $translation->set($update, ['guard' => false]);
         }
     }
     $entity->set('_i18n', $translations);
 }
Пример #7
0
 /**
  * Update a field, if it hasn't been updated already
  *
  * @param \Cake\Datasource\EntityInterface $entity Entity instance.
  * @param string $field Field name
  * @param bool $refreshTimestamp Whether to refresh timestamp.
  * @return void
  */
 protected function _updateField($entity, $field, $refreshTimestamp)
 {
     if ($entity->dirty($field)) {
         return;
     }
     $entity->set($field, $this->timestamp(null, $refreshTimestamp));
 }
Пример #8
0
 /**
  * Merges `$data` into `$entity` and recursively does the same for each one of
  * the association names passed in `$options`. When merging associations, if an
  * entity is not present in the parent entity for a given association, a new one
  * will be created.
  *
  * When merging HasMany or BelongsToMany associations, all the entities in the
  * `$data` array will appear, those that can be matched by primary key will get
  * the data merged, but those that cannot, will be discarded.
  *
  * ### Options:
  *
  * * associated: Associations listed here will be marshalled as well.
  * * fieldList: A whitelist of fields to be assigned to the entity. If not present
  *   the accessible fields list in the entity will be used.
  *
  * @param \Cake\Datasource\EntityInterface $entity the entity that will get the
  * data merged in
  * @param array $data key value list of fields to be merged into the entity
  * @param array $options List of options.
  * @return \Cake\Datasource\EntityInterface
  */
 public function merge(EntityInterface $entity, array $data, array $options = [])
 {
     $propertyMap = $this->_buildPropertyMap($options);
     $tableName = $this->_table->alias();
     if (isset($data[$tableName])) {
         $data = $data[$tableName];
     }
     $schema = $this->_table->schema();
     $properties = [];
     foreach ($data as $key => $value) {
         $columnType = $schema->columnType($key);
         $original = $entity->get($key);
         if (isset($propertyMap[$key])) {
             $assoc = $propertyMap[$key]['association'];
             $value = $this->_mergeAssociation($original, $assoc, $value, $propertyMap[$key]);
         } elseif ($columnType) {
             $converter = Type::build($columnType);
             $value = $converter->marshal($value);
             $isObject = is_object($value);
             if (!$isObject && $original === $value || $isObject && $original == $value) {
                 continue;
             }
         }
         $properties[$key] = $value;
     }
     if (!isset($options['fieldList'])) {
         $entity->set($properties);
         return $entity;
     }
     foreach ((array) $options['fieldList'] as $field) {
         if (isset($properties[$field])) {
             $entity->set($field, $properties[$field]);
         }
     }
     return $entity;
 }
Пример #9
0
 /**
  * Merges `$data` into `$entity` and recursively does the same for each one of
  * the association names passed in `$options`. When merging associations, if an
  * entity is not present in the parent entity for a given association, a new one
  * will be created.
  *
  * When merging HasMany or BelongsToMany associations, all the entities in the
  * `$data` array will appear, those that can be matched by primary key will get
  * the data merged, but those that cannot, will be discarded. `ids` option can be used
  * to determine whether the association must use the `_ids` format.
  *
  * ### Options:
  *
  * - associated: Associations listed here will be marshalled as well.
  * - validate: Whether or not to validate data before hydrating the entities. Can
  *   also be set to a string to use a specific validator. Defaults to true/default.
  * - fieldList: A whitelist of fields to be assigned to the entity. If not present
  *   the accessible fields list in the entity will be used.
  * - accessibleFields: A list of fields to allow or deny in entity accessible fields.
  *
  * The above options can be used in each nested `associated` array. In addition to the above
  * options you can also use the `onlyIds` option for HasMany and BelongsToMany associations.
  * When true this option restricts the request data to only be read from `_ids`.
  *
  * ```
  * $result = $marshaller->merge($entity, $data, [
  *   'associated' => ['Tags' => ['onlyIds' => true]]
  * ]);
  * ```
  *
  * @param \Cake\Datasource\EntityInterface $entity the entity that will get the
  * data merged in
  * @param array $data key value list of fields to be merged into the entity
  * @param array $options List of options.
  * @return \Cake\Datasource\EntityInterface
  */
 public function merge(EntityInterface $entity, array $data, array $options = [])
 {
     list($data, $options) = $this->_prepareDataAndOptions($data, $options);
     $propertyMap = $this->_buildPropertyMap($options);
     $isNew = $entity->isNew();
     $keys = [];
     if (!$isNew) {
         $keys = $entity->extract((array) $this->_table->primaryKey());
     }
     if (isset($options['accessibleFields'])) {
         foreach ((array) $options['accessibleFields'] as $key => $value) {
             $entity->accessible($key, $value);
         }
     }
     $errors = $this->_validate($data + $keys, $options, $isNew);
     $schema = $this->_table->schema();
     $properties = $marshalledAssocs = [];
     foreach ($data as $key => $value) {
         if (!empty($errors[$key])) {
             if ($entity instanceof InvalidPropertyInterface) {
                 $entity->invalid($key, $value);
             }
             continue;
         }
         $columnType = $schema->columnType($key);
         $original = $entity->get($key);
         if (isset($propertyMap[$key])) {
             $assoc = $propertyMap[$key]['association'];
             $value = $this->_mergeAssociation($original, $assoc, $value, $propertyMap[$key]);
             $marshalledAssocs[$key] = true;
         } elseif ($columnType) {
             $converter = Type::build($columnType);
             $value = $converter->marshal($value);
             $isObject = is_object($value);
             if (!$isObject && $original === $value || $isObject && $original == $value) {
                 continue;
             }
         }
         $properties[$key] = $value;
     }
     if (!isset($options['fieldList'])) {
         $entity->set($properties);
         $entity->errors($errors);
         foreach (array_keys($marshalledAssocs) as $field) {
             if ($properties[$field] instanceof EntityInterface) {
                 $entity->dirty($field, $properties[$field]->dirty());
             }
         }
         return $entity;
     }
     foreach ((array) $options['fieldList'] as $field) {
         if (array_key_exists($field, $properties)) {
             $entity->set($field, $properties[$field]);
             if ($properties[$field] instanceof EntityInterface && isset($marshalledAssocs[$field])) {
                 $entity->dirty($field, $properties[$field]->dirty());
             }
         }
     }
     $entity->errors($errors);
     return $entity;
 }
Пример #10
0
 /**
  * Auxiliary function to handle the insert of an entity's data in the table
  *
  * @param \Cake\Datasource\EntityInterface $entity the subject entity from were $data was extracted
  * @param array $data The actual data that needs to be saved
  * @return \Cake\Datasource\EntityInterface|bool
  * @throws \RuntimeException if not all the primary keys where supplied or could
  * be generated when the table has composite primary keys. Or when the table has no primary key.
  */
 protected function _insert($entity, $data)
 {
     $primary = (array) $this->primaryKey();
     if (empty($primary)) {
         $msg = sprintf('Cannot insert row in "%s" table, it has no primary key.', $this->table());
         throw new RuntimeException($msg);
     }
     $keys = array_fill(0, count($primary), null);
     $id = (array) $this->_newId($primary) + $keys;
     $primary = array_combine($primary, $id);
     $filteredKeys = array_filter($primary, 'strlen');
     $data = $data + $filteredKeys;
     if (count($primary) > 1) {
         $schema = $this->schema();
         foreach ($primary as $k => $v) {
             if (!isset($data[$k]) && empty($schema->column($k)['autoIncrement'])) {
                 $msg = 'Cannot insert row, some of the primary key values are missing. ';
                 $msg .= sprintf('Got (%s), expecting (%s)', implode(', ', $filteredKeys + $entity->extract(array_keys($primary))), implode(', ', array_keys($primary)));
                 throw new RuntimeException($msg);
             }
         }
     }
     $success = false;
     if (empty($data)) {
         return $success;
     }
     $statement = $this->query()->insert(array_keys($data))->values($data)->execute();
     if ($statement->rowCount() !== 0) {
         $success = $entity;
         $entity->set($filteredKeys, ['guard' => false]);
         $schema = $this->schema();
         $driver = $this->connection()->driver();
         foreach ($primary as $key => $v) {
             if (!isset($data[$key])) {
                 $id = $statement->lastInsertId($this->table(), $key);
                 $type = $schema->columnType($key);
                 $entity->set($key, Type::build($type)->toPHP($id, $driver));
                 break;
             }
         }
     }
     $statement->closeCursor();
     return $success;
 }
Пример #11
0
 /**
  * Replaces existing association links between the source entity and the target
  * with the ones passed. This method does a smart cleanup, links that are already
  * persisted and present in `$targetEntities` will not be deleted, new links will
  * be created for the passed target entities that are not already in the database
  * and the rest will be removed.
  *
  * For example, if an author has many articles, such as 'article1','article 2' and 'article 3' and you pass
  * to this method an array containing the entities for articles 'article 1' and 'article 4',
  * only the link for 'article 1' will be kept in database, the links for 'article 2' and 'article 3' will be
  * deleted and the link for 'article 4' will be created.
  *
  * Existing links are not deleted and created again, they are either left untouched
  * or updated.
  *
  * This method does not check link uniqueness.
  *
  * On success, the passed `$sourceEntity` will contain `$targetEntities` as  value
  * in the corresponding property for this association.
  *
  * Additional options for new links to be saved can be passed in the third argument,
  * check `Table::save()` for information on the accepted options.
  *
  * ### Example:
  *
  * ```
  * $author->articles = [$article1, $article2, $article3, $article4];
  * $authors->save($author);
  * $articles = [$article1, $article3];
  * $authors->association('articles')->replaceLinks($author, $articles);
  * ```
  *
  * `$author->get('articles')` will contain only `[$article1, $article3]` at the end
  *
  * @param \Cake\Datasource\EntityInterface $sourceEntity an entity persisted in the source table for
  * this association
  * @param array $targetEntities list of entities from the target table to be linked
  * @param array $options list of options to be passed to the internal `save`/`delete` calls
  * when persisting/updating new links, or deleting existing ones
  * @throws \InvalidArgumentException if non persisted entities are passed or if
  * any of them is lacking a primary key value
  * @return bool success
  */
 public function replace(EntityInterface $sourceEntity, array $targetEntities, array $options = [])
 {
     $property = $this->property();
     $sourceEntity->set($property, $targetEntities);
     $saveStrategy = $this->saveStrategy();
     $this->saveStrategy(self::SAVE_REPLACE);
     $result = $this->saveAssociated($sourceEntity, $options);
     $ok = $result instanceof EntityInterface;
     if ($ok) {
         $sourceEntity = $result;
     }
     $this->saveStrategy($saveStrategy);
     return $ok;
 }
Пример #12
0
 /**
  * When default server timezone is set as UTC (-> database stores dates as UTC) and the user's locale is not UTC, dates properties are updated in forms in the user's locale
  * As CakePHP 3.0.0-alpha2 marshalls dates values sent from forms in the default locale UTC, the timezones must be corrected to be saved correctly
  * 
  * Using this Listener allows to change the saved datetime timezones easily
  * 
  * Usage:
  *      AppController:
  *          
  *          Configure::write('display_timezone', 'Europe/Zurich);
  *          
  *      UsersController:
  *          
  *          $this->Users->eventManager()->attach(new TimezoneEventListener());
  *          
  *          $user = $this->Users->patchEntity($user, $this->request->data);
  * 
  * @param Event $event
  * @param EntityInterface $entity
  * @param unknown $options
  * @param Validator $validator
  * @return boolean
  */
 public function update_datetime_fields_timezone(Event $event, EntityInterface $entity, $options = [], Validator $validator)
 {
     $display_timezone = isset($this->_config['display_timezone']) ? $this->_config['display_timezone'] : Configure::read('display_timezone');
     $default_timezone = date_default_timezone_get();
     if (!empty($display_timezone) && $display_timezone != $default_timezone) {
         $data = $entity->toArray();
         foreach ($data as $property => $value) {
             if (!in_array($property, $this->_config['skipped_properties'])) {
                 $type = $event->subject()->schema()->columnType($property);
                 if ($type == 'datetime') {
                     if (is_a($data[$property], 'Cake\\I18n\\Time')) {
                         /*
                          * At this step, as the datetime has already been marshalled, the datetime has the value selected in the view, but its timezone is wrong
                          *
                          * Create a new Time object with the values from the saved datetime, but with the timezone used for display
                          */
                         $timezoned_value = Time::create($data[$property]->year, $data[$property]->month, $data[$property]->day, $data[$property]->hour, $data[$property]->minute, $data[$property]->second, $display_timezone);
                     } elseif (is_array($data[$property])) {
                         /*
                          * Actually if the Listener is attached to 'Model.beforeValidate', we probably never fall here as the date array has already been marshalled
                          */
                         $data[$property]['year'] = isset($data[$property]['year']) ? $data[$property]['year'] : null;
                         $data[$property]['month'] = isset($data[$property]['month']) ? $data[$property]['month'] : null;
                         $data[$property]['day'] = isset($data[$property]['day']) ? $data[$property]['day'] : null;
                         $data[$property]['hour'] = isset($data[$property]['hour']) ? $data[$property]['hour'] : null;
                         $data[$property]['minute'] = isset($data[$property]['minute']) ? $data[$property]['minute'] : null;
                         $data[$property]['second'] = isset($data[$property]['second']) ? $data[$property]['second'] : null;
                         $timezoned_value = Time::create($data[$property]['year'], $data[$property]['month'], $data[$property]['day'], $data[$property]['hour'], $data[$property]['minute'], $data[$property]['second'], $display_timezone);
                     }
                     if (isset($timezoned_value)) {
                         /*
                          * Transform the Time object to UTC timezone
                          */
                         $timezoned_value->setTimezone($default_timezone);
                         $entity->set($property, $timezoned_value);
                     }
                 }
             }
         }
     }
     return true;
 }
 /**
  * beforeSave callback.
  *
  * @param \Cake\Event\Event $event Event.
  * @param \Cake\Datasource\EntityInterface $entity Entity.
  * @return void
  */
 public function beforeSave(Event $event, EntityInterface $entity)
 {
     $field = $this->_config['discriminatorField'];
     if ($entity->isNew() && !$entity->has($field)) {
         $discriminator = $this->discriminator();
         $entity->set($field, $discriminator);
     }
 }
Пример #14
0
 /**
  * Sets up hashid for model.
  *
  * @param \Cake\Datasource\EntityInterface $entity The entity that is going to be saved
  * @return bool True if save should proceed, false otherwise
  */
 public function encode(EntityInterface $entity)
 {
     $idField = $this->_primaryKey;
     $id = $entity->get($idField);
     if (!$id) {
         return false;
     }
     $field = $this->_config['field'];
     if (!$field) {
         return false;
     }
     $hashid = $this->encodeId($id);
     $entity->set($field, $hashid);
     $entity->dirty($field, false);
     return true;
 }
Пример #15
0
 /**
  * Prepares entity's cache-columns (those defined using `cache` option).
  *
  * @param \Cake\Datasource\EntityInterface $entity The entity to prepare
  * @return \Cake\Datasource\EntityInterfa Modified entity
  */
 protected function _prepareCachedColumns(EntityInterface $entity)
 {
     if ($this->config('cacheMap')) {
         foreach ((array) $this->config('cacheMap') as $column => $fields) {
             if (in_array($column, $entity->visibleProperties())) {
                 $string = $entity->get($column);
                 if ($string == serialize(false) || @unserialize($string) !== false) {
                     $entity->set($column, unserialize($string));
                 } else {
                     $entity->set($column, new CachedColumn());
                 }
             }
         }
     }
     return $entity;
 }
Пример #16
0
 /**
  * Helper method used to generated multiple translated field entities
  * out of the data found in the `_translations` property in the passed
  * entity. The result will be put into its `_i18n` property
  *
  * @param \Cake\Datasource\EntityInterface $entity Entity
  * @return void
  */
 protected function _bundleTranslatedFields($entity)
 {
     $translations = (array) $entity->get('_translations');
     if (empty($translations) && !$entity->dirty('_translations')) {
         return;
     }
     $fields = $this->_config['fields'];
     $primaryKey = (array) $this->_table->primaryKey();
     $key = $entity->get(current($primaryKey));
     $find = [];
     foreach ($translations as $lang => $translation) {
         foreach ($fields as $field) {
             if (!$translation->dirty($field)) {
                 continue;
             }
             $find[] = ['locale' => $lang, 'field' => $field, 'foreign_key' => $key];
             $contents[] = new Entity(['content' => $translation->get($field)], ['useSetters' => false]);
         }
     }
     if (empty($find)) {
         return;
     }
     $results = $this->_findExistingTranslations($find);
     foreach ($find as $i => $translation) {
         if (!empty($results[$i])) {
             $contents[$i]->set('id', $results[$i], ['setter' => false]);
             $contents[$i]->isNew(false);
         } else {
             $translation['model'] = $this->_config['referenceName'];
             $contents[$i]->set($translation, ['setter' => false, 'guard' => false]);
             $contents[$i]->isNew(true);
         }
     }
     $entity->set('_i18n', $contents);
 }
Пример #17
0
 /**
  * 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\Datasource\EntityInterface $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|\Cake\Datasource\EntityInterface 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 saveAssociated(EntityInterface $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->bindingKey()));
     $target = $this->target();
     $original = $targetEntities;
     $options['_sourceTable'] = $this->source();
     foreach ($targetEntities as $k => $targetEntity) {
         if (!$targetEntity instanceof EntityInterface) {
             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;
 }
Пример #18
0
 /**
  * Callback to obfuscate the record(s)' primary key returned after a save operation.
  *
  * @param \Cake\ORM\Behavior\Event $event Event.
  * @param \Cake\ORM\Behavior\EntityInterface $entity Entity.
  * @param \ArrayObject $options Options.
  * @return void
  */
 public function afterSave(Event $event, EntityInterface $entity, ArrayObject $options)
 {
     $pk = $this->_table->primaryKey();
     $entity->set($pk, $this->obfuscate($entity->{$pk}));
     $entity->dirty($pk, false);
 }
Пример #19
0
 /**
  * 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\Datasource\EntityInterface $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|\Cake\Datasource\EntityInterface false if $entity could not be saved, otherwise it returns
  * the saved entity
  * @see Table::save()
  */
 public function saveAssociated(EntityInterface $entity, array $options = [])
 {
     $targetEntity = $entity->get($this->property());
     if (empty($targetEntity) || !$targetEntity instanceof EntityInterface) {
         return $entity;
     }
     $table = $this->target();
     $targetEntity = $table->save($targetEntity, $options);
     if (!$targetEntity) {
         return false;
     }
     $properties = array_combine((array) $this->foreignKey(), $targetEntity->extract((array) $this->bindingKey()));
     $entity->set($properties, ['guard' => false]);
     return $entity;
 }
Пример #20
0
 /**
  * Merges `$data` into `$entity` and recursively does the same for each one of
  * the association names passed in `$include`. When merging associations, if an
  * entity is not present in the parent entity for a given association, a new one
  * will be created.
  *
  * When merging HasMany or BelongsToMany associations, all the entities in the
  * `$data` array will appear, those that can be matched by primary key will get
  * the data merged, but those that cannot, will be discarded.
  *
  * @param \Cake\Datasource\EntityInterface $entity the entity that will get the
  * data merged in
  * @param array $data key value list of fields to be merged into the entity
  * @param array $include The list of associations to be merged
  * @return \Cake\Datasource\EntityInterface
  */
 public function merge(EntityInterface $entity, array $data, array $include = [])
 {
     $propertyMap = $this->_buildPropertyMap($include);
     $tableName = $this->_table->alias();
     if (isset($data[$tableName])) {
         $data = $data[$tableName];
     }
     $schema = $this->_table->schema();
     $properties = [];
     foreach ($data as $key => $value) {
         $columnType = $schema->columnType($key);
         $original = $entity->get($key);
         if (isset($propertyMap[$key])) {
             $assoc = $propertyMap[$key]['association'];
             $nested = $propertyMap[$key]['nested'];
             $value = $this->_mergeAssociation($original, $assoc, $value, $nested);
         } elseif ($columnType) {
             $converter = Type::build($columnType);
             $value = $converter->marshal($value);
             if ($original == $value) {
                 continue;
             }
         }
         $properties[$key] = $value;
     }
     $entity->set($properties);
     return $entity;
 }
Пример #21
0
 /**
  * Restores all (or given) trashed row(s).
  *
  * @param \Cake\Datasource\EntityInterface|null $entity to restore.
  * @return bool|\Cake\Datasource\EntityInterface|int|mixed
  */
 public function restoreTrash(EntityInterface $entity = null)
 {
     $data = [$this->getTrashField(false) => null];
     if ($entity instanceof EntityInterface) {
         if ($entity->dirty()) {
             throw new RuntimeException('Can not restore from a dirty entity.');
         }
         $entity->set($data);
         return $this->_table->save($entity);
     }
     return $this->_table->updateAll($data, $this->_getUnaryExpression());
 }
Пример #22
0
 /**
  * Merges `$data` into `$entity`.
  *
  * ### Options:
  *
  * * validate: Whether or not to validate data before hydrating the entities. Can
  *   also be set to a string to use a specific validator. Defaults to true/default.
  * * fieldList: A whitelist of fields to be assigned to the entity. If not present
  *   the accessible fields list in the entity will be used.
  * * accessibleFields: A list of fields to allow or deny in entity accessible fields.
  *
  * @param \Cake\Datasource\EntityInterface $entity the entity that will get the
  * data merged in
  * @param array $data key value list of fields to be merged into the entity
  * @param array $options List of options.
  * @return \Cake\Datasource\EntityInterface
  */
 public function merge(EntityInterface $entity, array $data, array $options = [])
 {
     list($data, $options) = $this->_prepareDataAndOptions($data, $options);
     $isNew = $entity->isNew();
     $keys = [];
     if (!$isNew) {
         $keys = $entity->extract((array) $this->_endpoint->primaryKey());
     }
     if (isset($options['accessibleFields'])) {
         foreach ((array) $options['accessibleFields'] as $key => $value) {
             $entity->accessible($key, $value);
         }
     }
     $errors = $this->_validate($data + $keys, $options, $isNew);
     $properties = [];
     foreach ($data as $key => $value) {
         if (!empty($errors[$key])) {
             continue;
         }
         $properties[$key] = $value;
     }
     if (!isset($options['fieldList'])) {
         $entity->set($properties);
         $entity->errors($errors);
         return $entity;
     }
     foreach ((array) $options['fieldList'] as $field) {
         if (array_key_exists($field, $properties)) {
             $entity->set($field, $properties[$field]);
         }
     }
     $entity->errors($errors);
     return $entity;
 }
Пример #23
0
 /**
  * Ensures that the provided entity contains non-empty values for the left and
  * right fields
  *
  * @param \Cake\Datasource\EntityInterface $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);
     }
 }
 /**
  * Merges `$data` into `$document`.
  *
  * ### Options:
  *
  * * fieldList: A whitelist of fields to be assigned to the entity. If not present
  *   the accessible fields list in the entity will be used.
  *
  * @param \Cake\Datasource\EntityInterface $entity the entity that will get the
  * data merged in
  * @param array $data key value list of fields to be merged into the entity
  * @param array $options List of options.
  * @return \Cake\Datasource\EntityInterface
  */
 public function merge(EntityInterface $entity, array $data, array $options = [])
 {
     list($data, $options) = $this->_prepareDataAndOptions($data, $options);
     $errors = $this->_validate($data, $options, $entity->isNew());
     $entity->errors($errors);
     foreach (array_keys($errors) as $badKey) {
         unset($data[$badKey]);
     }
     foreach ($this->type->embedded() as $embed) {
         $property = $embed->property();
         if (in_array($embed->alias(), $options['associated']) && isset($data[$property])) {
             $data[$property] = $this->mergeNested($embed, $entity->{$property}, $data[$property]);
         }
     }
     if (!isset($options['fieldList'])) {
         $entity->set($data);
         return $entity;
     }
     foreach ((array) $options['fieldList'] as $field) {
         if (array_key_exists($field, $data)) {
             $entity->set($field, $data[$field]);
         }
     }
     return $entity;
 }