Commit 814aed20 authored by alexpott's avatar alexpott
Browse files

Issue #2005716 by tim.plunkett, msonnabaum, dawehner, alexpott, effulgentsia:...

Issue #2005716 by tim.plunkett, msonnabaum, dawehner, alexpott, effulgentsia: Promote EntityType to a domain object.
parent 18cc78af
......@@ -7,6 +7,7 @@
use Drupal\Core\Config\Context\FreeConfigContext;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Symfony\Component\Yaml\Dumper;
/**
......@@ -202,8 +203,8 @@ function config_context_leave() {
* Either the entity type name, or NULL if none match.
*/
function config_get_entity_type_by_name($name) {
$entities = array_filter(entity_get_info(), function($entity_info) use ($name) {
return (isset($entity_info['config_prefix']) && strpos($name, $entity_info['config_prefix'] . '.') === 0);
$entities = array_filter(\Drupal::entityManager()->getDefinitions(), function (EntityTypeInterface $entity_info) use ($name) {
return ($config_prefix = $entity_info->getConfigPrefix()) && strpos($name, $config_prefix . '.') === 0;
});
return key($entities);
}
......
......@@ -266,11 +266,10 @@ function entity_revision_delete($entity_type, $revision_id) {
* @see \Drupal\Core\Entity\EntityManagerInterface
*/
function entity_load_by_uuid($entity_type, $uuid, $reset = FALSE) {
$entity_info = entity_get_info($entity_type);
if (empty($entity_info['entity_keys']['uuid'])) {
$entity_info = \Drupal::entityManager()->getDefinition($entity_type);
if (!$uuid_key = $entity_info->getKey('uuid')) {
throw new EntityStorageException("Entity type $entity_type does not support UUIDs.");
}
$uuid_key = $entity_info['entity_keys']['uuid'];
$controller = \Drupal::entityManager()->getStorageController($entity_type);
if ($reset) {
......
<?php
/**
* @file
* Contains \Drupal\Component\Annotation\AnnotationBase.
*/
namespace Drupal\Component\Annotation;
/**
* Provides a base class for classed annotations.
*/
abstract class AnnotationBase implements AnnotationInterface {
/**
* The annotated class ID.
*
* @var string
*/
public $id;
/**
* The class used for this annotated class.
*
* @var string
*/
protected $class;
/**
* The provider of the annotated class.
*
* @var string
*/
protected $provider;
/**
* {@inheritdoc}
*/
public function getProvider() {
return $this->provider;
}
/**
* {@inheritdoc}
*/
public function setProvider($provider) {
$this->provider = $provider;
}
/**
* {@inheritdoc}
*/
public function getId() {
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getClass() {
return $this->class;
}
/**
* {@inheritdoc}
*/
public function setClass($class) {
$this->class = $class;
}
}
......@@ -17,4 +17,39 @@ interface AnnotationInterface {
*/
public function get();
/**
* Returns the name of the provider of the annotated class.
*
* @return string
*/
public function getProvider();
/**
* Sets the name of the provider of the annotated class.
*
* @param string $provider
*/
public function setProvider($provider);
/**
* Returns the unique ID for this annotated class.
*
* @return string
*/
public function getId();
/**
* Returns the class of the annotated class.
*
* @return string
*/
public function getClass();
/**
* Sets the class of the annotated class.
*
* @param string $class
*/
public function setClass($class);
}
......@@ -71,10 +71,45 @@ protected function parse(array $values) {
}
/**
* Implements Drupal\Core\Annotation\AnnotationInterface::get().
* {@inheritdoc}
*/
public function get() {
return $this->definition;
}
/**
* {@inheritdoc}
*/
public function getProvider() {
return isset($this->definition['provider']) ? $this->definition['provider'] : FALSE;
}
/**
* {@inheritdoc}
*/
public function setProvider($provider) {
$this->definition['provider'] = $provider;
}
/**
* {@inheritdoc}
*/
public function getId() {
return $this->definition['id'];
}
/**
* {@inheritdoc}
*/
public function getClass() {
return $this->definition['class'];
}
/**
* {@inheritdoc}
*/
public function setClass($class) {
$this->definition['class'] = $class;
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\Component\Annotation\Plugin\Discovery;
use Drupal\Component\Annotation\AnnotationInterface;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Component\Annotation\Reflection\MockFileFinder;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
......@@ -115,12 +116,12 @@ public function getDefinitions() {
$finder = MockFileFinder::create($fileinfo->getPathName());
$parser = new StaticReflectionParser($class, $finder, TRUE);
/** @var $annotation \Drupal\Component\Annotation\AnnotationInterface */
if ($annotation = $reader->getClassAnnotation($parser->getReflectionClass(), $this->pluginDefinitionAnnotationName)) {
$this->prepareAnnotationDefinition($annotation, $class);
// AnnotationInterface::get() returns the array definition
// instead of requiring us to work with the annotation object.
$definition = $annotation->get();
$definition['class'] = $class;
$definitions[$definition['id']] = $definition;
$definitions[$annotation->getId()] = $annotation->get();
}
}
}
......@@ -134,6 +135,18 @@ public function getDefinitions() {
return $definitions;
}
/**
* Prepares the annotation definition.
*
* @param \Drupal\Component\Annotation\AnnotationInterface $annotation
* The annotation derived from the plugin.
* @param string $class
* The class used for the plugin.
*/
protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class) {
$annotation->setClass($class);
}
/**
* Returns an array of PSR-0 namespaces to search for plugin classes.
*/
......
......@@ -12,7 +12,7 @@
*
* @Annotation
*/
class PluginID implements AnnotationInterface {
class PluginID extends AnnotationBase {
/**
* The plugin ID.
......@@ -29,7 +29,16 @@ class PluginID implements AnnotationInterface {
public function get() {
return array(
'id' => $this->value,
'class' => $this->class,
'provider' => $this->provider,
);
}
/**
* {@inheritdoc}
*/
public function getId() {
return $this->value;
}
}
......@@ -7,7 +7,7 @@
namespace Drupal\Core\Annotation;
use Drupal\Component\Annotation\AnnotationInterface;
use Drupal\Component\Annotation\AnnotationBase;
/**
* @defgroup plugin_translatable Translatable plugin metadata
......@@ -45,7 +45,7 @@
*
* @ingroup plugin_translatable
*/
class Translation implements AnnotationInterface {
class Translation extends AnnotationBase {
/**
* The translation of the value passed to the constructor of the class.
......
......@@ -23,7 +23,7 @@ public function load() {
// Sort the entities using the entity class's sort() method.
// See \Drupal\Core\Config\Entity\ConfigEntityBase::sort().
uasort($entities, array($this->entityInfo['class'], 'sort'));
uasort($entities, array($this->entityInfo->getClass(), 'sort'));
return $entities;
}
......@@ -41,7 +41,7 @@ public function getOperations(EntityInterface $entity) {
$operations['edit']['href'] = $uri['path'];
}
if (isset($this->entityInfo['entity_keys']['status'])) {
if ($this->entityInfo->hasKey('status')) {
if (!$entity->status()) {
$operations['enable'] = array(
'title' => t('Enable'),
......
......@@ -13,6 +13,7 @@
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Component\Uuid\UuidInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -79,10 +80,8 @@ class ConfigStorageController extends EntityStorageControllerBase {
/**
* Constructs a ConfigStorageController object.
*
* @param string $entity_type
* The entity type for which the instance is created.
* @param array $entity_info
* An array of entity info for the entity type.
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_info
* The entity info for the entity type.
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The config factory service.
* @param \Drupal\Core\Config\StorageInterface $config_storage
......@@ -92,17 +91,11 @@ class ConfigStorageController extends EntityStorageControllerBase {
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
* The UUID service.
*/
public function __construct($entity_type, array $entity_info, ConfigFactory $config_factory, StorageInterface $config_storage, QueryFactory $entity_query_factory, UuidInterface $uuid_service) {
parent::__construct($entity_type, $entity_info);
public function __construct(EntityTypeInterface $entity_info, ConfigFactory $config_factory, StorageInterface $config_storage, QueryFactory $entity_query_factory, UuidInterface $uuid_service) {
parent::__construct($entity_info);
$this->idKey = $this->entityInfo['entity_keys']['id'];
if (isset($this->entityInfo['entity_keys']['status'])) {
$this->statusKey = $this->entityInfo['entity_keys']['status'];
}
else {
$this->statusKey = FALSE;
}
$this->idKey = $this->entityInfo->getKey('id');
$this->statusKey = $this->entityInfo->getKey('status');
$this->configFactory = $config_factory;
$this->configStorage = $config_storage;
......@@ -113,9 +106,8 @@ public function __construct($entity_type, array $entity_info, ConfigFactory $con
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_info) {
return new static(
$entity_type,
$entity_info,
$container->get('config.factory'),
$container->get('config.storage'),
......@@ -208,7 +200,7 @@ public function getQuery($conjunction = 'AND') {
* The full configuration prefix, for example 'views.view.'.
*/
public function getConfigPrefix() {
return $this->entityInfo['config_prefix'] . '.';
return $this->entityInfo->getConfigPrefix() . '.';
}
/**
......@@ -249,7 +241,7 @@ public static function getIDFromConfigName($config_name, $config_prefix) {
* A SelectQuery object for loading the entity.
*/
protected function buildQuery($ids, $revision_id = FALSE) {
$config_class = $this->entityInfo['class'];
$config_class = $this->entityInfo->getClass();
$prefix = $this->getConfigPrefix();
// Get the names of the configuration entities we are going to load.
......@@ -276,7 +268,7 @@ protected function buildQuery($ids, $revision_id = FALSE) {
* Implements Drupal\Core\Entity\EntityStorageControllerInterface::create().
*/
public function create(array $values) {
$class = $this->entityInfo['class'];
$class = $this->entityInfo->getClass();
$class::preCreate($this, $values);
// Set default language to site default if not provided.
......@@ -314,7 +306,7 @@ public function delete(array $entities) {
return;
}
$entity_class = $this->entityInfo['class'];
$entity_class = $this->entityInfo->getClass();
$entity_class::preDelete($this, $entities);
foreach ($entities as $entity) {
$this->invokeHook('predelete', $entity);
......@@ -458,7 +450,7 @@ public function importCreate($name, Config $new_config, Config $old_config) {
* A configuration object containing the old configuration data.
*/
public function importUpdate($name, Config $new_config, Config $old_config) {
$id = static::getIDFromConfigName($name, $this->entityInfo['config_prefix']);
$id = static::getIDFromConfigName($name, $this->entityInfo->getConfigPrefix());
$entity = $this->load($id);
$entity->setSyncing(TRUE);
$entity->original = clone $entity;
......@@ -489,7 +481,7 @@ public function importUpdate($name, Config $new_config, Config $old_config) {
* A configuration object containing the old configuration data.
*/
public function importDelete($name, Config $new_config, Config $old_config) {
$id = static::getIDFromConfigName($name, $this->entityInfo['config_prefix']);
$id = static::getIDFromConfigName($name, $this->entityInfo->getConfigPrefix());
$entity = $this->load($id);
$entity->setSyncing(TRUE);
$entity->delete();
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormInterface;
......@@ -41,12 +42,12 @@ abstract class DraggableListController extends ConfigEntityListController implem
/**
* {@inheritdoc}
*/
public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler) {
parent::__construct($entity_type, $entity_info, $storage, $module_handler);
public function __construct(EntityTypeInterface $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler) {
parent::__construct($entity_info, $storage, $module_handler);
// Check if the entity type supports weighting.
if (!empty($this->entityInfo['entity_keys']['weight'])) {
$this->weightKey = $this->entityInfo['entity_keys']['weight'];
if ($this->entityInfo->hasKey('weight')) {
$this->weightKey = $this->entityInfo->getKey('weight');
}
}
......@@ -99,7 +100,7 @@ public function buildForm(array $form, array &$form_state) {
$form[$this->entitiesKey] = array(
'#type' => 'table',
'#header' => $this->buildHeader(),
'#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo['label'])),
'#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo->getLabel())),
'#tabledrag' => array(
array(
'action' => 'order',
......
......@@ -86,7 +86,7 @@ public function condition($property, $value = NULL, $operator = NULL, $langcode
public function execute() {
// Load all config files.
$entity_info = $this->entityManager->getDefinition($this->getEntityType());
$prefix = $entity_info['config_prefix'] . '.';
$prefix = $entity_info->getConfigPrefix() . '.';
$prefix_length = strlen($prefix);
$names = $this->configStorage->listAll($prefix);
$configs = array();
......
......@@ -17,261 +17,33 @@
class EntityType extends Plugin {
/**
* The name of the entity type class.
* The class used to represent the entity type.
*
* This is not provided manually, it will be added by the discovery mechanism.
* It must implement \Drupal\Core\Entity\EntityTypeInterface.
*
* @var string
*/
public $class;
public $entity_type_class = 'Drupal\Core\Entity\EntityType';
/**
* The name of the entity type's base table.
*
* @todo This is only used by \Drupal\Core\Entity\DatabaseStorageController.
*
* @var string
*/
public $base_table;
/**
* An associative array where the keys are the names of different controller
* types (listed below) and the values are the names of the classes that
* implement that controller:
* - storage: The name of the class that is used to load the objects. The
* class must implement \Drupal\Core\Entity\EntityStorageControllerInterface.
* - form: An associative array where the keys are the names of the different
* form operations (such as 'create', 'edit', or 'delete') and the values
* are the names of the controller classes for those operations. The name of
* the operation is passed also to the form controller's constructor, so
* that one class can be used for multiple entity forms when the forms are
* similar. The classes must implement
* \Drupal\Core\Entity\EntityFormControllerInterface
* - list: The name of the class that provides listings of the entities. The
* class must implement \Drupal\Core\Entity\EntityListControllerInterface.
* - render: The name of the class that is used to render the entities. The
* class must implement \Drupal\Core\Entity\EntityViewBuilderInterface.
* - access: The name of the class that is used for access checks. The class
* must implement \Drupal\Core\Entity\EntityAccessControllerInterface.
* Defaults to \Drupal\Core\Entity\EntityAccessController.
* - translation: The name of the controller class that should be used to
* handle the translation process. The class must implement
* \Drupal\content_translation\ContentTranslationControllerInterface.
*
* @todo Interfaces from outside \Drupal\Core or \Drupal\Component should not
* be used here.
*
* @var array
*/
public $controllers = array(
'access' => 'Drupal\Core\Entity\EntityAccessController',
);
/**
* The name of the default administrative permission.
*
* The default \Drupal\Core\Entity\EntityAccessController class checks this
* permission for all operations in its checkAccess() method. Entities with
* more complex permissions can extend this class to do their own access
* checks.
*
* @var string (optional)
*/
public $admin_permission;
/**
* Boolean indicating whether fields can be attached to entities of this type.
*
* @var bool (optional)
*/
public $fieldable = FALSE;
/**
* Boolean indicating if the persistent cache of field data should be used.
*
* The persistent cache should usually only be disabled if a higher level
* persistent cache is available for the entity type. Defaults to TRUE.
*
* @var bool (optional)
*/
public $field_cache = TRUE;
/**
* The human-readable name of the type.
*
* @ingroup plugin_translatable
*
* @var \Drupal\Core\Annotation\Translation
*/
public $label;
/**
* The human-readable name of the entity bundles, e.g. Vocabulary.
*
* @ingroup plugin_translatable
*
* @var \Drupal\Core\Annotation\Translation
*/
public $bundle_label;
/**
* The name of a function that returns the label of the entity.
*
* The function takes an entity and optional langcode argument, and returns
* the label of the entity. If langcode is omitted, the entity's default
* language is used. The entity label is the main string associated with an
* entity; for example, the title of a node or the subject of a comment. If
* there is an entity object property that defines the label, use the 'label'
* element of the 'entity_keys' return value component to provide this
* information (see below). If more complex logic is needed to determine the
* label of an entity, you can instead specify a callback function here, which
* will be called to determine the entity label. See also the
* \Drupal\Core\Entity\EntityInterface::label() method, which implements this
* logic.
*
* @var string (optional)
*/
public $label_callback;
/**
* Boolean indicating whether entities should be statically cached during a page request.
*
* @todo This is only used by \Drupal\Core\Entity\DatabaseStorageController.
*
* @var bool (optional)
*/
public $static_cache = TRUE;
/**
* Boolean indicating whether the rendered output of entities should be
* cached.
*
* @var bool (optional)
*/
public $render_cache = TRUE;
/**
* Boolean indicating whether entities of this type have multilingual support.
*
* At an entity level, this indicates language support and at a bundle level
* this indicates translation support.
*
* @var bool (optional)
*/
public $translatable = FALSE;
/**
* @todo content_translation_entity_info_alter() uses this but it is undocumented.
* @todo content_translation_entity_info_alter() uses this but it is
* undocumented. Fix in https://drupal.org/node/1968970.
*
* @var array