Commit b77715c3 authored by webchick's avatar webchick

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

parent a820153f
......@@ -7,6 +7,8 @@
namespace Drupal\Component\Annotation;
use Drupal\Component\Utility\NestedArray;
/**
* Defines a Plugin annotation object.
*
......@@ -34,7 +36,13 @@ class Plugin implements AnnotationInterface {
* classed annotations that were used.
*/
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 @@
/**
* Manages entity type plugin definitions.
*
* Each entity type definition array is set in the entity type plugin's
* annotation and altered by hook_entity_info_alter(). The definition includes
* 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".
* Each entity type definition array is set in the entity type's
* annotation and altered by hook_entity_info_alter().
*
* The defaults for the plugin definition are provided in
* \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 hook_entity_info_alter()
*/
......@@ -139,30 +39,6 @@ class EntityManager extends PluginManagerBase {
*/
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.
*
......@@ -171,7 +47,10 @@ class EntityManager extends PluginManagerBase {
*/
public function __construct(array $namespaces) {
// 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 ProcessDecorator($this->discovery, array($this, 'processDefinition'));
$this->discovery = new AlterDecorator($this->discovery, 'entity_info');
......
......@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the aggregator feed entity class.
*
* @Plugin(
* @EntityType(
* id = "aggregator_feed",
* label = @Translation("Aggregator feed"),
* module = "aggregator",
......
......@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the aggregator item entity class.
*
* @Plugin(
* @EntityType(
* id = "aggregator_item",
* label = @Translation("Aggregator feed item"),
* module = "aggregator",
......
......@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the custom block entity class.
*
* @Plugin(
* @EntityType(
* id = "custom_block",
* label = @Translation("Custom Block"),
* bundle_label = @Translation("Custom Block type"),
......
......@@ -8,13 +8,13 @@
namespace Drupal\custom_block\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the custom block type entity.
*
* @Plugin(
* @EntityType(
* id = "custom_block_type",
* label = @Translation("Custom block type"),
* module = "custom_block",
......
......@@ -8,14 +8,14 @@
namespace Drupal\block\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
use Drupal\Component\Plugin\Exception\PluginException;
/**
* Defines a Block configuration entity class.
*
* @Plugin(
* @EntityType(
* id = "block",
* label = @Translation("Block"),
* module = "block",
......
......@@ -13,13 +13,13 @@
use Drupal\breakpoint\InvalidBreakpointSourceException;
use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
use Drupal\breakpoint\InvalidBreakpointMediaQueryException;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the Breakpoint entity.
*
* @Plugin(
* @EntityType(
* id = "breakpoint",
* label = @Translation("Breakpoint"),
* module = "breakpoint",
......
......@@ -10,13 +10,13 @@
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\breakpoint\InvalidBreakpointSourceException;
use Drupal\breakpoint\InvalidBreakpointSourceTypeException;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the BreakpointGroup entity.
*
* @Plugin(
* @EntityType(
* id = "breakpoint_group",
* label = @Translation("Breakpoint group"),
* module = "breakpoint",
......
......@@ -9,13 +9,13 @@
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityNG;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the comment entity class.
*
* @Plugin(
* @EntityType(
* id = "comment",
* label = @Translation("Comment"),
* bundle_label = @Translation("Content type"),
......
......@@ -7,13 +7,13 @@
namespace Drupal\config_test\Plugin\Core\Entity;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the ConfigQueryTest configuration entity used by the query test.
*
* @Plugin(
* @EntityType(
* id = "config_query_test",
* label = @Translation("Test configuration for query"),
* module = "config_test",
......
......@@ -8,13 +8,13 @@
namespace Drupal\config_test\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the ConfigTest configuration entity.
*
* @Plugin(
* @EntityType(
* id = "config_test",
* label = @Translation("Test configuration"),
* module = "config_test",
......
......@@ -8,13 +8,13 @@
namespace Drupal\config_test\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the ConfigTestEmptyManifest configuration entity.
*
* @Plugin(
* @EntityType(
* id = "config_test_empty_manifest",
* label = @Translation("Test empty manifest creation"),
* module = "config_test",
......
......@@ -8,13 +8,13 @@
namespace Drupal\contact\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the contact category entity.
*
* @Plugin(
* @EntityType(
* id = "contact_category",
* label = @Translation("Contact category"),
* module = "contact",
......
......@@ -7,14 +7,14 @@
namespace Drupal\contact\Plugin\Core\Entity;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\Entity;
/**
* Defines the contact message entity.
*
* @Plugin(
* @EntityType(
* id = "contact_message",
* label = @Translation("Contact message"),
* module = "contact",
......
......@@ -8,13 +8,13 @@
namespace Drupal\editor\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Defines the configured text editor entity.
*
* @Plugin(
* @EntityType(
* id = "editor",
* label = @Translation("Editor"),
* module = "editor",
......
......@@ -8,14 +8,14 @@
namespace Drupal\entity\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Entity\Annotation\EntityType;
use Drupal\Core\Annotation\Translation;
/**
* Configuration entity that contains display options for all components of a
* rendered entity in a given view mode..
*
* @Plugin(
* @EntityType(
* id = "entity_display",
* label = @Translation("Entity display"),
* module = "entity",
......