Пример #1
0
 /**
  * Checks if the given menu link should be marked as active.
  *
  * If `$item->activation` is a callable function it will be used to determinate
  * if the link should be active or not, returning true from callable indicates
  * link should be active, false indicates it should not be marked as active.
  * Callable receives current request object as first argument and $item as second.
  *
  * `$item->url` property MUST exists if "activation" is not a callable, and can
  * be either:
  *
  * - A string representing an external or internal URL (all internal links must
  *   starts with "/"). e.g. `/user/login`
  *
  * - An array compatible with \Cake\Routing\Router::url(). e.g. `['controller'
  *   => 'users', 'action' => 'login']`
  *
  * Both examples are equivalent.
  *
  * @param \Cake\Datasource\EntityInterface $item A menu's item
  * @return bool
  */
 public function isActive(EntityInterface $item)
 {
     if ($item->has('activation') && is_callable($item->get('activation'))) {
         $callable = $item->get('activation');
         return $callable($this->_View->request, $item);
     }
     $itemUrl = $this->sanitize($item->get('url'));
     if (!str_starts_with($itemUrl, '/')) {
         return false;
     }
     switch ($item->get('activation')) {
         case 'any':
             return $this->_requestMatches($item->get('active'));
         case 'none':
             return !$this->_requestMatches($item->get('active'));
         case 'php':
             return php_eval($item->get('active'), ['view', &$this->_View, 'item', &$item]) === true;
         case 'auto':
         default:
             static $requestUri = null;
             static $requestUrl = null;
             if ($requestUri === null) {
                 $requestUri = urldecode(env('REQUEST_URI'));
                 $requestUrl = str_replace('//', '/', '/' . urldecode($this->_View->request->url) . '/');
             }
             $isInternal = $itemUrl !== '/' && str_ends_with($itemUrl, str_replace_once($this->baseUrl(), '', $requestUri));
             $isIndex = $itemUrl === '/' && $this->_View->request->isHome();
             $isExact = str_replace('//', '/', "{$itemUrl}/") === $requestUrl || $itemUrl == $requestUri;
             if ($this->config('breadcrumbGuessing')) {
                 return $isInternal || $isIndex || $isExact || in_array($itemUrl, $this->_crumbs());
             }
             return $isInternal || $isIndex || $isExact;
     }
 }
 /**
  * Gets the image version data used to generate the versions.
  *
  * @param \Cake\Datasource\EntityInterface $entity An ImageStorage database record.
  * @param array $options Options for the version.
  * @return array Version data information as array.
  */
 protected function _getImageVersionData(EntityInterface $entity, array $options = [])
 {
     $versionData = (array) Configure::read('FileStorage.imageSizes.' . $entity->get('model'));
     if (isset($options['originalVersion'])) {
         $versionData['original'] = $options['originalVersion'];
     } else {
         Configure::write('FileStorage.imageSizes.' . $entity->get('model') . '.original', []);
         $versionData['original'] = [];
     }
     $versionData['original'] = isset($options['originalVersion']) ? $options['originalVersion'] : 'original';
     return $versionData;
 }
Пример #3
0
 /**
  * Performs the existence check
  *
  * @param \Cake\Datasource\EntityInterface $entity The entity from where to extract the fields
  * @param array $options Options passed to the check,
  * where the `repository` key is required.
  * @return bool
  */
 public function __invoke(EntityInterface $entity, array $options)
 {
     if (is_string($this->_repository)) {
         $this->_repository = $options['repository']->association($this->_repository);
     }
     $source = !empty($options['repository']) ? $options['repository'] : $this->_repository;
     $source = $source instanceof Association ? $source->source() : $source;
     $target = $this->_repository;
     if ($target instanceof Association) {
         $bindingKey = (array) $target->bindingKey();
         $target = $this->_repository->target();
     } else {
         $bindingKey = (array) $target->primaryKey();
     }
     if (!empty($options['_sourceTable']) && $target === $options['_sourceTable']) {
         return true;
     }
     if (!$entity->extract($this->_fields, true)) {
         return true;
     }
     $nulls = 0;
     $schema = $source->schema();
     foreach ($this->_fields as $field) {
         if ($schema->column($field) && $schema->isNullable($field) && $entity->get($field) === null) {
             $nulls++;
         }
     }
     if ($nulls === count($this->_fields)) {
         return true;
     }
     $primary = array_map([$this->_repository, 'aliasField'], $bindingKey);
     $conditions = array_combine($primary, $entity->extract($this->_fields));
     return $this->_repository->exists($conditions);
 }
 /**
  * afterSave Event
  *
  * @param Event $event Event
  * @param EntityInterface $entity Entity to be saved
  * @return void
  */
 public function afterSave(Event $event, EntityInterface $entity)
 {
     $uploads = $entity->get($this->config('formFieldName'));
     if (!empty($uploads)) {
         $this->Attachments->addUploads($entity, $uploads);
     }
 }
Пример #5
0
 /**
  * Performs the existence check
  *
  * @param \Cake\Datasource\EntityInterface $entity The entity from where to extract the fields
  * @param array $options Options passed to the check,
  * where the `repository` key is required.
  * @return bool
  */
 public function __invoke(EntityInterface $entity, array $options)
 {
     if (is_string($this->_repository)) {
         $this->_repository = $options['repository']->association($this->_repository);
     }
     if (!empty($options['_sourceTable'])) {
         $source = $this->_repository instanceof Association ? $this->_repository->target() : $this->_repository;
         if ($source === $options['_sourceTable']) {
             return true;
         }
     }
     if (!$entity->extract($this->_fields, true)) {
         return true;
     }
     $nulls = 0;
     $schema = $this->_repository->schema();
     foreach ($this->_fields as $field) {
         if ($schema->isNullable($field) && $entity->get($field) === null) {
             $nulls++;
         }
     }
     if ($nulls === count($this->_fields)) {
         return true;
     }
     $alias = $this->_repository->alias();
     $primary = array_map(function ($key) use($alias) {
         return "{$alias}.{$key}";
     }, (array) $this->_repository->primaryKey());
     $conditions = array_combine($primary, $entity->extract($this->_fields));
     return $this->_repository->exists($conditions);
 }
 /**
  * Triggers the callback "afterDetach", it also deletes all associated records
  * in the "field_values" table.
  *
  * @param \Cake\Event\Event $event The event that was triggered
  * @param \Field\Model\Entity\FieldInstance $instance The Field Instance that was deleted
  * @param \ArrayObject $options the options passed to the delete method
  * @return void
  */
 public function afterDelete(Event $event, FieldInstance $instance, ArrayObject $options = null)
 {
     if (!empty($this->_deleted)) {
         TableRegistry::get('Eav.EavAttributes')->delete($this->_deleted->get('eav_attribute'));
         $instance->afterDetach();
         $this->_deleted = null;
     }
 }
Пример #7
0
 /**
  * Callback before save entity.
  *
  * @param Event $event
  * @param EntityInterface $entity
  * @param \ArrayObject $options
  * @return bool
  */
 public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $options)
 {
     //  Hack for test fieldToggle.
     if ($entity->get('id') == 4) {
         return false;
     }
     return true;
 }
Пример #8
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));
         }
     }
 }
 /**
  * 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);
     }
     $foreignKey = (array) $this->foreignKey();
     $properties = array_combine($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;
         }
         if ($properties !== $targetEntity->extract($foreignKey)) {
             $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;
 }
Пример #11
0
 /**
  * Returns the depth level of a node in the tree.
  *
  * @param int|string|\Cake\Datasource\EntityInterface $entity The entity or primary key get the level of.
  * @return int|bool Integer of the level or false if the node does not exist.
  */
 public function getLevel($entity)
 {
     $primaryKey = $this->_getPrimaryKey();
     $id = $entity;
     if ($entity instanceof EntityInterface) {
         $id = $entity->get($primaryKey);
     }
     $config = $this->config();
     $entity = $this->_table->find('all')->select([$config['path']])->where([$primaryKey => $id])->first();
     if ($entity === null) {
         return false;
     }
     return substr_count($entity[$config['path']], '-') + 1;
 }
Пример #12
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);
 }
 /**
  * checkRules rule.
  *
  * @param \Cake\Datasource\EntityInterface $entity Entity.
  * @return bool
  */
 public function checkRules(EntityInterface $entity)
 {
     $field = $this->_config['discriminatorField'];
     if ($entity->dirty($field)) {
         return $this->_matches($entity->get($field), $this->acceptedDiscriminators());
     }
     return true;
 }
Пример #14
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;
     }
     $properties = array_combine((array) $this->foreignKey(), $entity->extract((array) $this->bindingKey()));
     $targetEntity->set($properties, ['guard' => false]);
     if (!$this->target()->save($targetEntity, $options)) {
         $targetEntity->unsetProperty(array_keys($properties));
         return false;
     }
     return $entity;
 }
Пример #15
0
 /**
  * Removes all links between the passed source entity and each of the provided
  * target entities. This method assumes that all passed objects are already persisted
  * in the database and that each of them contain a primary key value.
  *
  * ### Options
  *
  * Additionally to the default options accepted by `Table::delete()`, the following
  * keys are supported:
  *
  * - cleanProperty: Whether or not to remove all the objects in `$targetEntities` that
  * are stored in `$sourceEntity` (default: true)
  *
  * By default this method will unset each of the entity objects stored inside the
  * source entity.
  *
  * Changes are persisted in the database and also in the source entity.
  *
  * ### Example:
  *
  * ```
  * $user = $users->get(1);
  * $user->articles = [$article1, $article2, $article3, $article4];
  * $users->save($user, ['Associated' => ['Articles']]);
  * $allArticles = [$article1, $article2, $article3];
  * $users->Articles->unlink($user, $allArticles);
  * ```
  *
  * `$article->get('articles')` will contain only `[$article4]` after deleting in the database
  *
  * @param \Cake\Datasource\EntityInterface $sourceEntity an entity persisted in the source table for
  * this association
  * @param array $targetEntities list of entities persisted in the target table for
  * this association
  * @param array $options list of options to be passed to the internal `delete` call
  * @throws \InvalidArgumentException if non persisted entities are passed or if
  * any of them is lacking a primary key value
  * @return void
  */
 public function unlink(EntityInterface $sourceEntity, array $targetEntities, $options = [])
 {
     if (is_bool($options)) {
         $options = ['cleanProperty' => $options];
     } else {
         $options += ['cleanProperty' => true];
     }
     $foreignKey = (array) $this->foreignKey();
     $target = $this->target();
     $targetPrimaryKey = array_merge((array) $target->primaryKey(), $foreignKey);
     $property = $this->property();
     $conditions = ['OR' => (new Collection($targetEntities))->map(function ($entity) use($targetPrimaryKey) {
         return $entity->extract($targetPrimaryKey);
     })->toList()];
     $this->_unlink($foreignKey, $target, $conditions, $options);
     if ($options['cleanProperty']) {
         $sourceEntity->set($property, (new Collection($sourceEntity->get($property)))->reject(function ($assoc) use($targetEntities) {
             return in_array($assoc, $targetEntities);
         })->toList());
     }
     $sourceEntity->dirty($property, false);
 }
Пример #16
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`
  *
  * When using the 'append' strategy, this function will only create new links
  * between each side of this association. It will not destroy existing ones even
  * though they may not be present in the array of entities to be saved.
  *
  * When using the 'replace' strategy, existing links will be removed and new links
  * will be created in the joint table. If there exists links in the database to some
  * of the entities intended to be saved by this method, they will be updated,
  * not deleted.
  *
  * @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
  * @throws \InvalidArgumentException if the property representing the association
  * in the parent entity cannot be traversed
  * @return bool|\Cake\Datasource\EntityInterface false if $entity could not be saved, otherwise it returns
  * the saved entity
  * @see Table::save()
  * @see BelongsToMany::replaceLinks()
  */
 public function saveAssociated(EntityInterface $entity, array $options = [])
 {
     $targetEntity = $entity->get($this->property());
     $strategy = $this->saveStrategy();
     $isEmpty = in_array($targetEntity, [null, [], '', false], true);
     if ($isEmpty && $entity->isNew()) {
         return $entity;
     }
     if ($isEmpty) {
         $targetEntity = [];
     }
     if ($strategy === self::SAVE_APPEND) {
         return $this->_saveTarget($entity, $targetEntity, $options);
     }
     if ($this->replaceLinks($entity, $targetEntity, $options)) {
         return $entity;
     }
     return false;
 }
Пример #17
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;
 }
Пример #18
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;
 }
Пример #19
0
 /**
  * Generates a unique hash for the given entity.
  *
  * Used by revision system to detect if an entity has changed or not.
  *
  * @param \Cake\Datasource\EntityInterface $entity The entity for which calculate its hash
  * @return string MD5 hash for this particular entity
  */
 protected function _calculateHash($entity)
 {
     $hash = [];
     foreach ($entity->visibleProperties() as $property) {
         if (strpos($property, 'created') === false && strpos($property, 'created_by') === false && strpos($property, 'modified') === false && strpos($property, 'modified_by') === false) {
             if ($property == '_fields') {
                 foreach ($entity->get('_fields') as $field) {
                     if ($field instanceof \Field\Model\Entity\Field) {
                         $hash[] = is_object($field->value) || is_array($field->value) ? md5(serialize($field->value)) : md5($field->value);
                     }
                 }
             } else {
                 $hash[] = $entity->get($property);
             }
         }
     }
     return md5(serialize($hash));
 }
 /**
  * After the main file was deleted remove the the thumbnails
  *
  * Note that we do not call the parent::afterDelete(), we just want to trigger the ImageStorage.afterDelete event but not the FileStorage.afterDelete at the same time!
  *
  * @param \Cake\Event\Event $event
  * @param \Cake\Datasource\EntityInterface $entity
  * @param array $options
  * @return boolean
  */
 public function afterDelete(Event $event, EntityInterface $entity, $options)
 {
     $this->dispatchEvent('ImageStorage.afterDelete', ['record' => $entity, 'storage' => $this->storageAdapter($entity->get('adapter'))]);
     return true;
 }
Пример #21
0
 /**
  * Check whether or not the entity fields are nullable and null.
  *
  * @param \Cake\Datasource\EntityInterface $entity The entity to check.
  * @param \Cake\ORM\Table $source The table to use schema from.
  * @return bool
  */
 protected function _fieldsAreNull($entity, $source)
 {
     $nulls = 0;
     $schema = $source->schema();
     foreach ($this->_fields as $field) {
         if ($schema->column($field) && $schema->isNullable($field) && $entity->get($field) === null) {
             $nulls++;
         }
     }
     return $nulls === count($this->_fields);
 }
Пример #22
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;
 }
 /**
  * Checks if the entity can be deleted.
  *
  * @param EntityInterface $entity
  * @return bool
  */
 protected function _deleteAllowed(EntityInterface $entity)
 {
     $type = $this->_formatTypeName();
     if ($type !== false) {
         $fieldName = $this->config('field_name');
         if ($entity->has($fieldName) && strpos($entity->get($fieldName), $type) === false) {
             return false;
         }
     }
     return true;
 }
 /**
  * Delete a single resource.
  *
  * @param \Cake\Datasource\EntityInterface $resource The resource to remove.
  * @param array|\ArrayAccess $options The options for the delete.
  * @return bool success
  */
 public function delete(EntityInterface $resource, $options = [])
 {
     return (bool) $this->query()->delete()->where([$this->primaryKey() => $resource->get($this->primaryKey())])->execute();
 }
Пример #25
0
 /**
  * Calculates entity's primary key.
  *
  * If PK is composed of multiple columns they will be merged with `:` symbol.
  * For example, consider `Users` table with composed PK <nick, email>, then for
  * certain User entity this method could return:
  *
  *     john-locke:john@the-island.com
  *
  * @param \Cake\Datasource\EntityInterface $entity The entity
  * @return string
  */
 public function getEntityId(EntityInterface $entity)
 {
     $pk = [];
     $keys = $this->_table->primaryKey();
     $keys = !is_array($keys) ? [$keys] : $keys;
     foreach ($keys as $key) {
         $pk[] = $entity->get($key);
     }
     return implode(':', $pk);
 }
 /**
  * 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);
 }
Пример #27
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;
 }
Пример #28
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;
 }
Пример #29
0
 /**
  * Returns the depth level of a node in the tree.
  *
  * @param int|string|\Cake\Datasource\EntityInterface $entity The entity or primary key get the level of.
  * @return int|bool Integer of the level or false if the node does not exist.
  */
 public function getLevel($entity)
 {
     $primaryKey = $this->_getPrimaryKey();
     $id = $entity;
     if ($entity instanceof EntityInterface) {
         $id = $entity->get($primaryKey);
     }
     $config = $this->config();
     $entity = $this->_table->find('all')->select([$config['left'], $config['right']])->where([$primaryKey => $id])->first();
     if ($entity === null) {
         return false;
     }
     $query = $this->_table->find('all')->where([$config['left'] . ' <' => $entity[$config['left']], $config['right'] . ' >' => $entity[$config['right']]]);
     return $this->_scope($query)->count();
 }
Пример #30
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);
     $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();
     $options['isMerge'] = true;
     $propertyMap = $this->_buildPropertyMap($data, $options);
     $properties = $marshalledAssocs = [];
     foreach ($data as $key => $value) {
         if (!empty($errors[$key])) {
             if ($entity instanceof InvalidPropertyInterface) {
                 $entity->invalid($key, $value);
             }
             continue;
         }
         $original = $entity->get($key);
         if (isset($propertyMap[$key])) {
             $value = $propertyMap[$key]($value, $entity);
             // Don't dirty scalar values and objects that didn't
             // change. Arrays will always be marked as dirty because
             // the original/updated list could contain references to the
             // same objects, even though those objects may have changed internally.
             if (is_scalar($value) && $original === $value || $value === null && $original === $value || is_object($value) && !$value instanceof EntityInterface && $original == $value) {
                 continue;
             }
         }
         $properties[$key] = $value;
     }
     $entity->errors($errors);
     if (!isset($options['fieldList'])) {
         $entity->set($properties);
         foreach ($properties as $field => $value) {
             if ($value instanceof EntityInterface) {
                 $entity->dirty($field, $value->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) {
                 $entity->dirty($field, $properties[$field]->dirty());
             }
         }
     }
     return $entity;
 }