diff --git a/core/includes/config.inc b/core/includes/config.inc index 31f6e5b..047dfe9 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -25,7 +25,7 @@ function config_install_default_config($type, $name) { // If this module defines any ConfigEntity types then create an empty // manifest file for each of them. foreach (config_get_module_config_entities($name) as $entity_info) { - config('manifest.' . $entity_info['config_prefix'])->save(); + config('manifest.' . $entity_info->getConfigPrefix())->save(); } $config_dir = drupal_get_path($type, $name) . '/config'; @@ -63,8 +63,8 @@ function config_uninstall_default_config($type, $name) { // If this module defines any ConfigEntity types, then delete the manifest // file for each of them. - foreach (config_get_module_config_entities($name) as $entity_type) { - config('manifest.' . $entity_info['config_prefix'])->delete(); + foreach (config_get_module_config_entities($name) as $entity_type => $entity_info) { + config('manifest.' . $entity_info->getConfigPrefix())->delete(); } } @@ -150,8 +150,8 @@ function config_context_leave() { * @param string $module * The name of the module possibly providing config entities. * - * @return array - * An associative array containing the entity info for any config entities + * @return \Drupal\Core\Entity\Annotation\EntityType[] + * An associative array containing the entity type for any config entities * provided by the requested module, keyed by the entity type. */ function config_get_module_config_entities($module) { @@ -160,7 +160,7 @@ function config_get_module_config_entities($module) { // once per module. $info = entity_get_info(); return array_filter($info, function($entity_info) use ($module) { - return ($entity_info['module'] == $module) && is_subclass_of($entity_info['class'], 'Drupal\Core\Config\Entity\ConfigEntityInterface'); + return ($entity_info->getModule() == $module) && is_subclass_of($entity_info->getClass(), 'Drupal\Core\Config\Entity\ConfigEntityInterface'); }); } @@ -175,7 +175,7 @@ function config_get_module_config_entities($module) { */ 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); + return ($entity_info->getConfigPrefix() && strpos($name, $entity_info->getConfigPrefix() . '.') === 0); }); return key($entities); } diff --git a/core/includes/entity.inc b/core/includes/entity.inc index 702a56e..dd63a7a 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -68,7 +68,7 @@ function entity_get_bundles($entity_type = NULL) { // If no bundles are provided, use the entity type name and label. foreach (entity_get_info() as $type => $entity_info) { if (!isset($bundles[$type])) { - $bundles[$type][$type]['label'] = $entity_info['label']; + $bundles[$type][$type]['label'] = $entity_info->getLabel(); } } drupal_alter('entity_bundle_info', $bundles); @@ -224,10 +224,10 @@ function entity_revision_delete($entity_type, $revision_id) { */ function entity_load_by_uuid($entity_type, $uuid, $reset = FALSE) { $entity_info = entity_get_info($entity_type); - if (empty($entity_info['entity_keys']['uuid'])) { + if (!$entity_info->getKey('uuid')) { throw new EntityStorageException("Entity type $entity_type does not support UUIDs."); } - $uuid_key = $entity_info['entity_keys']['uuid']; + $uuid_key = $entity_info->getKey('uuid'); $controller = Drupal::entityManager()->getStorageController($entity_type); if ($reset) { @@ -520,7 +520,7 @@ function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_st // without changing existing entity properties that are not being edited by // this form. Copying field values must be done using // field_attach_extract_form_values(). - $values_excluding_fields = $info['fieldable'] ? array_diff_key($form_state['values'], field_info_instances($entity_type, $entity->bundle())) : $form_state['values']; + $values_excluding_fields = $info->isFieldable() ? array_diff_key($form_state['values'], field_info_instances($entity_type, $entity->bundle())) : $form_state['values']; foreach ($values_excluding_fields as $key => $value) { $entity->set($key, $value); } @@ -533,7 +533,7 @@ function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_st } // Copy field values to the entity. - if ($info['fieldable']) { + if ($info->isFieldable()) { field_attach_extract_form_values($entity, $form, $form_state); } } diff --git a/core/includes/install.inc b/core/includes/install.inc index 84dd851..0093562 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -641,7 +641,7 @@ function drupal_install_system() { ->save(); // Update the module list to include it. - drupal_container()->get('module_handler')->setModuleList(array('system' => $system_path . '/system.module')); + $kernel->updateModules(array('system' => 'system'), array('system' => $system_path . '/system.module')); config_install_default_config('module', 'system'); diff --git a/core/lib/Drupal/Core/AnnotationReader.php b/core/lib/Drupal/Core/AnnotationReader.php new file mode 100644 index 0000000..b569b2c --- /dev/null +++ b/core/lib/Drupal/Core/AnnotationReader.php @@ -0,0 +1,98 @@ +getClassAnnotations($class_name); + $filtered_annotations = array(); + foreach ($annotations as $annotation) { + if ($annotation instanceOf $annotation_name) { + return $annotation; + } + } + } + + public function getClassAnnotations($class_name) { + return $this->getFromCache($class_name) ?: $this->doGetClassAnnotations($class_name); + } + + protected function doGetClassAnnotations($class_name) { + $this->initialize(); + + $annotations = array(); + if (class_exists($class_name)) { + $reflection_class = new \ReflectionClass($class_name); + $annotations = $this->reader()->getClassAnnotations($reflection_class); + $this->setCache($class_name, $annotations); + } + return $annotations; + } + + protected function doGetClassAnnotationsStatic($class_name) { + $this->initialize(); + $parser = new StaticReflectionParser($class_name, $this->getLoader()); + $reflection_class = $parser->getReflectionClass(); + $annotations = $this->reader()->getClassAnnotations($reflection_class); + $this->setCache($class_name, $annotations); + return $annotations; + } + + protected function reader() { + if (!isset($this->reader)) { + $this->reader = new DoctrineAnnotationReader(); + foreach ($this->globalIgnoreNames() as $name) { + $this->reader->addGlobalIgnoredName($name); + } + } + return $this->reader; + } + + public function setReader($reader) { + $this->reader = $reader; + } + + protected function globalIgnoreNames() { + return array('endlink'); + } + + protected function getFromCache($name) { + return isset($this->cache[$name]) ? $this->cache[$name] : FALSE; + } + + protected function setCache($name, $value) { + $this->cache[$name] = $value; + } + + protected function getLoader() { + return $this->loader ?: $this->defaultLoader(); + } + + public function setLoader($loader) { + $this->loader = $loader; + } + + protected function defaultLoader() { + return drupal_classloader(); + } + + protected function initialize() { + if (!$this->initialized) { + // If the default loader isn't already callable, it's probably an instance + // of the class loader, so make it callable with the right method here. + if (!is_callable($loader = $this->getLoader())) { + $loader = array($loader, 'loadClass'); + } + AnnotationRegistry::registerLoader($loader); + $this->initialized = TRUE; + } + } +} diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php index c4fa043..a222051 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php @@ -20,7 +20,7 @@ class ConfigEntityListController extends EntityListController { */ public function load() { $entities = parent::load(); - uasort($entities, array($this->entityInfo['class'], 'sort')); + uasort($entities, array($this->entityInfo->getClass(), 'sort')); return $entities; } @@ -31,7 +31,7 @@ public function getOperations(EntityInterface $entity) { $operations = parent::getOperations($entity); $uri = $entity->uri(); - if (isset($this->entityInfo['entity_keys']['status'])) { + if ($this->entityInfo->getKey('status')) { if (!$entity->status()) { $operations['enable'] = array( 'title' => t('Enable'), diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php index 1ce4456..2b66e2c 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php @@ -9,6 +9,7 @@ use Drupal\Component\Uuid\Uuid; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityType; use Drupal\Core\Entity\EntityControllerInterface; use Drupal\Core\Entity\EntityMalformedException; use Drupal\Core\Entity\EntityStorageControllerInterface; @@ -106,19 +107,12 @@ class ConfigStorageController implements EntityStorageControllerInterface, Entit * @param \Drupal\Core\Config\StorageInterface $config_storage * The config storage service. */ - public function __construct($entity_type, array $entity_info, ConfigFactory $config_factory, StorageInterface $config_storage) { + public function __construct($entity_type, EntityType $entity_info, ConfigFactory $config_factory, StorageInterface $config_storage) { $this->entityType = $entity_type; $this->entityInfo = $entity_info; $this->hookLoadArguments = array(); - $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; } @@ -126,7 +120,7 @@ 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, $entity_type, EntityType $entity_info) { return new static( $entity_type, $entity_info, @@ -225,7 +219,7 @@ public function loadByProperties(array $values = array()) { * The full configuration prefix, for example 'views.view.'. */ public function getConfigPrefix() { - return $this->entityInfo['config_prefix'] . '.'; + return $this->entityInfo->getConfigPrefix() . '.'; } /** @@ -266,7 +260,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(); // Load all of the configuration entities. @@ -328,7 +322,7 @@ protected function attachLoad(&$queried_entities, $revision_id = FALSE) { * Implements Drupal\Core\Entity\EntityStorageControllerInterface::create(). */ public function create(array $values) { - $class = $this->entityInfo['class']; + $class = $this->entityInfo->getClass(); // Set default language to site default if not provided. $values += array('langcode' => language_default()->langcode); @@ -377,7 +371,7 @@ public function delete(array $entities) { // Remove the entity from the manifest file. Entity IDs can contain a dot // so we can not use Config::clear() to remove the entity from the // manifest. - $manifest = $this->configFactory->get('manifest.' . $this->entityInfo['config_prefix']); + $manifest = $this->configFactory->get('manifest.' . $this->entityInfo->getConfigPrefix()); $manifest_data = $manifest->get(); unset($manifest_data[$entity->id()]); $manifest->setData($manifest_data); @@ -453,7 +447,7 @@ public function save(EntityInterface $entity) { } $update_manifest = FALSE; - $config = $this->configFactory->get('manifest.' . $this->entityInfo['config_prefix']); + $config = $this->configFactory->get('manifest.' . $this->entityInfo->getConfigPrefix()); $manifest = $config->get(); // If the save operation resulted in a rename remove the old entity id from // the manifest file. @@ -580,7 +574,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()); $entities = $this->load(array($id)); $entity = $entities[$id]; $entity->original = clone $entity; @@ -611,7 +605,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()); $entities = $this->load(array($id)); $entity = $entities[$id]; $entity->delete(); diff --git a/core/lib/Drupal/Core/Config/Entity/Query/Query.php b/core/lib/Drupal/Core/Config/Entity/Query/Query.php index 8577c08..f046c81 100644 --- a/core/lib/Drupal/Core/Config/Entity/Query/Query.php +++ b/core/lib/Drupal/Core/Config/Entity/Query/Query.php @@ -83,7 +83,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) + 1; $names = $this->configStorage->listAll($prefix); $configs = array(); diff --git a/core/lib/Drupal/Core/Discovery/DiscoverableInterface.php b/core/lib/Drupal/Core/Discovery/DiscoverableInterface.php new file mode 100644 index 0000000..6938c9b --- /dev/null +++ b/core/lib/Drupal/Core/Discovery/DiscoverableInterface.php @@ -0,0 +1,7 @@ +name = $name; + $this->directories = $directories; + } + + public function findAll() { + $parser = $this->parser(); + $all = array_map(function($file) use ($parser) { + return $parser->parse(file_get_contents($file)); + }, $this->findFiles()); + return $all; + } + + protected function parser() { + if (!isset($this->parser)) { + $this->parser = new Parser(); + } + return $this->parser; + } + + protected function findFiles() { + $files = array(); + foreach ($this->directories as $directory) { + $file = $directory . '/' . basename($directory) . '.' . $this->name . '.yml'; + if (file_exists($file)) { + $files[] = $file; + } + } + return $files; + } +} diff --git a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php index 30c8252..59b687e 100644 --- a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php +++ b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php @@ -6,260 +6,51 @@ */ namespace Drupal\Core\Entity\Annotation; - -use Drupal\Component\Annotation\Plugin; +use Drupal\Component\Utility\NestedArray; /** - * 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; - - /** - * 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\EntityRenderControllerInterface. - * - 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\translation_entity\EntityTranslationControllerInterface. - * - * @todo Interfaces from outside \Drupal\Core or \Drupal\Component should not - * be used here. - * - * @var array - */ - public $controllers = array( - 'access' => 'Drupal\Core\Entity\EntityAccessController', - ); - - /** - * 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; +class EntityType { - /** - * 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; + public function __construct($values) { + $reflection = new \ReflectionClass($this); + // Only keep actual default values by ignoring NULL values. + $parsed_values = $this->parse(array_filter($values, function ($value) { + return $value !== NULL; + })); - /** - * @todo translation_entity_entity_info_alter() uses this but it is undocumented. - * - * @var array - */ - public $translation = array(); + $this->definition = $parsed_values; + } /** - * 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. + * Parses an annotation into its definition. * - * @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. + * @param array $values + * The annotation array. * - * @var array + * @return array + * The parsed annotation as a definition. */ - public $bundle_keys; + protected function parse(array $values) { + $definitions = array(); + foreach ($values as $key => $value) { + if ($value instanceof AnnotationInterface) { + $definitions[$key] = $value->get(); + } + elseif (is_array($value)) { + $definitions[$key] = $this->parse($value); + } + else { + $definitions[$key] = $value; + } + } + return $definitions; + } /** - * The base router path for the entity type's field administration page. - * - * If the entity type has a bundle, include {bundle} in the path. - * - * For example, the node entity type specifies - * "admin/structure/types/manage/{bundle}" as its base field admin path. - * - * @var string (optional) - */ - public $route_base_path; - - /** - * The prefix for the bundles of this entity type. - * - * For example, the comment bundle is prefixed with 'comment_node_'. - * - * @var string (optional) */ - public $bundle_prefix; - - /** - * 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'; - + public function get() { + return $this->definition; + } } diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php index bb8e2bb..28a235e 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php @@ -11,6 +11,7 @@ use PDO; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Entity\Query\QueryInterface; +use Drupal\Core\Entity\EntityType; use Drupal\Component\Uuid\Uuid; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Database\Connection; @@ -126,7 +127,7 @@ class DatabaseStorageController implements EntityStorageControllerInterface, Ent /** * {@inheritdoc} */ - public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { + public static function createInstance(ContainerInterface $container, $entity_type, EntityType $entity_info) { return new static( $entity_type, $entity_info, @@ -144,7 +145,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ * @param \Drupal\Core\Database\Connection $database * The database connection to be used. */ - public function __construct($entity_type, array $entity_info, Connection $database) { + public function __construct($entity_type, EntityType $entity_info, Connection $database) { $this->database = $database; $this->entityType = $entity_type; $this->entityInfo = $entity_info; @@ -152,32 +153,21 @@ public function __construct($entity_type, array $entity_info, Connection $databa $this->hookLoadArguments = array(); // Check if the entity type supports IDs. - if (isset($this->entityInfo['entity_keys']['id'])) { - $this->idKey = $this->entityInfo['entity_keys']['id']; - } - else { - $this->idKey = FALSE; - } - + $this->idKey = $this->entityInfo->getKey('id'); // Check if the entity type supports UUIDs. - if (!empty($this->entityInfo['entity_keys']['uuid'])) { - $this->uuidKey = $this->entityInfo['entity_keys']['uuid']; - } - else { - $this->uuidKey = FALSE; - } + $this->uuidKey = $this->entityInfo->getKey('uuid'); // Check if the entity type supports revisions. - if (!empty($this->entityInfo['entity_keys']['revision'])) { - $this->revisionKey = $this->entityInfo['entity_keys']['revision']; - $this->revisionTable = $this->entityInfo['revision_table']; + $this->revisionKey = $this->entityInfo->getKey('revision'); + if ($this->revisionKey) { + $this->revisionTable = $this->entityInfo->getRevisionTable(); } else { $this->revisionKey = FALSE; } // Check if the entity type supports static caching of loaded entities. - $this->cache = !empty($this->entityInfo['static_cache']); + $this->cache = $this->entityInfo->staticCacheable(); } /** @@ -223,11 +213,12 @@ public function load(array $ids = NULL) { // Build and execute the query. $query_result = $this->buildQuery($ids)->execute(); - if (!empty($this->entityInfo['class'])) { + $entity_class = $this->entityInfo->getClass(); + if (!empty($entity_class)) { // We provide the necessary arguments for PDO to create objects of the // specified entity class. // @see Drupal\Core\Entity\EntityInterface::__construct() - $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); + $query_result->setFetchMode(PDO::FETCH_CLASS, $entity_class, array(array(), $this->entityType)); } $queried_entities = $query_result->fetchAllAssoc($this->idKey); } @@ -277,11 +268,11 @@ public function loadRevision($revision_id) { // Build and execute the query. $query_result = $this->buildQuery(array(), $revision_id)->execute(); - if (!empty($this->entityInfo['class'])) { + if ($entity_class = $this->entityInfo->getClass()) { // We provide the necessary arguments for PDO to create objects of the // specified entity class. // @see Drupal\Core\Entity\EntityInterface::__construct() - $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); + $query_result->setFetchMode(PDO::FETCH_CLASS, $entity_class, array(array(), $this->entityType)); } $queried_entities = $query_result->fetchAllAssoc($this->idKey); @@ -358,7 +349,8 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value * A SelectQuery object for loading the entity. */ protected function buildQuery($ids, $revision_id = FALSE) { - $query = $this->database->select($this->entityInfo['base_table'], 'base'); + $base_table = $this->entityInfo->getBaseTable(); + $query = $this->database->select($this->entityInfo->getBaseTable(), 'base'); $query->addTag($this->entityType . '_load_multiple'); @@ -370,11 +362,11 @@ protected function buildQuery($ids, $revision_id = FALSE) { } // Add fields from the {entity} table. - $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']); + $entity_fields = drupal_schema_fields_sql($base_table); if ($this->revisionKey) { // Add all fields from the {entity_revision} table. - $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table'])); + $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo->getRevisionTable())); // The id field is provided by entity, so remove it. unset($entity_revision_fields[$this->idKey]); @@ -420,7 +412,7 @@ protected function buildQuery($ids, $revision_id = FALSE) { */ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { // Attach fields. - if ($this->entityInfo['fieldable']) { + if ($this->entityInfo->isFieldable()) { if ($load_revision) { field_attach_load_revision($this->entityType, $queried_entities); } @@ -475,7 +467,7 @@ protected function cacheSet($entities) { * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::create(). */ public function create(array $values) { - $class = $this->entityInfo['class']; + $class = $this->entityInfo->getClass(); $entity = new $class($values, $this->entityType); @@ -509,7 +501,7 @@ public function delete(array $entities) { } $ids = array_keys($entities); - $this->database->delete($this->entityInfo['base_table']) + $this->database->delete($this->entityInfo->getBaseTable()) ->condition($this->idKey, $ids, 'IN') ->execute(); @@ -552,7 +544,7 @@ public function save(EntityInterface $entity) { if (!$entity->isNew()) { if ($entity->isDefaultRevision()) { - $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey); + $return = drupal_write_record($this->entityInfo->getBaseTable(), $entity, $this->idKey); } else { // @todo, should a different value be returned when saving an entity @@ -567,7 +559,7 @@ public function save(EntityInterface $entity) { $this->invokeHook('update', $entity); } else { - $return = drupal_write_record($this->entityInfo['base_table'], $entity); + $return = drupal_write_record($this->entityInfo->getBaseTable(), $entity); if ($this->revisionKey) { $this->saveRevision($entity); } @@ -618,7 +610,7 @@ protected function saveRevision(EntityInterface $entity) { if ($entity->isNewRevision()) { drupal_write_record($this->revisionTable, $record); if ($entity->isDefaultRevision()) { - $this->database->update($this->entityInfo['base_table']) + $this->database->update($this->entityInfo->getBaseTable()) ->fields(array($this->revisionKey => $record[$this->revisionKey])) ->condition($this->idKey, $entity->id()) ->execute(); @@ -690,7 +682,7 @@ protected function invokeHook($hook, EntityInterface $entity) { if ($function == 'field_attach_revision_delete') { $function = 'field_attach_delete_revision'; } - if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { + if ($this->entityInfo->isFieldable() && function_exists($function)) { $function($entity); } // Invoke the hook. diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php index 91ec62d..abbe986 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php @@ -12,6 +12,7 @@ use Drupal\Core\Entity\Query\QueryInterface; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityType; use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\TypedData\ComplexDataInterface; @@ -54,21 +55,21 @@ class DatabaseStorageControllerNG extends DatabaseStorageController { /** * Overrides DatabaseStorageController::__construct(). */ - public function __construct($entity_type, array $entity_info, Connection $database) { + public function __construct($entity_type, EntityType $entity_info, Connection $database) { parent::__construct($entity_type,$entity_info, $database); - $this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE; - $this->entityClass = $this->entityInfo['class']; + $this->bundleKey = $this->entityInfo->getKey('bundle'); + $this->entityClass = $this->entityInfo->getClass(); // Check if the entity type has a dedicated table for properties. - if (!empty($this->entityInfo['data_table'])) { - $this->dataTable = $this->entityInfo['data_table']; + if ($data_table = $this->entityInfo->getDataTable()) { + $this->dataTable = $data_table; } // Work-a-round to let load() get stdClass storage records without having to // override it. We map storage records to entities in // DatabaseStorageControllerNG:: mapFromStorageRecords(). // @todo: Remove this once this is moved in the main controller. - unset($this->entityInfo['class']); + $this->entityInfo->setClass(NULL); } /** @@ -158,7 +159,7 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value * {@inheritdoc} */ protected function buildQuery($ids, $revision_id = FALSE) { - $query = $this->database->select($this->entityInfo['base_table'], 'base'); + $query = $this->database->select($this->entityInfo->getBaseTable(), 'base'); $is_revision_query = $this->revisionKey && ($revision_id || !$this->dataTable); $query->addTag($this->entityType . '_load_multiple'); @@ -171,11 +172,11 @@ protected function buildQuery($ids, $revision_id = FALSE) { } // Add fields from the {entity} table. - $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']); + $entity_fields = drupal_schema_fields_sql($this->entityInfo->getBaseTable()); if ($is_revision_query) { // Add all fields from the {entity_revision} table. - $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table'])); + $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo->getRevisionTable())); // The ID field is provided by entity, so remove it. unset($entity_revision_fields[$this->idKey]); @@ -212,7 +213,7 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { // Map the loaded stdclass records into entity objects and according fields. $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision); - if ($this->entityInfo['fieldable']) { + if ($this->entityInfo->isFieldable()) { if ($load_revision) { field_attach_load_revision($this->entityType, $queried_entities); } @@ -303,10 +304,10 @@ protected function attachPropertyData(array &$entities, $revision_id = FALSE) { $data = $query->execute(); $field_definition = $this->getFieldDefinitions(array()); if ($this->revisionTable) { - $data_fields = array_flip(array_diff(drupal_schema_fields_sql($this->entityInfo['revision_table']), drupal_schema_fields_sql($this->entityInfo['base_table']))); + $data_fields = array_flip(array_diff(drupal_schema_fields_sql($this->entityInfo->getRevisionTable()), drupal_schema_fields_sql($this->entityInfo->getBaseTable()))); } else { - $data_fields = array_flip(drupal_schema_fields_sql($this->entityInfo['data_table'])); + $data_fields = array_flip(drupal_schema_fields_sql($this->entityInfo->getDataTable())); } foreach ($data as $values) { @@ -359,10 +360,10 @@ public function save(EntityInterface $entity) { // Create the storage record to be saved. $record = $this->mapToStorageRecord($entity); - + $base_table = $this->entityInfo->getBaseTable(); if (!$entity->isNew()) { if ($entity->isDefaultRevision()) { - $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey); + $return = drupal_write_record($base_table, $record, $this->idKey); } else { // @todo, should a different value be returned when saving an entity @@ -380,7 +381,7 @@ public function save(EntityInterface $entity) { $this->invokeHook('update', $entity); } else { - $return = drupal_write_record($this->entityInfo['base_table'], $record); + $return = drupal_write_record($base_table, $record); $entity->{$this->idKey}->value = $record->{$this->idKey}; if ($this->revisionKey) { $record->{$this->revisionKey} = $this->saveRevision($entity); @@ -450,7 +451,7 @@ protected function saveRevision(EntityInterface $entity) { if ($entity->isNewRevision()) { drupal_write_record($this->revisionTable, $record); if ($entity->isDefaultRevision()) { - $this->database->update($this->entityInfo['base_table']) + $this->database->update($this->entityInfo->getBaseTable()) ->fields(array($this->revisionKey => $record->{$this->revisionKey})) ->condition($this->idKey, $record->{$this->idKey}) ->execute(); @@ -507,7 +508,7 @@ protected function invokeHook($hook, EntityInterface $entity) { if ($function == 'field_attach_revision_delete') { $function = 'field_attach_delete_revision'; } - if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { + if ($this->entityInfo->isFieldable() && function_exists($function)) { $function($entity); } @@ -528,7 +529,7 @@ protected function invokeHook($hook, EntityInterface $entity) { */ protected function mapToStorageRecord(EntityInterface $entity) { $record = new \stdClass(); - foreach (drupal_schema_fields_sql($this->entityInfo['base_table']) as $name) { + foreach (drupal_schema_fields_sql($this->entityInfo->getBaseTable()) as $name) { $record->$name = $entity->$name->value; } return $record; @@ -546,7 +547,7 @@ protected function mapToStorageRecord(EntityInterface $entity) { protected function mapToRevisionStorageRecord(ComplexDataInterface $entity) { $record = new \stdClass(); $definitions = $entity->getPropertyDefinitions(); - foreach (drupal_schema_fields_sql($this->entityInfo['revision_table']) as $name) { + foreach (drupal_schema_fields_sql($this->entityInfo->getRevisionTable()) as $name) { if (isset($definitions[$name]) && isset($entity->$name->value)) { $record->$name = $entity->$name->value; } @@ -571,10 +572,10 @@ protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) { // non-translatable properties are replicated for each language. $translation = $entity->getTranslation($langcode, FALSE); $definitions = $translation->getPropertyDefinitions(); - $schema = drupal_get_schema($this->entityInfo['data_table']); + $schema = drupal_get_schema($this->entityInfo->getDataTable()); $record = new \stdClass(); - foreach (drupal_schema_fields_sql($this->entityInfo['data_table']) as $name) { + foreach (drupal_schema_fields_sql($this->entityInfo->getDataTable()) as $name) { $info = $schema['fields'][$name]; $value = isset($definitions[$name]) && isset($translation->$name->value) ? $translation->$name->value : NULL; $record->$name = drupal_schema_get_field_value($info, $value); @@ -607,7 +608,7 @@ public function delete(array $entities) { } $ids = array_keys($entities); - $this->database->delete($this->entityInfo['base_table']) + $this->database->delete($this->entityInfo->getBaseTable()) ->condition($this->idKey, $ids) ->execute(); diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 7ea8b62..e5ccb22 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity; use Drupal\Component\Uuid\Uuid; +use Drupal\Core\Entity\EntityType; use Drupal\Core\Language\Language; use Drupal\Core\TypedData\TypedDataInterface; use IteratorAggregate; @@ -100,7 +101,7 @@ public function isNew() { */ public function isNewRevision() { $info = $this->entityInfo(); - return $this->newRevision || (!empty($info['entity_keys']['revision']) && !$this->getRevisionId()); + return $this->newRevision || ($info->getKey('revision') && !$this->getRevisionId()); } /** @@ -137,11 +138,14 @@ public function bundle() { public function label($langcode = NULL) { $label = NULL; $entity_info = $this->entityInfo(); - if (isset($entity_info['label_callback']) && function_exists($entity_info['label_callback'])) { - $label = $entity_info['label_callback']($this->entityType, $this, $langcode); + $label_callback = $entity_info->getLabelCallback(); + if (function_exists($label_callback)) { + $label = $label_callback($this->entityType, $this, $langcode); } - elseif (!empty($entity_info['entity_keys']['label']) && isset($this->{$entity_info['entity_keys']['label']})) { - $label = $this->{$entity_info['entity_keys']['label']}; + elseif ($label_key = $entity_info->getKey('label')) { + if (isset($this->{$label_key})) { + $label = $this->$label_key; + } } return $label; } @@ -158,8 +162,8 @@ public function uri() { if (isset($bundles[$bundle]['uri_callback'])) { $uri_callback = $bundles[$bundle]['uri_callback']; } - elseif (isset($entity_info['uri_callback'])) { - $uri_callback = $entity_info['uri_callback']; + elseif ($entity_info->getUriCallback()) { + $uri_callback = $entity_info->getUriCallback(); } // Invoke the callback to get the URI. If there is no callback, use the @@ -306,7 +310,7 @@ public function getTranslationLanguages($include_default = TRUE) { $languages = array($default_language->langcode => $default_language); $entity_info = $this->entityInfo(); - if ($entity_info['fieldable']) { + if ($entity_info->isFieldable()) { // Go through translatable properties and determine all languages for // which translated values are available. foreach (field_info_instances($this->entityType, $this->bundle()) as $field_name => $instance) { @@ -349,18 +353,18 @@ public function delete() { public function createDuplicate() { $duplicate = clone $this; $entity_info = $this->entityInfo(); - $duplicate->{$entity_info['entity_keys']['id']} = NULL; + $duplicate->{$entity_info->getKey('id')} = NULL; // Check if the entity type supports UUIDs and generate a new one if so. - if (!empty($entity_info['entity_keys']['uuid'])) { + if ($entity_info->getKey('uuid')) { $uuid = new Uuid(); - $duplicate->{$entity_info['entity_keys']['uuid']} = $uuid->generate(); + $duplicate->{$entity_info->getKey('uuid')} = $uuid->generate(); } return $duplicate; } /** - * Implements \Drupal\Core\Entity\EntityInterface::entityInfo(). + * {@inheritdoc} */ public function entityInfo() { return entity_get_info($this->entityType); diff --git a/core/lib/Drupal/Core/Entity/EntityControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityControllerInterface.php index 79232c1..8fa95c5 100644 --- a/core/lib/Drupal/Core/Entity/EntityControllerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityControllerInterface.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Entity\EntityType; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -38,6 +39,6 @@ * @return static * A new instance of the entity controller. */ - public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info); + public static function createInstance(ContainerInterface $container, $entity_type, EntityType $entity_info); } diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php index 7c5f7ed..2d76f81 100644 --- a/core/lib/Drupal/Core/Entity/EntityFormController.php +++ b/core/lib/Drupal/Core/Entity/EntityFormController.php @@ -147,7 +147,7 @@ public function form(array $form, array &$form_state) { // @todo Exploit the Field API to generate the default widgets for the // entity properties. $info = $entity->entityInfo(); - if (!empty($info['fieldable'])) { + if ($info->isfieldable()) { field_attach_form($entity, $form, $form_state, $this->getFormLangcode($form_state)); } @@ -246,7 +246,7 @@ public function validate(array $form, array &$form_state) { $entity = $this->buildEntity($form, $form_state); $info = $entity->entityInfo(); - if (!empty($info['fieldable'])) { + if ($info->isFieldable()) { field_attach_form_validate($entity, $form, $form_state); } diff --git a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php index 0c9dabd..35db42c 100644 --- a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php +++ b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php @@ -27,7 +27,7 @@ public function form(array $form, array &$form_state) { // @todo Exploit the Field API to generate the default widgets for the // entity fields. $info = $entity->entityInfo(); - if (!empty($info['fieldable'])) { + if ($info->isFieldable()) { field_attach_form($entity, $form, $form_state, $this->getFormLangcode($form_state)); } @@ -50,7 +50,7 @@ public function validate(array $form, array &$form_state) { $entity = $this->buildEntity($form, $form_state); $info = $entity->entityInfo(); - if (!empty($info['fieldable'])) { + if ($info->isFieldable()) { field_attach_form_validate($entity, $form, $form_state); } diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php index 57fe186..ac1f657 100644 --- a/core/lib/Drupal/Core/Entity/EntityInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityInterface.php @@ -166,7 +166,7 @@ public function createDuplicate(); /** * Returns the info of the type of the entity. * - * @see entity_get_info() + * @return \Drupal\Core\Entity\EntityType */ public function entityInfo(); diff --git a/core/lib/Drupal/Core/Entity/EntityListController.php b/core/lib/Drupal/Core/Entity/EntityListController.php index 354b27a..e760516 100644 --- a/core/lib/Drupal/Core/Entity/EntityListController.php +++ b/core/lib/Drupal/Core/Entity/EntityListController.php @@ -29,7 +29,7 @@ class EntityListController implements EntityListControllerInterface { /** * The entity info array. * - * @var array + * @var \Drupal\Core\Entity\Annotation\EntityType * * @see entity_get_info() */ @@ -151,7 +151,7 @@ public function render() { '#theme' => 'table', '#header' => $this->buildHeader(), '#rows' => array(), - '#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo['label'])), + '#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo->getLabel())), ); foreach ($this->load() as $entity) { $build['#rows'][$entity->id()] = $this->buildRow($entity); diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 24e7890..769f3c8 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -7,13 +7,8 @@ namespace Drupal\Core\Entity; -use Drupal\Component\Plugin\PluginManagerBase; -use Drupal\Component\Plugin\Factory\DefaultFactory; +use Drupal\Core\Entity\EntityTypes; use Drupal\Core\Language\Language; -use Drupal\Core\Plugin\Discovery\AlterDecorator; -use Drupal\Core\Plugin\Discovery\CacheDecorator; -use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; -use Drupal\Core\Plugin\Discovery\InfoHookDecorator; use Drupal\Core\Cache\CacheBackendInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -31,7 +26,7 @@ * @see entity_get_info() * @see hook_entity_info_alter() */ -class EntityManager extends PluginManagerBase { +class EntityManager { /** * The injection container that should be passed into the controller factory. @@ -47,6 +42,7 @@ class EntityManager extends PluginManagerBase { */ protected $controllers = array(); + protected $entity_types; /** * Constructs a new Entity plugin manager. * @@ -61,15 +57,48 @@ public function __construct(\Traversable $namespaces, ContainerInterface $contai $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 AlterDecorator($this->discovery, 'entity_info'); - $this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . language(Language::TYPE_INTERFACE)->langcode, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE)); - - $this->factory = new DefaultFactory($this->discovery); + $this->annotation_reader = new \Drupal\Core\AnnotationReader('Core/Entity', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\EntityType'); $this->container = $container; } + public function getDefinitions() { + return $this->entityTypes()->findAll(); + } + + /** + * Returns the entity Type object for a given entity type. + * + * @param string $name + * The name of the entity type. + * + * @return \Drupal\Core\Entity\EntityType + */ + public function getDefinition($name) { + try { + return $this->entityTypes()->findByName($name); + } + catch (\RuntimeException $e) { + return FALSE; + } + } + + public function clearCachedDefinitions() { + } + + protected function entityTypes() { + if (!isset($this->entity_types)) { + $this->entity_types = new EntityTypes; + } + return $this->entity_types; + } + + protected function getAnnotationReader() { + if (!isset($this->annotation_reader)) { + $this->annotation_reader = new \Drupal\Core\AnnotationReader(); + } + return $this->annotation_reader; + } + /** * Checks whether a certain entity type has a certain controller. * @@ -82,8 +111,7 @@ public function __construct(\Traversable $namespaces, ContainerInterface $contai * Returns TRUE if the entity type has the controller, else FALSE. */ public function hasController($entity_type, $controller_type) { - $definition = $this->getDefinition($entity_type); - return !empty($definition['controllers'][$controller_type]); + return $this->getDefinition($entity_type)->hasController($controller_type); } /** @@ -102,7 +130,7 @@ public function hasController($entity_type, $controller_type) { */ public function getControllerClass($entity_type, $controller_type, $nested = NULL) { $definition = $this->getDefinition($entity_type); - $definition = $definition['controllers']; + $definition = $definition->getControllers(); if (empty($definition[$controller_type])) { throw new \InvalidArgumentException(sprintf('The entity (%s) did not specify a %s.', $entity_type, $controller_type)); } @@ -252,13 +280,13 @@ public function getAdminPath($entity_type, $bundle) { $admin_path = ''; $entity_info = $this->getDefinition($entity_type); // Check for an entity type's admin base path. - if (isset($entity_info['route_base_path'])) { + if ($route_base_path = $entity_info->getRouteBasePath()) { // If the entity type has a bundle prefix, strip it out of the path. - if (isset($entity_info['bundle_prefix'])) { - $bundle = str_replace($entity_info['bundle_prefix'], '', $bundle); + if ($bundle_prefix = $entity_info->getBundlePrefix()) { + $bundle = str_replace($bundle_prefix, '', $bundle); } // Replace any dynamic 'bundle' portion of the path with the actual bundle. - $admin_path = str_replace('{bundle}', $bundle, $entity_info['route_base_path']); + $admin_path = str_replace('{bundle}', $bundle, $route_base_path); } return $admin_path; diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php index 2ccbfa8..de51feb 100644 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@ -483,17 +483,17 @@ public function __unset($name) { public function createDuplicate() { $duplicate = clone $this; $entity_info = $this->entityInfo(); - $duplicate->{$entity_info['entity_keys']['id']}->value = NULL; + $duplicate->{$entity_info->getKey('id')}->value = NULL; // Check if the entity type supports UUIDs and generate a new one if so. - if (!empty($entity_info['entity_keys']['uuid'])) { + if ($entity_info->getKey('uuid')) { $uuid = new Uuid(); - $duplicate->{$entity_info['entity_keys']['uuid']}->value = $uuid->generate(); + $duplicate->{$entity_info->getKey('uuid')}->value = $uuid->generate(); } // Check whether the entity type supports revisions and initialize it if so. - if (!empty($entity_info['entity_keys']['revision'])) { - $duplicate->{$entity_info['entity_keys']['revision']}->value = NULL; + if ($entity_info->getKey('revision')) { + $duplicate->{$entity_info->getKey('revision')}->value = NULL; } return $duplicate; @@ -519,11 +519,13 @@ public function __clone() { public function label($langcode = NULL) { $label = NULL; $entity_info = $this->entityInfo(); - if (isset($entity_info['label_callback']) && function_exists($entity_info['label_callback'])) { - $label = $entity_info['label_callback']($this->entityType, $this, $langcode); + if ($label_callback = $entity_info->getLabelCallback() && function_exists($label_callback)) { + $label = $label_callback($this->entityType, $this, $langcode); } - elseif (!empty($entity_info['entity_keys']['label']) && isset($this->{$entity_info['entity_keys']['label']})) { - $label = $this->{$entity_info['entity_keys']['label']}->value; + elseif ($label_key = $entity_info->getKey('label')) { + if (isset($this->{$label_key})) { + $label = $this->{$label_key}->value; + } } return $label; } diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php new file mode 100644 index 0000000..fbdfeac --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -0,0 +1,696 @@ + 'Drupal\Core\Entity\EntityAccessController', + ); + + /** + * 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 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 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 router path for the entity type's field administration page. + * + * If the entity type has a bundle, include {bundle} in the path. + * + * For example, the node entity type specifies + * "admin/structure/types/manage/{bundle}" as its base field admin path. + * + * @var string (optional) + */ + public $route_base_path; + + /** + * The prefix for the bundles of this entity type. + * + * For example, the comment bundle is prefixed with 'comment_node_'. + * + * @var string (optional) + */ + public $bundle_prefix; + + /** + * 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'; + + /** + * @todo + */ + public $config_prefix; + + /** + * Constructs a EntityType object. + * + * Builds up the plugin definition and invokes the get() method for any + * classed annotations that were used. + */ + public function __construct($values) { + foreach ($values as $key => $value) { + $this->{$key} = $value; + } + } + + /** + * Returns the name of the module providing the entity type. + * + * @return string + */ + public function getModule() { + return $this->module; + } + + /** + * Returns the name of the entity type class. + * + * This is not provided manually, it will be added by the discovery mechanism. + * + * @return string + */ + public function getClass() { + return $this->class; + } + + /** + * Sets the name of the entity type class. + * + * @param string $class + * The class + full namespace of the entity type. + * + * @return string + */ + public function setClass($class) { + return $this->class = $class; + } + + /** + * The name of the entity type's base table. + * + * @todo This is only used by \Drupal\Core\Entity\DatabaseStorageController. + * + * @return string + */ + public function getBaseTable() { + return $this->base_table; + } + + /** + * Whether the entity type has a base table + * + * @return bool + * Returns TRUE if the entity type has a base table else FALSE. + */ + public function hasBaseTable() { + return isset($this->base_table); + } + + /** + * The data table of the entity type. + * + * @return string|FALSE + * Returns the data table else FALSE. + */ + public function getDataTable() { + return $this->hasDataTable() ? $this->data_table : FALSE; + } + + /** + * Whether the entity type has a data table. + * + * @return bool + * Returns TRUE if the entity type has a data table else FALSE. + */ + public function hasDataTable() { + return isset($this->data_table); + } + + /** + * Whether the entity type has a revision table. + * + * @return bool + * Returns TRUE if the entity type has a revision table else FALSE. + */ + public function hasRevisionTable() { + return isset($this->revision_table); + } + + /** + * The revision table of the entity type. + * + * @return string|FALSE + * Returns the revision table else FALSE. + */ + public function getRevisionTable() { + return $this->hasRevisionTable() ? $this->revision_table : FALSE; + } + + /** + * 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\EntityRenderControllerInterface. + * - 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\translation_entity\EntityTranslationControllerInterface. + * + * @todo Interfaces from outside \Drupal\Core or \Drupal\Component should not + * be used here. + * + * @var array + */ + public function getControllers() { + return $this->controllers + array( + 'access' => 'Drupal\Core\Entity\EntityAccessController', + ); + } + + public function getController($controller) { + $controllers = $this->getControllers(); + return $controllers[$controller]; + } + + public function setController($controller, $value) { + return $this->controllers[$controller] = $value; + } + + public function hasController($controller) { + $controllers = $this->getControllers(); + return isset($controllers[$controller]); + } + + /** + * Boolean indicating whether fields can be attached to entities of this type. + * + * @return bool (optional) + * Returns TRUE if the entity type can has fields, otherwise FALSE. + */ + public function isFieldable() { + return isset($this->fieldable) ? $this->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. + * + * @return bool (optional) + * Returns TRUE if fields on this entity type can be cached, otherwise FALSE. + */ + public function fieldsCacheable() { + return isset($this->field_cache) ? $this->field_cache : TRUE; + } + + /** + * The human-readable name of the type. + * + * @ingroup plugin_translatable + * + * @var \Drupal\Core\Annotation\Translation + */ + public function getLabel() { + return $this->label->get(); + } + + /** + * The human-readable name of the entity bundles, e.g. Vocabulary. + * + * @ingroup plugin_translatable + * + * @var \Drupal\Core\Annotation\Translation + */ + public function getBundleLable() { + return $this->bundle_label->get(); + } + + /** + * 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. + * + * @return callable + * A callback for the label. + */ + public function getLabelCallback() { + return isset($this->label_callback) ? $this->label_callback : ''; + } + + public function getUriCallback() { + return $this->uri_callback; + } + + public function setUriCallback($callback) { + return $this->uri_callback = $callback; + } + + /** + * Boolean indicating whether entities should be statically cached during a page request. + * + * @todo This is only used by \Drupal\Core\Entity\DatabaseStorageController. + * + * @return bool (optional) + * Returns TRUE if the entity type should be statically cached, otherwise FALSE. + */ + public function staticCacheable() { + return isset($this->static_cache) ? $this->static_cache : TRUE; + } + + /** + * 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 function getKeys() { + return $this->entity_keys + array('revision' => '', 'bundle' => ''); + } + + public function getKey($key) { + $keys = $this->getKeys(); + return isset($keys[$key]) ? $keys[$key] : FALSE ; + } + + /** + * Get all bundle keys defined on the annotation. + * + * @return array + * 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. + */ + public function getBundleKeys() { + return isset($this->bundle_keys) ? $this->bundle_keys : array(); + } + + /** + * Returns a single bundle key. + * + * @param string $name + * The name of the bundle key. + * + * @return string + * The value of the bundle key. + */ + public function getBundleKey($name) { + return isset($this->bundle_keys[$name]) ? $this->bundle_keys[$name] : ''; + } + + public function getConfigPrefix() { + return isset($this->config_prefix) ? $this->config_prefix : ''; + return $this->config_prefix; + } + + /** + * Get the base router path for the entity type's field administration page. + * + * @return string + * The router base path. + * + * @see \Drupal\Core\Entity\Annotation\EntityType::$route_base_path + */ + public function getRouteBasePath() { + return isset($this->route_base_path) ? $this->route_base_path : NULL; + } + + /** + * Get the prefix for the bundles of this entity type. + * + * @return string + * The prefix. + * + * @see \Drupal\Core\Entity\Annotation\EntityType::$bundle_prefix + */ + public function getBundlePrefix() { + return isset($this->bundle_prefix) ? $this->bundle_prefix : ''; + } + + /** + * Get the base menu router path for entity admin user interface paths. + * + * @return string + * The base menu router path. + * + * @see \Drupal\Core\Entity\Annotation\EntityType::$menu_base_path + */ + public function getMenuBasePath() { + return isset($this->menu_base_path) ? $this->menu_base_path : ''; + } + + /** + * Get the menu router path to be used to view the entity. + * + * @return string + * A menu router path. + * + * @see \Drupal\Core\Entity\Annotation\EntityType::$menu_view_path + */ + public function getMenuViewPath() { + return isset($this->menu_view_path) ? $this->menu_view_path : ''; + } + + /** + * Get the menu router path to be uesd to edit the entity. + * + * @return string + * A menu router path. + * + * @see \Drupal\Core\Entity\Annotation\EntityType::$menu_edit_path + */ + public function getMenuEditPath() { + return isset($this->menu_edit_path) ? $this->menu_edit_path : ''; + } + + /** + * Get the identifier in the router path. + * + * @return string + * A identifier. + * + * @see \Drupal\Core\Entity\Annotation\EntityType::$menu_path_wildcard + */ + public function getMenuPathWildcard() { + return isset($this->menu_path_wildcard) ? $this->menu_path_wildcard : ''; + } + + /** + * Returns the granularity of the permissions. + * + * @return string|FALSE + * Returns either "entity_type", "bundle" or FALSE. + * + * @see \Drupal\Core\Entity\Annotation\EntityType::$permission_granularity + */ + public function getPermissionGranularity() { + return $this->permission_granularity; + } + + /** + * Returns whether the entity type is translatable. + * + * @return bool + * Returns TRUE if the entity type is translatable, otherwise FALSE. + * + * @see \Drupal\Core\Entity\Annotation\\Drupal\Core\Entity\Annotation\EntityType::$translatable + */ + public function isTranslatable() { + return isset($this->translatable) ? (bool) $this->translatable : FALSE; + } + + /** + * @todo + * + * @see \Drupal\Core\Entity\Annotation\\Drupal\Core\Entity\Annotation\EntityType::$translation + */ + public function getTranslation() { + return isset($this->translation) ? $this->translation : array(); + } + + /** + * Returns an arbitrary value of the entity type definition. + * + * @param string $name + * The name of the entity type definition. + * + * @return mixed + * The value of the entity type definition. + */ + public function get($name) { + return isset($this->values[$name]) ? $this->values[$name] : NULL; + } + +} diff --git a/core/lib/Drupal/Core/Entity/EntityTypes.php b/core/lib/Drupal/Core/Entity/EntityTypes.php new file mode 100644 index 0000000..3caf1c7 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityTypes.php @@ -0,0 +1,108 @@ +preloaded) { + $class_mappings = $this->loadMappingsFromFiles(); + foreach ($class_mappings as $name => $class) { + $this->types[$name] = $this->factory($class); + } + $this->invokeHooks(); + $this->preloaded = TRUE; + } + return $this->types; + } + + public function findByName($name) { + if (isset($this->types[$name])) { + return $this->types[$name]; + } + + if ($class = $this->getClassFromEntityName($name)) { + $this->types[$name] = $this->factory($class); + $this->invokeHooks(); + return $this->types[$name]; + } + else { + throw new \RuntimeException(sprintf("No such entity type %s!", $name)); + } + } + + protected function factory($class) { + $values = $this->getAnnotation($class) + array('class' => $class); + return new EntityType($values); + } + + protected function invokeHooks() { + $this->moduleHandler()->invokeAll('entity_info', array($this->types)); + $this->moduleHandler()->alter('entity_info', $this->types); + } + + protected function getClassFromEntityName($name) { + $class_mappings = $this->loadMappingsFromFiles(); + return isset($class_mappings[$name]) ? $class_mappings[$name] : FALSE; + } + + protected function loadMappingsFromFiles() { + if (empty($this->class_mapping)) { + $all = $this->fileFinder()->findAll(); + $this->class_mapping = call_user_func_array("array_merge", $all); + } + return $this->class_mapping; + } + + protected function name() { + return 'entity'; + } + + protected function getAnnotation($classname) { + $entity_type_annotation = $this->getAnnotationReader() + ->getClassAnnotation($classname, 'Drupal\Core\Entity\Annotation\EntityType'); + return $entity_type_annotation->get(); + } + + protected function fileFinder() { + if (!isset($this->file_finder)) { + $this->file_finder = new YamlDiscovery($this->name(), $this->directories()); + } + return $this->file_finder; + } + + protected function directories() { + return $this->moduleHandler()->getModuleDirectories(); + } + + protected function moduleHandler() { + return \Drupal::moduleHandler(); + } + + protected function getAnnotationReader() { + if (!isset($this->annotation_reader)) { + $this->annotation_reader = new \Drupal\Core\AnnotationReader(); + } + return $this->annotation_reader; + } + +} diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php index 3a5ffbe..75ca27e 100644 --- a/core/lib/Drupal/Core/Extension/ModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php @@ -890,4 +890,11 @@ public function uninstall($module_list = array(), $uninstall_dependents = TRUE) return TRUE; } + public function getModuleDirectories() { + $dirs = array(); + foreach ($this->getModuleList() as $module => $filename) { + $dirs[$module] = dirname($filename); + } + return $dirs; + } } diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php index f28906f..f252337 100644 --- a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php +++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php @@ -71,8 +71,6 @@ public function process(array &$variables, Route $route, array &$converted) { $options = $route->getOptions(); $configuredTypes = isset($options['converters']) ? $options['converters'] : array(); - $entityTypes = array_keys($this->entityManager->getDefinitions()); - foreach ($variable_names as $name) { // Do not process this variable if it's already marked as converted. if (in_array($name, $converted)) { @@ -88,7 +86,7 @@ public function process(array &$variables, Route $route, array &$converted) { $type = $name; } - if (in_array($type, $entityTypes)) { + if ($this->entityManager->getDefinition($type)) { $value = $variables[$name]; $storageController = $this->entityManager->getStorageController($type); diff --git a/core/modules/aggregator/aggregator.entity.yml b/core/modules/aggregator/aggregator.entity.yml new file mode 100644 index 0000000..619c7f7 --- /dev/null +++ b/core/modules/aggregator/aggregator.entity.yml @@ -0,0 +1,2 @@ +aggregator_feed: Drupal\aggregator\Plugin\Core\Entity\Feed +aggregator_item: Drupal\aggregator\Plugin\Core\Entity\Item diff --git a/core/modules/block/block.entity.yml b/core/modules/block/block.entity.yml new file mode 100644 index 0000000..a574c3f --- /dev/null +++ b/core/modules/block/block.entity.yml @@ -0,0 +1 @@ +block: Drupal\block\Plugin\Core\Entity\Block diff --git a/core/modules/block/custom_block/custom_block.entity.yml b/core/modules/block/custom_block/custom_block.entity.yml new file mode 100644 index 0000000..7b28d3f --- /dev/null +++ b/core/modules/block/custom_block/custom_block.entity.yml @@ -0,0 +1,3 @@ +custom_block: Drupal\custom_block\Plugin\Core\Entity\CustomBlock +custom_block_type: Drupal\custom_block\Plugin\Core\Entity\CustomBlockType + diff --git a/core/modules/breakpoint/breakpoint.entity.yml b/core/modules/breakpoint/breakpoint.entity.yml new file mode 100644 index 0000000..278b03f --- /dev/null +++ b/core/modules/breakpoint/breakpoint.entity.yml @@ -0,0 +1,2 @@ +breakpoint: Drupal\breakpoint\Plugin\Core\Entity\Breakpoint +breakpoint_group: Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup diff --git a/core/modules/breakpoint/breakpoint.module b/core/modules/breakpoint/breakpoint.module index b467011..f4ecdf6 100644 --- a/core/modules/breakpoint/breakpoint.module +++ b/core/modules/breakpoint/breakpoint.module @@ -192,7 +192,7 @@ function _breakpoint_delete_breakpoints($list, $source_type) { // Remove the breakpoint.breakpoint part of the breakpoint identifier. foreach ($ids as &$id) { - $id = ConfigStorageController::getIDFromConfigName($id, $entity_info['config_prefix']); + $id = ConfigStorageController::getIDFromConfigName($id, $entity_info->getConfigPrefix()); } $breakpoint_groups = entity_load_multiple('breakpoint_group', $ids); @@ -207,7 +207,7 @@ function _breakpoint_delete_breakpoints($list, $source_type) { // Remove the breakpoint.breakpoint part of the breakpoint identifier. foreach ($breakpoint_ids as &$breakpoint_id) { - $breakpoint_id = ConfigStorageController::getIDFromConfigName($breakpoint_id, $entity_info['config_prefix']); + $breakpoint_id = ConfigStorageController::getIDFromConfigName($breakpoint_id, $entity_info->getConfigPrefix()); } $breakpoints = entity_load_multiple('breakpoint', $breakpoint_ids); diff --git a/core/modules/comment/comment.entity.yml b/core/modules/comment/comment.entity.yml new file mode 100644 index 0000000..014f640 --- /dev/null +++ b/core/modules/comment/comment.entity.yml @@ -0,0 +1 @@ +comment: Drupal\comment\Plugin\Core\Entity\Comment diff --git a/core/modules/contact/contact.entity.yml b/core/modules/contact/contact.entity.yml new file mode 100644 index 0000000..2e5325f --- /dev/null +++ b/core/modules/contact/contact.entity.yml @@ -0,0 +1,2 @@ +contact_category: Drupal\contact\Plugin\Core\Entity\Category +contact_message: Drupal\contact\Plugin\Core\Entity\Message diff --git a/core/modules/editor/editor.entity.yml b/core/modules/editor/editor.entity.yml new file mode 100644 index 0000000..371e17e --- /dev/null +++ b/core/modules/editor/editor.entity.yml @@ -0,0 +1 @@ +editor: Drupal\editor\Plugin\Core\Entity\Editor diff --git a/core/modules/entity/entity.entity.yml b/core/modules/entity/entity.entity.yml new file mode 100644 index 0000000..beec211 --- /dev/null +++ b/core/modules/entity/entity.entity.yml @@ -0,0 +1,3 @@ +entity_form_display: Drupal\entity\Plugin\Core\Entity\EntityFormDisplay +entity_display: Drupal\entity\Plugin\Core\Entity\EntityDisplay +view_mode: Drupal\entity\Plugin\Core\Entity\EntityViewMode diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module index 7a9c8a8..d5b4465 100644 --- a/core/modules/entity/entity.module +++ b/core/modules/entity/entity.module @@ -19,7 +19,7 @@ function entity_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) { if ($bundle_old !== $bundle_new) { $ids = config_get_storage_names_with_prefix('entity.display.' . $entity_type . '.' . $bundle_old); foreach ($ids as $id) { - $id = ConfigStorageController::getIDFromConfigName($id, $entity_info['config_prefix']); + $id = ConfigStorageController::getIDFromConfigName($id, $entity_info->getConfigPrefix()); $display = entity_load('entity_display', $id); $new_id = $entity_type . '.' . $bundle_new . '.' . $display->mode; $display->id = $new_id; @@ -33,7 +33,7 @@ function entity_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) { if ($bundle_old !== $bundle_new) { $ids = config_get_storage_names_with_prefix('entity.form_display.' . $entity_type . '.' . $bundle_old); foreach ($ids as $id) { - $id = ConfigStorageController::getIDFromConfigName($id, $entity_info['config_prefix']); + $id = ConfigStorageController::getIDFromConfigName($id, $entity_info->getConfigPrefix()); $form_display = entity_load('entity_form_display', $id); $new_id = $entity_type . '.' . $bundle_new . '.' . $form_display->mode; $form_display->id = $new_id; @@ -52,14 +52,14 @@ function entity_entity_bundle_delete($entity_type, $bundle) { // Remove entity displays of the deleted bundle. $ids = config_get_storage_names_with_prefix('entity.display.' . $entity_type . '.' . $bundle); foreach ($ids as &$id) { - $id = ConfigStorageController::getIDFromConfigName($id, $entity_info['config_prefix']); + $id = ConfigStorageController::getIDFromConfigName($id, $entity_info->getConfigPrefix()); } entity_delete_multiple('entity_display', $ids); // Remove entity form displays of the deleted bundle. $ids = config_get_storage_names_with_prefix('entity.form_display.' . $entity_type . '.' . $bundle); foreach ($ids as &$id) { - $id = ConfigStorageController::getIDFromConfigName($id, $entity_info['config_prefix']); + $id = ConfigStorageController::getIDFromConfigName($id, $entity_info->getConfigPrefix()); } entity_delete_multiple('entity_form_display', $ids); } diff --git a/core/modules/entity_reference/entity_reference.install b/core/modules/entity_reference/entity_reference.install index c40d3ea..954098b 100644 --- a/core/modules/entity_reference/entity_reference.install +++ b/core/modules/entity_reference/entity_reference.install @@ -31,12 +31,12 @@ function entity_reference_field_schema($field) { ); // Create a foreign key to the target entity type base type. - $entity_manager = Drupal::service('plugin.manager.entity'); + $entity_manager = Drupal::entityManager(); if (is_subclass_of($entity_manager->getControllerClass($field['settings']['target_type'], 'storage'), 'Drupal\Core\Entity\DatabaseStorageController')) { $entity_info = $entity_manager->getDefinition($field['settings']['target_type']); - $base_table = $entity_info['base_table']; - $id_column = $entity_info['entity_keys']['id']; + $base_table = $entity_info->getBaseTable(); + $id_column = $entity_info->getKey('id'); $schema['foreign keys'][$base_table] = array( 'table' => $base_table, diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module index 3c68c46..05c424d 100644 --- a/core/modules/entity_reference/entity_reference.module +++ b/core/modules/entity_reference/entity_reference.module @@ -121,8 +121,8 @@ function entity_reference_field_presave(EntityInterface $entity, $field, $instan foreach ($items as $delta => $item) { if ($item['target_id'] == 'auto_create') { - $bundle_key = $entity_info['entity_keys']['bundle']; - $label_key = $entity_info['entity_keys']['label']; + $bundle_key = $entity_info->getKey('bundle'); + $label_key = $entity_info->getKey('label'); $values = array( $label_key => $item['label'], $bundle_key => $bundle, @@ -173,8 +173,8 @@ function entity_reference_field_settings_form($field, $instance, $has_data) { // @todo As the database schema can currently only store numeric IDs of // referenced entities and configuration entities have string IDs, prevent // configuration entities from being referenced. - if (!in_array('\Drupal\Core\Config\Entity\ConfigEntityInterface', class_implements($entity_info['class']))) { - $entity_type_options[$entity_type] = $entity_info['label']; + if (!in_array('\Drupal\Core\Config\Entity\ConfigEntityInterface', class_implements($entity_info->getClass()))) { + $entity_type_options[$entity_type] = $entity_info->getLabel(); } } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php index ab60905..5ccc268 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php @@ -78,7 +78,7 @@ public static function settingsForm(&$field, &$instance) { 'auto_create' => FALSE, ); - if (!empty($entity_info['entity_keys']['bundle'])) { + if ($entity_info->getKey('bundle')) { $bundle_options = array(); foreach ($bundles as $bundle_name => $bundle_info) { $bundle_options[$bundle_name] = $bundle_info['label']; @@ -113,7 +113,7 @@ public static function settingsForm(&$field, &$instance) { // @todo Use Entity::getPropertyDefinitions() when all entity types are // converted to the new Field API. - $fields = drupal_map_assoc(drupal_schema_fields_sql($entity_info['base_table'])); + $fields = drupal_map_assoc(drupal_schema_fields_sql($entity_info->getBaseTable())); foreach (field_info_instances($field['settings']['target_type']) as $bundle_instances) { foreach ($bundle_instances as $instance_name => $instance_info) { $field_info = field_info_field($instance_name); @@ -208,7 +208,7 @@ public function validateReferencableEntities(array $ids) { $entity_info = entity_get_info($target_type); $query = $this->buildEntityQuery(); $result = $query - ->condition($entity_info['entity_keys']['id'], $ids, 'IN') + ->condition($entity_info->getKey('id'), $ids, 'IN') ->execute(); } @@ -269,11 +269,11 @@ public function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') { $query = \Drupal::entityQuery($target_type); if (!empty($this->instance['settings']['handler_settings']['target_bundles'])) { - $query->condition($entity_info['entity_keys']['bundle'], $this->instance['settings']['handler_settings']['target_bundles'], 'IN'); + $query->condition($entity_info->getKey('bundle'), $this->instance['settings']['handler_settings']['target_bundles'], 'IN'); } - if (isset($match) && isset($entity_info['entity_keys']['label'])) { - $query->condition($entity_info['entity_keys']['label'], $match, $match_operator); + if (isset($match) && $entity_info->getKey('label')) { + $query->condition($entity_info->getKey('label'), $match, $match_operator); } // Add entity-access tag. diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc index baa7ff4..44f5994 100644 --- a/core/modules/field/field.attach.inc +++ b/core/modules/field/field.attach.inc @@ -893,7 +893,7 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $ $info = entity_get_info($entity_type); // Only the most current revision of non-deleted fields for cacheable entity // types can be cached. - $cache_read = $load_current && $info['field_cache'] && empty($options['deleted']); + $cache_read = $load_current && $info->fieldsCacheable() && empty($options['deleted']); // In addition, do not write to the cache when loading a single field. $cache_write = $cache_read && !isset($options['field_id']); @@ -1269,7 +1269,7 @@ function field_attach_update(EntityInterface $entity) { module_invoke_all('field_attach_update', $entity); $entity_info = $entity->entityInfo(); - if ($entity_info['field_cache']) { + if ($entity_info->fieldsCacheable()) { cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id()); } } @@ -1305,7 +1305,7 @@ function field_attach_delete(EntityInterface $entity) { module_invoke_all('field_attach_delete', $entity); $entity_info = $entity->entityInfo(); - if ($entity_info['field_cache']) { + if ($entity_info->fieldsCachable()) { cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id()); } } diff --git a/core/modules/field/field.entity.yml b/core/modules/field/field.entity.yml new file mode 100644 index 0000000..fb86419 --- /dev/null +++ b/core/modules/field/field.entity.yml @@ -0,0 +1,2 @@ +field_entity: Drupal\field\Plugin\Core\Entity\Field +field_instance: Drupal\field\Plugin\Core\Entity\FieldInstance diff --git a/core/modules/field/field.module b/core/modules/field/field.module index a720c4d..ec3098a 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -252,7 +252,7 @@ function field_data_type_info() { */ function field_entity_create(EntityInterface $entity) { $info = $entity->entityInfo(); - if (!empty($info['fieldable'])) { + if ($info->isFieldable()) { foreach ($entity->getTranslationLanguages() as $langcode => $language) { field_populate_default_values($entity, $langcode); } @@ -895,7 +895,7 @@ function field_has_data($field) { foreach ($field['bundles'] as $entity_type => $bundle) { // Entity Query throws an exception if there is no base table. $entity_info = entity_get_info($entity_type); - if (!isset($entity_info['base_table'])) { + if (!$entity_info->getBaseTable()) { continue; } $query = $factory->get($entity_type); @@ -972,8 +972,8 @@ function field_extract_bundle($entity_type, $bundle) { } $info = entity_get_info($entity_type); - if (is_object($bundle) && isset($info['bundle_keys']['bundle']) && isset($bundle->{$info['bundle_keys']['bundle']})) { - return $bundle->{$info['bundle_keys']['bundle']}; + if (is_object($bundle) && $info->getBundleKey('bundle') && isset($bundle->{$info->getBundleKey('bundle')})) { + return $bundle->{$info->getBundleKey('bundle')}; } } diff --git a/core/modules/field/field.multilingual.inc b/core/modules/field/field.multilingual.inc index 6f6e2d6..6f10d83 100644 --- a/core/modules/field/field.multilingual.inc +++ b/core/modules/field/field.multilingual.inc @@ -197,7 +197,7 @@ function field_is_translatable($entity_type, $field) { */ function field_has_translation_handler($entity_type, $handler = NULL) { $info = entity_get_info($entity_type); - return !empty($info['translatable']); + return $info->translatable; } /** diff --git a/core/modules/field/field.views.inc b/core/modules/field/field.views.inc index b01e882..042771e 100644 --- a/core/modules/field/field.views.inc +++ b/core/modules/field/field.views.inc @@ -115,7 +115,7 @@ function field_views_field_default_views_data($field) { // Build the relationships between the field table and the entity tables. foreach ($field['bundles'] as $entity => $bundles) { $entity_info = entity_get_info($entity); - $groups[$entity] = $entity_info['label']; + $groups[$entity] = $entity_info->getLabel(); // Override Node to Content. if ($groups[$entity] == t('Node')) { @@ -127,18 +127,22 @@ function field_views_field_default_views_data($field) { $group_name = $groups[$entity]; } - if (!isset($entity_info['base_table'])) { + if (!$entity_info->hasBaseTable()) { continue; } - $entity_tables[$entity_info['base_table']] = $entity; - $current_tables[$entity] = $entity_info['base_table']; - if (isset($entity_info['revision_table'])) { - $entity_tables[$entity_info['revision_table']] = $entity; - $revision_tables[$entity] = $entity_info['revision_table']; + $base_table = $entity_info->getBaseTable(); + $entity_tables[$base_table] = $entity; + $current_tables[$entity] = $base_table; + + // TODO: Working around a bug, this should be the opposite check + if (!$entity_info->hasRevisionTable()) { + $revision_table = $entity_info->getRevisionTable(); + $entity_tables[$revision_table] = $entity; + $revision_tables[$entity] = $revision_table; } - $data[$current_table]['table']['join'][$entity_info['base_table']] = array( - 'left_field' => $entity_info['entity_keys']['id'], + $data[$current_table]['table']['join'][$base_table] = array( + 'left_field' => $entity_info->getKey('id'), 'field' => 'entity_id', 'extra' => array( array('field' => 'entity_type', 'value' => $entity), @@ -146,9 +150,9 @@ function field_views_field_default_views_data($field) { ), ); - if (!empty($entity_info['entity_keys']['revision']) && !empty($entity_info['revision_table'])) { - $data[$revision_table]['table']['join'][$entity_info['revision_table']] = array( - 'left_field' => $entity_info['entity_keys']['revision'], + if ($revision_key = $entity_info->getKey('revision') && !empty($revision_table)) { + $data[$revision_table]['table']['join'][$revision_table] = array( + 'left_field' => $revision_key, 'field' => 'revision_id', 'extra' => array( array('field' => 'entity_type', 'value' => $entity), diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php index e7e9bd5..ce3e828 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php @@ -296,7 +296,7 @@ public function save() { // collisions with existing entity properties, but some is better than // none. foreach (\Drupal::entityManager()->getDefinitions() as $type => $info) { - if (in_array($this->id, $info['entity_keys'])) { + if (in_array($this->id, $info->getKeys())) { throw new FieldException(format_string('Attempt to create field %id which is reserved by entity type %type.', array('%id' => $this->id, '%type' => $type))); } } diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php index 4aa9613..f4eb45c 100644 --- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php @@ -218,7 +218,7 @@ function testTranslatableFieldSaveLoad() { // Enable field translations for nodes. field_test_entity_info_translatable('node', TRUE); $entity_info = entity_get_info('node'); - $this->assertTrue(count($entity_info['translatable']), 'Nodes are translatable.'); + $this->assertTrue(count($entity_info->fieldsCacheable()), 'Nodes are translatable.'); // Prepare the field translations. field_test_entity_info_translatable('test_entity', TRUE); diff --git a/core/modules/field/tests/modules/field_test/field_test.entity.inc b/core/modules/field/tests/modules/field_test/field_test.entity.inc index 817986f..1e7df4e 100644 --- a/core/modules/field/tests/modules/field_test/field_test.entity.inc +++ b/core/modules/field/tests/modules/field_test/field_test.entity.inc @@ -34,7 +34,7 @@ function field_test_entity_info_alter(&$entity_info) { function field_test_entity_view_mode_info_alter(&$view_modes) { $entity_info = entity_get_info(); foreach ($entity_info as $entity_type => $info) { - if ($entity_info[$entity_type]['module'] == 'field_test') { + if ($entity_info[$entity_type]->getModule() == 'field_test') { $view_modes[$entity_type] = array( 'full' => array( 'label' => t('Full object'), @@ -55,7 +55,7 @@ function field_test_entity_view_mode_info_alter(&$view_modes) { function field_test_entity_bundle_info_alter(&$bundles) { $entity_info = entity_get_info(); foreach ($bundles as $entity_type => $info) { - if ($entity_info[$entity_type]['module'] == 'field_test') { + if ($entity_info[$entity_type]->getModule() == 'field_test') { $bundles[$entity_type] = state()->get('field_test_bundles') ?: array('test_bundle' => array('label' => 'Test Bundle')); if ($entity_type == 'test_entity_bundle') { $bundles[$entity_type] += array('test_entity_2' => array('label' => 'Test entity 2')); diff --git a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Query.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Query.php index 930d367..994c5d6 100644 --- a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Query.php +++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Query.php @@ -21,7 +21,7 @@ class Query extends QueryBase implements QueryInterface { /** * Contains the entity info for the entity type of that query. * - * @var array + * @var \Drupal\Core\Entity\Annotation\EntityType * * @see \Drupal\Core\Entity\EntityManager */ @@ -117,19 +117,19 @@ public function execute() { protected function prepare() { $entity_type = $this->entityType; $this->entityInfo = $this->entityManager->getDefinition($entity_type); - if (!isset($this->entityInfo['base_table'])) { + if (!($base_table = $this->entityInfo->getBaseTable())) { throw new QueryException("No base table, invalid query."); } - $base_table = $this->entityInfo['base_table']; + $base_table = $base_table; $simple_query = TRUE; - if (isset($this->entityInfo['data_table'])) { + if ($this->entityInfo->getDataTable()) { $simple_query = FALSE; } $this->sqlQuery = $this->connection->select($base_table, 'base_table', array('conjunction' => $this->conjunction)); $this->sqlQuery->addMetaData('entity_type', $entity_type); - $id_field = $this->entityInfo['entity_keys']['id']; + $id_field = $this->entityInfo->getKey('id'); // Add the key field for fetchAllKeyed(). - if (empty($this->entityInfo['entity_keys']['revision'])) { + if (!($this->entityInfo->getKey('revision'))) { // When there is no revision support, the key field is the entity key. $this->sqlFields["base_table.$id_field"] = array('base_table', $id_field); // Now add the value column for fetchAllKeyed(). This is always the @@ -138,7 +138,7 @@ protected function prepare() { } else { // When there is revision support, the key field is the revision key. - $revision_field = $this->entityInfo['entity_keys']['revision']; + $revision_field = $this->entityInfo->getKey('revision'); $this->sqlFields["base_table.$revision_field"] = array('base_table', $revision_field); // Now add the value column for fetchAllKeyed(). This is always the // entity id. diff --git a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php index a387cf4..2c04daf 100644 --- a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php +++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php @@ -84,16 +84,16 @@ function addField($field, $type, $langcode) { for ($key = 0; $key <= $count; $key ++) { // If there is revision support and only the current revision is being // queried then use the revision id. Otherwise, the entity id will do. - if (!empty($entity_info['entity_keys']['revision']) && $age == FIELD_LOAD_CURRENT) { + if ($revision_key = $entity_info->getKey('revision') && $age == FIELD_LOAD_CURRENT) { // This contains the relevant SQL field to be used when joining entity // tables. - $entity_id_field = $entity_info['entity_keys']['revision']; + $entity_id_field = $revision_key; // This contains the relevant SQL field to be used when joining field // tables. $field_id_field = 'revision_id'; } else { - $entity_id_field = $entity_info['entity_keys']['id']; + $entity_id_field = $entity_info->getKey('id'); $field_id_field = 'entity_id'; } // This can either be the name of an entity property (non-configurable @@ -165,11 +165,12 @@ function addField($field, $type, $langcode) { // finds the property first. The data table is prefered, which is why // it gets added before the base table. $entity_tables = array(); - if (isset($entity_info['data_table'])) { + if ($data_table = $entity_info->getDataTable()) { $this->sqlQuery->addMetaData('simple_query', FALSE); - $entity_tables[$entity_info['data_table']] = drupal_get_schema($entity_info['data_table']); + $entity_tables[$entity_info->getDataTable()] = drupal_get_schema($data_table); } - $entity_tables[$entity_info['base_table']] = drupal_get_schema($entity_info['base_table']); + $entity_base_table = $entity_info->getBaseTable(); + $entity_tables[$entity_base_table] = drupal_get_schema($entity_base_table); $sql_column = $specifier; $table = $this->ensureEntityTable($index_prefix, $specifier, $type, $langcode, $base_table, $entity_id_field, $entity_tables); } @@ -183,8 +184,8 @@ function addField($field, $type, $langcode) { $values = array(); // If there are bundles, pick one. It does not matter which, // properties exist on all bundles. - if (!empty($entity_info['entity keys']['bundle'])) { - $values[$entity_info['entity keys']['bundle']] = key(entity_get_bundles('node')); + if ($bundle_key = $entity_info->getKey('bundle')) { + $values[$bundle_key] = key(entity_get_bundles('node')); } $entity = entity_create($entity_type, $values); $propertyDefinitions = $entity->$specifier->getPropertyDefinitions(); @@ -197,8 +198,8 @@ function addField($field, $type, $langcode) { $entity_type = $propertyDefinitions[$relationship_specifier]['constraints']['EntityType']; $entity_info = entity_get_info($entity_type); // Add the new entity base table using the table and sql column. - $join_condition= '%alias.' . $entity_info['entity_keys']['id'] . " = $table.$sql_column"; - $base_table = $this->sqlQuery->leftJoin($entity_info['base_table'], NULL, $join_condition); + $join_condition= '%alias.' . $entity_info->getKey('id') . " = $table.$sql_column"; + $base_table = $this->sqlQuery->leftJoin($entity_info->getBaseTable(), NULL, $join_condition); $propertyDefinitions = array(); $key++; $index_prefix .= "$next_index_prefix."; diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index cce8734..ebb045f 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -68,9 +68,9 @@ function field_ui_menu() { // Create tabs for all possible bundles. foreach (entity_get_info() as $entity_type => $entity_info) { - if ($entity_info['fieldable'] && isset($entity_info['route_base_path'])) { + // @fixme How to replace this. + if ($entity_info->fieldsCacheable() && $path = $entity_info->getRouteBasePath()) { // Extract path information from the entity type. - $path = $entity_info['route_base_path']; $default_path = preg_replace('/{' . DRUPAL_PHP_FUNCTION_PATTERN . '}/', '%', $path); // This is the position of the %field_ui_instance placeholder in the // items below. @@ -148,15 +148,15 @@ function field_ui_permission() { $permissions = array(); foreach (entity_get_info() as $entity_type => $entity_info) { - if ($entity_info['fieldable']) { + if ($entity_info->fieldsCacheable()) { // Create a permission for each fieldable entity to manage // the fields and the display. $permissions['administer ' . $entity_type . ' fields'] = array( - 'title' => t('%entity_label: Administer fields', array('%entity_label' => $entity_info['label'])), + 'title' => t('%entity_label: Administer fields', array('%entity_label' => $entity_info->getLabel())), 'restrict access' => TRUE, ); $permissions['administer ' . $entity_type . ' display'] = array( - 'title' => t('%entity_label: Administer display', array('%entity_label' => $entity_info['label'])) + 'title' => t('%entity_label: Administer display', array('%entity_label' => $entity_info->getLabel())), ); } } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php index 20f6c09..fe3ade2 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php @@ -76,8 +76,9 @@ public static function create(ContainerInterface $container) { */ public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) { $entity_info = $this->entityManager->getDefinition($entity_type); - if (!empty($entity_info['bundle_prefix'])) { - $bundle = $entity_info['bundle_prefix'] . $bundle; + // @fixme How to replace this. + if ($prefix = $entity_info->getBundlePrefix()) { + $bundle = $prefix . $bundle; } form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin'); diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php index 934a56e..2a80bf5 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php @@ -50,9 +50,8 @@ public function routes(RouteBuildEvent $event) { $collection = $event->getRouteCollection(); foreach ($this->manager->getDefinitions() as $entity_type => $entity_info) { $defaults = array(); - if ($entity_info['fieldable'] && isset($entity_info['route_base_path'])) { - $path = $entity_info['route_base_path']; - + // @fixme How to replace this. + if ($entity_info->fieldsCacheable() && $path = $entity_info->getRouteBasePath()) { $route = new Route( "$path/fields/{field_instance}", array('_form' => '\Drupal\field_ui\Form\FieldInstanceEditForm'), @@ -83,7 +82,7 @@ public function routes(RouteBuildEvent $event) { // If the entity type has no bundles, use the entity type. $defaults['entity_type'] = $entity_type; - if (empty($entity_info['entity_keys']['bundle'])) { + if (!$entity_info->getKey('bundle')) { $defaults['bundle'] = $entity_type; } $route = new Route( diff --git a/core/modules/file/file.entity.yml b/core/modules/file/file.entity.yml new file mode 100644 index 0000000..c5e1870 --- /dev/null +++ b/core/modules/file/file.entity.yml @@ -0,0 +1 @@ +file: Drupal\file\Plugin\Core\Entity\File diff --git a/core/modules/file/file.module b/core/modules/file/file.module index 9269272..1357578 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -1575,7 +1575,7 @@ function file_get_file_references(File $file, $field = NULL, $age = FIELD_LOAD_R // The usage table contains usage of every revision. If we are looking // for every revision or the entity does not support revisions then // every usage is already a match. - $match_entity_type = $age == FIELD_LOAD_REVISION || !isset($entity_info['entity_keys']['revision']); + $match_entity_type = $age == FIELD_LOAD_REVISION || !$entity_info->getKey('revision'); $entities = entity_load_multiple($entity_type, $entity_ids); foreach ($entities as $entity) { $bundle = $entity->bundle(); diff --git a/core/modules/file/file.views.inc b/core/modules/file/file.views.inc index c9e271f..dd35161 100644 --- a/core/modules/file/file.views.inc +++ b/core/modules/file/file.views.inc @@ -478,7 +478,7 @@ function file_field_views_data_views_data_alter(&$data, $field) { $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type; list($label, $all_labels) = field_views_field_label($field['field_name']); - $entity = $entity_info['label']; + $entity = $entity_info->getLabel(); if ($entity == t('Node')) { $entity = t('Content'); } @@ -490,8 +490,8 @@ function file_field_views_data_views_data_alter(&$data, $field) { 'field_name' => $field['field_name'], 'field table' => _field_sql_storage_tablename($field), 'field field' => $field['field_name'] . '_fid', - 'base' => $entity_info['base_table'], - 'base field' => $entity_info['entity_keys']['id'], + 'base' => $entity_info->getBaseTable(), + 'base field' => $entity_info->getKey('id'), 'label' => t('!field_name', array('!field_name' => $field['field_name'])), 'join_extra' => array( 0 => array( diff --git a/core/modules/file/lib/Drupal/file/FileStorageController.php b/core/modules/file/lib/Drupal/file/FileStorageController.php index d3ca601..dc2f75b 100644 --- a/core/modules/file/lib/Drupal/file/FileStorageController.php +++ b/core/modules/file/lib/Drupal/file/FileStorageController.php @@ -77,7 +77,7 @@ public function preDelete($entities) { * An integer containing the number of bytes used. */ public function spaceUsed($uid = NULL, $status = FILE_STATUS_PERMANENT) { - $query = db_select($this->entityInfo['base_table'], 'f') + $query = db_select($this->entityInfo->getBaseTable(), 'f') ->condition('f.status', $status); $query->addExpression('SUM(f.filesize)', 'filesize'); if (isset($uid)) { @@ -95,7 +95,7 @@ public function spaceUsed($uid = NULL, $status = FILE_STATUS_PERMANENT) { public function retrieveTemporaryFiles() { // Use separate placeholders for the status to avoid a bug in some versions // of PHP. See http://drupal.org/node/352956. - return db_query('SELECT fid FROM {' . $this->entityInfo['base_table'] . '} WHERE status <> :permanent AND timestamp < :timestamp', array( + return db_query('SELECT fid FROM {' . $this->entityInfo->getBaseTable() . '} WHERE status <> :permanent AND timestamp < :timestamp', array( ':permanent' => FILE_STATUS_PERMANENT, ':timestamp' => REQUEST_TIME - DRUPAL_MAXIMUM_TEMP_FILE_AGE )); diff --git a/core/modules/filter/filter.entity.yml b/core/modules/filter/filter.entity.yml new file mode 100644 index 0000000..a0303c15 --- /dev/null +++ b/core/modules/filter/filter.entity.yml @@ -0,0 +1 @@ +filter_format: Drupal\filter\Plugin\Core\Entity\FilterFormat diff --git a/core/modules/image/image.views.inc b/core/modules/image/image.views.inc index 77c4ea3..b8746a0 100644 --- a/core/modules/image/image.views.inc +++ b/core/modules/image/image.views.inc @@ -41,7 +41,7 @@ function image_field_views_data_views_data_alter(&$data, $field) { $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type; list($label, $all_labels) = field_views_field_label($field['field_name']); - $entity = $entity_info['label']; + $entity = $entity_info->getLabel(); if ($entity == t('Node')) { $entity = t('Content'); } @@ -53,8 +53,8 @@ function image_field_views_data_views_data_alter(&$data, $field) { 'field_name' => $field['field_name'], 'field table' => _field_sql_storage_tablename($field), 'field field' => $field['field_name'] . '_fid', - 'base' => $entity_info['base_table'], - 'base field' => $entity_info['entity_keys']['id'], + 'base' => $entity_info->getBaseTable(), + 'base field' => $entity_info->getKey('id'), 'label' => t('!field_name', array('!field_name' => $field['field_name'])), 'join_extra' => array( 0 => array( diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc index 33eaa6b..91e6100 100644 --- a/core/modules/language/language.admin.inc +++ b/core/modules/language/language.admin.inc @@ -786,7 +786,7 @@ function language_content_settings_form(array $form, array $form_state, array $s $default = array(); foreach ($supported as $entity_type) { - $labels[$entity_type] = isset($entity_info[$entity_type]['label']) ? $entity_info[$entity_type]['label'] : $entity_type; + $labels[$entity_type] = $entity_info[$entity_type]->getLabel() ? $entity_info[$entity_type]->getLabel() : $entity_type; $default[$entity_type] = FALSE; // Check whether we have any custom setting. @@ -826,7 +826,7 @@ function language_content_settings_form(array $form, array $form_state, array $s '#type' => 'container', '#entity_type' => $entity_type, '#theme' => 'language_content_settings_table', - '#bundle_label' => isset($info['bundle_label']) ? $info['bundle_label'] : $label, + '#bundle_label' => $info->getBundleLable() ?: $label, '#states' => array( 'visible' => array( ':input[name="entity_types[' . $entity_type . ']"]' => array('checked' => TRUE), diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module index 14c41b0..b250373 100644 --- a/core/modules/menu/menu.module +++ b/core/modules/menu/menu.module @@ -145,11 +145,13 @@ function menu_menu() { * Implements hook_entity_info_alter(). */ function menu_entity_info_alter(&$entity_info) { - $entity_info['menu']['controllers']['list'] = 'Drupal\menu\MenuListController'; - $entity_info['menu']['uri_callback'] = 'menu_uri'; - $entity_info['menu']['controllers']['form'] = array( - 'default' => 'Drupal\menu\MenuFormController', - ); + if (isset($entity_info['menu'])) { + $entity_info['menu']->setController('list', 'Drupal\menu\MenuListController'); + $entity_info['menu']->setUriCallback('menu_uri'); + $entity_info['menu']->setController('form', array( + 'default' => 'Drupal\menu\MenuFormController', + )); + } } /** diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php index 6a3eddb..ab037a4 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityType; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Database\Connection; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -56,7 +57,7 @@ class MenuLinkStorageController extends DatabaseStorageController { * @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $route_provider * The route provider service. */ - public function __construct($entity_type, array $entity_info, Connection $database, RouteProviderInterface $route_provider) { + public function __construct($entity_type, EntityType $entity_info, Connection $database, RouteProviderInterface $route_provider) { parent::__construct($entity_type, $entity_info, $database); $this->routeProvider = $route_provider; @@ -69,7 +70,7 @@ public function __construct($entity_type, array $entity_info, Connection $databa /** * {@inheritdoc} */ - public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { + public static function createInstance(ContainerInterface $container, $entity_type, EntityType $entity_info) { return new static( $entity_type, $entity_info, @@ -145,7 +146,7 @@ public function save(EntityInterface $entity) { } if ($entity->isNew()) { - $entity->mlid = $this->database->insert($this->entityInfo['base_table'])->fields(array('menu_name' => 'tools'))->execute(); + $entity->mlid = $this->database->insert($this->entityInfo->getBaseTable())->fields(array('menu_name' => 'tools'))->execute(); $entity->enforceIsNew(); } @@ -161,7 +162,7 @@ public function save(EntityInterface $entity) { // $entity may have additional keys left over from building a router entry. // The intersect removes the extra keys, allowing a meaningful comparison. if ($entity->isNew() || (array_intersect_key(get_object_vars($entity), get_object_vars($entity->original)) != get_object_vars($entity->original))) { - $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey); + $return = drupal_write_record($this->entityInfo->getBaseTable(), $entity, $this->idKey); if ($return) { if (!$entity->isNew()) { @@ -380,11 +381,11 @@ public function loadUpdatedCustomized(array $router_paths) { ); $query_result = $query->execute(); - if (!empty($this->entityInfo['class'])) { + if ($entity_class = $this->entityInfo->getClass()) { // We provide the necessary arguments for PDO to create objects of the // specified entity class. // @see Drupal\Core\Entity\EntityInterface::__construct() - $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); + $query_result->setFetchMode(\PDO::FETCH_CLASS, $entity_class, array(array(), $this->entityType)); } return $query_result->fetchAllAssoc($this->idKey); @@ -590,7 +591,7 @@ public function findChildrenRelativeDepth(EntityInterface $entity) { * A menu link entity. */ protected function moveChildren(EntityInterface $entity) { - $query = $this->database->update($this->entityInfo['base_table']); + $query = $this->database->update($this->entityInfo->getBaseTable()); $query->fields(array('menu_name' => $entity->menu_name)); diff --git a/core/modules/menu_link/menu_link.entity.yml b/core/modules/menu_link/menu_link.entity.yml new file mode 100644 index 0000000..c8c37bb --- /dev/null +++ b/core/modules/menu_link/menu_link.entity.yml @@ -0,0 +1 @@ +menu_link: Drupal\menu_link\Plugin\Core\Entity\MenuLink diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index db3ba75..aac1e85 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -103,7 +103,7 @@ protected function invokeHook($hook, EntityInterface $node) { if ($function == 'field_attach_revision_delete') { $function = 'field_attach_delete_revision'; } - if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { + if ($this->entityInfo->isFieldable() && function_exists($function)) { $function($node); } diff --git a/core/modules/node/node.entity.yml b/core/modules/node/node.entity.yml new file mode 100644 index 0000000..94b4ab6 --- /dev/null +++ b/core/modules/node/node.entity.yml @@ -0,0 +1 @@ +node: Drupal\node\Plugin\Core\Entity\Node diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php index 343dbd3..0e54c20 100644 --- a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php +++ b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php @@ -19,7 +19,7 @@ class PictureMappingListController extends ConfigEntityListController { * Overrides Drupal\config\EntityListControllerBase::hookMenu(). */ public function hookMenu() { - $path = $this->entityInfo['list path']; + $path = $this->entityInfo->get('list_path'); $items = parent::hookMenu(); // Override the access callback. diff --git a/core/modules/rest/lib/Drupal/rest/LinkManager/TypeLinkManager.php b/core/modules/rest/lib/Drupal/rest/LinkManager/TypeLinkManager.php index 6802282..66fb4ea 100644 --- a/core/modules/rest/lib/Drupal/rest/LinkManager/TypeLinkManager.php +++ b/core/modules/rest/lib/Drupal/rest/LinkManager/TypeLinkManager.php @@ -83,7 +83,7 @@ protected function writeCache() { $entity_info = entity_get_info(); foreach (entity_get_bundles() as $entity_type => $bundles) { $entity_type_info = $entity_info[$entity_type]; - $reflection = new \ReflectionClass($entity_type_info['class']); + $reflection = new \ReflectionClass($entity_type_info->getClass()); // Only content entities are supported currently. // @todo Consider supporting config entities. if ($reflection->implementsInterface('\Drupal\Core\Config\Entity\ConfigEntityInterface')) { diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php b/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php index 310d843..72e5034 100644 --- a/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php +++ b/core/modules/rest/lib/Drupal/rest/Plugin/Derivative/EntityDerivative.php @@ -43,8 +43,8 @@ public function getDerivativeDefinitions(array $base_plugin_definition) { $this->derivatives[$entity_type] = array( 'id' => 'entity:' . $entity_type, 'entity_type' => $entity_type, - 'serialization_class' => $entity_info['class'], - 'label' => $entity_info['label'], + 'serialization_class' => $entity_info->getClass(), + 'label' => $entity_info->getLabel(), ); $this->derivatives[$entity_type] += $base_plugin_definition; } diff --git a/core/modules/shortcut/shortcut.entity.yml b/core/modules/shortcut/shortcut.entity.yml new file mode 100644 index 0000000..3649b4e --- /dev/null +++ b/core/modules/shortcut/shortcut.entity.yml @@ -0,0 +1 @@ +shortcut: Drupal\shortcut\Plugin\Core\Entity\Shortcut diff --git a/core/modules/system/lib/Drupal/system/Plugin/views/row/EntityRow.php b/core/modules/system/lib/Drupal/system/Plugin/views/row/EntityRow.php index 0a5ef91..b227c00 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/views/row/EntityRow.php +++ b/core/modules/system/lib/Drupal/system/Plugin/views/row/EntityRow.php @@ -59,8 +59,8 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o $this->entityType = $this->definition['entity_type']; $this->entityInfo = entity_get_info($this->entityType); - $this->base_table = $this->entityInfo['base_table']; - $this->base_field = $this->entityInfo['entity_keys']['id']; + $this->base_table = $this->entityInfo->getBaseTable(); + $this->base_field = $this->entityInfo->getKey('id'); } /** diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php index cb0ea4d..3af91d0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php @@ -28,6 +28,7 @@ public static function getInfo() { function testEntityInfoChanges() { module_enable(array('entity_cache_test')); $entity_info = entity_get_info(); + // @fixme How to replace this. $this->assertTrue(isset($entity_info['entity_cache_test']), 'Test entity type found.'); // Change the label of the test entity type and make sure changes appear @@ -42,6 +43,7 @@ function testEntityInfoChanges() { // Disable the providing module and make sure the entity type is gone. module_disable(array('entity_cache_test', 'entity_cache_test_dependency')); $entity_info = entity_get_info(); + // @fixme How to replace this. $this->assertFalse(isset($entity_info['entity_cache_test']), 'Entity type of the providing module is gone.'); } diff --git a/core/modules/system/system.entity.yml b/core/modules/system/system.entity.yml new file mode 100644 index 0000000..462c85b --- /dev/null +++ b/core/modules/system/system.entity.yml @@ -0,0 +1 @@ +menu: Drupal\system\Plugin\Core\Entity\Menu diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index 9ceab31..808505e 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -127,7 +127,7 @@ function entity_test_delete_bundle($bundle, $entity_type = 'entity_test') { function entity_test_entity_bundle_info_alter(&$bundles) { $entity_info = entity_get_info(); foreach ($bundles as $entity_type => $info) { - if ($entity_info[$entity_type]['module'] == 'entity_test') { + if ($entity_info[$entity_type]->getModule() == 'entity_test') { $bundles[$entity_type] = Drupal::state()->get($entity_type . '.bundles') ?: array($entity_type => array('label' => 'Entity Test Bundle')); } } diff --git a/core/modules/taxonomy/taxonomy.entity.yml b/core/modules/taxonomy/taxonomy.entity.yml new file mode 100644 index 0000000..8bb8951 --- /dev/null +++ b/core/modules/taxonomy/taxonomy.entity.yml @@ -0,0 +1,2 @@ +taxonomy_vocabulary: Drupal\taxonomy\Plugin\Core\Entity\Vocabulary +taxonomy_term: Drupal\taxonomy\Plugin\Core\Entity\Term diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc index 679deb5..9c18d16 100644 --- a/core/modules/taxonomy/taxonomy.views.inc +++ b/core/modules/taxonomy/taxonomy.views.inc @@ -369,7 +369,7 @@ function taxonomy_field_views_data_views_data_alter(&$data, $field) { $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type; list($label, $all_labels) = field_views_field_label($field['field_name']); - $entity = $entity_info['label']; + $entity = $entity_info->getLabel(); if ($entity == t('Node')) { $entity = t('Content'); } @@ -381,8 +381,8 @@ function taxonomy_field_views_data_views_data_alter(&$data, $field) { 'field_name' => $field['field_name'], 'field table' => _field_sql_storage_tablename($field), 'field field' => $field['field_name'] . '_tid', - 'base' => $entity_info['base_table'], - 'base field' => $entity_info['entity_keys']['id'], + 'base' => $entity_info->getBaseTable(), + 'base field' => $entity_info->getKey('id'), 'label' => t('!field_name', array('!field_name' => $field['field_name'])), 'join_extra' => array( 0 => array( diff --git a/core/modules/tour/tour.entity.yml b/core/modules/tour/tour.entity.yml new file mode 100644 index 0000000..372f76e --- /dev/null +++ b/core/modules/tour/tour.entity.yml @@ -0,0 +1 @@ +tour: Drupal\tour\Plugin\Core\Entity\Tour diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php index 906248a..ca6cb48 100644 --- a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php +++ b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php @@ -73,6 +73,7 @@ public function retranslate(EntityInterface $entity, $langcode = NULL) { * Implements EntityTranslationControllerInterface::getBasePath(). */ public function getBasePath(EntityInterface $entity) { + // @fixme How to replace this. return $this->getPathInstance($this->entityInfo['menu_base_path'], $entity->id()); } @@ -80,6 +81,7 @@ public function getBasePath(EntityInterface $entity) { * Implements EntityTranslationControllerInterface::getEditPath(). */ public function getEditPath(EntityInterface $entity) { + // @fixme How to replace this. return isset($this->entityInfo['menu_edit_path']) ? $this->getPathInstance($this->entityInfo['menu_edit_path'], $entity->id()) : FALSE; } @@ -87,6 +89,7 @@ public function getEditPath(EntityInterface $entity) { * Implements EntityTranslationControllerInterface::getViewPath(). */ public function getViewPath(EntityInterface $entity) { + // @fixme How to replace this. return isset($this->entityInfo['menu_view_path']) ? $this->getPathInstance($this->entityInfo['menu_view_path'], $entity->id()) : FALSE; } @@ -107,8 +110,8 @@ public function getTranslationAccess(EntityInterface $entity, $op) { $translate_permission = TRUE; // If no permission granularity is defined this entity type does not need an // explicit translate permission. - if (!user_access('translate any entity') && !empty($info['permission_granularity'])) { - $translate_permission = user_access($info['permission_granularity'] == 'bundle' ? "translate {$entity->bundle()} {$entity->entityType()}" : "translate {$entity->entityType()}"); + if (!user_access('translate any entity') && $info->get('permission_granularity')) { + $translate_permission = user_access($info->get('permission_granularity') == 'bundle' ? "translate {$entity->bundle()} {$entity->entityType()}" : "translate {$entity->entityType()}"); } return $translate_permission && user_access("$op entity translations"); } @@ -520,6 +523,7 @@ protected function entityFormTitle(EntityInterface $entity) { * The instantiated path. */ protected function getPathInstance($path, $entity_id) { + // @fixme How to replace this. $wildcard = $this->entityInfo['menu_path_wildcard']; return str_replace($wildcard, $entity_id, $path); } diff --git a/core/modules/translation_entity/translation_entity.admin.inc b/core/modules/translation_entity/translation_entity.admin.inc index 9f44bdf..94c4e29 100644 --- a/core/modules/translation_entity/translation_entity.admin.inc +++ b/core/modules/translation_entity/translation_entity.admin.inc @@ -82,7 +82,7 @@ function _translation_entity_form_language_content_settings_form_alter(array &$f // Only show the checkbox to enable translation if the bundles in the // entity might have fields and if there are fields to translate. - if (!empty($entity_info['fieldable'])) { + if ($entity_info->fieldsCachable()) { $fields = field_info_instances($entity_type, $bundle); if ($fields) { $form['settings'][$entity_type][$bundle]['translatable'] = array( diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module index f51c2cb..37ff243 100644 --- a/core/modules/translation_entity/translation_entity.module +++ b/core/modules/translation_entity/translation_entity.module @@ -504,7 +504,8 @@ function translation_entity_types_translatable() { function translation_entity_controller($entity_type) { $entity_info = entity_get_info($entity_type); // @todo Throw an exception if the key is missing. - return new $entity_info['controllers']['translation']($entity_type, $entity_info); + $translation_controller = $entity_info->getController('translation'); + return new $translation_controller($entity_type, $entity_info); } /** diff --git a/core/modules/translation_entity/translation_entity.pages.inc b/core/modules/translation_entity/translation_entity.pages.inc index c7de9e2..4780177 100644 --- a/core/modules/translation_entity/translation_entity.pages.inc +++ b/core/modules/translation_entity/translation_entity.pages.inc @@ -196,7 +196,7 @@ function translation_entity_add_page(EntityInterface $entity, Language $source = // @todo Exploit the upcoming hook_entity_prepare() when available. translation_entity_prepare_translation($entity, $source, $target); $info = $entity->entityInfo(); - $operation = isset($info['default_operation']) ? $info['default_operation'] : 'default'; + $operation = $info->get('default_operation') ?: 'default'; $form_state['langcode'] = $target->langcode; $form_state['translation_entity']['source'] = $source; $form_state['translation_entity']['target'] = $target; @@ -220,7 +220,7 @@ function translation_entity_add_page(EntityInterface $entity, Language $source = function translation_entity_edit_page(EntityInterface $entity, Language $language = NULL) { $language = !empty($language) ? $language : language(Language::TYPE_CONTENT); $info = $entity->entityInfo(); - $operation = isset($info['default_operation']) ? $info['default_operation'] : 'default'; + $operation = $info->get('default_operation') ?: 'default'; $form_state['langcode'] = $language->langcode; $form_state['translation_entity']['translation_form'] = TRUE; return entity_get_form($entity, $operation, $form_state); diff --git a/core/modules/user/lib/Drupal/user/RoleListController.php b/core/modules/user/lib/Drupal/user/RoleListController.php index 9ff5c83..29d61c7 100644 --- a/core/modules/user/lib/Drupal/user/RoleListController.php +++ b/core/modules/user/lib/Drupal/user/RoleListController.php @@ -91,7 +91,7 @@ public function buildForm(array $form, array &$form_state) { $form['entities'] = 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('order', 'sibling', 'weight'), ), diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php index e282226..a5c363a 100644 --- a/core/modules/user/lib/Drupal/user/UserStorageController.php +++ b/core/modules/user/lib/Drupal/user/UserStorageController.php @@ -8,6 +8,7 @@ namespace Drupal\user; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityType; use Drupal\Core\Entity\EntityMalformedException; use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Password\PasswordInterface; @@ -61,7 +62,7 @@ public function __construct($entity_type, $entity_info, Connection $database, Pa /** * {@inheritdoc} */ - public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { + public static function createInstance(ContainerInterface $container, $entity_type, EntityType $entity_info) { return new static( $entity_type, $entity_info, diff --git a/core/modules/user/user.entity.yml b/core/modules/user/user.entity.yml new file mode 100644 index 0000000..fb68dd8 --- /dev/null +++ b/core/modules/user/user.entity.yml @@ -0,0 +1,2 @@ +user: Drupal\user\Plugin\Core\Entity\User +user_role: Drupal\user\Plugin\Core\Entity\Role diff --git a/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php b/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php index f872f7d..d258d0a 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php +++ b/core/modules/views/lib/Drupal/views/Plugin/entity_reference/selection/ViewsSelection.php @@ -54,7 +54,7 @@ public static function settingsForm(&$field, &$instance) { $options = array(); foreach ($displays as $data) { list($view, $display_id) = $data; - if ($view->storage->get('base_table') == $entity_info['base_table']) { + if ($view->storage->get('base_table') == $entity_info->getBaseTable()) { $name = $view->storage->get('id'); $display = $view->storage->get('display'); $options[$name . ':' . $display_id] = $name . ' - ' . $display[$display_id]['display_title']; diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php index 7f6b104..38fb9da 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php @@ -1565,9 +1565,9 @@ public function buildOptionsForm(&$form, &$form_state) { $entity_tables = array(); $has_translation_handlers = FALSE; foreach ($entities as $type => $entity_info) { - $entity_tables[] = $entity_info['base_table']; + $entity_tables[] = $entity_info->getBaseTable(); - if (!empty($entity_info['translation'])) { + if (!empty($entity_info->translation)) { $has_translation_handlers = TRUE; } } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/filter/Bundle.php b/core/modules/views/lib/Drupal/views/Plugin/views/filter/Bundle.php index 3c1f54f..4234ad2 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/filter/Bundle.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/Bundle.php @@ -30,7 +30,7 @@ class Bundle extends InOperator { /** * The entity info for the entity type. * - * @var array + * @var \Drupal\Core\Entity\Annotation\EntityType */ protected $entityInfo; @@ -42,7 +42,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o $this->entityType = $this->getEntityType(); $this->entityInfo = entity_get_info($this->entityType); - $this->real_field = $this->entityInfo['entity_keys']['bundle']; + $this->real_field = $this->entityInfo->getKey('bundle'); } /** @@ -51,7 +51,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o public function getValueOptions() { if (!isset($this->value_options)) { $types = entity_get_bundles($this->entityType); - $this->value_title = t('@entity types', array('@entity' => $this->entityInfo['label'])); + $this->value_title = t('@entity types', array('@entity' => $this->entityInfo->getLabel())); $options = array(); foreach ($types as $type => $info) { diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php b/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php index 9534f1d..fe6daf7 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php @@ -1332,7 +1332,7 @@ public function query($get_count = FALSE) { foreach ($entity_tables as $table_alias => $table) { $info = entity_get_info($table['entity_type']); - $base_field = empty($table['revision']) ? $info['entity_keys']['id'] : $info['entity_keys']['revision']; + $base_field = empty($table['revision']) ? $info->getKey('id') : $info->getKey('revision'); $this->add_field($table_alias, $base_field, '', $params); } } @@ -1568,7 +1568,7 @@ public function getEntityTables() { // Determine which of the tables are revision tables. foreach ($entity_tables as $table_alias => $table) { $info = entity_get_info($table['entity_type']); - if (isset($info['revision table']) && $info['revision table'] == $table['base']) { + if ($info->hasRevisionTable() && $info->getRevisionTable() == $table['base']) { $entity_tables[$table_alias]['revision'] = TRUE; } } @@ -1601,7 +1601,7 @@ function loadEntities(&$results) { foreach ($entity_tables as $table_alias => $table) { $entity_type = $table['entity_type']; $info = entity_get_info($entity_type); - $id_key = empty($table['revision']) ? $info['entity_keys']['id'] : $info['entity_keys']['revision']; + $id_key = empty($table['revision']) ? $info->getKey('id') : $info->getKey('revision'); $id_alias = $this->getFieldAlias($table_alias, $id_key); foreach ($results as $index => $result) { diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php index da82322..9938d69 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php @@ -120,7 +120,7 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi $entities = entity_get_info(); foreach ($entities as $entity_type => $entity_info) { - if (isset($entity_info['base_table']) && $this->base_table == $entity_info['base_table']) { + if ($this->base_table == $entity_info->getBaseTable()) { $this->entity_info = $entity_info; $this->entity_type = $entity_type; } @@ -559,7 +559,7 @@ protected function buildFilters(&$form, &$form_state) { $bundles = entity_get_bundles($this->entity_type); // If the current base table support bundles and has more than one (like user). - if (isset($this->entity_info['bundle_keys']) && !empty($bundles)) { + if ($this->entity_info->getBundleKeys() && !empty($bundles)) { // Get all bundles and their human readable names. $options = array('all' => t('All')); foreach ($bundles as $type => $bundle) { @@ -826,7 +826,7 @@ protected function default_display_filters_user(array $form, array &$form_state) $filters = array(); if (!empty($form_state['values']['show']['type']) && $form_state['values']['show']['type'] != 'all') { - $bundle_key = $this->entity_info['bundle_keys']['bundle']; + $bundle_key = $this->entity_info->getBundleKey('bundle'); // Figure out the table where $bundle_key lives. It may not be the same as // the base table for the view; the taxonomy vocabulary machine_name, for // example, is stored in taxonomy_vocabulary, not taxonomy_term_data. diff --git a/core/modules/views/views.entity.yml b/core/modules/views/views.entity.yml new file mode 100644 index 0000000..ca3f94e --- /dev/null +++ b/core/modules/views/views.entity.yml @@ -0,0 +1 @@ +view: Drupal\views\Plugin\Core\Entity\View diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc index 99d23c1..d1ab497 100644 --- a/core/modules/views/views.views.inc +++ b/core/modules/views/views.views.inc @@ -109,8 +109,8 @@ function views_views_data() { // Registers an entity area handler per entity type. foreach (entity_get_info() as $entity_type => $entity_info) { // Exclude entity types, which cannot be rendered. - if (!empty($entity_info['controllers']['render'])) { - $label = $entity_info['label']; + if (!$entity_info->hasController('render')) { + $label = $entity_info->getLabel(); $data['views']['entity_' . $entity_type] = array( 'title' => t('Rendered entity - @label', array('@label' => $label)), 'help' => t('Displays a rendered @label entity in an area.', array('@label' => $label)), diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module index bd73fa8..e4398be 100644 --- a/core/modules/views_ui/views_ui.module +++ b/core/modules/views_ui/views_ui.module @@ -5,6 +5,7 @@ * Provide structure for the administrative interface to Views. */ +use Drupal\Core\Entity\EntityType; use Drupal\views\ViewExecutable; use Drupal\views\ViewStorageInterface; use Drupal\views_ui\ViewUI; @@ -100,16 +101,16 @@ function views_ui_menu() { /** * Implements hook_entity_info(). */ -function views_ui_entity_info(&$entity_info) { - $entity_info['view']['controllers'] += array( - 'list' => 'Drupal\views_ui\ViewListController', - 'form' => array( +function views_ui_entity_info($entity_info) { + if (isset($entity_info['view'])) { + $entity_info['view']->setController('list', 'Drupal\views_ui\ViewListController'); + $entity_info['view']->setController('form', array( 'edit' => 'Drupal\views_ui\ViewEditFormController', 'add' => 'Drupal\views_ui\ViewAddFormController', 'preview' => 'Drupal\views_ui\ViewPreviewFormController', 'clone' => 'Drupal\views_ui\ViewCloneFormController', - ), - ); + )); + } } /** diff --git a/core/tests/Drupal/Tests/Core/AnnotationReaderTest.php b/core/tests/Drupal/Tests/Core/AnnotationReaderTest.php new file mode 100644 index 0000000..16d8eb8 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/AnnotationReaderTest.php @@ -0,0 +1,44 @@ + 'Annotation reader tesst', + 'description' => '.', + 'group' => 'core' + ); + } + + public function setUp() { + $this->reader = new AnnotationReader; + $this->reader->setLoader(test_classloader()); + } + + public function testGetClassAnnotation() { + $res = $this->reader->getClassAnnotation('Drupal\Tests\Core\TestAnnotationClass', 'Drupal\Core\Entity\Annotation\EntityType'); + $expected = new EntityType(array('id' => "test", 'label' => "Test")); + $this->assertEquals($expected, $res); + } + + public function testGetClassAnnotationCache() { + $reader_mock = $this->getMock('Doctrine\Common\Annotations\AnnotationReader'); + $return_annotation = new EntityType(array('id' => "test", 'label' => "Test")); + $reader_mock->expects($this->once()) + ->method('getClassAnnotations') + ->will($this->returnValue($return_annotation)); + $this->reader->setReader($reader_mock); + + // Expectation is to only call $reader_mock once, so this would fail if the + // cache wasn't working correctly. + $this->reader->getClassAnnotations('Drupal\Tests\Core\TestAnnotationClass'); + $this->reader->getClassAnnotations('Drupal\Tests\Core\TestAnnotationClass'); + } +} diff --git a/core/tests/Drupal/Tests/Core/TestAnnotationClass.php b/core/tests/Drupal/Tests/Core/TestAnnotationClass.php new file mode 100644 index 0000000..f7e4994 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/TestAnnotationClass.php @@ -0,0 +1,17 @@ +add('Drupal\\', __DIR__); -$loader->add('Drupal\Core', __DIR__ . "/../../core/lib"); -$loader->add('Drupal\Component', __DIR__ . "/../../core/lib"); +function test_classloader() { + // Register the namespaces we'll need to autoload from. + $loader = require __DIR__ . "/../vendor/autoload.php"; + $loader->add('Drupal\\', __DIR__); + $loader->add('Drupal\Core', __DIR__ . "/../../core/lib"); + $loader->add('Drupal\Component', __DIR__ . "/../../core/lib"); -foreach (scandir(__DIR__ . "/../modules") as $module) { - $loader->add('Drupal\\' . $module, __DIR__ . "/../modules/" . $module . "/lib"); - // Add test module classes. - $test_modules_dir = __DIR__ . "/../modules/$module/tests/modules"; - if (is_dir($test_modules_dir)) { - foreach (scandir($test_modules_dir) as $test_module) { - $loader->add('Drupal\\' . $test_module, $test_modules_dir . '/' . $test_module . '/lib'); + foreach (scandir(__DIR__ . "/../modules") as $module) { + $loader->add('Drupal\\' . $module, __DIR__ . "/../modules/" . $module . "/lib"); + // Add test module classes. + $test_modules_dir = __DIR__ . "/../modules/$module/tests/modules"; + if (is_dir($test_modules_dir)) { + foreach (scandir($test_modules_dir) as $test_module) { + $loader->add('Drupal\\' . $test_module, $test_modules_dir . '/' . $test_module . '/lib'); + } } } + return $loader; } +test_classloader(); require __DIR__ . "/../../core/lib/Drupal.php"; // Look into removing this later. define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);