/** * 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; } }
/** * Perform the delete operation. * * Will soft delete the entity provided. Will remove rows from any * dependent associations, and clear out join tables for BelongsToMany associations. * * @param \Cake\DataSource\EntityInterface $entity The entity to soft delete. * @param \ArrayObject $options The options for the delete. * @throws \InvalidArgumentException if there are no primary key values of the * passed entity * @return bool success */ protected function _processDelete($entity, $options) { if ($entity->isNew()) { return false; } $primaryKey = (array) $this->primaryKey(); if (!$entity->has($primaryKey)) { $msg = 'Deleting requires all primary key values.'; throw new \InvalidArgumentException($msg); } if ($options['checkRules'] && !$this->checkRules($entity, RulesChecker::DELETE, $options)) { return false; } $event = $this->dispatchEvent('Model.beforeDelete', ['entity' => $entity, 'options' => $options]); if ($event->isStopped()) { return $event->result; } $this->_associations->cascadeDelete($entity, ['_primary' => false] + $options->getArrayCopy()); $query = $this->query(); $conditions = (array) $entity->extract($primaryKey); $statement = $query->update()->set([$this->getSoftDeleteField() => 0])->where($conditions)->execute(); $success = $statement->rowCount() > 0; if (!$success) { return $success; } $this->dispatchEvent('Model.afterDelete', ['entity' => $entity, 'options' => $options]); return $success; }
/** * 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. * @throws \RuntimeException When the rule refers to an undefined association. * @return bool */ public function __invoke(EntityInterface $entity, array $options) { if (is_string($this->_repository)) { $alias = $this->_repository; $this->_repository = $options['repository']->association($alias); if (empty($this->_repository)) { throw new RuntimeException(sprintf("ExistsIn rule for '%s' is invalid. The '%s' association is not defined.", implode(', ', $this->_fields), $alias)); } } $source = $target = $this->_repository; if (!empty($options['repository'])) { $source = $options['repository']; } if ($source instanceof Association) { $source = $source->source(); } if ($target instanceof Association) { $bindingKey = (array) $target->bindingKey(); $target = $target->target(); } else { $bindingKey = (array) $target->primaryKey(); } if (!empty($options['_sourceTable']) && $target === $options['_sourceTable']) { return true; } if (!$entity->extract($this->_fields, true)) { return true; } if ($this->_fieldsAreNull($entity, $source)) { return true; } $primary = array_map([$target, 'aliasField'], $bindingKey); $conditions = array_combine($primary, $entity->extract($this->_fields)); return $target->exists($conditions); }
/** * 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); }
/** * 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); }
/** * 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); } }
/** * Send the reset password email to the user * * @param EntityInterface $user User entity * @param string $template string, note the first_name of the user will be prepended if exists * * @return array email send result */ protected function resetPassword(EntityInterface $user, $template = 'CakeDC/Users.reset_password') { $firstName = isset($user['first_name']) ? $user['first_name'] . ', ' : ''; $subject = __d('Users', '{0}Your reset password link', $firstName); $user->hiddenProperties(['password', 'token_expires', 'api_token']); $this->to($user['email'])->subject($subject)->viewVars($user->toArray())->template($template); }
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; }
public function beforeSave(Event $event, EntityInterface $entity) { $config = $this->config(); $new = $entity->isNew(); if ($config['when'] === 'always' || $config['when'] === 'new' && $new || $config['when'] === 'existing' && !$new) { $this->slug($entity); } }
/** * 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; }
/** * Render a multi select with all available tags of entity and the tags of attachment preselected * * @param EntityInterface $entity the entity to get all allowed tags from * @param Attachment\Model\Entity\Attachment $attachment the attachment entity to add the tag to * @return string */ public function tagsChooser(EntityInterface $entity, $attachment) { if (!TableRegistry::exists($entity->source())) { throw new Cake\Network\Exception\MissingTableException('Could not find Table ' . $entity->source()); } $Table = TableRegistry::get($entity->source()); return $this->Form->select('tags', $Table->getAttachmentsTags(), ['type' => 'select', 'class' => 'tag-chooser', 'style' => 'display: block; width: 100%', 'label' => false, 'multiple' => true, 'value' => $attachment->tags]); }
public function afterSaveCommit(Event $event, EntityInterface $entity, \ArrayObject $options) { $rev = $this->_table->Revisions->newEntity(); unset($entity->revisions); $rev->data = $entity->toArray(); $rev->ref = $this->_table->alias(); $rev->ref_id = $entity->id; $this->_table->Revisions->save($rev); }
/** * 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()); } }
/** * Gets the repository for this entity * * @param EntityInterface $entity * @return Table */ protected function _repository($entity) { $source = $entity->source(); if ($source === null) { list(, $class) = namespaceSplit(get_class($entity)); $source = Inflector::pluralize($class); } return TableRegistry::get($source); }
/** * afterSave Callback * * @param Event $event CakePHP Event * @param EntityInterface $entity Entity that was saved * @return void */ public function afterSave(Event $event, EntityInterface $entity) { $action = $entity->isNew() ? ModelHistory::ACTION_CREATE : ModelHistory::ACTION_UPDATE; $dirtyFields = null; if ($action === ModelHistory::ACTION_UPDATE && isset($this->_dirtyFields[$entity->id])) { $dirtyFields = $this->_dirtyFields[$entity->id]; unset($this->_dirtyFields[$entity->id]); } $this->ModelHistory->add($entity, $action, $this->_getUserId(), ['dirtyFields' => $dirtyFields]); }
public function toggle(EntityInterface $entity) { $limit = $this->config('implementedServices.' . $entity->source())->config('limit'); if ($limit !== 1) { throw new Exception(sprintf('Toggle disabled, type "%s" limit is "%s"', $entity->source(), $limit)); } // if current user in $entity->reviewed_by // if so goto unreview // else goto review }
public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options) { if (empty($entity->display)) { $entity->display = Inflector::humanize($entity->name); } if ($entity->dirty('is_default') && $entity->is_default) { $this->updateAll(['is_default' => false], ['is_default' => true]); } elseif ($entity->dirty('is_default') && !$entity->is_default) { $entity->is_default = $entity->getOriginal('is_default'); } }
/** * 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; }
/** * 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)); } }
/** * DRY for update active and token based on validateEmail flag * * @param EntityInterface $user User to be updated. * @param type $validateEmail email user to validate. * @param type $tokenExpiration token to be updated. * @return EntityInterface */ protected function _updateActive(EntityInterface $user, $validateEmail, $tokenExpiration) { $emailValidated = $user['validated']; if (!$emailValidated && $validateEmail) { $user['active'] = false; $user->updateToken($tokenExpiration); } else { $user['active'] = true; $user['activation_date'] = new Time(); } return $user; }
/** * Save the file to the storage backend after the record was created. * * @param \Cake\Event\Event $event * @param \Cake\Datasource\EntityInterface $entity * @return void */ public function afterSave(Event $event, EntityInterface $entity) { if ($this->_checkEvent($event) && $entity->isNew()) { $fileField = $this->config('fileField'); $entity['hash'] = $this->getFileHash($entity, $fileField); $entity['path'] = $this->pathBuilder()->path($entity); if (!$this->_storeFile($event)) { return; } $event->stopPropagation(); } }
/** * Performs the uniqueness 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 (!$entity->extract($this->_fields, true)) { return true; } $conditions = $entity->extract($this->_fields); if ($entity->isNew() === false) { $keys = (array) $options['repository']->primaryKey(); $keys = $entity->extract($keys); if (array_filter($keys, 'strlen')) { $conditions['NOT'] = $keys; } } return !$options['repository']->exists($conditions); }
/** * Validates a single entity by getting the correct validator object from * the table and traverses associations passed in $options to validate them * as well. * * @param \Cake\Datasource\EntityInterface $entity The entity to be validated * @param array|\ArrayObject $options options for validation, including an optional key of * associations to also be validated. This argument should use the same format as the $options * argument to \Cake\ORM\Table::save(). * @return bool true if all validations passed, false otherwise */ public function one(EntityInterface $entity, $options = []) { $valid = true; $types = [Association::ONE_TO_ONE, Association::MANY_TO_ONE]; $propertyMap = $this->_buildPropertyMap($options); $options = new ArrayObject($options); foreach ($propertyMap as $key => $assoc) { $value = $entity->get($key); $association = $assoc['association']; if (!$value) { continue; } $isOne = in_array($association->type(), $types); if ($isOne && !$value instanceof EntityInterface) { $valid = false; continue; } $validator = new self($association->target()); if ($isOne) { $valid = $validator->one($value, $assoc['options']) && $valid; } else { $valid = $validator->many($value, $assoc['options']) && $valid; } } if (!isset($options['validate'])) { $options['validate'] = true; } if (!$entity instanceof ValidatableInterface) { return $valid; } return $this->_processValidation($entity, $options) && $valid; }
/** * Save the file to the storage backend after the record was created. * * @param \Cake\Event\Event $event * @param \Cake\Datasource\EntityInterface $entity * @return void */ public function afterSave(Event $event, EntityInterface $entity) { if ($this->_checkEvent($event) && $entity->isNew()) { $fileField = $this->config('fileField'); $entity['hash'] = $this->getFileHash($entity, $fileField); $entity['path'] = $this->pathBuilder()->fullPath($entity); if (!$this->_storeFile($event)) { return; } if ($this->_config['imageProcessing'] === true) { $this->autoProcessImageVersions($entity, 'create'); } $event->result = true; $event->stopPropagation(); } }
/** * 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)); } } }
/** * Modify entity * * @param \Cake\Datasource\EntityInterface entity * @param \Cake\ORM\Association table * @param string path prefix * @return void */ protected function _modifyEntity(EntityInterface $entity, Association $table = null, $pathPrefix = '') { if (is_null($table)) { $table = $this->_table; } // unset primary key unset($entity->{$table->primaryKey()}); // unset foreign key if ($table instanceof Association) { unset($entity->{$table->foreignKey()}); } // unset configured foreach ($this->config('remove') as $field) { $field = $this->_fieldByPath($field, $pathPrefix); if ($field) { unset($entity->{$field}); } } // set / prepend / append foreach (['set', 'prepend', 'append'] as $action) { foreach ($this->config($action) as $field => $value) { $field = $this->_fieldByPath($field, $pathPrefix); if ($field) { if ($action == 'prepend') { $value .= $entity->{$field}; } if ($action == 'append') { $value = $entity->{$field} . $value; } $entity->{$field} = $value; } } } // set as new $entity->isNew(true); // modify related entities foreach ($this->config('contain') as $contain) { if (preg_match('/^' . preg_quote($pathPrefix, '/') . '([^.]+)/', $contain, $matches)) { foreach ($entity->{Inflector::tableize($matches[1])} as $related) { if ($related->isNew()) { continue; } $this->_modifyEntity($related, $table->{$matches[1]}, $pathPrefix . $matches[1] . '.'); } } } }
/** * Extracts nested validation errors * * @param EntityInterface $entity Entity to extract * * @return array */ protected function _getErrors(EntityInterface $entity) { $errors = $entity->errors(); foreach ($entity->visibleProperties() as $property) { $v = $entity[$property]; if ($v instanceof EntityInterface) { $errors[$property] = $this->_getErrors($v); } elseif (is_array($v)) { foreach ($v as $key => $varValue) { if ($varValue instanceof EntityInterface) { $errors[$property][$key] = $this->_getErrors($varValue); } } } } return Hash::filter($errors); }
/** * 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; } $conditions = array_combine((array) $this->_repository->primaryKey(), $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; } }
/** * Cascade a delete to remove dependent records. * * This method does nothing if the association is not dependent. * * @param \Cake\Datasource\EntityInterface $entity The entity that started the cascaded delete. * @param array $options The options for the original delete. * @return bool Success. */ public function cascadeDelete(EntityInterface $entity, array $options = []) { if (!$this->dependent()) { return true; } $table = $this->target(); $foreignKey = (array) $this->foreignKey(); $bindingKey = (array) $this->bindingKey(); $conditions = array_combine($foreignKey, $entity->extract($bindingKey)); if ($this->_cascadeCallbacks) { foreach ($this->find()->where($conditions)->toList() as $related) { $table->delete($related, $options); } return true; } $conditions = array_merge($conditions, $this->conditions()); return $table->deleteAll($conditions); }