123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928 |
- <?php
- namespace Drupal\Core\Entity;
- use Drupal\Component\Plugin\Definition\PluginDefinition;
- use Drupal\Component\Utility\Unicode;
- use Drupal\Core\Entity\Exception\EntityTypeIdLengthException;
- use Drupal\Core\StringTranslation\StringTranslationTrait;
- use Drupal\Core\StringTranslation\TranslatableMarkup;
- /**
- * Provides an implementation of an entity type and its metadata.
- *
- * @ingroup entity_api
- */
- class EntityType extends PluginDefinition implements EntityTypeInterface {
- use StringTranslationTrait;
- /**
- * Indicates whether entities should be statically cached.
- *
- * @var bool
- */
- protected $static_cache = TRUE;
- /**
- * Indicates whether the rendered output of entities should be cached.
- *
- * @var bool
- */
- protected $render_cache = TRUE;
- /**
- * Indicates if the persistent cache of field data should be used.
- *
- * @var bool
- */
- protected $persistent_cache = TRUE;
- /**
- * An array of entity keys.
- *
- * @var array
- */
- protected $entity_keys = [];
- /**
- * The unique identifier of this entity type.
- *
- * @var string
- */
- protected $id;
- /**
- * The name of the original entity type class.
- *
- * This is only set if the class name is changed.
- *
- * @var string
- */
- protected $originalClass;
- /**
- * An array of handlers.
- *
- * @var array
- */
- protected $handlers = [];
- /**
- * The name of the default administrative permission.
- *
- * @var string
- */
- protected $admin_permission;
- /**
- * The permission granularity level.
- *
- * The allowed values are respectively "entity_type" or "bundle".
- *
- * @var string
- */
- protected $permission_granularity = 'entity_type';
- /**
- * Link templates using the URI template syntax.
- *
- * @var array
- */
- protected $links = [];
- /**
- * The name of a callback that returns the label of the entity.
- *
- * @var callable|null
- *
- * @deprecated in Drupal 8.0.x-dev and will be removed before Drupal 9.0.0.
- * Use Drupal\Core\Entity\EntityInterface::label() for complex label
- * generation as needed.
- *
- * @see \Drupal\Core\Entity\EntityInterface::label()
- *
- * @todo Remove usages of label_callback https://www.drupal.org/node/2450793.
- */
- protected $label_callback = NULL;
- /**
- * The name of the entity type which provides bundles.
- *
- * @var string
- */
- protected $bundle_entity_type = NULL;
- /**
- * The name of the entity type for which bundles are provided.
- *
- * @var string|null
- */
- protected $bundle_of = NULL;
- /**
- * The human-readable name of the entity bundles, e.g. Vocabulary.
- *
- * @var string|null
- */
- protected $bundle_label = NULL;
- /**
- * The name of the entity type's base table.
- *
- * @var string|null
- */
- protected $base_table = NULL;
- /**
- * The name of the entity type's revision data table.
- *
- * @var string|null
- */
- protected $revision_data_table = NULL;
- /**
- * The name of the entity type's revision table.
- *
- * @var string|null
- */
- protected $revision_table = NULL;
- /**
- * The name of the entity type's data table.
- *
- * @var string|null
- */
- protected $data_table = NULL;
- /**
- * Indicates whether the entity data is internal.
- *
- * @var bool
- */
- protected $internal = FALSE;
- /**
- * Indicates whether entities of this type have multilingual support.
- *
- * @var bool
- */
- protected $translatable = FALSE;
- /**
- * Indicates whether the revision form fields should be added to the form.
- *
- * @var bool
- */
- protected $show_revision_ui = FALSE;
- /**
- * The human-readable name of the type.
- *
- * @var string
- *
- * @see \Drupal\Core\Entity\EntityTypeInterface::getLabel()
- */
- protected $label = '';
- /**
- * The human-readable label for a collection of entities of the type.
- *
- * @var string
- *
- * @see \Drupal\Core\Entity\EntityTypeInterface::getCollectionLabel()
- */
- protected $label_collection = '';
- /**
- * The indefinite singular name of the type.
- *
- * @var string
- *
- * @see \Drupal\Core\Entity\EntityTypeInterface::getSingularLabel()
- */
- protected $label_singular = '';
- /**
- * The indefinite plural name of the type.
- *
- * @var string
- *
- * @see \Drupal\Core\Entity\EntityTypeInterface::getPluralLabel()
- */
- protected $label_plural = '';
- /**
- * A definite singular/plural name of the type.
- *
- * Needed keys: "singular" and "plural".
- *
- * @var string[]
- *
- * @see \Drupal\Core\Entity\EntityTypeInterface::getCountLabel()
- */
- protected $label_count = [];
- /**
- * A callable that can be used to provide the entity URI.
- *
- * @var callable|null
- */
- protected $uri_callback = NULL;
- /**
- * The machine name of the entity type group.
- */
- protected $group;
- /**
- * The human-readable name of the entity type group.
- */
- protected $group_label;
- /**
- * The route name used by field UI to attach its management pages.
- *
- * @var string
- */
- protected $field_ui_base_route;
- /**
- * Indicates whether this entity type is commonly used as a reference target.
- *
- * This is used by the Entity reference field to promote an entity type in the
- * add new field select list in Field UI.
- *
- * @var bool
- */
- protected $common_reference_target = FALSE;
- /**
- * The list cache contexts for this entity type.
- *
- * @var string[]
- */
- protected $list_cache_contexts = [];
- /**
- * The list cache tags for this entity type.
- *
- * @var string[]
- */
- protected $list_cache_tags = [];
- /**
- * Entity constraint definitions.
- *
- * @var array[]
- */
- protected $constraints = [];
- /**
- * Any additional properties and values.
- *
- * @var array
- */
- protected $additional = [];
- /**
- * Constructs a new EntityType.
- *
- * @param array $definition
- * An array of values from the annotation.
- *
- * @throws \Drupal\Core\Entity\Exception\EntityTypeIdLengthException
- * Thrown when attempting to instantiate an entity type with too long ID.
- */
- public function __construct($definition) {
- // Throw an exception if the entity type ID is longer than 32 characters.
- if (Unicode::strlen($definition['id']) > static::ID_MAX_LENGTH) {
- throw new EntityTypeIdLengthException('Attempt to create an entity type with an ID longer than ' . static::ID_MAX_LENGTH . " characters: {$definition['id']}.");
- }
- foreach ($definition as $property => $value) {
- $this->set($property, $value);
- }
- // Ensure defaults.
- $this->entity_keys += [
- 'revision' => '',
- 'bundle' => '',
- 'langcode' => '',
- 'default_langcode' => 'default_langcode',
- 'revision_translation_affected' => 'revision_translation_affected',
- ];
- $this->handlers += [
- 'access' => 'Drupal\Core\Entity\EntityAccessControlHandler',
- ];
- if (isset($this->handlers['storage'])) {
- $this->checkStorageClass($this->handlers['storage']);
- }
- // Automatically add the "EntityChanged" constraint if the entity type
- // tracks the changed time.
- if ($this->entityClassImplements(EntityChangedInterface::class)) {
- $this->addConstraint('EntityChanged');
- }
- // Automatically add the "EntityUntranslatableFields" constraint if we have
- // an entity type supporting translatable fields and pending revisions.
- if ($this->entityClassImplements(ContentEntityInterface::class)) {
- $this->addConstraint('EntityUntranslatableFields');
- }
- // Ensure a default list cache tag is set.
- if (empty($this->list_cache_tags)) {
- $this->list_cache_tags = [$definition['id'] . '_list'];
- }
- }
- /**
- * {@inheritdoc}
- */
- public function get($property) {
- if (property_exists($this, $property)) {
- $value = isset($this->{$property}) ? $this->{$property} : NULL;
- }
- else {
- $value = isset($this->additional[$property]) ? $this->additional[$property] : NULL;
- }
- return $value;
- }
- /**
- * {@inheritdoc}
- */
- public function set($property, $value) {
- if (property_exists($this, $property)) {
- $this->{$property} = $value;
- }
- else {
- $this->additional[$property] = $value;
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isInternal() {
- return $this->internal;
- }
- /**
- * {@inheritdoc}
- */
- public function isStaticallyCacheable() {
- return $this->static_cache;
- }
- /**
- * {@inheritdoc}
- */
- public function isRenderCacheable() {
- return $this->render_cache;
- }
- /**
- * {@inheritdoc}
- */
- public function isPersistentlyCacheable() {
- return $this->persistent_cache;
- }
- /**
- * {@inheritdoc}
- */
- public function getKeys() {
- return $this->entity_keys;
- }
- /**
- * {@inheritdoc}
- */
- public function getKey($key) {
- $keys = $this->getKeys();
- return isset($keys[$key]) ? $keys[$key] : FALSE;
- }
- /**
- * {@inheritdoc}
- */
- public function hasKey($key) {
- $keys = $this->getKeys();
- return !empty($keys[$key]);
- }
- /**
- * {@inheritdoc}
- */
- public function getOriginalClass() {
- return $this->originalClass ?: $this->class;
- }
- /**
- * {@inheritdoc}
- */
- public function setClass($class) {
- if (!$this->originalClass && $this->class) {
- // If the original class is currently not set, set it to the current
- // class, assume that is the original class name.
- $this->originalClass = $this->class;
- }
- return parent::setClass($class);
- }
- /**
- * {@inheritdoc}
- */
- public function entityClassImplements($interface) {
- return is_subclass_of($this->getClass(), $interface);
- }
- /**
- * {@inheritdoc}
- */
- public function isSubclassOf($class) {
- return $this->entityClassImplements($class);
- }
- /**
- * {@inheritdoc}
- */
- public function getHandlerClasses() {
- return $this->handlers;
- }
- /**
- * {@inheritdoc}
- */
- public function getHandlerClass($handler_type, $nested = FALSE) {
- if ($this->hasHandlerClass($handler_type, $nested)) {
- $handlers = $this->getHandlerClasses();
- return $nested ? $handlers[$handler_type][$nested] : $handlers[$handler_type];
- }
- }
- /**
- * {@inheritdoc}
- */
- public function setHandlerClass($handler_type, $value) {
- $this->handlers[$handler_type] = $value;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasHandlerClass($handler_type, $nested = FALSE) {
- $handlers = $this->getHandlerClasses();
- if (!isset($handlers[$handler_type]) || ($nested && !isset($handlers[$handler_type][$nested]))) {
- return FALSE;
- }
- $handler = $handlers[$handler_type];
- if ($nested) {
- $handler = $handler[$nested];
- }
- return class_exists($handler);
- }
- /**
- * {@inheritdoc}
- */
- public function getStorageClass() {
- return $this->getHandlerClass('storage');
- }
- /**
- * {@inheritdoc}
- */
- public function setStorageClass($class) {
- $this->checkStorageClass($class);
- $this->handlers['storage'] = $class;
- return $this;
- }
- /**
- * Checks that the provided class is compatible with the current entity type.
- *
- * @param string $class
- * The class to check.
- */
- protected function checkStorageClass($class) {
- // Nothing to check by default.
- }
- /**
- * {@inheritdoc}
- */
- public function getFormClass($operation) {
- return $this->getHandlerClass('form', $operation);
- }
- /**
- * {@inheritdoc}
- */
- public function setFormClass($operation, $class) {
- $this->handlers['form'][$operation] = $class;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasFormClasses() {
- return !empty($this->handlers['form']);
- }
- /**
- * {@inheritdoc}
- */
- public function hasRouteProviders() {
- return !empty($this->handlers['route_provider']);
- }
- /**
- * {@inheritdoc}
- */
- public function getListBuilderClass() {
- return $this->getHandlerClass('list_builder');
- }
- /**
- * {@inheritdoc}
- */
- public function setListBuilderClass($class) {
- $this->handlers['list_builder'] = $class;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasListBuilderClass() {
- return $this->hasHandlerClass('list_builder');
- }
- /**
- * {@inheritdoc}
- */
- public function getViewBuilderClass() {
- return $this->getHandlerClass('view_builder');
- }
- /**
- * {@inheritdoc}
- */
- public function setViewBuilderClass($class) {
- $this->handlers['view_builder'] = $class;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasViewBuilderClass() {
- return $this->hasHandlerClass('view_builder');
- }
- /**
- * {@inheritdoc}
- */
- public function getRouteProviderClasses() {
- return !empty($this->handlers['route_provider']) ? $this->handlers['route_provider'] : [];
- }
- /**
- * {@inheritdoc}
- */
- public function getAccessControlClass() {
- return $this->getHandlerClass('access');
- }
- /**
- * {@inheritdoc}
- */
- public function setAccessClass($class) {
- $this->handlers['access'] = $class;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getAdminPermission() {
- return $this->admin_permission ?: FALSE;
- }
- /**
- * {@inheritdoc}
- */
- public function getPermissionGranularity() {
- return $this->permission_granularity;
- }
- /**
- * {@inheritdoc}
- */
- public function getLinkTemplates() {
- return $this->links;
- }
- /**
- * {@inheritdoc}
- */
- public function getLinkTemplate($key) {
- $links = $this->getLinkTemplates();
- return isset($links[$key]) ? $links[$key] : FALSE;
- }
- /**
- * {@inheritdoc}
- */
- public function hasLinkTemplate($key) {
- $links = $this->getLinkTemplates();
- return isset($links[$key]);
- }
- /**
- * {@inheritdoc}
- */
- public function setLinkTemplate($key, $path) {
- if ($path[0] !== '/') {
- throw new \InvalidArgumentException('Link templates accepts paths, which have to start with a leading slash.');
- }
- $this->links[$key] = $path;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getLabelCallback() {
- return $this->label_callback;
- }
- /**
- * {@inheritdoc}
- */
- public function setLabelCallback($callback) {
- $this->label_callback = $callback;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function hasLabelCallback() {
- return isset($this->label_callback);
- }
- /**
- * {@inheritdoc}
- */
- public function getBundleEntityType() {
- return $this->bundle_entity_type;
- }
- /**
- * {@inheritdoc}
- */
- public function getBundleOf() {
- return $this->bundle_of;
- }
- /**
- * {@inheritdoc}
- */
- public function getBundleLabel() {
- // If there is no bundle label defined, try to provide some sensible
- // fallbacks.
- if (!empty($this->bundle_label)) {
- return (string) $this->bundle_label;
- }
- elseif ($bundle_entity_type_id = $this->getBundleEntityType()) {
- return (string) \Drupal::entityTypeManager()->getDefinition($bundle_entity_type_id)->getLabel();
- }
- return (string) new TranslatableMarkup('@type_label bundle', ['@type_label' => $this->getLabel()], [], $this->getStringTranslation());
- }
- /**
- * {@inheritdoc}
- */
- public function getBaseTable() {
- return $this->base_table;
- }
- /**
- * {@inheritdoc}
- */
- public function showRevisionUi() {
- return $this->isRevisionable() && $this->show_revision_ui;
- }
- /**
- * {@inheritdoc}
- */
- public function isTranslatable() {
- return !empty($this->translatable);
- }
- /**
- * {@inheritdoc}
- */
- public function isRevisionable() {
- // Entity types are revisionable if a revision key has been specified.
- return $this->hasKey('revision');
- }
- /**
- * {@inheritdoc}
- */
- public function getRevisionDataTable() {
- return $this->revision_data_table;
- }
- /**
- * {@inheritdoc}
- */
- public function getRevisionTable() {
- return $this->revision_table;
- }
- /**
- * {@inheritdoc}
- */
- public function getDataTable() {
- return $this->data_table;
- }
- /**
- * {@inheritdoc}
- */
- public function getLabel() {
- return $this->label;
- }
- /**
- * {@inheritdoc}
- */
- public function getLowercaseLabel() {
- return Unicode::strtolower($this->getLabel());
- }
- /**
- * {@inheritdoc}
- */
- public function getCollectionLabel() {
- if (empty($this->label_collection)) {
- $label = $this->getLabel();
- $this->label_collection = new TranslatableMarkup('@label entities', ['@label' => $label], [], $this->getStringTranslation());
- }
- return $this->label_collection;
- }
- /**
- * {@inheritdoc}
- */
- public function getSingularLabel() {
- if (empty($this->label_singular)) {
- $lowercase_label = $this->getLowercaseLabel();
- $this->label_singular = $lowercase_label;
- }
- return $this->label_singular;
- }
- /**
- * {@inheritdoc}
- */
- public function getPluralLabel() {
- if (empty($this->label_plural)) {
- $lowercase_label = $this->getLowercaseLabel();
- $this->label_plural = new TranslatableMarkup('@label entities', ['@label' => $lowercase_label], [], $this->getStringTranslation());
- }
- return $this->label_plural;
- }
- /**
- * {@inheritdoc}
- */
- public function getCountLabel($count) {
- if (empty($this->label_count)) {
- return $this->formatPlural($count, '@count @label', '@count @label entities', ['@label' => $this->getLowercaseLabel()], ['context' => 'Entity type label']);
- }
- $context = isset($this->label_count['context']) ? $this->label_count['context'] : 'Entity type label';
- return $this->formatPlural($count, $this->label_count['singular'], $this->label_count['plural'], ['context' => $context]);
- }
- /**
- * {@inheritdoc}
- */
- public function getUriCallback() {
- return $this->uri_callback;
- }
- /**
- * {@inheritdoc}
- */
- public function setUriCallback($callback) {
- $this->uri_callback = $callback;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getGroup() {
- return $this->group;
- }
- /**
- * {@inheritdoc}
- */
- public function getGroupLabel() {
- return !empty($this->group_label) ? $this->group_label : $this->t('Other', [], ['context' => 'Entity type group']);
- }
- /**
- * {@inheritdoc}
- */
- public function getListCacheContexts() {
- return $this->list_cache_contexts;
- }
- /**
- * {@inheritdoc}
- */
- public function getListCacheTags() {
- return $this->list_cache_tags;
- }
- /**
- * {@inheritdoc}
- */
- public function getConfigDependencyKey() {
- // Return 'content' for the default implementation as important distinction
- // is that dependencies on other configuration entities are hard
- // dependencies and have to exist before creating the dependent entity.
- return 'content';
- }
- /**
- * {@inheritdoc}
- */
- public function isCommonReferenceTarget() {
- return $this->common_reference_target;
- }
- /**
- * {@inheritdoc}
- */
- public function getConstraints() {
- return $this->constraints;
- }
- /**
- * {@inheritdoc}
- */
- public function setConstraints(array $constraints) {
- $this->constraints = $constraints;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function addConstraint($constraint_name, $options = NULL) {
- $this->constraints[$constraint_name] = $options;
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function getBundleConfigDependency($bundle) {
- // If this entity type uses entities to manage its bundles then depend on
- // the bundle entity.
- if ($bundle_entity_type_id = $this->getBundleEntityType()) {
- if (!$bundle_entity = \Drupal::entityManager()->getStorage($bundle_entity_type_id)->load($bundle)) {
- throw new \LogicException(sprintf('Missing bundle entity, entity type %s, entity id %s.', $bundle_entity_type_id, $bundle));
- }
- $config_dependency = [
- 'type' => 'config',
- 'name' => $bundle_entity->getConfigDependencyName(),
- ];
- }
- else {
- // Depend on the provider of the entity type.
- $config_dependency = [
- 'type' => 'module',
- 'name' => $this->getProvider(),
- ];
- }
- return $config_dependency;
- }
- }
|