Update to Drupal 8.0.0. For more information, see https://www.drupal.org/node/2619030
This commit is contained in:
parent
7784f4c23d
commit
25a6735fb3
49 changed files with 1394 additions and 281 deletions
|
@ -511,8 +511,6 @@ class ConfigImporter {
|
|||
* If the configuration is already importing.
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->createExtensionChangelist();
|
||||
|
||||
// Ensure that the changes have been validated.
|
||||
$this->validate();
|
||||
|
||||
|
@ -710,8 +708,10 @@ class ConfigImporter {
|
|||
* @throws \Drupal\Core\Config\ConfigImporterException
|
||||
* Exception thrown if the validate event logged any errors.
|
||||
*/
|
||||
protected function validate() {
|
||||
public function validate() {
|
||||
if (!$this->validated) {
|
||||
// Create the list of installs and uninstalls.
|
||||
$this->createExtensionChangelist();
|
||||
// Validate renames.
|
||||
foreach ($this->getUnprocessedConfiguration('rename') as $name) {
|
||||
$names = $this->storageComparer->extractRenameNames($name);
|
||||
|
|
|
@ -69,9 +69,6 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface {
|
|||
// Always add a default 'uuid' key.
|
||||
$this->entity_keys['uuid'] = 'uuid';
|
||||
$this->entity_keys['langcode'] = 'langcode';
|
||||
if (isset($this->handlers['storage'])) {
|
||||
$this->checkStorageClass($this->handlers['storage']);
|
||||
}
|
||||
$this->handlers += array(
|
||||
'storage' => 'Drupal\Core\Config\Entity\ConfigEntityStorage',
|
||||
);
|
||||
|
@ -135,23 +132,12 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see \Drupal\Core\Config\Entity\ConfigEntityStorage.
|
||||
*
|
||||
* @throws \Drupal\Core\Config\Entity\Exception\ConfigEntityStorageClassException
|
||||
* Exception thrown when the provided class is not an instance of
|
||||
* \Drupal\Core\Config\Entity\ConfigEntityStorage.
|
||||
*/
|
||||
public function setStorageClass($class) {
|
||||
$this->checkStorageClass($class);
|
||||
parent::setStorageClass($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the provided class is an instance of ConfigEntityStorage.
|
||||
*
|
||||
* @param string $class
|
||||
* The class to check.
|
||||
*
|
||||
* @see \Drupal\Core\Config\Entity\ConfigEntityStorage.
|
||||
*/
|
||||
protected function checkStorageClass($class) {
|
||||
if (!is_a($class, 'Drupal\Core\Config\Entity\ConfigEntityStorage', TRUE)) {
|
||||
throw new ConfigEntityStorageClassException("$class is not \\Drupal\\Core\\Config\\Entity\\ConfigEntityStorage or it does not extend it");
|
||||
|
|
|
@ -808,6 +808,13 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
return !empty($this->translations[$langcode]['status']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isNewTranslation() {
|
||||
return $this->translations[$this->activeLangcode]['status'] == static::TRANSLATION_CREATED;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -822,37 +829,11 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C
|
|||
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.
|
||||
$entity_type = $this->getEntityType();
|
||||
|
||||
$default_values = array(
|
||||
$entity_type->getKey('bundle') => $this->bundle(),
|
||||
$this->langcodeKey => $langcode,
|
||||
);
|
||||
$entity = $this->entityManager()
|
||||
->getStorage($this->getEntityTypeId())
|
||||
->create($default_values);
|
||||
|
||||
foreach ($entity as $name => $field) {
|
||||
if (!isset($values[$name]) && !$field->isEmpty()) {
|
||||
$values[$name] = $field->getValue();
|
||||
}
|
||||
}
|
||||
$values[$this->langcodeKey] = $langcode;
|
||||
$values[$this->defaultLangcodeKey] = FALSE;
|
||||
|
||||
// Initialize the translation object.
|
||||
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
|
||||
$storage = $this->entityManager()->getStorage($this->getEntityTypeId());
|
||||
$this->translations[$langcode]['status'] = static::TRANSLATION_CREATED;
|
||||
$translation = $this->getTranslation($langcode);
|
||||
$definitions = $translation->getFieldDefinitions();
|
||||
|
||||
foreach ($values as $name => $value) {
|
||||
if (isset($definitions[$name]) && $definitions[$name]->isTranslatable()) {
|
||||
$translation->values[$name][$langcode] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $translation;
|
||||
return $storage->createTranslation($this, $langcode, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,10 @@ use Drupal\Core\Field\FieldDefinitionInterface;
|
|||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class ContentEntityStorageBase extends EntityStorageBase implements DynamicallyFieldableEntityStorageInterface {
|
||||
/**
|
||||
* Base class for content entity storage handlers.
|
||||
*/
|
||||
abstract class ContentEntityStorageBase extends EntityStorageBase implements ContentEntityStorageInterface, DynamicallyFieldableEntityStorageInterface {
|
||||
|
||||
/**
|
||||
* The entity bundle key.
|
||||
|
@ -87,13 +90,32 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Dyn
|
|||
$bundle = $values[$this->bundleKey];
|
||||
}
|
||||
$entity = new $this->entityClass(array(), $this->entityTypeId, $bundle);
|
||||
$this->initFieldValues($entity, $values);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes field values.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* An entity object.
|
||||
* @param array $values
|
||||
* (optional) An associative array of initial field values keyed by field
|
||||
* name. If none is provided default values will be applied.
|
||||
* @param array $field_names
|
||||
* (optional) An associative array of field names to be initialized. If none
|
||||
* is provided all fields will be initialized.
|
||||
*/
|
||||
protected function initFieldValues(ContentEntityInterface $entity, array $values = [], array $field_names = []) {
|
||||
// Populate field values.
|
||||
foreach ($entity as $name => $field) {
|
||||
if (isset($values[$name])) {
|
||||
$entity->$name = $values[$name];
|
||||
}
|
||||
elseif (!array_key_exists($name, $values)) {
|
||||
$entity->get($name)->applyDefaultValue();
|
||||
if (!$field_names || isset($field_names[$name])) {
|
||||
if (isset($values[$name])) {
|
||||
$entity->$name = $values[$name];
|
||||
}
|
||||
elseif (!array_key_exists($name, $values)) {
|
||||
$entity->get($name)->applyDefaultValue();
|
||||
}
|
||||
}
|
||||
unset($values[$name]);
|
||||
}
|
||||
|
@ -102,7 +124,23 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Dyn
|
|||
foreach ($values as $name => $value) {
|
||||
$entity->$name = $value;
|
||||
}
|
||||
return $entity;
|
||||
|
||||
// Make sure modules can alter field initial values.
|
||||
$this->invokeHook('field_values_init', $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []) {
|
||||
$translation = $entity->getTranslation($langcode);
|
||||
$definitions = array_filter($translation->getFieldDefinitions(), function(FieldDefinitionInterface $definition) { return $definition->isTranslatable(); });
|
||||
$field_names = array_map(function(FieldDefinitionInterface $definition) { return $definition->getName(); }, $definitions);
|
||||
$values[$this->langcodeKey] = $langcode;
|
||||
$values[$this->getEntityType()->getKey('default_langcode')] = FALSE;
|
||||
$this->initFieldValues($translation, $values, $field_names);
|
||||
$this->invokeHook('translation_create', $entity);
|
||||
return $translation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\ContentEntityStorageInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity;
|
||||
|
||||
/**
|
||||
* A storage that supports content entity types.
|
||||
*/
|
||||
interface ContentEntityStorageInterface extends EntityStorageInterface {
|
||||
|
||||
/**
|
||||
* Constructs a new entity translation object, without permanently saving it.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The entity object being translated.
|
||||
* @param string $langcode
|
||||
* The translation language code.
|
||||
* @param array $values
|
||||
* (optional) An associative array of initial field values keyed by field
|
||||
* name. If none is provided default values will be applied.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||
* A new entity translation object.
|
||||
*/
|
||||
public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []);
|
||||
|
||||
}
|
|
@ -30,4 +30,20 @@ class ContentEntityType extends EntityType implements ContentEntityTypeInterface
|
|||
return 'content';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see \Drupal\Core\Entity\ContentEntityStorageInterface.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* If the provided class does not implement
|
||||
* \Drupal\Core\Entity\ContentEntityStorageInterface.
|
||||
*/
|
||||
protected function checkStorageClass($class) {
|
||||
$required_interface = ContentEntityStorageInterface::class;
|
||||
if (!is_subclass_of($class, $required_interface)) {
|
||||
throw new \InvalidArgumentException("$class does not implement $required_interface");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -276,6 +276,9 @@ class EntityType implements EntityTypeInterface {
|
|||
$this->handlers += array(
|
||||
'access' => 'Drupal\Core\Entity\EntityAccessControlHandler',
|
||||
);
|
||||
if (isset($this->handlers['storage'])) {
|
||||
$this->checkStorageClass($this->handlers['storage']);
|
||||
}
|
||||
|
||||
// Automatically add the EntityChanged constraint if the entity type tracks
|
||||
// the changed time.
|
||||
|
@ -459,9 +462,20 @@ class EntityType implements EntityTypeInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStorageClass($class) {
|
||||
$this->checkStorageClass($class);
|
||||
$this->handlers['storage'] = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the provided class is an instance of ConfigEntityStorage.
|
||||
*
|
||||
* @param string $class
|
||||
* The class to check.
|
||||
*/
|
||||
protected function checkStorageClass($class) {
|
||||
// Nothing to check by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\KeyValueStore\KeyValueContentEntityStorage.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity\KeyValueStore;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\ContentEntityStorageInterface;
|
||||
|
||||
/**
|
||||
* Provides a key value backend for content entities.
|
||||
*/
|
||||
class KeyValueContentEntityStorage extends KeyValueEntityStorage implements ContentEntityStorageInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []) {
|
||||
// @todo
|
||||
}
|
||||
|
||||
}
|
|
@ -780,10 +780,9 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Act on a newly created entity.
|
||||
* Acts when creating a new entity.
|
||||
*
|
||||
* This hook runs after a new entity object has just been instantiated. It can
|
||||
* be used to set initial values, e.g. to provide defaults.
|
||||
* This hook runs after a new entity object has just been instantiated.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity object.
|
||||
|
@ -792,16 +791,13 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) {
|
|||
* @see hook_ENTITY_TYPE_create()
|
||||
*/
|
||||
function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
|
||||
if ($entity instanceof FieldableEntityInterface && !$entity->foo->value) {
|
||||
$entity->foo->value = 'some_initial_value';
|
||||
}
|
||||
\Drupal::logger('example')->info('Entity created: @label', ['@label' => $entity->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on a newly created entity of a specific type.
|
||||
* Acts when creating a new entity of a specific type.
|
||||
*
|
||||
* This hook runs after a new entity object has just been instantiated. It can
|
||||
* be used to set initial values, e.g. to provide defaults.
|
||||
* This hook runs after a new entity object has just been instantiated.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity object.
|
||||
|
@ -810,9 +806,7 @@ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
|
|||
* @see hook_entity_create()
|
||||
*/
|
||||
function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) {
|
||||
if (!$entity->foo->value) {
|
||||
$entity->foo->value = 'some_initial_value';
|
||||
}
|
||||
\Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1011,6 +1005,38 @@ function hook_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) {
|
|||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Acts when creating a new entity translation.
|
||||
*
|
||||
* This hook runs after a new entity translation object has just been
|
||||
* instantiated.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $translation
|
||||
* The entity object.
|
||||
*
|
||||
* @ingroup entity_crud
|
||||
* @see hook_ENTITY_TYPE_translation_create()
|
||||
*/
|
||||
function hook_entity_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
|
||||
\Drupal::logger('example')->info('Entity translation created: @label', ['@label' => $translation->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acts when creating a new entity translation of a specific type.
|
||||
*
|
||||
* This hook runs after a new entity translation object has just been
|
||||
* instantiated.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $translation
|
||||
* The entity object.
|
||||
*
|
||||
* @ingroup entity_crud
|
||||
* @see hook_entity_translation_create()
|
||||
*/
|
||||
function hook_ENTITY_TYPE_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
|
||||
\Drupal::logger('example')->info('ENTITY_TYPE translation created: @label', ['@label' => $translation->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to creation of a new entity translation.
|
||||
*
|
||||
|
@ -1886,6 +1912,44 @@ function hook_entity_field_access_alter(array &$grants, array $context) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Acts when initializing a fieldable entity object.
|
||||
*
|
||||
* This hook runs after a new entity object or a new entity translation object
|
||||
* has just been instantiated. It can be used to set initial values, e.g. to
|
||||
* provide defaults.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
||||
* The entity object.
|
||||
*
|
||||
* @ingroup entity_crud
|
||||
* @see hook_ENTITY_TYPE_field_values_init()
|
||||
*/
|
||||
function hook_entity_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
|
||||
if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface && !$entity->foo->value) {
|
||||
$entity->foo->value = 'some_initial_value';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Acts when initializing a fieldable entity object.
|
||||
*
|
||||
* This hook runs after a new entity object or a new entity translation object
|
||||
* has just been instantiated. It can be used to set initial values, e.g. to
|
||||
* provide defaults.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
||||
* The entity object.
|
||||
*
|
||||
* @ingroup entity_crud
|
||||
* @see hook_entity_field_values_init()
|
||||
*/
|
||||
function hook_ENTITY_TYPE_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
|
||||
if (!$entity->foo->value) {
|
||||
$entity->foo->value = 'some_initial_value';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes "pseudo-field" components on content entities.
|
||||
*
|
||||
|
|
|
@ -28,6 +28,14 @@ interface TranslatableInterface {
|
|||
*/
|
||||
public function isDefaultTranslation();
|
||||
|
||||
/**
|
||||
* Checks whether the translation is new.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the translation is new, FALSE otherwise.
|
||||
*/
|
||||
public function isNewTranslation();
|
||||
|
||||
/**
|
||||
* Returns the languages the data is translated to.
|
||||
*
|
||||
|
|
Reference in a new issue