/** * 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; }
/** * 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; } }
/** * 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)); } }
/** * Delete a single entity. * * Deletes an entity and possibly related associations from the database * based on the 'dependent' option used when defining the association. * * Triggers the `Model.beforeDelete` and `Model.afterDelete` events. * * @param \Cake\Datasource\EntityInterface $entity The entity to remove. * @param array $options The options for the delete. * @return bool success */ public function delete(EntityInterface $entity, $options = []) { if (!$entity->has('id')) { $msg = 'Deleting requires an "id" value.'; throw new InvalidArgumentException($msg); } $options += ['checkRules' => true]; $options = new ArrayObject($options); $event = $this->dispatchEvent('Model.beforeDelete', ['entity' => $entity, 'options' => $options]); if ($event->isStopped()) { return $event->result; } if (!$this->checkRules($entity, RulesChecker::DELETE, $options)) { return false; } $data = $entity->toArray(); unset($data['id']); $doc = new ElasticaDocument($entity->id, $data); $type = $this->connection()->getIndex()->getType($this->name()); $result = $type->deleteDocument($doc); $this->dispatchEvent('Model.afterDelete', ['entity' => $entity, 'options' => $options]); return $result->isOk(); }
/** * 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; }
/** * Auxiliary function to handle the update 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 \InvalidArgumentException When primary key data is missing. */ protected function _update($entity, $data) { $primaryColumns = (array) $this->primaryKey(); $primaryKey = $entity->extract($primaryColumns); $data = array_diff_key($data, $primaryKey); if (empty($data)) { return $entity; } if (!$entity->has($primaryColumns)) { $message = 'All primary key value(s) are needed for updating'; throw new InvalidArgumentException($message); } $query = $this->query(); $statement = $query->update()->set($data)->where($primaryKey)->execute(); $success = false; if ($statement->errorCode() === '00000') { $success = $entity; } $statement->closeCursor(); return $success; }
/** * Adds a new comment for the given entity. * * @param \Cake\Datasource\EntityInterface $entity The entity where to attach new comment * @return bool True on success, false otherwise */ public function post(EntityInterface $entity) { $pk = (string) TableRegistry::get($entity->source())->primaryKey(); if (empty($this->_controller->request->data['comment']) || $this->config('settings.visibility') !== 1 || !$entity->has($pk)) { return false; } $this->_controller->loadModel('Comment.Comments'); $data = $this->_getRequestData($entity); $this->_controller->Comments->validator('commentValidation', $this->_createValidator()); $comment = $this->_controller->Comments->newEntity($data, ['validate' => 'commentValidation']); $errors = $comment->errors(); $errors = !empty($errors); if (!$errors) { $persist = true; $saved = true; $this->_controller->Comments->addBehavior('Tree', ['scope' => ['entity_id' => $data['entity_id'], 'table_alias' => $data['table_alias']]]); if ($this->config('settings.use_akismet')) { $newStatus = $this->_akismetStatus($data); $comment->set('status', $newStatus); if ($newStatus == 'spam' && $this->config('settings.akismet_action') != 'mark') { $persist = false; } } if ($persist) { $saved = $this->_controller->Comments->save($comment); } if ($saved) { $this->_afterSave($comment); return true; // all OK } else { $errors = true; } } if ($errors) { $this->_setErrors($comment); $errorMessage = $this->config('errorMessage'); if (is_callable($errorMessage)) { $errorMessage = $errorMessage($comment, $this->_controller); } $this->_controller->Flash->danger($errorMessage, ['key' => 'commentsForm']); } return false; }
/** * beforeDelete callback. * * @param \Cake\Event\Event $event Event. * @param \Cake\Datasource\EntityInterface $entity Entity. * @return bool */ public function beforeDelete(Event $event, EntityInterface $entity) { $discriminatorField = $this->_config['discriminatorField']; if ($entity->has($discriminatorField) && !$this->isAcceptedDiscriminator($entity->get($discriminatorField))) { $event->stopPropagation(); return false; } }
/** * Calculates an item's ID * * @param \Cake\Datasource\EntityInterface $item The item * @return string The ID, it may be an empty */ protected function _calculateItemId(EntityInterface $item) { if ($item->has('id')) { return $item->id; } if (is_array($item->url)) { return Inflector::slug(strtolower(implode(' ', array_values($item->url)))); } return Inflector::slug(strtolower($item->url)); }
/** * Creates a new Virtual "Field" to be attached to the given entity. * * This mock Field represents a new property (table column) of the entity. * * @param \Cake\Datasource\EntityInterface $entity The entity where the * generated virtual field will be attached * @param \Cake\Datasource\EntityInterface $attribute The attribute where to get * the information when creating the mock field. * @return \Field\Model\Entity\Field */ protected function _prepareMockField(EntityInterface $entity, EntityInterface $attribute) { $type = $this->_toolbox->mapType($attribute->get('type')); if (!$attribute->has(':value')) { $bundle = $this->_resolveBundle($entity); $conditions = ['EavAttribute.table_alias' => $this->_table->table(), 'EavAttribute.name' => $attribute->get('name'), 'EavValues.entity_id' => $entity->get((string) $this->_table->primaryKey())]; if ($bundle) { $conditions['EavAttribute.bundle'] = $bundle; } $storedValue = TableRegistry::get('Eav.EavValues')->find()->contain(['EavAttribute'])->select(['id', "value_{$type}", 'extra'])->where($conditions)->limit(1)->first(); } else { $storedValue = $attribute->get(':value'); } $mockField = new Field(['name' => $attribute->get('name'), 'label' => $attribute->get('instance')->get('label'), 'value' => null, 'extra' => null, 'metadata' => new Entity(['value_id' => null, 'instance_id' => $attribute->get('instance')->get('id'), 'attribute_id' => $attribute->get('id'), 'entity_id' => $this->_toolbox->getEntityId($entity), 'table_alias' => $attribute->get('table_alias'), 'type' => $type, 'bundle' => $attribute->get('bundle'), 'handler' => $attribute->get('instance')->get('handler'), 'required' => $attribute->get('instance')->required, 'description' => $attribute->get('instance')->description, 'settings' => $attribute->get('instance')->settings, 'view_modes' => $attribute->get('instance')->view_modes, 'entity' => $entity, 'errors' => []])]); if ($storedValue) { $mockField->set('value', $this->_toolbox->marshal($storedValue->get("value_{$type}"), $type)); $mockField->set('extra', $storedValue->get('extra')); $mockField->metadata->set('value_id', $storedValue->id); } $mockField->isNew($entity->isNew()); return $mockField; }