Commit 74c409f1 authored by catch's avatar catch

Issue #1495024 by Berdir, Rob Loach, fago: Convert the entity system to PSR-0.

parent 6616910f
......@@ -582,8 +582,8 @@ function file_save_htaccess($directory, $private = TRUE) {
* (deprecated) An associative array of conditions on the {file_managed}
* table, where the keys are the database fields and the values are the
* values those fields must have. Instead, it is preferable to use
* EntityFieldQuery to retrieve a list of entity IDs loadable by
* this function.
* Drupal\entity\EntityFieldQuery to retrieve a list of entity IDs
* loadable by this function.
*
* @return array
* An array of file objects, indexed by fid.
......@@ -593,7 +593,7 @@ function file_save_htaccess($directory, $private = TRUE) {
* @see hook_file_load()
* @see file_load()
* @see entity_load()
* @see EntityFieldQuery
* @see Drupal\entity\EntityFieldQuery
*/
function file_load_multiple($fids = array(), array $conditions = array()) {
return entity_load_multiple('file', $fids, $conditions);
......
......@@ -1506,8 +1506,8 @@ function comment_delete_multiple($cids) {
* (deprecated) An associative array of conditions on the {comments}
* table, where the keys are the database fields and the values are the
* values those fields must have. Instead, it is preferable to use
* EntityFieldQuery to retrieve a list of entity IDs loadable by
* this function.
* Drupal\entity\EntityFieldQuery to retrieve a list of entity IDs
* loadable by this function.
* @param bool $reset
* Whether to reset the internal static entity cache. Note that the static
* cache is disabled in comment_entity_info() by default.
......@@ -1518,7 +1518,7 @@ function comment_delete_multiple($cids) {
* @todo Remove $conditions in Drupal 8.
*
* @see entity_load()
* @see EntityFieldQuery
* @see Drupal\entity\EntityFieldQuery
*/
function comment_load_multiple($cids = array(), array $conditions = array(), $reset = FALSE) {
return entity_load_multiple('comment', $cids, $conditions, $reset);
......
......@@ -7,7 +7,7 @@
namespace Drupal\comment;
use Entity;
use Drupal\entity\Entity;
/**
* Defines the comment entity class.
......
......@@ -7,8 +7,8 @@
namespace Drupal\comment;
use EntityDatabaseStorageController;
use EntityInterface;
use Drupal\entity\EntityInterface;
use Drupal\entity\EntityDatabaseStorageController;
/**
* Defines the controller class for comments.
......
......@@ -22,18 +22,19 @@
* properties of those types that the system needs to know about:
* - label: The human-readable name of the type.
* - controller class: The name of the class that is used to load the objects.
* The class has to implement the DrupalEntityControllerInterface interface.
* Leave blank to use the DrupalDefaultEntityController implementation.
* - base table: (used by DrupalDefaultEntityController) The name of the
* The class has to implement the Drupal\entity\EntityControllerInterface
* interface. Leave blank to use the Drupal\entity\EntityController
* implementation.
* - base table: (used by Drupal\entity\EntityController) The name of the
* entity type's base table.
* - static cache: (used by DrupalDefaultEntityController) FALSE to disable
* - static cache: (used by Drupal\entity\EntityController) FALSE to disable
* static caching of entities during a page request. Defaults to TRUE.
* - field cache: (used by Field API loading and saving of field data) FALSE
* to disable Field API's persistent cache of field data. Only recommended
* if a higher level persistent cache is available for the entity type.
* Defaults to TRUE.
* - load hook: The name of the hook which should be invoked by
* DrupalDefaultEntityController:attachLoad(), for example 'node_load'.
* Drupal\entity\EntityController::attachLoad(), for example 'node_load'.
* - uri callback: A function taking an entity as argument and returning the
* uri elements of the entity, e.g. 'path' and 'options'. The actual entity
* uri can be constructed by passing these elements to url().
......@@ -210,8 +211,8 @@ function hook_entity_info() {
*/
function hook_entity_info_alter(&$entity_info) {
// Set the controller class for nodes to an alternate implementation of the
// DrupalEntityController interface.
$entity_info['node']['controller class'] = 'MyCustomNodeController';
// Drupal\entity\EntityController interface.
$entity_info['node']['controller class'] = 'Drupal\mymodule\MyCustomNodeController';
}
/**
......@@ -337,9 +338,9 @@ function hook_entity_delete($entity, $type) {
}
/**
* Alter or execute an EntityFieldQuery.
* Alter or execute an Drupal\entity\EntityFieldQuery.
*
* @param EntityFieldQuery $query
* @param Drupal\entity\EntityFieldQuery $query
* An EntityFieldQuery. One of the most important properties to be changed is
* EntityFieldQuery::executeCallback. If this is set to an existing function,
* this function will get the query as its single argument and its result
......
......@@ -4,9 +4,6 @@ package = Core
version = VERSION
core = 8.x
required = TRUE
files[] = entity.class.inc
files[] = entity.query.inc
files[] = entity.controller.inc
files[] = tests/entity_crud_hook_test.test
files[] = tests/entity_query.test
files[] = tests/entity.test
......@@ -5,6 +5,8 @@
* Entity API for handling entities like nodes or users.
*/
use Drupal\entity\EntityMalformedException;
/**
* Implements hook_help().
*/
......@@ -66,7 +68,7 @@ function entity_get_info($entity_type = NULL) {
foreach ($entity_info as $name => $data) {
$entity_info[$name] += array(
'fieldable' => FALSE,
'controller class' => 'DrupalDefaultEntityController',
'controller class' => 'Drupal\entity\EntityController',
'static cache' => TRUE,
'field cache' => TRUE,
'load hook' => $name . '_load',
......@@ -90,7 +92,7 @@ function entity_get_info($entity_type = NULL) {
$entity_info[$name]['bundles'] = array($name => array('label' => $entity_info[$name]['label']));
}
// Prepare entity schema fields SQL info for
// DrupalEntityControllerInterface::buildQuery().
// Drupal\entity\EntityControllerInterface::buildQuery().
if (isset($entity_info[$name]['base table'])) {
$entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
if (isset($entity_info[$name]['revision table'])) {
......@@ -204,9 +206,9 @@ function entity_create_stub_entity($entity_type, $ids) {
*
* @see hook_entity_info()
* @see entity_load_multiple()
* @see DrupalEntityControllerInterface
* @see DrupalDefaultEntityController
* @see EntityFieldQuery
* @see Drupal\entity\EntityControllerInterface
* @see Drupal\entity\EntityController
* @see Drupal\entity\EntityFieldQuery
*/
function entity_load($entity_type, $id, $reset = FALSE) {
$entities = entity_load_multiple($entity_type, array($id), array(), $reset);
......@@ -221,13 +223,13 @@ function entity_load($entity_type, $id, $reset = FALSE) {
* database access if loaded again during the same page request.
*
* The actual loading is done through a class that has to implement the
* DrupalEntityControllerInterface interface. By default,
* DrupalDefaultEntityController is used. Entity types can specify that a
* different class should be used by setting the 'controller class' key in
* hook_entity_info(). These classes can either implement the
* DrupalEntityControllerInterface interface, or, most commonly, extend the
* DrupalDefaultEntityController class. See node_entity_info() and the
* NodeController in node.module as an example.
* Drupal\entity\EntityControllerInterface interface. By default,
* Drupal\entity\EntityController is used. Entity types can specify
* that a different class should be used by setting the 'controller class' key
* in hook_entity_info(). These classes can either implement the
* Drupal\entity\EntityControllerInterface interface, or, most
* commonly, extend the Drupal\entity\EntityController class. See
* node_entity_info() and the NodeController in node.module as an example.
*
* @param string $entity_type
* The entity type to load, e.g. node or user.
......@@ -247,9 +249,9 @@ function entity_load($entity_type, $id, $reset = FALSE) {
* @todo Remove $conditions in Drupal 8.
*
* @see hook_entity_info()
* @see DrupalEntityControllerInterface
* @see DrupalDefaultEntityController
* @see EntityFieldQuery
* @see Drupal\entity\EntityControllerInterface
* @see Drupal\entity\EntityController
* @see Drupal\entity\EntityFieldQuery
*/
function entity_load_multiple($entity_type, $ids = FALSE, $conditions = array(), $reset = FALSE) {
if ($reset) {
......@@ -301,7 +303,7 @@ function entity_delete_multiple($entity_type, $ids) {
* An array of values to set, keyed by property name. If the entity type has
* bundles the bundle key has to be specified.
*
* @return EntityInterface
* @return Drupal\entity\EntityInterface
* A new entity object.
*/
function entity_create($entity_type, array $values) {
......@@ -311,7 +313,7 @@ function entity_create($entity_type, array $values) {
/**
* Gets the entity controller class for an entity type.
*
* @return EntityStorageControllerInterface
* @return Drupal\entity\EntityStorageControllerInterface
*/
function entity_get_controller($entity_type) {
$controllers = &drupal_static(__FUNCTION__, array());
......@@ -495,8 +497,3 @@ function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_st
field_attach_submit($entity_type, $entity, $form, $form_state);
}
}
/**
* Defines an exception thrown when a malformed entity is passed.
*/
class EntityMalformedException extends Exception { }
......@@ -2,185 +2,10 @@
/**
* @file
* Provides an interface and a base class for entities.
* Definition of Drupal\entity\Entity.
*/
/**
* Defines a common interface for all entity objects.
*/
interface EntityInterface {
/**
* Constructs a new entity object.
*
* @param $values
* An array of values to set, keyed by property name. If the entity type
* has bundles, the bundle key has to be specified.
* @param $entity_type
* The type of the entity to create.
*/
public function __construct(array $values, $entity_type);
/**
* Returns the entity identifier (the entity's machine name or numeric ID).
*
* @return
* The identifier of the entity, or NULL if the entity does not yet have
* an identifier.
*/
public function id();
/**
* Returns whether the entity is new.
*
* Usually an entity is new if no ID exists for it yet. However, entities may
* be enforced to be new with existing IDs too.
*
* @return
* TRUE if the entity is new, or FALSE if the entity has already been saved.
*
* @see EntityInterface::enforceIsNew()
*/
public function isNew();
/**
* Enforces an entity to be new.
*
* Allows migrations to create entities with pre-defined IDs by forcing the
* entity to be new before saving.
*
* @param bool $value
* (optional) Whether the entity should be forced to be new. Defaults to
* TRUE.
*
* @see EntityInterface::isNew()
*/
public function enforceIsNew($value = TRUE);
/**
* Returns the type of the entity.
*
* @return
* The type of the entity.
*/
public function entityType();
/**
* Returns the bundle of the entity.
*
* @return
* The bundle of the entity. Defaults to the entity type if the entity type
* does not make use of different bundles.
*/
public function bundle();
/**
* Returns the label of the entity.
*
* @return
* The label of the entity, or NULL if there is no label defined.
*/
public function label();
/**
* Returns the URI elements of the entity.
*
* @return
* An array containing the 'path' and 'options' keys used to build the URI
* of the entity, and matching the signature of url(). NULL if the entity
* has no URI of its own.
*/
public function uri();
/**
* Returns the default language of a language-specific entity.
*
* @return
* The language object of the entity's default language, or FALSE if the
* entity is not language-specific.
*
* @see EntityInterface::translations()
*/
public function language();
/**
* Returns the languages the entity is translated to.
*
* @return
* An array of language objects, keyed by language codes.
*
* @see EntityInterface::language()
*/
public function translations();
/**
* Returns the value of an entity property.
*
* @param $property_name
* The name of the property to return; e.g., 'title'.
* @param $langcode
* (optional) If the property is translatable, the language code of the
* language that should be used for getting the property. If set to NULL,
* the entity's default language is being used.
*
* @return
* The property value, or NULL if it is not defined.
*
* @see EntityInterface::language()
*/
public function get($property_name, $langcode = NULL);
/**
* Sets the value of an entity property.
*
* @param $property_name
* The name of the property to set; e.g., 'title'.
* @param $value
* The value to set, or NULL to unset the property.
* @param $langcode
* (optional) If the property is translatable, the language code of the
* language that should be used for getting the property. If set to
* NULL, the entity's default language is being used.
*
* @see EntityInterface::language()
*/
public function set($property_name, $value, $langcode = NULL);
/**
* Saves an entity permanently.
*
* @return
* Either SAVED_NEW or SAVED_UPDATED, depending on the operation performed.
*
* @throws EntityStorageException
* In case of failures an exception is thrown.
*/
public function save();
/**
* Deletes an entity permanently.
*
* @throws EntityStorageException
* In case of failures an exception is thrown.
*/
public function delete();
/**
* Creates a duplicate of the entity.
*
* @return EntityInterface
* A clone of the current entity with all identifiers unset, so saving
* it inserts a new entity into the storage system.
*/
public function createDuplicate();
/**
* Returns the info of the type of the entity.
*
* @see entity_get_info()
*/
public function entityInfo();
}
namespace Drupal\entity;
/**
* Defines a base entity class.
......
......@@ -2,62 +2,22 @@
/**
* @file
* Entity API controller classes and interface.
* Definition of Drupal\entity\EntityController.
*/
/**
* Defines a common interface for entity controller classes.
*
* All entity controller classes specified via the 'controller class' key
* returned by hook_entity_info() or hook_entity_info_alter() have to implement
* this interface.
*
* Most simple, SQL-based entity controllers will do better by extending
* DrupalDefaultEntityController instead of implementing this interface
* directly.
*/
interface DrupalEntityControllerInterface {
/**
* Constructs a new DrupalEntityControllerInterface object.
*
* @param $entityType
* The entity type for which the instance is created.
*/
public function __construct($entityType);
namespace Drupal\entity;
/**
* Resets the internal, static entity cache.
*
* @param $ids
* (optional) If specified, the cache is reset for the entities with the
* given ids only.
*/
public function resetCache(array $ids = NULL);
/**
* Loads one or more entities.
*
* @param $ids
* An array of entity IDs, or FALSE to load all entities.
* @param $conditions
* An array of conditions in the form 'field' => $value.
*
* @return
* An array of entity objects indexed by their ids.
*/
public function load($ids = array(), $conditions = array());
}
use PDO;
/**
* Defines a base entity controller class.
*
* Default implementation of DrupalEntityControllerInterface.
* Default implementation of Drupal\entity\EntityControllerInterface.
*
* This class can be used as-is by most simple entity types. Entity types
* requiring special handling can extend the class.
*/
class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
class EntityController implements EntityControllerInterface {
/**
* Static cache of entities.
......@@ -85,7 +45,7 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
/**
* Additional arguments to pass to hook_TYPE_load().
*
* Set before calling DrupalDefaultEntityController::attachLoad().
* Set before calling Drupal\entity\EntityController::attachLoad().
*
* @var array
*/
......@@ -124,7 +84,7 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface {
protected $cache;
/**
* Implements DrupalEntityControllerInterface::__construct().
* Implements Drupal\entity\EntityController::__construct().
*
* Sets basic variables.
*/
......@@ -149,7 +109,7 @@ public function __construct($entityType) {
}
/**
* Implements DrupalEntityControllerInterface::resetCache().
* Implements Drupal\entity\EntityControllerInterface::resetCache().
*/
public function resetCache(array $ids = NULL) {
if (isset($ids)) {
......@@ -163,7 +123,7 @@ public function resetCache(array $ids = NULL) {
}
/**
* Implements DrupalEntityControllerInterface::load().
* Implements Drupal\entity\EntityControllerInterface::load().
*/
public function load($ids = array(), $conditions = array()) {
$entities = array();
......@@ -204,7 +164,7 @@ public function load($ids = array(), $conditions = array()) {
if (!empty($this->entityInfo['entity class'])) {
// We provide the necessary arguments for PDO to create objects of the
// specified entity class.
// @see EntityInterface::__construct()
// @see Drupal\entity\EntityInterface::__construct()
$query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['entity class'], array(array(), $this->entityType));
}
$queried_entities = $query_result->fetchAllAssoc($this->idKey);
......@@ -397,199 +357,3 @@ protected function cacheSet($entities) {
$this->entityCache += $entities;
}
}
/**
* Defines a common interface for entity storage controllers.
*/
interface EntityStorageControllerInterface extends DrupalEntityControllerInterface {
/**
* Constructs a new entity object, without permanently saving it.
*
* @param $values
* An array of values to set, keyed by property name. If the entity type has
* bundles the bundle key has to be specified.
*
* @return EntityInterface
* A new entity object.
*/
public function create(array $values);
/**
* Deletes permanently saved entities.
*
* @param $ids
* An array of entity IDs.
*
* @throws EntityStorageException
* In case of failures, an exception is thrown.
*/
public function delete($ids);
/**
* Saves the entity permanently.
*
* @param EntityInterface $entity
* The entity to save.
*
* @return
* SAVED_NEW or SAVED_UPDATED is returned depending on the operation
* performed.
*
* @throws EntityStorageException
* In case of failures, an exception is thrown.
*/
public function save(EntityInterface $entity);
}
/**
* Defines an exception thrown when storage operations fail.
*/
class EntityStorageException extends Exception { }
/**
* Implements the entity storage controller interface for the database.
*/
class EntityDatabaseStorageController extends DrupalDefaultEntityController implements EntityStorageControllerInterface {
/**
* Implements EntityStorageControllerInterface::create().
*/
public function create(array $values) {
$class = isset($this->entityInfo['entity class']) ? $this->entityInfo['entity class'] : 'Entity';
return new $class($values, $this->entityType);
}
/**
* Implements EntityStorageControllerInterface::delete().
*/
public function delete($ids) {
$entities = $ids ? $this->load($ids) : FALSE;
if (!$entities) {
// If no IDs or invalid IDs were passed, do nothing.
return;
}
$transaction = db_transaction();
try {
$this->preDelete($entities);
foreach ($entities as $id => $entity) {
$this->invokeHook('predelete', $entity);
}
$ids = array_keys($entities);
db_delete($this->entityInfo['base table'])
->condition($this->idKey, $ids, 'IN')
->execute();
// Reset the cache as soon as the changes have been applied.
$this->resetCache($ids);
$this->postDelete($entities);
foreach ($entities as $id => $entity) {
$this->invokeHook('delete', $entity);
}
// Ignore slave server temporarily.
db_ignore_slave();
}
catch (Exception $e) {
$transaction->rollback();
watchdog_exception($this->entityType, $e);
throw new EntityStorageException($e->getMessage, $e->getCode, $e);
}
}
/**
* Implements EntityStorageControllerInterface::save().
*/
public function save(EntityInterface $entity) {
$transaction = db_transaction();
try {
// Load the stored entity, if any.
if (!$entity->isNew() && !isset($entity->original)) {
$entity->original = entity_load_unchanged($this->entityType, $entity->id());
}
$this->preSave($entity);
$this->invokeHook('presave', $entity);
if (!$entity->isNew()) {
$return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey);
$this->resetCache(array($entity->{$this->idKey}));
$this->postSave($entity, TRUE);