Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
namespace Drupal\Core\Entity\Annotation;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Defines a config entity type annotation object.
|
||||
|
@ -37,7 +37,7 @@ class ConfigEntityType extends EntityType {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function get() {
|
||||
$this->definition['group_label'] = new TranslationWrapper('Configuration', array(), array('context' => 'Entity type group'));
|
||||
$this->definition['group_label'] = new TranslatableMarkup('Configuration', array(), array('context' => 'Entity type group'));
|
||||
|
||||
return parent::get();
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
namespace Drupal\Core\Entity\Annotation;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Defines a content entity type annotation object.
|
||||
|
@ -37,7 +37,7 @@ class ContentEntityType extends EntityType {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function get() {
|
||||
$this->definition['group_label'] = new TranslationWrapper('Content', array(), array('context' => 'Entity type group'));
|
||||
$this->definition['group_label'] = new TranslatableMarkup('Content', array(), array('context' => 'Entity type group'));
|
||||
|
||||
return parent::get();
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ use Drupal\Component\Annotation\Plugin;
|
|||
*
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface
|
||||
* @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase
|
||||
* @see \Drupal\Core\Entity\Plugin\Derivative\SelectionBase
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
|
|
41
core/lib/Drupal/Core/Entity/BundleEntityFormBase.php
Normal file
41
core/lib/Drupal/Core/Entity/BundleEntityFormBase.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\BundleEntityFormBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity;
|
||||
|
||||
/**
|
||||
* Class BundleEntityFormBase is a base form for bundle config entities.
|
||||
*/
|
||||
class BundleEntityFormBase extends EntityForm {
|
||||
|
||||
/**
|
||||
* Protects the bundle entity's ID property's form element against changes.
|
||||
*
|
||||
* This method is assumed to be called on a completely built entity form,
|
||||
* including a form element for the bundle config entity's ID property.
|
||||
*
|
||||
* @param array $form
|
||||
* The completely built entity bundle form array.
|
||||
*
|
||||
* @return array
|
||||
* The updated entity bundle form array.
|
||||
*/
|
||||
protected function protectBundleIdElement(array $form) {
|
||||
$entity = $this->getEntity();
|
||||
$id_key = $entity->getEntityType()->getKey('id');
|
||||
assert('isset($form[$id_key])');
|
||||
$element = &$form[$id_key];
|
||||
|
||||
// Make sure the element is not accidentally re-enabled if it has already
|
||||
// been disabled.
|
||||
if (empty($element['#disabled'])) {
|
||||
$element['#disabled'] = !$entity->isNew();
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
|
@ -70,7 +70,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
/**
|
||||
* Local cache for the available language objects.
|
||||
*
|
||||
* @var array
|
||||
* @var \Drupal\Core\Language\LanguageInterface[]
|
||||
*/
|
||||
protected $languages;
|
||||
|
||||
|
@ -138,7 +138,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
protected $isDefaultRevision = TRUE;
|
||||
|
||||
/**
|
||||
* Holds translatable entity keys such as the ID, bundle and revision ID.
|
||||
* Holds untranslatable entity keys such as the ID, bundle, and revision ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -593,7 +593,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
}
|
||||
return $this->entityManager()
|
||||
->getAccessControlHandler($this->entityTypeId)
|
||||
->access($this, $operation, $this->activeLangcode, $account, $return_as_object);
|
||||
->access($this, $operation, $account, $return_as_object);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -737,22 +737,11 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
if (isset($this->translations[$langcode]['entity'])) {
|
||||
$translation = $this->translations[$langcode]['entity'];
|
||||
}
|
||||
else {
|
||||
if (isset($this->translations[$langcode])) {
|
||||
$translation = $this->initializeTranslation($langcode);
|
||||
$this->translations[$langcode]['entity'] = $translation;
|
||||
}
|
||||
else {
|
||||
// If we were given a valid language and there is no translation for it,
|
||||
// we return a new one.
|
||||
$this->getLanguages();
|
||||
if (isset($this->languages[$langcode])) {
|
||||
// If the entity or the requested language is not a configured
|
||||
// language, we fall back to the entity itself, since in this case it
|
||||
// cannot have translations.
|
||||
$translation = !$this->languages[$this->defaultLangcode]->isLocked() && !$this->languages[$langcode]->isLocked() ? $this->addTranslation($langcode) : $this;
|
||||
}
|
||||
}
|
||||
// Otherwise if an existing translation language was specified we need to
|
||||
// instantiate the related translation.
|
||||
elseif (isset($this->translations[$langcode])) {
|
||||
$translation = $this->initializeTranslation($langcode);
|
||||
$this->translations[$langcode]['entity'] = $translation;
|
||||
}
|
||||
|
||||
if (empty($translation)) {
|
||||
|
@ -823,10 +812,15 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function addTranslation($langcode, array $values = array()) {
|
||||
// Make sure we do not attempt to create a translation if an invalid
|
||||
// language is specified or the entity cannot be translated.
|
||||
$this->getLanguages();
|
||||
if (!isset($this->languages[$langcode]) || $this->hasTranslation($langcode)) {
|
||||
if (!isset($this->languages[$langcode]) || $this->hasTranslation($langcode) || $this->languages[$langcode]->isLocked()) {
|
||||
throw new \InvalidArgumentException("Invalid translation language ($langcode) specified.");
|
||||
}
|
||||
if ($this->languages[$this->defaultLangcode]->isLocked()) {
|
||||
throw new \InvalidArgumentException("The entity cannot be translated since it is language neutral ({$this->defaultLangcode}).");
|
||||
}
|
||||
|
||||
// Instantiate a new empty entity so default values will be populated in the
|
||||
// specified language.
|
||||
|
|
|
@ -62,6 +62,15 @@ class ContentEntityForm extends EntityForm implements ContentEntityFormInterface
|
|||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
// Update the changed timestamp of the entity.
|
||||
$this->updateChangedTime($this->entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -164,7 +173,7 @@ class ContentEntityForm extends EntityForm implements ContentEntityFormInterface
|
|||
// language.
|
||||
$this->initFormLangcodes($form_state);
|
||||
$langcode = $this->getFormLangcode($form_state);
|
||||
$this->entity = $this->entity->getTranslation($langcode);
|
||||
$this->entity = $this->entity->hasTranslation($langcode) ? $this->entity->getTranslation($langcode) : $this->entity->addTranslation($langcode);
|
||||
|
||||
$form_display = EntityFormDisplay::collectRenderDisplay($this->entity, $this->getOperation());
|
||||
$this->setFormDisplay($form_display, $form_state);
|
||||
|
@ -269,4 +278,18 @@ class ContentEntityForm extends EntityForm implements ContentEntityFormInterface
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the changed time of the entity.
|
||||
*
|
||||
* Applies only if the entity implements the EntityChangedInterface.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity updated with the submitted values.
|
||||
*/
|
||||
public function updateChangedTime(EntityInterface $entity) {
|
||||
if ($entity->getEntityType()->isSubclassOf(EntityChangedInterface::class)) {
|
||||
$entity->setChangedTime(REQUEST_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -336,7 +336,7 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Dyn
|
|||
$this->invokeHook('translation_insert', $entity->getTranslation($langcode));
|
||||
}
|
||||
elseif (!isset($translations[$langcode]) && isset($original_translations[$langcode])) {
|
||||
$this->invokeHook('translation_delete', $entity->getTranslation($langcode));
|
||||
$this->invokeHook('translation_delete', $entity->original->getTranslation($langcode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,17 +91,14 @@ class EntityViewController implements ContainerInjectionInterface {
|
|||
* @param string $view_mode
|
||||
* (optional) The view mode that should be used to display the entity.
|
||||
* Defaults to 'full'.
|
||||
* @param string $langcode
|
||||
* (optional) For which language the entity should be rendered, defaults to
|
||||
* the current content language.
|
||||
*
|
||||
* @return array
|
||||
* A render array as expected by drupal_render().
|
||||
*/
|
||||
public function view(EntityInterface $_entity, $view_mode = 'full', $langcode = NULL) {
|
||||
public function view(EntityInterface $_entity, $view_mode = 'full') {
|
||||
$page = $this->entityManager
|
||||
->getViewBuilder($_entity->getEntityTypeId())
|
||||
->view($_entity, $view_mode, $langcode);
|
||||
->view($_entity, $view_mode);
|
||||
|
||||
$page['#pre_render'][] = [$this, 'buildTitle'];
|
||||
$page['#entity_type'] = $_entity->getEntityTypeId();
|
||||
|
|
|
@ -155,7 +155,7 @@ class EntityAutocomplete extends Textfield {
|
|||
if ($match === NULL) {
|
||||
// Try to get a match from the input string when the user didn't use
|
||||
// the autocomplete but filled in a value manually.
|
||||
$match = $handler->validateAutocompleteInput($input, $element, $form_state, $complete_form, !$autocreate);
|
||||
$match = static::matchEntityByTitle($handler, $input, $element, $form_state, !$autocreate);
|
||||
}
|
||||
|
||||
if ($match !== NULL) {
|
||||
|
@ -202,6 +202,60 @@ class EntityAutocomplete extends Textfield {
|
|||
$form_state->setValueForElement($element, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an entity from an autocomplete input without an explicit ID.
|
||||
*
|
||||
* The method will return an entity ID if one single entity unambuguously
|
||||
* matches the incoming input, and sill assign form errors otherwise.
|
||||
*
|
||||
* @param string $input
|
||||
* Single string from autocomplete element.
|
||||
* @param array $element
|
||||
* The form element to set a form error.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current form state.
|
||||
* @param bool $strict
|
||||
* Whether to trigger a form error if an element from $input (eg. an entity)
|
||||
* is not found.
|
||||
*
|
||||
* @return integer|null
|
||||
* Value of a matching entity ID, or NULL if none.
|
||||
*/
|
||||
protected static function matchEntityByTitle($handler, $input, &$element, FormStateInterface $form_state, $strict) {
|
||||
$entities_by_bundle = $handler->getReferenceableEntities($input, '=', 6);
|
||||
$entities = array_reduce($entities_by_bundle, function ($flattened, $bundle_entities) {
|
||||
return $flattened + $bundle_entities;
|
||||
}, []);
|
||||
$params = array(
|
||||
'%value' => $input,
|
||||
'@value' => $input,
|
||||
);
|
||||
if (empty($entities)) {
|
||||
if ($strict) {
|
||||
// Error if there are no entities available for a required field.
|
||||
$form_state->setError($element, t('There are no entities matching "%value".', $params));
|
||||
}
|
||||
}
|
||||
elseif (count($entities) > 5) {
|
||||
$params['@id'] = key($entities);
|
||||
// Error if there are more than 5 matching entities.
|
||||
$form_state->setError($element, t('Many entities are called %value. Specify the one you want by appending the id in parentheses, like "@value (@id)".', $params));
|
||||
}
|
||||
elseif (count($entities) > 1) {
|
||||
// More helpful error if there are only a few matching entities.
|
||||
$multiples = array();
|
||||
foreach ($entities as $id => $name) {
|
||||
$multiples[] = $name . ' (' . $id . ')';
|
||||
}
|
||||
$params['@id'] = $id;
|
||||
$form_state->setError($element, t('Multiple entities match this reference; "%multiple". Specify the one you want by appending the id in parentheses, like "@value (@id)".', array('%multiple' => implode('", "', $multiples))));
|
||||
}
|
||||
else {
|
||||
// Take the one and only matching entity.
|
||||
return key($entities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of entity objects into a string of entity labels.
|
||||
*
|
||||
|
|
|
@ -311,9 +311,9 @@ abstract class Entity implements EntityInterface {
|
|||
->getAccessControlHandler($this->entityTypeId)
|
||||
->createAccess($this->bundle(), $account, [], $return_as_object);
|
||||
}
|
||||
return $this->entityManager()
|
||||
return $this->entityManager()
|
||||
->getAccessControlHandler($this->entityTypeId)
|
||||
->access($this, $operation, LanguageInterface::LANGCODE_DEFAULT, $account, $return_as_object);
|
||||
->access($this, $operation, $account, $return_as_object);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -181,6 +181,7 @@ class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayIn
|
|||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
// Reset the render cache for the target entity type.
|
||||
parent::postSave($storage, $update);
|
||||
if (\Drupal::entityManager()->hasHandler($this->targetEntityType, 'view_builder')) {
|
||||
\Drupal::entityManager()->getViewBuilder($this->targetEntityType)->resetCache();
|
||||
}
|
||||
|
@ -248,7 +249,7 @@ class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayIn
|
|||
$items = $grouped_items[$id];
|
||||
/** @var \Drupal\Core\Access\AccessResultInterface $field_access */
|
||||
$field_access = $items->access('view', NULL, TRUE);
|
||||
$build_list[$id][$name] = $field_access->isAllowed() ? $formatter->view($items) : [];
|
||||
$build_list[$id][$name] = $field_access->isAllowed() ? $formatter->view($items, $entity->language()->getId()) : [];
|
||||
// Apply the field access cacheability metadata to the render array.
|
||||
$this->renderer->addCacheableDependency($build_list[$id][$name], $field_access);
|
||||
}
|
||||
|
|
|
@ -53,8 +53,9 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(EntityInterface $entity, $operation, $langcode = LanguageInterface::LANGCODE_DEFAULT, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
public function access(EntityInterface $entity, $operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
$account = $this->prepareUser($account);
|
||||
$langcode = $entity->language()->getId();
|
||||
|
||||
if (($return = $this->getCache($entity->uuid(), $operation, $langcode, $account)) !== NULL) {
|
||||
// Cache hit, no work necessary.
|
||||
|
@ -71,8 +72,8 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
|
|||
// - No modules say to deny access.
|
||||
// - At least one module says to grant access.
|
||||
$access = array_merge(
|
||||
$this->moduleHandler()->invokeAll('entity_access', array($entity, $operation, $account, $langcode)),
|
||||
$this->moduleHandler()->invokeAll($entity->getEntityTypeId() . '_access', array($entity, $operation, $account, $langcode))
|
||||
$this->moduleHandler()->invokeAll('entity_access', [$entity, $operation, $account]),
|
||||
$this->moduleHandler()->invokeAll($entity->getEntityTypeId() . '_access', [$entity, $operation, $account])
|
||||
);
|
||||
|
||||
$return = $this->processAccessHookResults($access);
|
||||
|
@ -80,7 +81,7 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
|
|||
// Also execute the default access check except when the access result is
|
||||
// already forbidden, as in that case, it can not be anything else.
|
||||
if (!$return->isForbidden()) {
|
||||
$return = $return->orIf($this->checkAccess($entity, $operation, $langcode, $account));
|
||||
$return = $return->orIf($this->checkAccess($entity, $operation, $account));
|
||||
}
|
||||
$result = $this->setCache($return, $entity->uuid(), $operation, $langcode, $account);
|
||||
return $return_as_object ? $result : $result->isAllowed();
|
||||
|
@ -124,15 +125,13 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
|
|||
* The entity for which to check access.
|
||||
* @param string $operation
|
||||
* The entity operation. Usually one of 'view', 'update' or 'delete'.
|
||||
* @param string $langcode
|
||||
* The language code for which to check access.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The user for which to check access.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
if ($operation == 'delete' && $entity->isNew()) {
|
||||
return AccessResult::forbidden()->cacheUntilEntityChanges($entity);
|
||||
}
|
||||
|
|
|
@ -29,9 +29,6 @@ interface EntityAccessControlHandlerInterface {
|
|||
* @param string $operation
|
||||
* The operation access should be checked for.
|
||||
* Usually one of "view", "update" or "delete".
|
||||
* @param string $langcode
|
||||
* (optional) The language code for which to check access. Defaults to
|
||||
* LanguageInterface::LANGCODE_DEFAULT.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* (optional) The user session for which to check access, or NULL to check
|
||||
* access for the current user. Defaults to NULL.
|
||||
|
@ -45,7 +42,7 @@ interface EntityAccessControlHandlerInterface {
|
|||
* returned, i.e. TRUE means access is explicitly allowed, FALSE means
|
||||
* access is either explicitly forbidden or "no opinion".
|
||||
*/
|
||||
public function access(EntityInterface $entity, $operation, $langcode = LanguageInterface::LANGCODE_DEFAULT, AccountInterface $account = NULL, $return_as_object = FALSE);
|
||||
public function access(EntityInterface $entity, $operation, AccountInterface $account = NULL, $return_as_object = FALSE);
|
||||
|
||||
/**
|
||||
* Checks access to create an entity.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Drupal\Core\Entity;
|
||||
|
||||
/**
|
||||
* An interface for reacting to entity bundle creation, deletion, and renames.
|
||||
* An interface for reacting to entity bundle creation and deletion.
|
||||
*
|
||||
* @todo Convert to Symfony events: https://www.drupal.org/node/2332935
|
||||
*/
|
||||
|
@ -24,20 +24,6 @@ interface EntityBundleListenerInterface {
|
|||
*/
|
||||
public function onBundleCreate($bundle, $entity_type_id);
|
||||
|
||||
/**
|
||||
* Reacts to a bundle being renamed.
|
||||
*
|
||||
* This method runs before fields are updated with the new bundle name.
|
||||
*
|
||||
* @param string $bundle
|
||||
* The name of the bundle being renamed.
|
||||
* @param string $bundle_new
|
||||
* The new name of the bundle.
|
||||
* @param string $entity_type_id
|
||||
* The entity type to which the bundle is bound; e.g. 'node' or 'user'.
|
||||
*/
|
||||
public function onBundleRename($bundle, $bundle_new, $entity_type_id);
|
||||
|
||||
/**
|
||||
* Reacts to a bundle being deleted.
|
||||
*
|
||||
|
|
|
@ -29,6 +29,16 @@ interface EntityChangedInterface {
|
|||
*/
|
||||
public function getChangedTime();
|
||||
|
||||
/**
|
||||
* Sets the timestamp of the last entity change for the current translation.
|
||||
*
|
||||
* @param int $timestamp
|
||||
* The timestamp of the last entity save operation.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setChangedTime($timestamp);
|
||||
|
||||
/**
|
||||
* Gets the timestamp of the last entity change across all translations.
|
||||
*
|
||||
|
|
|
@ -28,4 +28,26 @@ trait EntityChangedTrait {
|
|||
return $changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timestamp of the last entity change for the current translation.
|
||||
*
|
||||
* @return int
|
||||
* The timestamp of the last entity save operation.
|
||||
*/
|
||||
public function getChangedTime() {
|
||||
return $this->get('changed')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp of the last entity change for the current translation.
|
||||
*
|
||||
* @param int $timestamp
|
||||
* The timestamp of the last entity save operation.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setChangedTime($timestamp) {
|
||||
$this->set('changed', $timestamp);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class EntityDeleteForm extends EntityConfirmFormBase {
|
|||
if (!($entity instanceof ConfigEntityInterface)) {
|
||||
return $form;
|
||||
}
|
||||
$this->addDependencyListsToForm($form, $entity->getConfigDependencyKey(), [$entity->getConfigDependencyName()], $this->getConfigManager(), $this->entityManager);
|
||||
$this->addDependencyListsToForm($form, $entity->getConfigDependencyKey(), $this->getConfigNamesToDelete($entity), $this->getConfigManager(), $this->entityManager);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
@ -49,4 +49,17 @@ class EntityDeleteForm extends EntityConfirmFormBase {
|
|||
return \Drupal::service('config.manager');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns config names to delete for the deletion confirmation form.
|
||||
*
|
||||
* @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
|
||||
* The entity being deleted.
|
||||
*
|
||||
* @return string[]
|
||||
* A list of configuration names that will be deleted by this form.
|
||||
*/
|
||||
protected function getConfigNamesToDelete(ConfigEntityInterface $entity) {
|
||||
return [$entity->getConfigDependencyName()];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -278,7 +278,7 @@ abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDispl
|
|||
$mode_entity = $this->entityManager()->getStorage('entity_' . $this->displayContext . '_mode')->load($target_entity_type->id() . '.' . $this->mode);
|
||||
$this->addDependency('config', $mode_entity->getConfigDependencyName());
|
||||
}
|
||||
return $this->dependencies;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -428,18 +428,87 @@ abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDispl
|
|||
}
|
||||
}
|
||||
foreach ($this->getComponents() as $name => $component) {
|
||||
if (isset($component['type']) && $definition = $this->pluginManager->getDefinition($component['type'], FALSE)) {
|
||||
if (in_array($definition['provider'], $dependencies['module'])) {
|
||||
if ($renderer = $this->getRenderer($name)) {
|
||||
if (in_array($renderer->getPluginDefinition()['provider'], $dependencies['module'])) {
|
||||
// Revert to the defaults if the plugin that supplies the widget or
|
||||
// formatter depends on a module that is being uninstalled.
|
||||
$this->setComponent($name);
|
||||
$changed = TRUE;
|
||||
}
|
||||
|
||||
// Give this component the opportunity to react on dependency removal.
|
||||
$component_removed_dependencies = $this->getPluginRemovedDependencies($renderer->calculateDependencies(), $dependencies);
|
||||
if ($component_removed_dependencies) {
|
||||
if ($renderer->onDependencyRemoval($component_removed_dependencies)) {
|
||||
// Update component settings to reflect changes.
|
||||
$component['settings'] = $renderer->getSettings();
|
||||
$component['third_party_settings'] = [];
|
||||
foreach ($renderer->getThirdPartyProviders() as $module) {
|
||||
$component['third_party_settings'][$module] = $renderer->getThirdPartySettings($module);
|
||||
}
|
||||
$this->setComponent($name, $component);
|
||||
$changed = TRUE;
|
||||
}
|
||||
// If there are unresolved deleted dependencies left, disable this
|
||||
// component to avoid the removal of the entire display entity.
|
||||
if ($this->getPluginRemovedDependencies($renderer->calculateDependencies(), $dependencies)) {
|
||||
$this->removeComponent($name);
|
||||
$arguments = [
|
||||
'@display' => (string) $this->getEntityType()->getLabel(),
|
||||
'@id' => $this->id(),
|
||||
'@name' => $name,
|
||||
];
|
||||
$this->getLogger()->warning("@display '@id': Component '@name' was disabled because its settings depend on removed dependencies.", $arguments);
|
||||
$changed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin dependencies being removed.
|
||||
*
|
||||
* The function recursively computes the intersection between all plugin
|
||||
* dependencies and all removed dependencies.
|
||||
*
|
||||
* Note: The two arguments do not have the same structure.
|
||||
*
|
||||
* @param array[] $plugin_dependencies
|
||||
* A list of dependencies having the same structure as the return value of
|
||||
* ConfigEntityInterface::calculateDependencies().
|
||||
* @param array[] $removed_dependencies
|
||||
* A list of dependencies having the same structure as the input argument of
|
||||
* ConfigEntityInterface::onDependencyRemoval().
|
||||
*
|
||||
* @return array
|
||||
* A recursively computed intersection.
|
||||
*
|
||||
* @see \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies()
|
||||
* @see \Drupal\Core\Config\Entity\ConfigEntityInterface::onDependencyRemoval()
|
||||
*/
|
||||
protected function getPluginRemovedDependencies(array $plugin_dependencies, array $removed_dependencies) {
|
||||
$intersect = [];
|
||||
foreach ($plugin_dependencies as $type => $dependencies) {
|
||||
if ($removed_dependencies[$type]) {
|
||||
// Config and content entities have the dependency names as keys while
|
||||
// module and theme dependencies are indexed arrays of dependency names.
|
||||
// @see \Drupal\Core\Config\ConfigManager::callOnDependencyRemoval()
|
||||
if (in_array($type, ['config', 'content'])) {
|
||||
$removed = array_intersect_key($removed_dependencies[$type], array_flip($dependencies));
|
||||
}
|
||||
else {
|
||||
$removed = array_values(array_intersect($removed_dependencies[$type], $dependencies));
|
||||
}
|
||||
if ($removed) {
|
||||
$intersect[$type] = $removed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $intersect;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -471,4 +540,14 @@ abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDispl
|
|||
$this->__construct($values, $this->entityTypeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the 'system' channel logger service.
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
* The 'system' channel logger.
|
||||
*/
|
||||
protected function getLogger() {
|
||||
return \Drupal::logger('system');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ abstract class EntityDisplayModeBase extends ConfigEntityBase implements EntityD
|
|||
parent::calculateDependencies();
|
||||
$target_entity_type = \Drupal::entityManager()->getDefinition($this->targetEntityType);
|
||||
$this->addDependency('module', $target_entity_type->getProvider());
|
||||
return $this->dependencies;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -240,10 +240,19 @@ interface EntityInterface extends AccessibleInterface, CacheableDependencyInterf
|
|||
/**
|
||||
* Acts on an entity before the presave hook is invoked.
|
||||
*
|
||||
* Used before the entity is saved and before invoking the presave hook.
|
||||
* Used before the entity is saved and before invoking the presave hook. Note
|
||||
* that in case of translatable content entities this callback is only fired
|
||||
* on their current translation. It is up to the developer to iterate
|
||||
* over all translations if needed. This is different from its counterpart in
|
||||
* the Field API, FieldItemListInterface::preSave(), which is fired on all
|
||||
* field translations automatically.
|
||||
* @todo Adjust existing implementations and the documentation according to
|
||||
* https://www.drupal.org/node/2577609 to have a consistent API.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage object.
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldItemListInterface::preSave()
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage);
|
||||
|
||||
|
@ -251,7 +260,9 @@ interface EntityInterface extends AccessibleInterface, CacheableDependencyInterf
|
|||
* Acts on a saved entity before the insert or update hook is invoked.
|
||||
*
|
||||
* Used after the entity is saved, but before invoking the insert or update
|
||||
* hook.
|
||||
* hook. Note that in case of translatable content entities this callback is
|
||||
* only fired on their current translation. It is up to the developer to
|
||||
* iterate over all translations if needed.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage object.
|
||||
|
|
|
@ -228,6 +228,7 @@ class EntityListBuilder extends EntityHandlerBase implements EntityListBuilderIn
|
|||
'#empty' => $this->t('There is no @label yet.', array('@label' => $this->entityType->getLabel())),
|
||||
'#cache' => [
|
||||
'contexts' => $this->entityType->getListCacheContexts(),
|
||||
'tags' => $this->entityType->getListCacheTags(),
|
||||
],
|
||||
);
|
||||
foreach ($this->load() as $entity) {
|
||||
|
|
|
@ -32,7 +32,7 @@ use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
|
|||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Core\TypedData\TranslatableInterface;
|
||||
use Drupal\Core\TypedData\TypedDataManager;
|
||||
use Drupal\Core\TypedData\TypedDataManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
@ -111,7 +111,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
/**
|
||||
* The typed data manager.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\TypedDataManager
|
||||
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
|
||||
*/
|
||||
protected $typedDataManager;
|
||||
|
||||
|
@ -193,14 +193,14 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
* The string translationManager.
|
||||
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
|
||||
* The class resolver.
|
||||
* @param \Drupal\Core\TypedData\TypedDataManager $typed_data_manager
|
||||
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
|
||||
* The typed data manager.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
|
||||
* The keyvalue factory.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* The event dispatcher.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManager $typed_data_manager, KeyValueFactoryInterface $key_value_factory, EventDispatcherInterface $event_dispatcher) {
|
||||
public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManagerInterface $typed_data_manager, KeyValueFactoryInterface $key_value_factory, EventDispatcherInterface $event_dispatcher) {
|
||||
parent::__construct('Entity', $namespaces, $module_handler, 'Drupal\Core\Entity\EntityInterface');
|
||||
|
||||
$this->setCacheBackend($cache, 'entity_type', array('entity_types'));
|
||||
|
@ -945,7 +945,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
|
||||
foreach ($definitions as $entity_type_id => $definition) {
|
||||
if ($group) {
|
||||
$options[$definition->getGroupLabel()][$entity_type_id] = $definition->getLabel();
|
||||
$options[(string) $definition->getGroupLabel()][$entity_type_id] = $definition->getLabel();
|
||||
}
|
||||
else {
|
||||
$options[$entity_type_id] = $definition->getLabel();
|
||||
|
@ -960,7 +960,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
|
||||
// Make sure that the 'Content' group is situated at the top.
|
||||
$content = $this->t('Content', array(), array('context' => 'Entity type group'));
|
||||
$options = array($content => $options[$content]) + $options;
|
||||
$options = array((string) $content => $options[(string) $content]) + $options;
|
||||
}
|
||||
|
||||
return $options;
|
||||
|
@ -1088,15 +1088,29 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewModeOptions($entity_type, $include_disabled = FALSE) {
|
||||
return $this->getDisplayModeOptions('view_mode', $entity_type, $include_disabled);
|
||||
public function getViewModeOptions($entity_type_id) {
|
||||
return $this->getDisplayModeOptions('view_mode', $entity_type_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormModeOptions($entity_type, $include_disabled = FALSE) {
|
||||
return $this->getDisplayModeOptions('form_mode', $entity_type, $include_disabled);
|
||||
public function getFormModeOptions($entity_type_id) {
|
||||
return $this->getDisplayModeOptions('form_mode', $entity_type_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewModeOptionsByBundle($entity_type_id, $bundle) {
|
||||
return $this->getDisplayModeOptionsByBundle('view_mode', $entity_type_id, $bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormModeOptionsByBundle($entity_type_id, $bundle) {
|
||||
return $this->getDisplayModeOptionsByBundle('form_mode', $entity_type_id, $bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1106,19 +1120,55 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
* The display type to be retrieved. It can be "view_mode" or "form_mode".
|
||||
* @param string $entity_type_id
|
||||
* The entity type whose display mode options should be returned.
|
||||
* @param bool $include_disabled
|
||||
* Force to include disabled display modes. Defaults to FALSE.
|
||||
*
|
||||
* @return array
|
||||
* An array of display mode labels, keyed by the display mode ID.
|
||||
*/
|
||||
protected function getDisplayModeOptions($display_type, $entity_type_id, $include_disabled = FALSE) {
|
||||
protected function getDisplayModeOptions($display_type, $entity_type_id) {
|
||||
$options = array('default' => t('Default'));
|
||||
foreach ($this->getDisplayModesByEntityType($display_type, $entity_type_id) as $mode => $settings) {
|
||||
if (!empty($settings['status']) || $include_disabled) {
|
||||
$options[$mode] = $settings['label'];
|
||||
$options[$mode] = $settings['label'];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of display mode options by bundle.
|
||||
*
|
||||
* @param $display_type
|
||||
* The display type to be retrieved. It can be "view_mode" or "form_mode".
|
||||
* @param string $entity_type_id
|
||||
* The entity type whose display mode options should be returned.
|
||||
* @param string $bundle
|
||||
* The name of the bundle.
|
||||
*
|
||||
* @return array
|
||||
* An array of display mode labels, keyed by the display mode ID.
|
||||
*/
|
||||
protected function getDisplayModeOptionsByBundle($display_type, $entity_type_id, $bundle) {
|
||||
// Collect all the entity's display modes.
|
||||
$options = $this->getDisplayModeOptions($display_type, $entity_type_id);
|
||||
|
||||
// Filter out modes for which the entity display is disabled
|
||||
// (or non-existent).
|
||||
$load_ids = array();
|
||||
// Get the list of available entity displays for the current bundle.
|
||||
foreach (array_keys($options) as $mode) {
|
||||
$load_ids[] = $entity_type_id . '.' . $bundle . '.' . $mode;
|
||||
}
|
||||
|
||||
// Load the corresponding displays.
|
||||
$displays = $this->getStorage($display_type == 'form_mode' ? 'entity_form_display' : 'entity_view_display')
|
||||
->loadMultiple($load_ids);
|
||||
|
||||
// Unset the display modes that are not active or do not exist.
|
||||
foreach (array_keys($options) as $mode) {
|
||||
$display_id = $entity_type_id . '.' . $bundle . '.' . $mode;
|
||||
if (!isset($displays[$display_id]) || !$displays[$display_id]->status()) {
|
||||
unset($options[$mode]);
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
|
@ -1317,31 +1367,6 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
$this->moduleHandler->invokeAll('entity_bundle_create', array($entity_type_id, $bundle));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onBundleRename($bundle_old, $bundle_new, $entity_type_id) {
|
||||
$this->clearCachedBundles();
|
||||
// Notify the entity storage.
|
||||
$storage = $this->getStorage($entity_type_id);
|
||||
if ($storage instanceof EntityBundleListenerInterface) {
|
||||
$storage->onBundleRename($bundle_old, $bundle_new, $entity_type_id);
|
||||
}
|
||||
|
||||
// Rename existing base field bundle overrides.
|
||||
$overrides = $this->getStorage('base_field_override')->loadByProperties(array('entity_type' => $entity_type_id, 'bundle' => $bundle_old));
|
||||
foreach ($overrides as $override) {
|
||||
$override->set('id', $entity_type_id . '.' . $bundle_new . '.' . $override->getName());
|
||||
$override->set('bundle', $bundle_new);
|
||||
$override->allowBundleRename();
|
||||
$override->save();
|
||||
}
|
||||
|
||||
// Invoke hook_entity_bundle_rename() hook.
|
||||
$this->moduleHandler->invokeAll('entity_bundle_rename', array($entity_type_id, $bundle_old, $bundle_new));
|
||||
$this->clearCachedFieldDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -252,9 +252,9 @@ interface EntityManagerInterface extends PluginManagerInterface, EntityTypeListe
|
|||
* Creates a new handler instance for a entity type and handler type.
|
||||
*
|
||||
* @param string $entity_type
|
||||
* The entity type for this controller.
|
||||
* The entity type for this handler.
|
||||
* @param string $handler_type
|
||||
* The controller type to create an instance for.
|
||||
* The handler type to create an instance for.
|
||||
*
|
||||
* @return object
|
||||
* A handler instance.
|
||||
|
@ -432,26 +432,48 @@ interface EntityManagerInterface extends PluginManagerInterface, EntityTypeListe
|
|||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type whose view mode options should be returned.
|
||||
* @param bool $include_disabled
|
||||
* Force to include disabled view modes. Defaults to FALSE.
|
||||
*
|
||||
* @return array
|
||||
* An array of view mode labels, keyed by the display mode ID.
|
||||
*/
|
||||
public function getViewModeOptions($entity_type_id, $include_disabled = FALSE);
|
||||
public function getViewModeOptions($entity_type_id);
|
||||
|
||||
/**
|
||||
* Gets an array of form mode options.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type whose form mode options should be returned.
|
||||
* @param bool $include_disabled
|
||||
* Force to include disabled form modes. Defaults to FALSE.
|
||||
*
|
||||
* @return array
|
||||
* An array of form mode labels, keyed by the display mode ID.
|
||||
*/
|
||||
public function getFormModeOptions($entity_type_id, $include_disabled = FALSE);
|
||||
public function getFormModeOptions($entity_type_id);
|
||||
|
||||
/**
|
||||
* Returns an array of view mode options by bundle.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type whose view mode options should be returned.
|
||||
* @param string $bundle
|
||||
* The name of the bundle.
|
||||
*
|
||||
* @return array
|
||||
* An array of view mode labels, keyed by the display mode ID.
|
||||
*/
|
||||
public function getViewModeOptionsByBundle($entity_type_id, $bundle);
|
||||
|
||||
/**
|
||||
* Returns an array of form mode options by bundle.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type whose form mode options should be returned.
|
||||
* @param string $bundle
|
||||
* The name of the bundle.
|
||||
*
|
||||
* @return array
|
||||
* An array of form mode labels, keyed by the display mode ID.
|
||||
*/
|
||||
public function getFormModeOptionsByBundle($entity_type_id, $bundle);
|
||||
|
||||
/**
|
||||
* Loads an entity by UUID.
|
||||
|
|
|
@ -8,16 +8,13 @@
|
|||
namespace Drupal\Core\Entity\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\PluginFormInterface;
|
||||
|
||||
/**
|
||||
* Interface definition for Entity Reference Selection plugins.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager
|
||||
* @see \Drupal\Core\Entity\Annotation\EntityReferenceSelection
|
||||
* @see \Drupal\Core\Entity\Plugin\Derivative\SelectionBase
|
||||
* @see plugin_api
|
||||
*/
|
||||
interface SelectionInterface extends PluginFormInterface {
|
||||
|
@ -27,7 +24,7 @@ interface SelectionInterface extends PluginFormInterface {
|
|||
*
|
||||
* @return array
|
||||
* A nested array of entities, the first level is keyed by the
|
||||
* entity bundle, which contains an array of entity labels (safe HTML),
|
||||
* entity bundle, which contains an array of entity labels (escaped),
|
||||
* keyed by the entity ID.
|
||||
*/
|
||||
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0);
|
||||
|
@ -48,28 +45,6 @@ interface SelectionInterface extends PluginFormInterface {
|
|||
*/
|
||||
public function validateReferenceableEntities(array $ids);
|
||||
|
||||
/**
|
||||
* Validates input from an autocomplete widget that has no ID.
|
||||
*
|
||||
* @param string $input
|
||||
* Single string from autocomplete widget.
|
||||
* @param array $element
|
||||
* The form element to set a form error.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current form state.
|
||||
* @param array $form
|
||||
* The form.
|
||||
* @param bool $strict
|
||||
* Whether to trigger a form error if an element from $input (eg. an entity)
|
||||
* is not found. Defaults to TRUE.
|
||||
*
|
||||
* @return integer|null
|
||||
* Value of a matching entity ID, or NULL if none.
|
||||
*
|
||||
* @see \Drupal\entity_reference\Plugin\Field\FieldWidget::elementValidate()
|
||||
*/
|
||||
public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE);
|
||||
|
||||
/**
|
||||
* Allows the selection to alter the SelectQuery generated by EntityFieldQuery.
|
||||
*
|
||||
|
|
|
@ -19,8 +19,6 @@ use Drupal\Core\Plugin\DefaultPluginManager;
|
|||
*
|
||||
* @see \Drupal\Core\Entity\Annotation\EntityReferenceSelection
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface
|
||||
* @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase
|
||||
* @see \Drupal\Core\Entity\Plugin\Derivative\SelectionBase
|
||||
* @see plugin_api
|
||||
*/
|
||||
class SelectionPluginManager extends DefaultPluginManager implements SelectionPluginManagerInterface, FallbackPluginManagerInterface {
|
||||
|
|
|
@ -351,20 +351,26 @@ abstract class EntityStorageBase extends EntityHandlerBase implements EntityStor
|
|||
return;
|
||||
}
|
||||
|
||||
// Ensure that the entities are keyed by ID.
|
||||
$keyed_entities = [];
|
||||
foreach ($entities as $entity) {
|
||||
$keyed_entities[$entity->id()] = $entity;
|
||||
}
|
||||
|
||||
// Allow code to run before deleting.
|
||||
$entity_class = $this->entityClass;
|
||||
$entity_class::preDelete($this, $entities);
|
||||
foreach ($entities as $entity) {
|
||||
$entity_class::preDelete($this, $keyed_entities);
|
||||
foreach ($keyed_entities as $entity) {
|
||||
$this->invokeHook('predelete', $entity);
|
||||
}
|
||||
|
||||
// Perform the delete and reset the static cache for the deleted entities.
|
||||
$this->doDelete($entities);
|
||||
$this->resetCache(array_keys($entities));
|
||||
$this->doDelete($keyed_entities);
|
||||
$this->resetCache(array_keys($keyed_entities));
|
||||
|
||||
// Allow code to run after deleting.
|
||||
$entity_class::postDelete($this, $entities);
|
||||
foreach ($entities as $entity) {
|
||||
$entity_class::postDelete($this, $keyed_entities);
|
||||
foreach ($keyed_entities as $entity) {
|
||||
$this->invokeHook('delete', $entity);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,15 @@ class EntityType implements EntityTypeInterface {
|
|||
/**
|
||||
* The name of a callback that returns the label of the entity.
|
||||
*
|
||||
* @var string|null
|
||||
* @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;
|
||||
|
||||
|
@ -688,7 +696,7 @@ class EntityType implements EntityTypeInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLabel() {
|
||||
return (string) $this->label;
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -725,7 +733,7 @@ class EntityType implements EntityTypeInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getGroupLabel() {
|
||||
return !empty($this->group_label) ? (string) $this->group_label : $this->t('Other', array(), array('context' => 'Entity type group'));
|
||||
return !empty($this->group_label) ? $this->group_label : $this->t('Other', array(), array('context' => 'Entity type group'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
namespace Drupal\Core\Entity;
|
||||
|
||||
use Drupal\Component\Plugin\Definition\PluginDefinitionInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for an entity type and its metadata.
|
||||
*
|
||||
|
@ -15,7 +17,7 @@ namespace Drupal\Core\Entity;
|
|||
* implemented to alter existing data and fill-in defaults. Module-specific
|
||||
* properties should be documented in the hook implementations defining them.
|
||||
*/
|
||||
interface EntityTypeInterface {
|
||||
interface EntityTypeInterface extends PluginDefinitionInterface {
|
||||
|
||||
/**
|
||||
* The maximum length of ID, in characters.
|
||||
|
@ -66,14 +68,6 @@ interface EntityTypeInterface {
|
|||
*/
|
||||
public function getProvider();
|
||||
|
||||
/**
|
||||
* Gets the name of the entity type class.
|
||||
*
|
||||
* @return string
|
||||
* The name of the entity type class.
|
||||
*/
|
||||
public function getClass();
|
||||
|
||||
/**
|
||||
* Gets the name of the original entity type class.
|
||||
*
|
||||
|
@ -108,8 +102,8 @@ interface EntityTypeInterface {
|
|||
* - label: (optional) 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).
|
||||
* logic is required to build the label,
|
||||
* \Drupal\Core\Entity\EntityInterface::label() should be used.
|
||||
* - langcode: (optional) The name of the property that contains the
|
||||
* language code. For instance, if the entity's language is located in
|
||||
* $entity->langcode, then 'langcode' should be specified here.
|
||||
|
@ -170,16 +164,6 @@ interface EntityTypeInterface {
|
|||
*/
|
||||
public function isPersistentlyCacheable();
|
||||
|
||||
/**
|
||||
* Sets the name of the entity type class.
|
||||
*
|
||||
* @param string $class
|
||||
* The name of the entity type class.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setClass($class);
|
||||
|
||||
/**
|
||||
* Determines if there is a handler for a given type.
|
||||
*
|
||||
|
@ -493,15 +477,23 @@ interface EntityTypeInterface {
|
|||
* 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.
|
||||
* 'entity_keys' return value component to provide this information. 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.
|
||||
*
|
||||
* @return callable|null
|
||||
* The callback, or NULL if none exists.
|
||||
*
|
||||
* @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()
|
||||
* @see \Drupal\Core\Entity\EntityTypeInterface::setLabelCallback()
|
||||
* @see \Drupal\Core\Entity\EntityTypeInterface::hasLabelCallback()
|
||||
*
|
||||
* @todo Remove usages of label_callback https://www.drupal.org/node/2450793.
|
||||
*/
|
||||
public function getLabelCallback();
|
||||
|
||||
|
@ -512,6 +504,13 @@ interface EntityTypeInterface {
|
|||
* A callable that returns the label of the entity.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated in Drupal 8.0.x-dev and will be removed before Drupal 9.0.0.
|
||||
* Use EntityInterface::label() for complex label generation as needed.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityInterface::label()
|
||||
* @see \Drupal\Core\Entity\EntityTypeInterface::getLabelCallback()
|
||||
* @see \Drupal\Core\Entity\EntityTypeInterface::hasLabelCallback()
|
||||
*/
|
||||
public function setLabelCallback($callback);
|
||||
|
||||
|
@ -519,6 +518,13 @@ interface EntityTypeInterface {
|
|||
* Indicates if a label callback exists.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated in Drupal 8.0.x-dev and will be removed before Drupal 9.0.0.
|
||||
* Use EntityInterface::label() for complex label generation as needed.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityInterface::label()
|
||||
* @see \Drupal\Core\Entity\EntityTypeInterface::getLabelCallback()
|
||||
* @see \Drupal\Core\Entity\EntityTypeInterface::setLabelCallback()
|
||||
*/
|
||||
public function hasLabelCallback();
|
||||
|
||||
|
@ -645,6 +651,20 @@ interface EntityTypeInterface {
|
|||
*/
|
||||
public function setUriCallback($callback);
|
||||
|
||||
/**
|
||||
* Gets the machine name of the entity type group.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGroup();
|
||||
|
||||
/**
|
||||
* Gets the human-readable name of the entity type group.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGroupLabel();
|
||||
|
||||
/**
|
||||
* The list cache contexts associated with this entity type.
|
||||
*
|
||||
|
|
|
@ -12,10 +12,9 @@ use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
|||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\Core\Field\FieldItemInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\TypedData\TranslatableInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\TypedData\TranslatableInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -120,7 +119,6 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
$build_list = array(
|
||||
'#sorted' => TRUE,
|
||||
'#pre_render' => array(array($this, 'buildMultiple')),
|
||||
'#langcode' => $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(),
|
||||
);
|
||||
$weight = 0;
|
||||
foreach ($entities as $key => $entity) {
|
||||
|
@ -129,10 +127,9 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
$entity = $this->entityManager->getTranslationFromContext($entity, $langcode);
|
||||
|
||||
// Set build defaults.
|
||||
$entity_langcode = $entity->language()->getId();
|
||||
$build_list[$key] = $this->getBuildDefaults($entity, $view_mode, $entity_langcode);
|
||||
$build_list[$key] = $this->getBuildDefaults($entity, $view_mode);
|
||||
$entityType = $this->entityTypeId;
|
||||
$this->moduleHandler()->alter(array($entityType . '_build_defaults', 'entity_build_defaults'), $build_list[$key], $entity, $view_mode, $entity_langcode);
|
||||
$this->moduleHandler()->alter(array($entityType . '_build_defaults', 'entity_build_defaults'), $build_list[$key], $entity, $view_mode);
|
||||
|
||||
$build_list[$key]['#weight'] = $weight++;
|
||||
}
|
||||
|
@ -147,22 +144,18 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
* The entity for which the defaults should be provided.
|
||||
* @param string $view_mode
|
||||
* The view mode that should be used.
|
||||
* @param string $langcode
|
||||
* For which language the entity should be prepared, defaults to
|
||||
* the current content language.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) {
|
||||
protected function getBuildDefaults(EntityInterface $entity, $view_mode) {
|
||||
// Allow modules to change the view mode.
|
||||
$context = array('langcode' => $langcode);
|
||||
$context = [];
|
||||
$this->moduleHandler()->alter('entity_view_mode', $view_mode, $entity, $context);
|
||||
|
||||
$build = array(
|
||||
'#theme' => $this->entityTypeId,
|
||||
"#{$this->entityTypeId}" => $entity,
|
||||
'#view_mode' => $view_mode,
|
||||
'#langcode' => $langcode,
|
||||
// Collect cache defaults for this entity.
|
||||
'#cache' => array(
|
||||
'tags' => Cache::mergeTags($this->getCacheTags(), $entity->getCacheTags()),
|
||||
|
@ -185,7 +178,7 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
);
|
||||
|
||||
if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
|
||||
$build['#cache']['keys'][] = $langcode;
|
||||
$build['#cache']['keys'][] = $entity->language()->getId();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,10 +204,7 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
* @see drupal_render()
|
||||
*/
|
||||
public function build(array $build) {
|
||||
$build_list = array(
|
||||
'#langcode' => $build['#langcode'],
|
||||
);
|
||||
$build_list[] = $build;
|
||||
$build_list = [$build];
|
||||
$build_list = $this->buildMultiple($build_list);
|
||||
return $build_list[0];
|
||||
}
|
||||
|
@ -240,7 +230,6 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
public function buildMultiple(array $build_list) {
|
||||
// Build the view modes and display objects.
|
||||
$view_modes = array();
|
||||
$langcode = $build_list['#langcode'];
|
||||
$entity_type_key = "#{$this->entityTypeId}";
|
||||
$view_hook = "{$this->entityTypeId}_view";
|
||||
|
||||
|
@ -259,16 +248,16 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
// Build content for the displays represented by the entities.
|
||||
foreach ($view_modes as $view_mode => $view_mode_entities) {
|
||||
$displays = EntityViewDisplay::collectRenderDisplays($view_mode_entities, $view_mode);
|
||||
$this->buildComponents($build_list, $view_mode_entities, $displays, $view_mode, $langcode);
|
||||
$this->buildComponents($build_list, $view_mode_entities, $displays, $view_mode);
|
||||
foreach (array_keys($view_mode_entities) as $key) {
|
||||
// Allow for alterations while building, before rendering.
|
||||
$entity = $build_list[$key][$entity_type_key];
|
||||
$display = $displays[$entity->bundle()];
|
||||
|
||||
$this->moduleHandler()->invokeAll($view_hook, array(&$build_list[$key], $entity, $display, $view_mode, $langcode));
|
||||
$this->moduleHandler()->invokeAll('entity_view', array(&$build_list[$key], $entity, $display, $view_mode, $langcode));
|
||||
$this->moduleHandler()->invokeAll($view_hook, [&$build_list[$key], $entity, $display, $view_mode]);
|
||||
$this->moduleHandler()->invokeAll('entity_view', [&$build_list[$key], $entity, $display, $view_mode]);
|
||||
|
||||
$this->alterBuild($build_list[$key], $entity, $display, $view_mode, $langcode);
|
||||
$this->alterBuild($build_list[$key], $entity, $display, $view_mode);
|
||||
|
||||
// Assign the weights configured in the display.
|
||||
// @todo: Once https://www.drupal.org/node/1875974 provides the missing
|
||||
|
@ -291,7 +280,7 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildComponents(array &$build, array $entities, array $displays, $view_mode, $langcode = NULL) {
|
||||
public function buildComponents(array &$build, array $entities, array $displays, $view_mode) {
|
||||
$entities_by_bundle = array();
|
||||
foreach ($entities as $id => $entity) {
|
||||
// Initialize the field item attributes for the fields being displayed.
|
||||
|
@ -335,11 +324,8 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
|||
* entity components.
|
||||
* @param string $view_mode
|
||||
* The view mode that should be used to prepare the entity.
|
||||
* @param string $langcode
|
||||
* (optional) For which language the entity should be prepared, defaults to
|
||||
* the current content language.
|
||||
*/
|
||||
protected function alterBuild(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode, $langcode = NULL) { }
|
||||
protected function alterBuild(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
|
|
@ -29,11 +29,8 @@ interface EntityViewBuilderInterface {
|
|||
* configured for the entity components, keyed by bundle name.
|
||||
* @param string $view_mode
|
||||
* The view mode in which the entity is being viewed.
|
||||
* @param string $langcode
|
||||
* (optional) For which language the entity should be build, defaults to
|
||||
* the current content language.
|
||||
*/
|
||||
public function buildComponents(array &$build, array $entities, array $displays, $view_mode, $langcode = NULL);
|
||||
public function buildComponents(array &$build, array $entities, array $displays, $view_mode);
|
||||
|
||||
/**
|
||||
* Builds the render array for the provided entity.
|
||||
|
|
|
@ -146,10 +146,7 @@ class KeyValueEntityStorage extends EntityStorageBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function doDelete($entities) {
|
||||
$entity_ids = array();
|
||||
foreach ($entities as $entity) {
|
||||
$entity_ids[] = $entity->id();
|
||||
}
|
||||
$entity_ids = array_keys($entities);
|
||||
$this->keyValueStore->deleteMultiple($entity_ids);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\Plugin\Derivative\SelectionBase.
|
||||
* Contains \Drupal\Core\Entity\Plugin\Derivative\DefaultSelectionDeriver.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity\Plugin\Derivative;
|
||||
|
@ -13,15 +13,15 @@ use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
|||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides derivative plugins for Entity Reference Selection plugins.
|
||||
* Provides derivative plugins for the DefaultSelection plugin.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase
|
||||
* @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager
|
||||
* @see \Drupal\Core\Entity\Annotation\EntityReferenceSelection
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface
|
||||
* @see plugin_api
|
||||
*/
|
||||
class SelectionBase extends DeriverBase implements ContainerDeriverInterface {
|
||||
class DefaultSelectionDeriver extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* The entity manager
|
||||
|
@ -58,7 +58,20 @@ class SelectionBase extends DeriverBase implements ContainerDeriverInterface {
|
|||
$this->derivatives[$entity_type_id]['entity_types'] = array($entity_type_id);
|
||||
$this->derivatives[$entity_type_id]['label'] = t('@entity_type selection', array('@entity_type' => $entity_type->getLabel()));
|
||||
$this->derivatives[$entity_type_id]['base_plugin_label'] = (string) $base_plugin_definition['label'];
|
||||
|
||||
// If the entity type doesn't provide a 'label' key in its plugin
|
||||
// definition, we have to use the alternate PhpSelection class as default
|
||||
// plugin, which allows filtering the target entities by their label()
|
||||
// method. The major downside of PhpSelection is that it is more expensive
|
||||
// performance-wise than SelectionBase because it has to load all the
|
||||
// target entities in order to perform the filtering process, regardless
|
||||
// of whether a limit has been passed.
|
||||
// @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\PhpSelection
|
||||
if (!$entity_type->hasKey('label')) {
|
||||
$this->derivatives[$entity_type_id]['class'] = 'Drupal\Core\Entity\Plugin\EntityReferenceSelection\PhpSelection';
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getDerivativeDefinitions($base_plugin_definition);
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ namespace Drupal\Core\Entity\Plugin\EntityReferenceSelection;
|
|||
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
|
@ -63,11 +62,6 @@ class Broken implements SelectionInterface {
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Database\Query\AlterableInterface;
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Default plugin implementation of the Entity Reference Selection plugin.
|
||||
*
|
||||
* Also serves as a base class for specific types of Entity Reference
|
||||
* Selection plugins.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager
|
||||
* @see \Drupal\Core\Entity\Annotation\EntityReferenceSelection
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface
|
||||
* @see \Drupal\Core\Entity\Plugin\Derivative\DefaultSelectionDeriver
|
||||
* @see plugin_api
|
||||
*
|
||||
* @EntityReferenceSelection(
|
||||
* id = "default",
|
||||
* label = @Translation("Default"),
|
||||
* group = "default",
|
||||
* weight = 0,
|
||||
* deriver = "Drupal\Core\Entity\Plugin\Derivative\DefaultSelectionDeriver"
|
||||
* )
|
||||
*/
|
||||
class DefaultSelection extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs a new SelectionBase object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$entity_type_id = $this->configuration['target_type'];
|
||||
$selection_handler_settings = $this->configuration['handler_settings'];
|
||||
$entity_type = $this->entityManager->getDefinition($entity_type_id);
|
||||
$bundles = $this->entityManager->getBundleInfo($entity_type_id);
|
||||
|
||||
// Merge-in default values.
|
||||
$selection_handler_settings += array(
|
||||
// For the 'target_bundles' setting, a NULL value is equivalent to "allow
|
||||
// entities from any bundle to be referenced" and an empty array value is
|
||||
// equivalent to "no entities from any bundle can be referenced".
|
||||
'target_bundles' => NULL,
|
||||
'sort' => array(
|
||||
'field' => '_none',
|
||||
),
|
||||
'auto_create' => FALSE,
|
||||
);
|
||||
|
||||
if ($entity_type->hasKey('bundle')) {
|
||||
$bundle_options = array();
|
||||
foreach ($bundles as $bundle_name => $bundle_info) {
|
||||
$bundle_options[$bundle_name] = $bundle_info['label'];
|
||||
}
|
||||
|
||||
$form['target_bundles'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Bundles'),
|
||||
'#options' => $bundle_options,
|
||||
'#default_value' => (array) $selection_handler_settings['target_bundles'],
|
||||
'#required' => TRUE,
|
||||
'#size' => 6,
|
||||
'#multiple' => TRUE,
|
||||
'#element_validate' => [[get_class($this), 'elementValidateFilter']],
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['target_bundles'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
if ($entity_type->isSubclassOf('\Drupal\Core\Entity\FieldableEntityInterface')) {
|
||||
$fields = array();
|
||||
foreach (array_keys($bundles) as $bundle) {
|
||||
$bundle_fields = array_filter($this->entityManager->getFieldDefinitions($entity_type_id, $bundle), function ($field_definition) {
|
||||
return !$field_definition->isComputed();
|
||||
});
|
||||
foreach ($bundle_fields as $field_name => $field_definition) {
|
||||
/* @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
|
||||
$columns = $field_definition->getFieldStorageDefinition()->getColumns();
|
||||
// If there is more than one column, display them all, otherwise just
|
||||
// display the field label.
|
||||
// @todo: Use property labels instead of the column name.
|
||||
if (count($columns) > 1) {
|
||||
foreach ($columns as $column_name => $column_info) {
|
||||
$fields[$field_name . '.' . $column_name] = $this->t('@label (@column)', array('@label' => $field_definition->getLabel(), '@column' => $column_name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$fields[$field_name] = $this->t('@label', array('@label' => $field_definition->getLabel()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['sort']['field'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Sort by'),
|
||||
'#options' => array(
|
||||
'_none' => $this->t('- None -'),
|
||||
) + $fields,
|
||||
'#ajax' => TRUE,
|
||||
'#limit_validation_errors' => array(),
|
||||
'#default_value' => $selection_handler_settings['sort']['field'],
|
||||
);
|
||||
|
||||
$form['sort']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array('class' => array('entity_reference-settings')),
|
||||
'#process' => [[EntityReferenceItem::class, 'formProcessMergeParent']],
|
||||
);
|
||||
|
||||
if ($selection_handler_settings['sort']['field'] != '_none') {
|
||||
// Merge-in default values.
|
||||
$selection_handler_settings['sort'] += array(
|
||||
'direction' => 'ASC',
|
||||
);
|
||||
|
||||
$form['sort']['settings']['direction'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Sort direction'),
|
||||
'#required' => TRUE,
|
||||
'#options' => array(
|
||||
'ASC' => $this->t('Ascending'),
|
||||
'DESC' => $this->t('Descending'),
|
||||
),
|
||||
'#default_value' => $selection_handler_settings['sort']['direction'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
// If no checkboxes were checked for 'target_bundles', store NULL ("all
|
||||
// bundles are referenceable") rather than empty array ("no bundle is
|
||||
// referenceable" - typically happens when all referenceable bundles have
|
||||
// been deleted).
|
||||
if ($form_state->getValue(['settings', 'handler_settings', 'target_bundles']) === []) {
|
||||
$form_state->setValue(['settings', 'handler_settings', 'target_bundles'], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* Form element validation handler; Filters the #value property of an element.
|
||||
*/
|
||||
public static function elementValidateFilter(&$element, FormStateInterface $form_state) {
|
||||
$element['#value'] = array_filter($element['#value']);
|
||||
$form_state->setValueForElement($element, $element['#value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
|
||||
$target_type = $this->configuration['target_type'];
|
||||
|
||||
$query = $this->buildEntityQuery($match, $match_operator);
|
||||
if ($limit > 0) {
|
||||
$query->range(0, $limit);
|
||||
}
|
||||
|
||||
$result = $query->execute();
|
||||
|
||||
if (empty($result)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$options = array();
|
||||
$entities = entity_load_multiple($target_type, $result);
|
||||
foreach ($entities as $entity_id => $entity) {
|
||||
$bundle = $entity->bundle();
|
||||
$options[$bundle][$entity_id] = Html::escape($entity->label());
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = $this->buildEntityQuery($match, $match_operator);
|
||||
return $query
|
||||
->count()
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateReferenceableEntities(array $ids) {
|
||||
$result = array();
|
||||
if ($ids) {
|
||||
$target_type = $this->configuration['target_type'];
|
||||
$entity_type = $this->entityManager->getDefinition($target_type);
|
||||
$query = $this->buildEntityQuery();
|
||||
$result = $query
|
||||
->condition($entity_type->getKey('id'), $ids, 'IN')
|
||||
->execute();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an EntityQuery to get referenceable entities.
|
||||
*
|
||||
* @param string|null $match
|
||||
* (Optional) Text to match the label against. Defaults to NULL.
|
||||
* @param string $match_operator
|
||||
* (Optional) The operation the matching should be done with. Defaults
|
||||
* to "CONTAINS".
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Query\QueryInterface
|
||||
* The EntityQuery object with the basic conditions and sorting applied to
|
||||
* it.
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$target_type = $this->configuration['target_type'];
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
$entity_type = $this->entityManager->getDefinition($target_type);
|
||||
|
||||
$query = $this->entityManager->getStorage($target_type)->getQuery();
|
||||
|
||||
// If 'target_bundles' is NULL, all bundles are referenceable, no further
|
||||
// conditions are needed.
|
||||
if (isset($handler_settings['target_bundles']) && is_array($handler_settings['target_bundles'])) {
|
||||
// If 'target_bundles' is an empty array, no bundle is referenceable,
|
||||
// force the query to never return anything and bail out early.
|
||||
if ($handler_settings['target_bundles'] === []) {
|
||||
$query->condition($entity_type->getKey('id'), NULL, '=');
|
||||
return $query;
|
||||
}
|
||||
else {
|
||||
$query->condition($entity_type->getKey('bundle'), $handler_settings['target_bundles'], 'IN');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($match) && $label_key = $entity_type->getKey('label')) {
|
||||
$query->condition($label_key, $match, $match_operator);
|
||||
}
|
||||
|
||||
// Add entity-access tag.
|
||||
$query->addTag($target_type . '_access');
|
||||
|
||||
// Add the Selection handler for system_query_entity_reference_alter().
|
||||
$query->addTag('entity_reference');
|
||||
$query->addMetaData('entity_reference_selection_handler', $this);
|
||||
|
||||
// Add the sort option.
|
||||
if (!empty($handler_settings['sort'])) {
|
||||
$sort_settings = $handler_settings['sort'];
|
||||
if ($sort_settings['field'] != '_none') {
|
||||
$query->sort($sort_settings['field'], $sort_settings['direction']);
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function entityQueryAlter(SelectInterface $query) { }
|
||||
|
||||
/**
|
||||
* Helper method: Passes a query to the alteration system again.
|
||||
*
|
||||
* This allows Entity Reference to add a tag to an existing query so it can
|
||||
* ask access control mechanisms to alter it again.
|
||||
*/
|
||||
protected function reAlterQuery(AlterableInterface $query, $tag, $base_table) {
|
||||
// Save the old tags and metadata.
|
||||
// For some reason, those are public.
|
||||
$old_tags = $query->alterTags;
|
||||
$old_metadata = $query->alterMetaData;
|
||||
|
||||
$query->alterTags = array($tag => TRUE);
|
||||
$query->alterMetaData['base_table'] = $base_table;
|
||||
$this->moduleHandler->alter(array('query', 'query_' . $tag), $query);
|
||||
|
||||
// Restore the tags and metadata.
|
||||
$query->alterTags = $old_tags;
|
||||
$query->alterMetaData = $old_metadata;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\Plugin\EntityReferenceSelection\PhpSelection.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
||||
/**
|
||||
* Defines an alternative to the default Entity Reference Selection plugin.
|
||||
*
|
||||
* This selection plugin uses PHP for more advanced cases when the entity query
|
||||
* cannot filter properly, for example when the target entity type has no
|
||||
* 'label' key provided in the entity type plugin definition.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\Plugin\Derivative\DefaultSelectionDeriver
|
||||
*/
|
||||
class PhpSelection extends DefaultSelection {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
|
||||
// No input, return everything from the entity query.
|
||||
if ($match === NULL || $match === '') {
|
||||
return parent::getReferenceableEntities($match, $match_operator, $limit);
|
||||
}
|
||||
|
||||
// Start with the selection results returned by the entity query. Don't use
|
||||
// any limit because we have to apply a limit after filtering the items.
|
||||
$options = parent::getReferenceableEntities($match, $match_operator);
|
||||
|
||||
// Always use a case-insensitive, escaped match. Entity labels returned by
|
||||
// SelectionInterface::getReferenceableEntities() are already escaped, so
|
||||
// the incoming $match needs to be escaped as well, making the comparison
|
||||
// possible.
|
||||
// @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface::getReferenceableEntities()
|
||||
if (is_string($match)) {
|
||||
$match = Html::escape(Unicode::strtolower($match));
|
||||
}
|
||||
elseif (is_array($match)) {
|
||||
array_walk($match, function (&$item) {
|
||||
$item = Html::escape(Unicode::strtolower($item));
|
||||
});
|
||||
}
|
||||
|
||||
$filtered = [];
|
||||
$count = 0;
|
||||
// Filter target entities by the output of their label() method.
|
||||
foreach ($options as $bundle => &$items) {
|
||||
foreach ($items as $entity_id => $label) {
|
||||
if ($this->matchLabel($match, $match_operator, $label)) {
|
||||
$filtered[$bundle][$entity_id] = $label;
|
||||
$count++;
|
||||
|
||||
if ($limit && $count >= $limit) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$count = 0;
|
||||
foreach ($this->getReferenceableEntities($match, $match_operator) as &$items) {
|
||||
$count += count($items);
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches an entity label to an input string.
|
||||
*
|
||||
* @param mixed $match
|
||||
* The value to compare. This can be any valid entity query condition value.
|
||||
* @param string $match_operator
|
||||
* The comparison operator.
|
||||
* @param string $label
|
||||
* The entity label to match against.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE when matches, FALSE otherwise.
|
||||
*/
|
||||
protected function matchLabel($match, $match_operator, $label) {
|
||||
// Always use a case-insensitive value.
|
||||
$label = Unicode::strtolower($label);
|
||||
|
||||
switch ($match_operator) {
|
||||
case '=':
|
||||
return $label == $match;
|
||||
case '>':
|
||||
return $label > $match;
|
||||
case '<':
|
||||
return $label < $match;
|
||||
case '>=':
|
||||
return $label >= $match;
|
||||
case '<=':
|
||||
return $label <= $match;
|
||||
case '<>':
|
||||
return $label != $match;
|
||||
case 'IN':
|
||||
return array_search($label, $match) !== FALSE;
|
||||
case 'NOT IN':
|
||||
return array_search($label, $match) === FALSE;
|
||||
case 'STARTS_WITH':
|
||||
return strpos($label, $match) === 0;
|
||||
case 'CONTAINS':
|
||||
return strpos($label, $match) !== FALSE;
|
||||
case 'ENDS_WITH':
|
||||
return Unicode::substr($label, -Unicode::strlen($match)) === (string) $match;
|
||||
case 'IS NOT NULL':
|
||||
return TRUE;
|
||||
case 'IS NULL':
|
||||
return FALSE;
|
||||
default:
|
||||
// Invalid match operator.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,376 +7,8 @@
|
|||
|
||||
namespace Drupal\Core\Entity\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Database\Query\AlterableInterface;
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Default plugin implementation of the Entity Reference Selection plugin.
|
||||
*
|
||||
* Also serves as a base class for specific types of Entity Reference
|
||||
* Selection plugins.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager
|
||||
* @see \Drupal\Core\Entity\Annotation\EntityReferenceSelection
|
||||
* @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface
|
||||
* @see \Drupal\Core\Entity\Plugin\Derivative\SelectionBase
|
||||
* @see plugin_api
|
||||
*
|
||||
* @EntityReferenceSelection(
|
||||
* id = "default",
|
||||
* label = @Translation("Default"),
|
||||
* group = "default",
|
||||
* weight = 0,
|
||||
* deriver = "Drupal\Core\Entity\Plugin\Derivative\SelectionBase"
|
||||
* )
|
||||
* @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection
|
||||
*/
|
||||
class SelectionBase extends PluginBase implements SelectionInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs a new SelectionBase object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$entity_type_id = $this->configuration['target_type'];
|
||||
$selection_handler_settings = $this->configuration['handler_settings'];
|
||||
$entity_type = $this->entityManager->getDefinition($entity_type_id);
|
||||
$bundles = $this->entityManager->getBundleInfo($entity_type_id);
|
||||
|
||||
// Merge-in default values.
|
||||
$selection_handler_settings += array(
|
||||
'target_bundles' => array(),
|
||||
'sort' => array(
|
||||
'field' => '_none',
|
||||
),
|
||||
'auto_create' => FALSE,
|
||||
);
|
||||
|
||||
if ($entity_type->hasKey('bundle')) {
|
||||
$bundle_options = array();
|
||||
foreach ($bundles as $bundle_name => $bundle_info) {
|
||||
$bundle_options[$bundle_name] = $bundle_info['label'];
|
||||
}
|
||||
|
||||
$form['target_bundles'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Bundles'),
|
||||
'#options' => $bundle_options,
|
||||
'#default_value' => (!empty($selection_handler_settings['target_bundles'])) ? $selection_handler_settings['target_bundles'] : array(),
|
||||
'#required' => TRUE,
|
||||
'#size' => 6,
|
||||
'#multiple' => TRUE,
|
||||
'#element_validate' => array('_entity_reference_element_validate_filter'),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['target_bundles'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
if ($entity_type->isSubclassOf('\Drupal\Core\Entity\FieldableEntityInterface')) {
|
||||
$fields = array();
|
||||
foreach (array_keys($bundles) as $bundle) {
|
||||
$bundle_fields = array_filter($this->entityManager->getFieldDefinitions($entity_type_id, $bundle), function ($field_definition) {
|
||||
return !$field_definition->isComputed();
|
||||
});
|
||||
foreach ($bundle_fields as $field_name => $field_definition) {
|
||||
/* @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
|
||||
$columns = $field_definition->getFieldStorageDefinition()->getColumns();
|
||||
// If there is more than one column, display them all, otherwise just
|
||||
// display the field label.
|
||||
// @todo: Use property labels instead of the column name.
|
||||
if (count($columns) > 1) {
|
||||
foreach ($columns as $column_name => $column_info) {
|
||||
$fields[$field_name . '.' . $column_name] = $this->t('@label (@column)', array('@label' => $field_definition->getLabel(), '@column' => $column_name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$fields[$field_name] = $this->t('@label', array('@label' => $field_definition->getLabel()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['sort']['field'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Sort by'),
|
||||
'#options' => array(
|
||||
'_none' => $this->t('- None -'),
|
||||
) + $fields,
|
||||
'#ajax' => TRUE,
|
||||
'#limit_validation_errors' => array(),
|
||||
'#default_value' => $selection_handler_settings['sort']['field'],
|
||||
);
|
||||
|
||||
$form['sort']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array('class' => array('entity_reference-settings')),
|
||||
'#process' => array('_entity_reference_form_process_merge_parent'),
|
||||
);
|
||||
|
||||
if ($selection_handler_settings['sort']['field'] != '_none') {
|
||||
// Merge-in default values.
|
||||
$selection_handler_settings['sort'] += array(
|
||||
'direction' => 'ASC',
|
||||
);
|
||||
|
||||
$form['sort']['settings']['direction'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Sort direction'),
|
||||
'#required' => TRUE,
|
||||
'#options' => array(
|
||||
'ASC' => $this->t('Ascending'),
|
||||
'DESC' => $this->t('Descending'),
|
||||
),
|
||||
'#default_value' => $selection_handler_settings['sort']['direction'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
|
||||
$target_type = $this->configuration['target_type'];
|
||||
|
||||
$query = $this->buildEntityQuery($match, $match_operator);
|
||||
if ($limit > 0) {
|
||||
$query->range(0, $limit);
|
||||
}
|
||||
|
||||
$result = $query->execute();
|
||||
|
||||
if (empty($result)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$options = array();
|
||||
$entities = entity_load_multiple($target_type, $result);
|
||||
foreach ($entities as $entity_id => $entity) {
|
||||
$bundle = $entity->bundle();
|
||||
$options[$bundle][$entity_id] = SafeMarkup::checkPlain($entity->label());
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = $this->buildEntityQuery($match, $match_operator);
|
||||
return $query
|
||||
->count()
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateReferenceableEntities(array $ids) {
|
||||
$result = array();
|
||||
if ($ids) {
|
||||
$target_type = $this->configuration['target_type'];
|
||||
$entity_type = $this->entityManager->getDefinition($target_type);
|
||||
$query = $this->buildEntityQuery();
|
||||
$result = $query
|
||||
->condition($entity_type->getKey('id'), $ids, 'IN')
|
||||
->execute();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE) {
|
||||
$bundled_entities = $this->getReferenceableEntities($input, '=', 6);
|
||||
$entities = array();
|
||||
foreach ($bundled_entities as $entities_list) {
|
||||
$entities += $entities_list;
|
||||
}
|
||||
$params = array(
|
||||
'%value' => $input,
|
||||
'@value' => $input,
|
||||
);
|
||||
if (empty($entities)) {
|
||||
if ($strict) {
|
||||
// Error if there are no entities available for a required field.
|
||||
$form_state->setError($element, $this->t('There are no entities matching "%value".', $params));
|
||||
}
|
||||
}
|
||||
elseif (count($entities) > 5) {
|
||||
$params['@id'] = key($entities);
|
||||
// Error if there are more than 5 matching entities.
|
||||
$form_state->setError($element, $this->t('Many entities are called %value. Specify the one you want by appending the id in parentheses, like "@value (@id)".', $params));
|
||||
}
|
||||
elseif (count($entities) > 1) {
|
||||
// More helpful error if there are only a few matching entities.
|
||||
$multiples = array();
|
||||
foreach ($entities as $id => $name) {
|
||||
$multiples[] = $name . ' (' . $id . ')';
|
||||
}
|
||||
$params['@id'] = $id;
|
||||
$form_state->setError($element, $this->t('Multiple entities match this reference; "%multiple". Specify the one you want by appending the id in parentheses, like "@value (@id)".', array('%multiple' => implode('", "', $multiples))));
|
||||
}
|
||||
else {
|
||||
// Take the one and only matching entity.
|
||||
return key($entities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an EntityQuery to get referenceable entities.
|
||||
*
|
||||
* @param string|null $match
|
||||
* (Optional) Text to match the label against. Defaults to NULL.
|
||||
* @param string $match_operator
|
||||
* (Optional) The operation the matching should be done with. Defaults
|
||||
* to "CONTAINS".
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Query\QueryInterface
|
||||
* The EntityQuery object with the basic conditions and sorting applied to
|
||||
* it.
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$target_type = $this->configuration['target_type'];
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
$entity_type = $this->entityManager->getDefinition($target_type);
|
||||
|
||||
$query = $this->entityManager->getStorage($target_type)->getQuery();
|
||||
if (!empty($handler_settings['target_bundles'])) {
|
||||
$query->condition($entity_type->getKey('bundle'), $handler_settings['target_bundles'], 'IN');
|
||||
}
|
||||
|
||||
if (isset($match) && $label_key = $entity_type->getKey('label')) {
|
||||
$query->condition($label_key, $match, $match_operator);
|
||||
}
|
||||
|
||||
// Add entity-access tag.
|
||||
$query->addTag($target_type . '_access');
|
||||
|
||||
// Add the Selection handler for
|
||||
// entity_reference_query_entity_reference_alter().
|
||||
$query->addTag('entity_reference');
|
||||
$query->addMetaData('entity_reference_selection_handler', $this);
|
||||
|
||||
// Add the sort option.
|
||||
if (!empty($handler_settings['sort'])) {
|
||||
$sort_settings = $handler_settings['sort'];
|
||||
if ($sort_settings['field'] != '_none') {
|
||||
$query->sort($sort_settings['field'], $sort_settings['direction']);
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function entityQueryAlter(SelectInterface $query) { }
|
||||
|
||||
/**
|
||||
* Helper method: Passes a query to the alteration system again.
|
||||
*
|
||||
* This allows Entity Reference to add a tag to an existing query so it can
|
||||
* ask access control mechanisms to alter it again.
|
||||
*/
|
||||
protected function reAlterQuery(AlterableInterface $query, $tag, $base_table) {
|
||||
// Save the old tags and metadata.
|
||||
// For some reason, those are public.
|
||||
$old_tags = $query->alterTags;
|
||||
$old_metadata = $query->alterMetaData;
|
||||
|
||||
$query->alterTags = array($tag => TRUE);
|
||||
$query->alterMetaData['base_table'] = $base_table;
|
||||
$this->moduleHandler->alter(array('query', 'query_' . $tag), $query);
|
||||
|
||||
// Restore the tags and metadata.
|
||||
$query->alterTags = $old_tags;
|
||||
$query->alterMetaData = $old_metadata;
|
||||
}
|
||||
|
||||
}
|
||||
class SelectionBase extends DefaultSelection { }
|
||||
|
|
|
@ -25,7 +25,7 @@ class EntityChangedConstraintValidator extends ConstraintValidator {
|
|||
$saved_entity = \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id());
|
||||
// A change to any other translation must add a violation to the current
|
||||
// translation because there might be untranslatable shared fields.
|
||||
if ($saved_entity && $saved_entity->getChangedTimeAcrossTranslations() > $entity->getChangedTime()) {
|
||||
if ($saved_entity && $saved_entity->getChangedTimeAcrossTranslations() > $entity->getChangedTimeAcrossTranslations()) {
|
||||
$this->context->addViolation($constraint->message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,4 +28,11 @@ class ValidReferenceConstraint extends Constraint {
|
|||
*/
|
||||
public $message = 'The referenced entity (%type: %id) does not exist.';
|
||||
|
||||
/**
|
||||
* Validation message when the target_id is empty.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $nullMessage = 'This value should not be null.';
|
||||
|
||||
}
|
||||
|
|
|
@ -19,10 +19,18 @@ class ValidReferenceConstraintValidator extends ConstraintValidator {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($value, Constraint $constraint) {
|
||||
/* @var \Drupal\Core\Field\FieldItemInterface $value */
|
||||
/** @var \Drupal\Core\Field\FieldItemInterface $value */
|
||||
/** @var ValidReferenceConstraint $constraint */
|
||||
if (!isset($value)) {
|
||||
return;
|
||||
}
|
||||
// We don't use a regular NotNull constraint for the target_id property as
|
||||
// a NULL value is valid if the entity property contains an unsaved entity.
|
||||
// @see \Drupal\Core\TypedData\DataReferenceTargetDefinition::getConstraints
|
||||
if (!$value->isEmpty() && $value->target_id === NULL && !$value->entity->isNew()) {
|
||||
$this->context->addViolation($constraint->nullMessage);
|
||||
return;
|
||||
}
|
||||
$id = $value->get('target_id')->getValue();
|
||||
// '0' or NULL are considered valid empty references.
|
||||
if (empty($id)) {
|
||||
|
|
|
@ -230,7 +230,7 @@ abstract class QueryBase implements QueryInterface {
|
|||
public function sort($field, $direction = 'ASC', $langcode = NULL) {
|
||||
$this->sort[] = array(
|
||||
'field' => $field,
|
||||
'direction' => $direction,
|
||||
'direction' => strtoupper($direction),
|
||||
'langcode' => $langcode,
|
||||
);
|
||||
return $this;
|
||||
|
|
|
@ -258,8 +258,8 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
|
|||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The update entity type.
|
||||
*
|
||||
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
|
||||
* See https://www.drupal.org/node/2274017.
|
||||
* @internal Only to be used internally by Entity API. Expected to be
|
||||
* removed by https://www.drupal.org/node/2274017.
|
||||
*/
|
||||
public function setEntityType(EntityTypeInterface $entity_type) {
|
||||
if ($this->entityType->id() == $entity_type->id()) {
|
||||
|
@ -1493,40 +1493,6 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
|
|||
*/
|
||||
public function onBundleDelete($bundle, $entity_type_id) { }
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onBundleRename($bundle, $bundle_new, $entity_type_id) {
|
||||
// The method runs before the field definitions are updated, so we use the
|
||||
// old bundle name.
|
||||
$field_definitions = $this->entityManager->getFieldDefinitions($this->entityTypeId, $bundle);
|
||||
// We need to handle deleted fields too. For now, this only makes sense for
|
||||
// configurable fields, so we use the specific API.
|
||||
// @todo Use the unified store of deleted field definitions instead in
|
||||
// https://www.drupal.org/node/2282119
|
||||
$field_definitions += entity_load_multiple_by_properties('field_config', array('entity_type' => $this->entityTypeId, 'bundle' => $bundle, 'deleted' => TRUE, 'include_deleted' => TRUE));
|
||||
$table_mapping = $this->getTableMapping();
|
||||
|
||||
foreach ($field_definitions as $field_definition) {
|
||||
$storage_definition = $field_definition->getFieldStorageDefinition();
|
||||
if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) {
|
||||
$is_deleted = $this->storageDefinitionIsDeleted($storage_definition);
|
||||
$table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $is_deleted);
|
||||
$revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $is_deleted);
|
||||
$this->database->update($table_name)
|
||||
->fields(array('bundle' => $bundle_new))
|
||||
->condition('bundle', $bundle)
|
||||
->execute();
|
||||
if ($this->entityType->isRevisionable()) {
|
||||
$this->database->update($revision_name)
|
||||
->fields(array('bundle' => $bundle_new))
|
||||
->condition('bundle', $bundle)
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\Core\Entity\Sql;
|
|||
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Database\DatabaseException;
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
use Drupal\Core\Entity\ContentEntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
|
@ -29,6 +30,8 @@ use Drupal\field\FieldStorageConfigInterface;
|
|||
*/
|
||||
class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorageSchemaInterface {
|
||||
|
||||
use DependencySerializationTrait;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
|
@ -364,9 +367,14 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
|
|||
$this->originalDefinitions = $field_storage_definitions;
|
||||
$table_mapping = $this->storage->getTableMapping($field_storage_definitions);
|
||||
foreach ($field_storage_definitions as $field_storage_definition) {
|
||||
// If we have a field having dedicated storage we need to drop it,
|
||||
// otherwise we just remove the related schema data.
|
||||
if ($table_mapping->requiresDedicatedTableStorage($field_storage_definition)) {
|
||||
$this->deleteDedicatedTableSchema($field_storage_definition);
|
||||
}
|
||||
elseif ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
|
||||
$this->deleteFieldSchemaData($field_storage_definition);
|
||||
}
|
||||
}
|
||||
$this->originalDefinitions = NULL;
|
||||
|
||||
|
|
|
@ -139,8 +139,8 @@ use Drupal\node\Entity\NodeType;
|
|||
* - Field configuration preSave(): hook_field_storage_config_update_forbid()
|
||||
* - Node postSave(): hook_node_access_records() and
|
||||
* hook_node_access_records_alter()
|
||||
* - Config entities that are acting as entity bundles, in postSave():
|
||||
* hook_entity_bundle_create() or hook_entity_bundle_rename() as appropriate
|
||||
* - Config entities that are acting as entity bundles in postSave():
|
||||
* hook_entity_bundle_create()
|
||||
* - Comment: hook_comment_publish() and hook_comment_unpublish() as
|
||||
* appropriate.
|
||||
*
|
||||
|
@ -350,6 +350,7 @@ use Drupal\node\Entity\NodeType;
|
|||
* 'bundle_entity_type' on the \Drupal\node\Entity\Node class. Also, the
|
||||
* bundle config entity type annotation must have a 'bundle_of' entry,
|
||||
* giving the machine name of the entity type it is acting as a bundle for.
|
||||
* These machine names are considered permanent, they may not be renamed.
|
||||
* - Additional annotations can be seen on entity class examples such as
|
||||
* \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
|
||||
* (configuration). These annotations are documented on
|
||||
|
@ -467,7 +468,9 @@ use Drupal\node\Entity\NodeType;
|
|||
* @endcode
|
||||
* Then, to build and render the entity:
|
||||
* @code
|
||||
* // You can omit the language ID if the default language is being used.
|
||||
* // You can omit the language ID, by default the current content language will
|
||||
* // be used. If no translation is available for the current language, fallback
|
||||
* // rules will be used.
|
||||
* $build = $view_builder->view($entity, 'view_mode_name', $language->getId());
|
||||
* // $build is a render array.
|
||||
* $rendered = drupal_render($build);
|
||||
|
@ -501,6 +504,7 @@ use Drupal\node\Entity\NodeType;
|
|||
*
|
||||
* @see i18n
|
||||
* @see entity_crud
|
||||
* @see \Drupal\Core\Entity\EntityManagerInterface::getTranslationFromContext()
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
@ -517,19 +521,17 @@ use Drupal\node\Entity\NodeType;
|
|||
* @param string $operation
|
||||
* The operation that is to be performed on $entity.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The account trying to access the entity.
|
||||
* @param string $langcode
|
||||
* The code of the language $entity is accessed in.
|
||||
* The account trying to access the entity.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result. The final result is calculated by using
|
||||
* \Drupal\Core\Access\AccessResultInterface::orIf() on the result of every
|
||||
* hook_entity_access() and hook_ENTITY_TYPE_access() implementation, and the
|
||||
* result of the entity-specific checkAccess() method in the entity access
|
||||
* control handler. Be careful when writing generalized access checks shared
|
||||
* between routing and entity checks: routing uses the andIf() operator. So
|
||||
* returning an isNeutral() does not determine entity access at all but it
|
||||
* always ends up denying access while routing.
|
||||
* The access result. The final result is calculated by using
|
||||
* \Drupal\Core\Access\AccessResultInterface::orIf() on the result of every
|
||||
* hook_entity_access() and hook_ENTITY_TYPE_access() implementation, and the
|
||||
* result of the entity-specific checkAccess() method in the entity access
|
||||
* control handler. Be careful when writing generalized access checks shared
|
||||
* between routing and entity checks: routing uses the andIf() operator. So
|
||||
* returning an isNeutral() does not determine entity access at all but it
|
||||
* always ends up denying access while routing.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityAccessControlHandler
|
||||
* @see hook_entity_create_access()
|
||||
|
@ -537,7 +539,7 @@ use Drupal\node\Entity\NodeType;
|
|||
*
|
||||
* @ingroup entity_api
|
||||
*/
|
||||
function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
|
||||
function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
|
||||
// No opinion.
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
@ -550,12 +552,10 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat
|
|||
* @param string $operation
|
||||
* The operation that is to be performed on $entity.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The account trying to access the entity.
|
||||
* @param string $langcode
|
||||
* The code of the language $entity is accessed in.
|
||||
* The account trying to access the entity.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result. hook_entity_access() has detailed documentation.
|
||||
* The access result. hook_entity_access() has detailed documentation.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityAccessControlHandler
|
||||
* @see hook_ENTITY_TYPE_create_access()
|
||||
|
@ -563,7 +563,7 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat
|
|||
*
|
||||
* @ingroup entity_api
|
||||
*/
|
||||
function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
|
||||
function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
|
||||
// No opinion.
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
@ -572,16 +572,16 @@ function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $o
|
|||
* Control entity create access.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The account trying to access the entity.
|
||||
* The account trying to access the entity.
|
||||
* @param array $context
|
||||
* An associative array of additional context values. By default it contains
|
||||
* language:
|
||||
* - langcode - the current language code.
|
||||
* An associative array of additional context values. By default it contains
|
||||
* language:
|
||||
* - langcode - the current language code.
|
||||
* @param string $entity_bundle
|
||||
* The entity bundle name.
|
||||
* The entity bundle name.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
* The access result.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityAccessControlHandler
|
||||
* @see hook_entity_access()
|
||||
|
@ -598,16 +598,16 @@ function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $accoun
|
|||
* Control entity create access for a specific entity type.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The account trying to access the entity.
|
||||
* The account trying to access the entity.
|
||||
* @param array $context
|
||||
* An associative array of additional context values. By default it contains
|
||||
* language:
|
||||
* - langcode - the current language code.
|
||||
* An associative array of additional context values. By default it contains
|
||||
* language:
|
||||
* - langcode - the current language code.
|
||||
* @param string $entity_bundle
|
||||
* The entity bundle name.
|
||||
* The entity bundle name.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
* The access result.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityAccessControlHandler
|
||||
* @see hook_ENTITY_TYPE_access()
|
||||
|
@ -740,31 +740,6 @@ function hook_entity_bundle_create($entity_type_id, $bundle) {
|
|||
\Drupal::service('router.builder')->setRebuildNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entity_bundle_rename().
|
||||
*
|
||||
* This hook is invoked after the operation has been performed.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type to which the bundle is bound.
|
||||
* @param string $bundle_old
|
||||
* The previous name of the bundle.
|
||||
* @param string $bundle_new
|
||||
* The new name of the bundle.
|
||||
*
|
||||
* @see entity_crud
|
||||
*/
|
||||
function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) {
|
||||
// Update the settings associated with the bundle in my_module.settings.
|
||||
$config = \Drupal::config('my_module.settings');
|
||||
$bundle_settings = $config->get('bundle_settings');
|
||||
if (isset($bundle_settings[$entity_type_id][$bundle_old])) {
|
||||
$bundle_settings[$entity_type_id][$bundle_new] = $bundle_settings[$entity_type_id][$bundle_old];
|
||||
unset($bundle_settings[$entity_type_id][$bundle_old]);
|
||||
$config->set('bundle_settings', $bundle_settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on entity_bundle_delete().
|
||||
*
|
||||
|
@ -1064,7 +1039,7 @@ function hook_ENTITY_TYPE_translation_insert(\Drupal\Core\Entity\EntityInterface
|
|||
*
|
||||
* This hook runs once the entity translation has been deleted from storage.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* @param \Drupal\Core\Entity\EntityInterface $translation
|
||||
* The original entity object.
|
||||
*
|
||||
* @ingroup entity_crud
|
||||
|
@ -1084,7 +1059,7 @@ function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $tra
|
|||
*
|
||||
* This hook runs once the entity translation has been deleted from storage.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* @param \Drupal\Core\Entity\EntityInterface $translation
|
||||
* The original entity object.
|
||||
*
|
||||
* @ingroup entity_crud
|
||||
|
@ -1256,8 +1231,6 @@ function hook_entity_query_alter(\Drupal\Core\Entity\Query\QueryInterface $query
|
|||
* entity components.
|
||||
* @param $view_mode
|
||||
* The view mode the entity is rendered in.
|
||||
* @param $langcode
|
||||
* The language code used for rendering.
|
||||
*
|
||||
* The module may add elements to $build prior to rendering. The
|
||||
* structure of $build is a renderable array as expected by
|
||||
|
@ -1268,7 +1241,7 @@ function hook_entity_query_alter(\Drupal\Core\Entity\Query\QueryInterface $query
|
|||
*
|
||||
* @ingroup entity_crud
|
||||
*/
|
||||
function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
|
||||
function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
|
||||
// Only do the extra work if the component is configured to be displayed.
|
||||
// This assumes a 'mymodule_addition' extra field has been defined for the
|
||||
// entity bundle in hook_entity_extra_field_info().
|
||||
|
@ -1292,8 +1265,6 @@ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $en
|
|||
* entity components.
|
||||
* @param $view_mode
|
||||
* The view mode the entity is rendered in.
|
||||
* @param $langcode
|
||||
* The language code used for rendering.
|
||||
*
|
||||
* The module may add elements to $build prior to rendering. The
|
||||
* structure of $build is a renderable array as expected by
|
||||
|
@ -1304,7 +1275,7 @@ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $en
|
|||
*
|
||||
* @ingroup entity_crud
|
||||
*/
|
||||
function hook_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
|
||||
function hook_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
|
||||
// Only do the extra work if the component is configured to be displayed.
|
||||
// This assumes a 'mymodule_addition' extra field has been defined for the
|
||||
// entity bundle in hook_entity_extra_field_info().
|
||||
|
@ -1467,8 +1438,6 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter
|
|||
* The entity that is being viewed.
|
||||
* @param string $view_mode
|
||||
* The view_mode that is to be used to display the entity.
|
||||
* @param string $langcode
|
||||
* The code of the language $entity is accessed in.
|
||||
*
|
||||
* @see drupal_render()
|
||||
* @see \Drupal\Core\Entity\EntityViewBuilder
|
||||
|
@ -1476,7 +1445,7 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter
|
|||
*
|
||||
* @ingroup entity_crud
|
||||
*/
|
||||
function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode, $langcode) {
|
||||
function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1493,8 +1462,6 @@ function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entit
|
|||
* The entity that is being viewed.
|
||||
* @param string $view_mode
|
||||
* The view_mode that is to be used to display the entity.
|
||||
* @param string $langcode
|
||||
* The code of the language $entity is accessed in.
|
||||
*
|
||||
* @see drupal_render()
|
||||
* @see \Drupal\Core\Entity\EntityViewBuilder
|
||||
|
@ -1502,7 +1469,7 @@ function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entit
|
|||
*
|
||||
* @ingroup entity_crud
|
||||
*/
|
||||
function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode, $langcode) {
|
||||
function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1679,7 +1646,7 @@ function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $en
|
|||
* @see hook_entity_bundle_field_info_alter()
|
||||
*
|
||||
* @todo WARNING: This hook will be changed in
|
||||
* https://www.drupal.org/node/2346329.
|
||||
* https://www.drupal.org/node/2346329.
|
||||
*/
|
||||
function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
|
||||
// Alter the mymodule_text field to use a custom class.
|
||||
|
@ -1714,7 +1681,7 @@ function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityT
|
|||
* @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions()
|
||||
*
|
||||
* @todo WARNING: This hook will be changed in
|
||||
* https://www.drupal.org/node/2346347.
|
||||
* https://www.drupal.org/node/2346347.
|
||||
*/
|
||||
function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
|
||||
// Add a property only to nodes of the 'article' bundle.
|
||||
|
@ -1743,7 +1710,7 @@ function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $
|
|||
* @see hook_entity_bundle_field_info()
|
||||
*
|
||||
* @todo WARNING: This hook will be changed in
|
||||
* https://www.drupal.org/node/2346347.
|
||||
* https://www.drupal.org/node/2346347.
|
||||
*/
|
||||
function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
|
||||
if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) {
|
||||
|
|
Reference in a new issue