Commit b77715c3 authored by webchick's avatar webchick

Issue #1967294 by tim.plunkett: Add a dedicated @EntityType annotation.

parent a820153f
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace Drupal\Component\Annotation; namespace Drupal\Component\Annotation;
use Drupal\Component\Utility\NestedArray;
/** /**
* Defines a Plugin annotation object. * Defines a Plugin annotation object.
* *
...@@ -34,7 +36,13 @@ class Plugin implements AnnotationInterface { ...@@ -34,7 +36,13 @@ class Plugin implements AnnotationInterface {
* classed annotations that were used. * classed annotations that were used.
*/ */
public function __construct($values) { public function __construct($values) {
$this->definition = $this->parse($values); $reflection = new \ReflectionClass($this);
// Only keep actual default values by ignoring NULL values.
$defaults = array_filter($reflection->getDefaultProperties(), function ($value) {
return $value !== NULL;
});
$parsed_values = $this->parse($values);
$this->definition = NestedArray::mergeDeep($defaults, $parsed_values);
} }
/** /**
......
<?php
/**
* @file
* Contains \Drupal\Core\Entity\Annotation\EntityType.
*/
namespace Drupal\Core\Entity\Annotation;
use Drupal\Component\Annotation\Plugin;
/**
* Defines an Entity type annotation object.
*
* @Annotation
*/
class EntityType extends Plugin {
/**
* The name of the module providing the type.
*
* @var string
*/
public $module;
/**
* The name of the entity type class.
*
* This is not provided manually, it will be added by the discovery mechanism.
*
* @var string
*/
public $class;
/**
* The name of the entity type's base table.
*
* @todo This is only used by \Drupal\Core\Entity\DatabaseStorageController.
*
* @var string
*/
public $base_table;
/**
* The name of the class that is used to load the objects.
*
* This must implement \Drupal\Core\Entity\EntityStorageControllerInterface.
*
* @var string
*/
public $controller_class = 'Drupal\Core\Entity\DatabaseStorageController';
/**
* 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 names of classes for various form operations.
*
* 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.
* Defaults to Drupal\Core\Entity\EntityFormController.
*
* @var array (optional)
*/
public $form_controller_class = array('Drupal\Core\Entity\EntityFormController');
/**
* The human-readable name of the type.
*
* @var string
*/
public $label;
/**
* The human-readable name of the entity bundles, e.g. Vocabulary.
*
* @var string
*/
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;
/**
* The name of the class that provides listings of the entities.
*
* The class must implement \Drupal\Core\Entity\EntityListControllerInterface.
*
* @var string
*/
public $list_controller_class = 'Drupal\Core\Entity\EntityListController';
/**
* The name of the class that is used to render the entities.
*
* @var string
*/
public $render_controller_class;
/**
* The name of the class that is used for access checks.
*
* The class must implement \Drupal\Core\Entity\EntityAccessControllerInterface.
*
* @var string
*/
public $access_controller_class = 'Drupal\Core\Entity\EntityAccessController';
/**
* The name of the translation controller class that should be used to handle the translation process.
*
* The class must implement \Drupal\translation_entity\EntityTranslationControllerInterface.
*
* @todo Interfaces from outside \Drupal\Core or \Drupal\Component should not
* be used here.
*
* @var string
*/
public $translation_controller_class;
/**
* 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 entities of this type have mutlilingual support.
*
* @var bool (optional)
*/
public $translatable = FALSE;
/**
* @todo translation_entity_entity_info_alter() uses this but it is undocumented.
*
* @var array
*/
public $translation = array();
/**
* An array describing how the Field API can extract certain information from
* objects of this entity type:
* - id: The name of the property that contains the primary ID of the entity.
* Every entity object passed to the Field API must have this property and
* its value must be numeric.
* - revision: (optional) The name of the property that contains the revision
* ID of the entity. The Field API assumes that all revision IDs are unique
* across all entities of a type. This entry can be omitted if the entities
* of this type are not versionable.
* - bundle: (optional) The name of the property that contains the bundle name
* for the entity. The bundle name defines which set of fields are attached
* to the entity (e.g. what nodes call "content type"). This entry can be
* omitted if this entity type exposes a single bundle (such that all
* entities have the same collection of fields). The name of this single
* bundle will be the same as the entity type.
* - label: The name of the property that contains the entity label. For
* example, if the entity's label is located in $entity->subject, then
* 'subject' should be specified here. If complex logic is required to build
* the label, a 'label_callback' should be defined instead (see the
* $label_callback block above for details).
* - uuid (optional): The name of the property that contains the universally
* unique identifier of the entity, which is used to distinctly identify an
* entity across different systems.
*
* @var array
*/
public $entity_keys = array(
'revision' => '',
'bundle' => '',
);
/**
* An array describing how the Field API can extract the information it needs
* from the bundle objects for this type (e.g Vocabulary objects for terms;
* not applicable for nodes):
* - bundle: The name of the property that contains the name of the bundle
* object.
*
* This entry can be omitted if this type's bundles do not exist as standalone
* objects.
*
* @var array
*/
public $bundle_keys;
/**
* The base menu router path to which the entity admin user interface responds.
*
* It can be used to generate UI links and to attach additional router items
* to the entity UI in a generic fashion.
*
* @var string (optional)
*/
public $menu_base_path;
/**
* The menu router path to be used to view the entity.
*
* @var string (optional)
*/
public $menu_view_path;
/**
* The menu router path to be used to edit the entity.
*
* @var string (optional)
*/
public $menu_edit_path;
/**
* A string identifying the menu loader in the router path.
*
* @var string (optional)
*/
public $menu_path_wildcard;
/**
* Specifies whether a module exposing permissions for the current entity type
* should use entity-type level granularity, bundle level granularity or just
* skip this entity. The allowed values are respectively "entity_type",
* "bundle" or FALSE.
*
* @var string|bool (optional)
*/
public $permission_granularity = 'entity_type';
}
...@@ -19,114 +19,14 @@ ...@@ -19,114 +19,14 @@
/** /**
* Manages entity type plugin definitions. * Manages entity type plugin definitions.
* *
* Each entity type definition array is set in the entity type plugin's * Each entity type definition array is set in the entity type's
* annotation and altered by hook_entity_info_alter(). The definition includes * annotation and altered by hook_entity_info_alter().
* the following keys:
* - module: The name of the module providing the type.
* - class: The name of the entity type class. Defaults to
* Drupal\Core\Entity\Entity.
* - base_table: The name of the entity type's base table. Used by
* Drupal\Core\Entity\DatabaseStorageController.
* - controller_class: The name of the class that is used to load the objects.
* The class must implement
* Drupal\Core\Entity\EntityStorageControllerInterface. Defaults to
* Drupal\Core\Entity\DatabaseStorageController.
* - fieldable: (optional) Boolean indicating whether fields can be attached
* to entities of this type. Defaults to FALSE.
* - field_cache: (optional) Boolean indicating whether the Field API's
* Field API's 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.
* - form_controller_class: (optional) 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. Defaults to
* Drupal\Core\Entity\EntityFormController.
* - label: The human-readable name of the type.
* - bundle_label: The human-readable name of the entity bundles, e.g.
* Vocabulary.
* - label_callback: (optional) A function taking an entity and optional
* langcode argument, and returning 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\Entity::label() method, which implements this logic.
* - list_controller_class: (optional) The name of the class that provides
* listings of the entities. The class must implement
* Drupal\Core\Entity\EntityListControllerInterface. Defaults to
* Drupal\Core\Entity\EntityListController.
* - render_controller_class: The name of the class that is used to render the
* entities. Defaults to Drupal\Core\Entity\EntityRenderController.
* - access_controller_class: 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_controller_class: (optional) The name of the translation
* controller class that should be used to handle the translation process.
* See Drupal\translation_entity\EntityTranslationControllerInterface for more
* information.
* - static_cache: (optional) Boolean indicating whether entities should be
* statically cached during a page request. Used by
* Drupal\Core\Entity\DatabaseStorageController. Defaults to TRUE.
* - translatable: (optional) Boolean indicating whether entities of this type
* have mutlilingual support. Defaults to FALSE.
* - entity_keys: An array describing how the Field API can extract certain
* information from objects of this entity type. Elements:
* - id: The name of the property that contains the primary ID of the
* entity. Every entity object passed to the Field API must have this
* property and its value must be numeric.
* - revision: (optional) The name of the property that contains the
* revision ID of the entity. The Field API assumes that all revision IDs
* are unique across all entities of a type. This entry can be omitted if
* the entities of this type are not versionable.
* - bundle: (optional) The name of the property that contains the bundle
* name for the entity. The bundle name defines which set of fields are
* attached to the entity (e.g. what nodes call "content type"). This
* entry can be omitted if this entity type exposes a single bundle (such
* that all entities have the same collection of fields). The name of
* this single bundle will be the same as the entity type.
* - label: The name of the property that contains the entity label. For
* example, if the entity's label is located in $entity->subject, then
* 'subject' should be specified here. If complex logic is required to
* build the label, a 'label_callback' should be defined instead (see
* the 'label_callback' section above for details).
* - uuid (optional): The name of the property that contains the universally
* unique identifier of the entity, which is used to distinctly identify
* an entity across different systems.
* - bundle_keys: An array describing how the Field API can extract the
* information it needs from the bundle objects for this type (e.g
* Vocabulary objects for terms; not applicable for nodes). This entry can
* be omitted if this type's bundles do not exist as standalone objects.
* Elements:
* - bundle: The name of the property that contains the name of the bundle
* object.
* - menu_base_path: (optional) The base menu router path to which the entity
* administration user interface responds. It can be used to generate UI
* links and to attach additional router items to the entity UI in a generic
* fashion.
* - menu_view_path: (optional) The menu router path to be used to view the
* entity.
* - menu_edit_path: (optional) The menu router path to be used to edit the
* entity.
* - menu_path_wildcard: (optional) A string identifying the menu loader in the
* router path.
* - permission_granularity: (optional) Specifies whether a module exposing
* permissions for the current entity type should use entity-type level
* granularity, bundle level granularity or just skip this entity. The allowed
* values are respectively "entity_type", "bundle" or FALSE. Defaults to
* "entity_type".
* *
* The defaults for the plugin definition are provided in * The defaults for the plugin definition are provided in
* \Drupal\Core\Entity\EntityManager::defaults. * \Drupal\Core\Entity\EntityManager::defaults.
* *
* @see \Drupal\Core\Entity\Entity * @see \Drupal\Core\Entity\Annotation\EntityType
* @see \Drupal\Core\Entity\EntityInterface
* @see entity_get_info() * @see entity_get_info()
* @see hook_entity_info_alter() * @see hook_entity_info_alter()
*/ */
...@@ -139,30 +39,6 @@ class EntityManager extends PluginManagerBase { ...@@ -139,30 +39,6 @@ class EntityManager extends PluginManagerBase {
*/ */
protected $controllers = array(); protected $controllers = array();
/**
* The default values for optional keys of the entity plugin definition.
*
* @var array
*/
protected $defaults = array(
'class' => 'Drupal\Core\Entity\Entity',
'controller_class' => 'Drupal\Core\Entity\DatabaseStorageController',
'entity_keys' => array(
'revision' => '',
'bundle' => '',
),
'fieldable' => FALSE,
'field_cache' => TRUE,
'form_controller_class' => array(
'default' => 'Drupal\Core\Entity\EntityFormController',
),
'list_controller_class' => 'Drupal\Core\Entity\EntityListController',
'access_controller_class' => 'Drupal\Core\Entity\EntityAccessController',
'static_cache' => TRUE,
'translation' => array(),
'permission_granularity' => 'entity_type',
);
/** /**
* Constructs a new Entity plugin manager. * Constructs a new Entity plugin manager.
* *
...@@ -171,7 +47,10 @@ class EntityManager extends PluginManagerBase { ...@@ -171,7 +47,10 @@ class EntityManager extends PluginManagerBase {
*/ */
public function __construct(array $namespaces) { public function __construct(array $namespaces) {
// Allow the plugin definition to be altered by hook_entity_info_alter(). // Allow the plugin definition to be altered by hook_entity_info_alter().
$this->discovery = new AnnotatedClassDiscovery('Core', 'Entity', $namespaces); $annotation_namespaces = array(
'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib',
);
$this->discovery = new AnnotatedClassDiscovery('Core', 'Entity', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
$this->discovery = new InfoHookDecorator($this->discovery, 'entity_info'); $this->discovery = new InfoHookDecorator($this->discovery, 'entity_info');
$this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition')); $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
$this->discovery = new AlterDecorator($this->discovery, 'entity_info'); $this->discovery = new AlterDecorator($this->discovery, 'entity_info');
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG; use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the aggregator feed entity class. * Defines the aggregator feed entity class.
* *
* @Plugin( * @EntityType(
* id = "aggregator_feed", * id = "aggregator_feed",
* label = @Translation("Aggregator feed"), * label = @Translation("Aggregator feed"),
* module = "aggregator", * module = "aggregator",
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG; use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the aggregator item entity class. * Defines the aggregator item entity class.
* *
* @Plugin( * @EntityType(
* id = "aggregator_item", * id = "aggregator_item",
* label = @Translation("Aggregator feed item"), * label = @Translation("Aggregator feed item"),
* module = "aggregator", * module = "aggregator",
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG; use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the custom block entity class. * Defines the custom block entity class.
* *
* @Plugin( * @EntityType(
* id = "custom_block", * id = "custom_block",
* label = @Translation("Custom Block"), * label = @Translation("Custom Block"),
* bundle_label = @Translation("Custom Block type"), * bundle_label = @Translation("Custom Block type"),
......
...@@ -8,13 +8,13 @@ ...@@ -8,13 +8,13 @@
namespace Drupal\custom_block\Plugin\Core\Entity; namespace Drupal\custom_block\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the custom block type entity. * Defines the custom block type entity.
* *
* @Plugin( * @EntityType(
* id = "custom_block_type", * id = "custom_block_type",
* label = @Translation("Custom block type"), * label = @Translation("Custom block type"),
* module = "custom_block", * module = "custom_block",
......
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
namespace Drupal\block\Plugin\Core\Entity; namespace Drupal\block\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Component\Plugin\Exception\PluginException; use Drupal\Component\Plugin\Exception\PluginException;
/** /**
* Defines a Block configuration entity class. * Defines a Block configuration entity class.
* *
* @Plugin( * @EntityType(
* id = "block", * id = "block",
* label = @Translation("Block"), * label = @Translation("Block"),
* module = "block", * module = "block",
......
...@@ -13,13 +13,13 @@ ...@@ -13,13 +13,13 @@
use Drupal\breakpoint\InvalidBreakpointSourceException; use Drupal\breakpoint\InvalidBreakpointSourceException;
use Drupal\breakpoint\InvalidBreakpointSourceTypeException; use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
use Drupal\breakpoint\InvalidBreakpointMediaQueryException; use Drupal\breakpoint\InvalidBreakpointMediaQueryException;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the Breakpoint entity. * Defines the Breakpoint entity.
* *
* @Plugin( * @EntityType(
* id = "breakpoint", * id = "breakpoint",
* label = @Translation("Breakpoint"), * label = @Translation("Breakpoint"),
* module = "breakpoint", * module = "breakpoint",
......
...@@ -10,13 +10,13 @@ ...@@ -10,13 +10,13 @@
use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\breakpoint\InvalidBreakpointSourceException; use Drupal\breakpoint\InvalidBreakpointSourceException;
use Drupal\breakpoint\InvalidBreakpointSourceTypeException; use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the BreakpointGroup entity. * Defines the BreakpointGroup entity.
* *
* @Plugin( * @EntityType(
* id = "breakpoint_group", * id = "breakpoint_group",
* label = @Translation("Breakpoint group"), * label = @Translation("Breakpoint group"),
* module = "breakpoint", * module = "breakpoint",
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG; use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the comment entity class. * Defines the comment entity class.
* *
* @Plugin( * @EntityType(
* id = "comment", * id = "comment",
* label = @Translation("Comment"), * label = @Translation("Comment"),
* bundle_label = @Translation("Content type"), * bundle_label = @Translation("Content type"),
......
...@@ -7,13 +7,13 @@ ...@@ -7,13 +7,13 @@
namespace Drupal\config_test\Plugin\Core\Entity; namespace Drupal\config_test\Plugin\Core\Entity;
use Drupal\Component\Annotation\Plugin; use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
/** /**
* Defines the ConfigQueryTest configuration entity used by the query test. * Defines the ConfigQueryTest configuration entity used by the query test.
* *
* @Plugin( * @EntityType(
* id = "config_query_test", * id = "config_query_test",
* label = @Translation("Test configuration for query"), * label = @Translation("Test configuration for query"),
* module = "config_test", * module = "config_test",
......
...@@ -8,13 +8,13 @@ ...@@ -8,13 +8,13 @@
namespace Drupal\config_test\Plugin\Core\Entity; namespace Drupal\config_test\Plugin\Core\Entity;