Issue #1869250 by fago, Berdir, das-peter, YesCT, mradcliffe, fubhy: Various EntityNG and TypedData API improvements.
parent
85c8d12ec9
commit
c96966f079
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Core\Config\Entity;
|
||||
|
||||
use Drupal\Core\Entity\Entity;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
|
||||
/**
|
||||
* Defines a base configuration entity class.
|
||||
|
@ -126,4 +127,53 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::getBCEntity().
|
||||
*/
|
||||
public function getBCEntity() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::getOriginalEntity().
|
||||
*/
|
||||
public function getOriginalEntity() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getRoot().
|
||||
*/
|
||||
public function getRoot() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getPropertyPath().
|
||||
*/
|
||||
public function getPropertyPath() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getParent().
|
||||
*/
|
||||
public function getParent() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::setContext().
|
||||
*/
|
||||
public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
// As entities are always the root of the tree, we do not need to set any
|
||||
// context.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,13 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
|
|||
*/
|
||||
protected $entityFieldInfo;
|
||||
|
||||
/**
|
||||
* Static cache of field definitions per bundle.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldDefinitions;
|
||||
|
||||
/**
|
||||
* Additional arguments to pass to hook_TYPE_load().
|
||||
*
|
||||
|
@ -687,15 +694,17 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
|
|||
}
|
||||
}
|
||||
|
||||
$definitions = $this->entityFieldInfo['definitions'];
|
||||
$bundle = !empty($constraints['bundle']) ? $constraints['bundle'] : FALSE;
|
||||
|
||||
// Add in per-bundle properties.
|
||||
// @todo: Should this be statically cached as well?
|
||||
if (!empty($constraints['bundle']) && isset($this->entityFieldInfo['bundle map'][$constraints['bundle']])) {
|
||||
$definitions += array_intersect_key($this->entityFieldInfo['optional'], array_flip($this->entityFieldInfo['bundle map'][$constraints['bundle']]));
|
||||
}
|
||||
if (!isset($this->fieldDefinitions[$bundle])) {
|
||||
$this->fieldDefinitions[$bundle] = $this->entityFieldInfo['definitions'];
|
||||
|
||||
return $definitions;
|
||||
if ($bundle && isset($this->entityFieldInfo['bundle map'][$constraints['bundle']])) {
|
||||
$this->fieldDefinitions[$bundle] += array_intersect_key($this->entityFieldInfo['optional'], array_flip($this->entityFieldInfo['bundle map'][$constraints['bundle']]));
|
||||
}
|
||||
}
|
||||
return $this->fieldDefinitions[$bundle];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -77,20 +77,17 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
* A new entity object.
|
||||
*/
|
||||
public function create(array $values) {
|
||||
$entity = new $this->entityClass(array(), $this->entityType);
|
||||
// We have to determine the bundle first.
|
||||
$bundle = $this->bundleKey ? $values[$this->bundleKey] : FALSE;
|
||||
$entity = new $this->entityClass(array(), $this->entityType, $bundle);
|
||||
|
||||
// Make sure to set the bundle first.
|
||||
if ($this->bundleKey) {
|
||||
$entity->{$this->bundleKey} = $values[$this->bundleKey];
|
||||
unset($values[$this->bundleKey]);
|
||||
}
|
||||
// Set all other given values.
|
||||
foreach ($values as $name => $value) {
|
||||
$entity->$name = $value;
|
||||
}
|
||||
|
||||
// Assign a new UUID if there is none yet.
|
||||
if ($this->uuidKey && !isset($entity->{$this->uuidKey})) {
|
||||
if ($this->uuidKey && !isset($entity->{$this->uuidKey}->value)) {
|
||||
$uuid = new Uuid();
|
||||
$entity->{$this->uuidKey}->value = $uuid->generate();
|
||||
}
|
||||
|
@ -109,19 +106,20 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
|
||||
// Attach fields.
|
||||
if ($this->entityInfo['fieldable']) {
|
||||
// Prepare BC compatible entities for field API.
|
||||
$bc_entities = array();
|
||||
foreach ($queried_entities as $key => $entity) {
|
||||
$bc_entities[$key] = $entity->getBCEntity();
|
||||
}
|
||||
|
||||
if ($load_revision) {
|
||||
field_attach_load_revision($this->entityType, $queried_entities);
|
||||
field_attach_load_revision($this->entityType, $bc_entities);
|
||||
}
|
||||
else {
|
||||
field_attach_load($this->entityType, $queried_entities);
|
||||
field_attach_load($this->entityType, $bc_entities);
|
||||
}
|
||||
}
|
||||
|
||||
// Loading is finished, so disable compatibility mode now.
|
||||
foreach ($queried_entities as $entity) {
|
||||
$entity->setCompatibilityMode(FALSE);
|
||||
}
|
||||
|
||||
// Call hook_entity_load().
|
||||
foreach (module_implements('entity_load') as $module) {
|
||||
$function = $module . '_entity_load';
|
||||
|
@ -150,13 +148,14 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
protected function mapFromStorageRecords(array $records, $load_revision = FALSE) {
|
||||
|
||||
foreach ($records as $id => $record) {
|
||||
$entity = new $this->entityClass(array(), $this->entityType);
|
||||
$entity->setCompatibilityMode(TRUE);
|
||||
|
||||
$values = array();
|
||||
foreach ($record as $name => $value) {
|
||||
$entity->{$name}[LANGUAGE_DEFAULT][0]['value'] = $value;
|
||||
// Avoid unnecessary array hierarchies to save memory.
|
||||
$values[$name][LANGUAGE_DEFAULT] = $value;
|
||||
}
|
||||
$records[$id] = $entity;
|
||||
$bundle = $this->bundleKey ? $record->{$this->bundleKey} : FALSE;
|
||||
// Turn the record into an entity class.
|
||||
$records[$id] = new $this->entityClass($values, $this->entityType, $bundle);
|
||||
}
|
||||
return $records;
|
||||
}
|
||||
|
@ -179,11 +178,6 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
|
||||
// Create the storage record to be saved.
|
||||
$record = $this->maptoStorageRecord($entity);
|
||||
// Update the original values so that the compatibility mode works with
|
||||
// the update values, what is required by field API attachers.
|
||||
// @todo Once field API has been converted to use the Field API, move
|
||||
// this after insert/update hooks.
|
||||
$entity->updateOriginalValues();
|
||||
|
||||
if (!$entity->isNew()) {
|
||||
if ($entity->isDefaultRevision()) {
|
||||
|
@ -215,6 +209,7 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
$this->postSave($entity, FALSE);
|
||||
$this->invokeHook('insert', $entity);
|
||||
}
|
||||
$entity->updateOriginalValues();
|
||||
|
||||
// Ignore slave server temporarily.
|
||||
db_ignore_slave();
|
||||
|
@ -270,8 +265,7 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
/**
|
||||
* Overrides DatabaseStorageController::invokeHook().
|
||||
*
|
||||
* Invokes field API attachers in compatibility mode and disables it
|
||||
* afterwards.
|
||||
* Invokes field API attachers with a BC entity.
|
||||
*/
|
||||
protected function invokeHook($hook, EntityInterface $entity) {
|
||||
$function = 'field_attach_' . $hook;
|
||||
|
@ -281,9 +275,7 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
$function = 'field_attach_delete_revision';
|
||||
}
|
||||
if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {
|
||||
$entity->setCompatibilityMode(TRUE);
|
||||
$function($this->entityType, $entity);
|
||||
$entity->setCompatibilityMode(FALSE);
|
||||
$function($this->entityType, $entity->getBCEntity());
|
||||
}
|
||||
|
||||
// Invoke the hook.
|
||||
|
@ -311,7 +303,6 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
|
|||
foreach ($this->entityInfo['schema_fields_sql']['revision_table'] as $name) {
|
||||
$record->$name = $entity->$name->value;
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\Core\Entity;
|
|||
|
||||
use Drupal\Component\Uuid\Uuid;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use IteratorAggregate;
|
||||
|
||||
/**
|
||||
|
@ -379,4 +380,53 @@ class Entity implements IteratorAggregate, EntityInterface {
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::getBCEntity().
|
||||
*/
|
||||
public function getBCEntity() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::getOriginalEntity().
|
||||
*/
|
||||
public function getOriginalEntity() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getRoot().
|
||||
*/
|
||||
public function getRoot() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getPropertyPath().
|
||||
*/
|
||||
public function getPropertyPath() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getParent().
|
||||
*/
|
||||
public function getParent() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::setContext().
|
||||
*/
|
||||
public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
// As entities are always the root of the tree, we do not need to set any
|
||||
// context.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,368 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Entity\EntityBCDecorator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Entity;
|
||||
|
||||
use IteratorAggregate;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
|
||||
/**
|
||||
* Implements a decorator providing backwards compatible entity field access.
|
||||
*
|
||||
* Allows using entities converted to the new Entity Field API with the Drupal 7
|
||||
* way of accessing fields or properties.
|
||||
*
|
||||
* Note: We access the protected 'values' and 'fields' properties of the entity
|
||||
* via the magic getter - which returns them by reference for us. We do so, as
|
||||
* providing references to this arrays makes $entity->values and $entity->fields
|
||||
* to references itself as well, which is problematic during __clone() (this is
|
||||
* something that would not be easy to fix as an unset() on the variable is
|
||||
* problematic with the magic getter/setter then).
|
||||
*/
|
||||
class EntityBCDecorator implements IteratorAggregate, EntityInterface {
|
||||
|
||||
/**
|
||||
* The EntityInterface object being decorated.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $decorated;
|
||||
|
||||
/**
|
||||
* Constructs a Drupal\Core\Entity\EntityCompatibilityDecorator object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $decorated
|
||||
* The decorated entity.
|
||||
*/
|
||||
function __construct(EntityNG $decorated) {
|
||||
$this->decorated = $decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Entity::getOriginalEntity().
|
||||
*/
|
||||
public function getOriginalEntity() {
|
||||
return $this->decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Entity::getBCEntity().
|
||||
*/
|
||||
public function getBCEntity() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the magic method for getting object properties.
|
||||
*
|
||||
* Directly accesses the plain field values, as done in Drupal 7.
|
||||
*/
|
||||
public function &__get($name) {
|
||||
// Make sure $this->decorated->values reflects the latest values.
|
||||
if (!empty($this->decorated->fields[$name])) {
|
||||
foreach ($this->decorated->fields[$name] as $langcode => $field) {
|
||||
$this->decorated->values[$name][$langcode] = $field->getValue();
|
||||
}
|
||||
// Values might be changed by reference, so remove the field object to
|
||||
// avoid them becoming out of sync.
|
||||
unset($this->decorated->fields[$name]);
|
||||
}
|
||||
// Allow accessing field values in entity default languages other than
|
||||
// LANGUAGE_DEFAULT by mapping the values to LANGUAGE_DEFAULT.
|
||||
$langcode = $this->decorated->language()->langcode;
|
||||
if ($langcode != LANGUAGE_DEFAULT && isset($this->decorated->values[$name][LANGUAGE_DEFAULT]) && !isset($this->decorated->values[$name][$langcode])) {
|
||||
$this->decorated->values[$name][$langcode] = &$this->decorated->values[$name][LANGUAGE_DEFAULT];
|
||||
}
|
||||
|
||||
if (!isset($this->decorated->values[$name])) {
|
||||
$this->decorated->values[$name] = NULL;
|
||||
}
|
||||
return $this->decorated->values[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the magic method for setting object properties.
|
||||
*
|
||||
* Directly writes to the plain field values, as done by Drupal 7.
|
||||
*/
|
||||
public function __set($name, $value) {
|
||||
if (is_array($value) && $definition = $this->decorated->getPropertyDefinition($name)) {
|
||||
// If field API sets a value with a langcode in entity language, move it
|
||||
// to LANGUAGE_DEFAULT.
|
||||
foreach ($value as $langcode => $data) {
|
||||
if ($langcode != LANGUAGE_DEFAULT && $langcode == $this->decorated->language()->langcode) {
|
||||
$value[LANGUAGE_DEFAULT] = $data;
|
||||
unset($value[$langcode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->decorated->values[$name] = $value;
|
||||
unset($this->decorated->fields[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the magic method for isset().
|
||||
*/
|
||||
public function __isset($name) {
|
||||
$value = $this->__get($name);
|
||||
return isset($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the magic method for unset().
|
||||
*/
|
||||
public function __unset($name) {
|
||||
$value = &$this->__get($name);
|
||||
$value = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL) {
|
||||
return $this->decorated->access($account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function get($property_name) {
|
||||
return $this->decorated->get($property_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function set($property_name, $value) {
|
||||
return $this->decorated->set($property_name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getProperties($include_computed = FALSE) {
|
||||
return $this->decorated->getProperties($include_computed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getPropertyValues() {
|
||||
return $this->decorated->getPropertyValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function setPropertyValues($values) {
|
||||
return $this->decorated->setPropertyValues($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getPropertyDefinition($name) {
|
||||
return $this->decorated->getPropertyDefinition($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getPropertyDefinitions() {
|
||||
return $this->decorated->getPropertyDefinitions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function isEmpty() {
|
||||
return $this->decorated->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getIterator() {
|
||||
return $this->decorated->getIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function id() {
|
||||
return $this->decorated->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function uuid() {
|
||||
return $this->decorated->uuid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function isNew() {
|
||||
return $this->decorated->isNew();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function isNewRevision() {
|
||||
return $this->decorated->isNewRevision();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function setNewRevision($value = TRUE) {
|
||||
return $this->decorated->setNewRevision($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function enforceIsNew($value = TRUE) {
|
||||
return $this->decorated->enforceIsNew($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function entityType() {
|
||||
return $this->decorated->entityType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function bundle() {
|
||||
return $this->decorated->bundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function label($langcode = NULL) {
|
||||
return $this->decorated->label($langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function uri() {
|
||||
return $this->decorated->uri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function save() {
|
||||
return $this->decorated->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function delete() {
|
||||
return $this->decorated->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function createDuplicate() {
|
||||
return $this->decorated->createDuplicate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function entityInfo() {
|
||||
return $this->decorated->entityInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getRevisionId() {
|
||||
return $this->decorated->getRevisionId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function isDefaultRevision($new_value = NULL) {
|
||||
return $this->decorated->isDefaultRevision($new_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function language() {
|
||||
return $this->decorated->language();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getTranslationLanguages($include_default = TRUE) {
|
||||
return $this->decorated->getTranslationLanguages($include_default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getTranslation($langcode, $strict = TRUE) {
|
||||
return $this->decorated->getTranslation($langcode, $strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->decorated->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getRoot() {
|
||||
return $this->decorated->getRoot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getPropertyPath() {
|
||||
return $this->decorated->getPropertyPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->decorated->getParent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
$this->decorated->setContext($name, $parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the call to the decorated entity.
|
||||
*/
|
||||
public function getExportProperties() {
|
||||
$this->decorated->getExportProperties();
|
||||
}
|
||||
}
|
|
@ -23,9 +23,7 @@ class EntityFormControllerNG extends EntityFormController {
|
|||
// entity properties.
|
||||
$info = $entity->entityInfo();
|
||||
if (!empty($info['fieldable'])) {
|
||||
$entity->setCompatibilityMode(TRUE);
|
||||
field_attach_form($entity->entityType(), $entity, $form, $form_state, $this->getFormLangcode($form_state));
|
||||
$entity->setCompatibilityMode(FALSE);
|
||||
field_attach_form($entity->entityType(), $entity->getBCEntity(), $form, $form_state, $this->getFormLangcode($form_state));
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
@ -40,9 +38,7 @@ class EntityFormControllerNG extends EntityFormController {
|
|||
$info = $entity->entityInfo();
|
||||
|
||||
if (!empty($info['fieldable'])) {
|
||||
$entity->setCompatibilityMode(TRUE);
|
||||
field_attach_form_validate($entity->entityType(), $entity, $form, $form_state);
|
||||
$entity->setCompatibilityMode(FALSE);
|
||||
field_attach_form_validate($entity->entityType(), $entity->getBCEntity(), $form, $form_state);
|
||||
}
|
||||
|
||||
// @todo Remove this.
|
||||
|
@ -82,9 +78,7 @@ class EntityFormControllerNG extends EntityFormController {
|
|||
|
||||
// Copy field values to the entity.
|
||||
if ($info['fieldable']) {
|
||||
$entity->setCompatibilityMode(TRUE);
|
||||
field_attach_submit($entity_type, $entity, $form, $form_state);
|
||||
$entity->setCompatibilityMode(FALSE);
|
||||
field_attach_submit($entity_type, $entity->getBCEntity(), $form, $form_state);
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Core\Entity;
|
||||
|
||||
use Drupal\Core\TypedData\AccessibleInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\TranslatableInterface;
|
||||
|
||||
|
@ -17,7 +18,7 @@ use Drupal\Core\TypedData\TranslatableInterface;
|
|||
* When implementing this interface which extends Traversable, make sure to list
|
||||
* IteratorAggregate or Iterator before this interface in the implements clause.
|
||||
*/
|
||||
interface EntityInterface extends ComplexDataInterface, AccessibleInterface, TranslatableInterface {
|
||||
interface EntityInterface extends ContextAwareInterface, ComplexDataInterface, AccessibleInterface, TranslatableInterface {
|
||||
|
||||
/**
|
||||
* Returns the entity identifier (the entity's machine name or numeric ID).
|
||||
|
@ -190,4 +191,23 @@ interface EntityInterface extends ComplexDataInterface, AccessibleInterface, Tra
|
|||
*/
|
||||
public function getExportProperties();
|
||||
|
||||
/**
|
||||
* Gets a backward compatibility decorator entity.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* The backward compatible entity.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityInterface::getOriginalEntity()
|
||||
*/
|
||||
public function getBCEntity();
|
||||
|
||||
/**
|
||||
* Removes any possible (backward compatibility) decorator in use.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* The original, not backward compatible entity object.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityInterface::getBCEntity()
|
||||
*/
|
||||
public function getOriginalEntity();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,13 @@ use InvalidArgumentException;
|
|||
*/
|
||||
class EntityNG extends Entity {
|
||||
|
||||
/**
|
||||
* Local cache holding the value of the bundle field.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bundle;
|
||||
|
||||
/**
|
||||
* The plain data values of the contained fields.
|
||||
*
|
||||
|
@ -50,22 +57,69 @@ class EntityNG extends Entity {
|
|||
protected $fields = array();
|
||||
|
||||
/**
|
||||
* Whether the entity is in pre-Entity Field API compatibility mode.
|
||||
* An instance of the backward compatibility decorator.
|
||||
*
|
||||
* If set to TRUE, field values are written directly to $this->values, thus
|
||||
* must be plain property values keyed by language code. This must be enabled
|
||||
* when calling legacy field API attachers.
|
||||
*
|
||||
* @var bool
|
||||
* @var EntityBCDecorator
|
||||
*/
|
||||
protected $compatibilityMode = FALSE;
|
||||
|
||||
protected $bcEntity;
|
||||
|
||||
/**
|
||||
* Overrides Entity::id().
|
||||
* Local cache for field definitions.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldDefinitions;
|
||||
|
||||
/**
|
||||
* Overrides Entity::__construct().
|
||||
*/
|
||||
public function __construct(array $values, $entity_type, $bundle = FALSE) {
|
||||
$this->entityType = $entity_type;
|
||||
$this->bundle = $bundle ? $bundle : $this->entityType;
|
||||
foreach ($values as $key => $value) {
|
||||
$this->values[$key] = $value;
|
||||
}
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the typed data type of the entity.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the object. Invoked upon construction and wake up.
|
||||
*/
|
||||
protected function init() {
|
||||
// We unset all defined properties, so magic getters apply.
|
||||
unset($this->langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic __wakeup() implemenation.
|
||||
*/
|
||||
public function __wakeup() {
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::id().
|
||||
*/
|
||||
public function id() {
|
||||
return $this->get('id')->value;
|
||||
return $this->id->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::bundle().
|
||||
*/
|
||||
public function bundle() {
|
||||
return $this->bundle;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,9 +159,11 @@ class EntityNG extends Entity {
|
|||
$this->fields[$property_name][$langcode] = $this->getTranslatedField($property_name, LANGUAGE_DEFAULT);
|
||||
}
|
||||
else {
|
||||
$value = isset($this->values[$property_name][$langcode]) ? $this->values[$property_name][$langcode] : NULL;
|
||||
$context = array('parent' => $this, 'name' => $property_name);
|
||||
$this->fields[$property_name][$langcode] = typed_data()->create($definition, $value, $context);
|
||||
$value = NULL;
|
||||
if (isset($this->values[$property_name][$langcode])) {
|
||||
$value = $this->values[$property_name][$langcode];
|
||||
}
|
||||
$this->fields[$property_name][$langcode] = typed_data()->getPropertyInstance($this, $property_name, $value);
|
||||
}
|
||||
}
|
||||
return $this->fields[$property_name][$langcode];
|
||||
|
@ -144,18 +200,14 @@ class EntityNG extends Entity {
|
|||
* Implements ComplexDataInterface::getPropertyDefinition().
|
||||
*/
|
||||
public function getPropertyDefinition($name) {
|
||||
// First try getting property definitions which apply to all entities of
|
||||
// this type. Then if this fails add in definitions of optional properties
|
||||
// as well. That way we can use property definitions of base properties
|
||||
// when determining the optional properties of an entity.
|
||||
$definitions = entity_get_controller($this->entityType)->getFieldDefinitions(array());
|
||||
|
||||
if (isset($definitions[$name])) {
|
||||
return $definitions[$name];
|
||||
if (!isset($this->fieldDefinitions)) {
|
||||
$this->getPropertyDefinitions();
|
||||
}
|
||||
// Add in optional properties if any.
|
||||
if ($definitions = $this->getPropertyDefinitions()) {
|
||||
return isset($definitions[$name]) ? $definitions[$name] : FALSE;
|
||||
if (isset($this->fieldDefinitions[$name])) {
|
||||
return $this->fieldDefinitions[$name];
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,10 +215,13 @@ class EntityNG extends Entity {
|
|||
* Implements ComplexDataInterface::getPropertyDefinitions().
|
||||
*/
|
||||
public function getPropertyDefinitions() {
|
||||
return entity_get_controller($this->entityType)->getFieldDefinitions(array(
|
||||
'entity type' => $this->entityType,
|
||||
'bundle' => $this->bundle(),
|
||||
));
|
||||
if (!isset($this->fieldDefinitions)) {
|
||||
$this->fieldDefinitions = entity_get_controller($this->entityType)->getFieldDefinitions(array(
|
||||
'entity type' => $this->entityType,
|
||||
'bundle' => $this->bundle,
|
||||
));
|
||||
}
|
||||
return $this->fieldDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,7 +263,13 @@ class EntityNG extends Entity {
|
|||
* Implements TranslatableInterface::language().
|
||||
*/
|
||||
public function language() {
|
||||
return $this->get('langcode')->language;
|
||||
$language = $this->get('langcode')->language;
|
||||
if (!$language) {
|
||||
// Make sure we return a proper language object.
|
||||
// @todo Refactor this, see: http://drupal.org/node/1834542.
|
||||
$language = language_default();
|
||||
}
|
||||
return $language;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,6 +297,9 @@ class EntityNG extends Entity {
|
|||
$fields[$name] = $this->getTranslatedField($name, $langcode);
|
||||
}
|
||||
}
|
||||
// @todo: Add a way to get the definition of a translation to the
|
||||
// TranslatableInterface and leverage TypeDataManager::getPropertyInstance
|
||||
// also.
|
||||
$translation_definition = array(
|
||||
'type' => 'entity_translation',
|
||||
'constraints' => array(
|
||||
|
@ -243,11 +307,11 @@ class EntityNG extends Entity {
|
|||
'bundle' => $this->bundle(),
|
||||
),
|
||||
);
|
||||
$translation = typed_data()->create($translation_definition, $fields, array(
|
||||
'parent' => $this,
|
||||
'name' => $langcode,
|
||||
));
|
||||
$translation = typed_data()->create($translation_definition, $fields);
|
||||
$translation->setStrictMode($strict);
|
||||
if ($translation instanceof ContextAwareInterface) {
|
||||
$translation->setContext('@' . $langcode, $this);
|
||||
}
|
||||
return $translation;
|
||||
}
|
||||
|
||||
|
@ -256,89 +320,101 @@ class EntityNG extends Entity {
|
|||
*/
|
||||
public function getTranslationLanguages($include_default = TRUE) {
|
||||
$translations = array();
|
||||
// Build an array with the translation langcodes set as keys.
|
||||
// Build an array with the translation langcodes set as keys. Empty
|
||||
// translations must be filtered out.
|
||||
foreach ($this->getProperties() as $name => $property) {
|
||||
if (isset($this->values[$name])) {
|
||||
$translations += $this->values[$name];
|
||||
foreach ($this->fields[$name] as $langcode => $field) {
|
||||
if (!$field->isEmpty()) {
|
||||
$translations[$langcode] = TRUE;
|
||||
}
|
||||
if (isset($this->values[$name])) {
|
||||
foreach ($this->values[$name] as $langcode => $values) {
|
||||
if ($values && !(isset($this->fields[$name][$langcode]) && $this->fields[$name][$langcode]->isEmpty())) {
|
||||
$translations[$langcode] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$translations += $this->fields[$name];
|
||||
}
|
||||
unset($translations[LANGUAGE_DEFAULT]);
|
||||
|
||||
if ($include_default) {
|
||||
$translations[$this->language()->langcode] = TRUE;
|
||||
}
|
||||
|
||||
// Now get languages based upon translation langcodes. Empty languages must
|
||||
// be filtered out as they concern empty/unset properties.
|
||||
$languages = array_intersect_key(language_list(LANGUAGE_ALL), array_filter($translations));
|
||||
return $languages;
|
||||
// Now get languages based upon translation langcodes.
|
||||
return array_intersect_key(language_list(LANGUAGE_ALL), $translations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disable the compatibility mode.
|
||||
* Overrides Entity::translations().
|
||||
*
|
||||
* @param bool $enabled
|
||||
* Whether to enable the mode.
|
||||
*
|
||||
* @see EntityNG::compatibilityMode
|
||||
* @todo: Remove once Entity::translations() gets removed.
|
||||
*/
|
||||
public function setCompatibilityMode($enabled) {
|
||||
$this->compatibilityMode = (bool) $enabled;
|
||||
if ($enabled) {
|
||||
$this->updateOriginalValues();
|
||||
$this->fields = array();
|
||||
public function translations() {
|
||||
return $this->getTranslationLanguages(FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Entity::getBCEntity().
|
||||
*/
|
||||
public function getBCEntity() {
|
||||
if (!isset($this->bcEntity)) {
|
||||
$this->bcEntity = new EntityBCDecorator($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the compatibility mode is active.
|
||||
*/
|
||||
public function getCompatibilityMode() {
|
||||
return $this->compatibilityMode;
|
||||
return $this->bcEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the original values with the interim changes.
|
||||
*
|
||||
* Note: This should be called by the storage controller during a save
|
||||
* operation.
|
||||
*/
|
||||
public function updateOriginalValues() {
|
||||
foreach ($this->fields as $name => $properties) {
|
||||
foreach ($properties as $langcode => $property) {
|
||||
$this->values[$name][$langcode] = $property->getValue();
|
||||
if (!$this->fields) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->getPropertyDefinitions() as $name => $definition) {
|
||||
if (empty($definition['computed']) && !empty($this->fields[$name])) {
|
||||
foreach ($this->fields[$name] as $langcode => $field) {
|
||||
$this->values[$name][$langcode] = $field->getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter: Gets the property in default language.
|
||||
* Implements the magic method for setting object properties.
|
||||
*
|
||||
* Uses default language always.
|
||||
* For compatibility mode to work this must return a reference.
|
||||
*/
|
||||
public function &__get($name) {
|
||||
if ($this->compatibilityMode) {
|
||||
if (!isset($this->values[$name])) {
|
||||
$this->values[$name] = NULL;
|
||||
}
|
||||
return $this->values[$name];
|
||||
}
|
||||
if (isset($this->fields[$name][LANGUAGE_DEFAULT])) {
|
||||
return $this->fields[$name][LANGUAGE_DEFAULT];
|
||||
}
|
||||
if ($this->getPropertyDefinition($name)) {
|
||||
$return = $this->get($name);
|
||||
// Inline getPropertyDefinition() to speed up things.
|
||||
if (!isset($this->fieldDefinitions)) {
|
||||
$this->getPropertyDefinitions();
|
||||
}
|
||||
if (isset($this->fieldDefinitions[$name])) {
|
||||
$return = $this->getTranslatedField($name, LANGUAGE_DEFAULT);
|
||||
return $return;
|
||||
}
|
||||
if (!isset($this->$name)) {
|
||||
$this->$name = NULL;
|
||||
// Allow the EntityBCDecorator to directly access the values and fields.
|
||||
// @todo: Remove once the EntityBCDecorator gets removed.
|
||||
if ($name == 'values' || $name == 'fields') {
|
||||
return $this->$name;
|
||||
}
|
||||
return $this->$name;
|
||||
// Else directly read/write plain values. That way, fields not yet converted
|
||||
// to the entity field API can always be directly accessed.
|
||||
if (!isset($this->values[$name])) {
|
||||
$this->values[$name] = NULL;
|
||||
}
|
||||
return $this->values[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter: Sets the property in default language.
|
||||
* Implements the magic method for setting object properties.
|
||||
*
|
||||
* Uses default language always.
|
||||
*/
|
||||
public function __set($name, $value) {
|
||||
// Support setting values via property objects.
|
||||
|
@ -346,41 +422,40 @@ class EntityNG extends Entity {
|
|||
$value = $value->getValue();
|
||||
}
|
||||
|
||||
if ($this->compatibilityMode) {
|
||||
$this->values[$name] = $value;
|
||||
}
|
||||
elseif (isset($this->fields[$name][LANGUAGE_DEFAULT])) {
|
||||
if (isset($this->fields[$name][LANGUAGE_DEFAULT])) {
|
||||
$this->fields[$name][LANGUAGE_DEFAULT]->setValue($value);
|
||||
}
|
||||
elseif ($this->getPropertyDefinition($name)) {
|
||||
$this->get($name)->setValue($value);
|
||||
$this->getTranslatedField($name, LANGUAGE_DEFAULT)->setValue($value);
|
||||
}
|
||||
// Else directly read/write plain values. That way, fields not yet converted
|
||||
// to the entity field API can always be directly accessed.
|
||||
else {
|
||||
$this->$name = $value;
|
||||
$this->values[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method.
|
||||
* Implements the magic method for isset().
|
||||
*/
|
||||
public function __isset($name) {
|
||||
if ($this->compatibilityMode) {
|
||||
return isset($this->values[$name]);
|
||||
if ($this->getPropertyDefinition($name)) {
|
||||
return $this->get($name)->getValue() !== NULL;
|
||||
}
|
||||
elseif ($this->getPropertyDefinition($name)) {
|
||||
return $this->get($name)->valueIsSet();
|
||||
else {
|
||||
return isset($this->values[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method.
|
||||
* Implements the magic method for unset.
|
||||
*/
|
||||
public function __unset($name) {
|
||||
if ($this->compatibilityMode) {
|
||||
unset($this->values[$name]);
|
||||
if ($this->getPropertyDefinition($name)) {
|
||||
$this->get($name)->setValue(NULL);
|
||||
}
|
||||
elseif ($this->getPropertyDefinition($name)) {
|
||||
$this->get($name)->unsetValue();
|
||||
else {
|
||||
unset($this->values[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,13 +479,30 @@ class EntityNG extends Entity {
|
|||
* Implements a deep clone.
|
||||
*/
|
||||
public function __clone() {
|
||||
$this->bcEntity = NULL;
|
||||
|
||||
foreach ($this->fields as $name => $properties) {
|
||||
foreach ($properties as $langcode => $property) {
|
||||
$this->fields[$name][$langcode] = clone $property;
|
||||
if ($property instanceof ContextAwareInterface) {
|
||||
$this->fields[$name][$langcode]->setParent($this);
|
||||
$this->fields[$name][$langcode]->setContext($name, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Entity::label() to access the label field with the new API.
|
||||
*/
|
||||
public function label($langcode = NULL) {
|
||||
$label = NULL;
|
||||
$entity_info = $this->entityInfo();
|
||||
if (isset($entity_info['label_callback']) && function_exists($entity_info['label_callback'])) {
|
||||
$label = $entity_info['label_callback']($this->entityType, $this, $langcode);
|
||||
}
|
||||
elseif (!empty($entity_info['entity_keys']['label']) && isset($this->{$entity_info['entity_keys']['label']})) {
|
||||
$label = $this->{$entity_info['entity_keys']['label']}->value;
|
||||
}
|
||||
return $label;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,23 +68,8 @@ class EntityRenderController implements EntityRenderControllerInterface {
|
|||
|
||||
// Prepare and build field content, grouped by view mode.
|
||||
foreach ($view_modes as $view_mode => $view_mode_entities) {
|
||||
$call_prepare = array();
|
||||
// To ensure hooks are only run once per entity, check for an
|
||||
// entity_view_prepared flag and only process relevant entities.
|
||||
foreach ($view_mode_entities as $entity) {
|
||||
if (empty($entity->entity_view_prepared) || $entity->entity_view_prepared != $view_mode) {
|
||||
// Add this entity to the items to be prepared.
|
||||
$call_prepare[$entity->id()] = $entity;
|
||||
|
||||
// Mark this item as prepared for this view mode.
|
||||
$entity->entity_view_prepared = $view_mode;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($call_prepare)) {
|
||||
field_attach_prepare_view($this->entityType, $call_prepare, $displays[$view_mode], $langcode);
|
||||
module_invoke_all('entity_prepare_view', $call_prepare, $this->entityType);
|
||||
}
|
||||
field_attach_prepare_view($this->entityType, $view_mode_entities, $displays[$view_mode], $langcode);
|
||||
module_invoke_all('entity_prepare_view', $view_mode_entities, $this->entityType);
|
||||
|
||||
foreach ($view_mode_entities as $entity) {
|
||||
$entity->content += field_attach_view($this->entityType, $entity, $displays[$view_mode][$entity->bundle()], $langcode);
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\Entity\Field;
|
||||
|
||||
use Drupal\Core\TypedData\Type\TypedData;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareTypedData;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\user;
|
||||
|
@ -24,21 +23,7 @@ use InvalidArgumentException;
|
|||
*
|
||||
* @see \Drupal\Core\Entity\Field\FieldItemInterface
|
||||
*/
|
||||
abstract class FieldItemBase extends TypedData implements IteratorAggregate, FieldItemInterface {
|
||||
|
||||
/**
|
||||
* The item delta or name.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The parent entity field.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Field\FieldInterface
|
||||
*/
|
||||
protected $parent;
|
||||
abstract class FieldItemBase extends ContextAwareTypedData implements IteratorAggregate, FieldItemInterface {
|
||||
|
||||
/**
|
||||
* The array of properties.
|
||||
|
@ -52,10 +37,10 @@ abstract class FieldItemBase extends TypedData implements IteratorAggregate, Fie
|
|||
protected $properties = array();
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::__construct().
|
||||
* Overrides ContextAwareTypedData::__construct().
|
||||
*/
|
||||
public function __construct(array $definition) {
|
||||
$this->definition = $definition;
|
||||
public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
parent::__construct($definition, $name, $parent);
|
||||
|
||||
// Initialize all property objects, but postpone the creating of computed
|
||||
// properties to a second step. That way computed properties can safely get
|
||||
|
@ -63,17 +48,15 @@ abstract class FieldItemBase extends TypedData implements IteratorAggregate, Fie
|
|||
$step2 = array();
|
||||
foreach ($this->getPropertyDefinitions() as $name => $definition) {
|
||||
if (empty($definition['computed'])) {
|
||||
$context = array('name' => $name, 'parent' => $this);
|
||||
$this->properties[$name] = typed_data()->create($definition, NULL, $context);
|
||||
$this->properties[$name] = typed_data()->getPropertyInstance($this, $name);
|
||||
}
|
||||
else {
|
||||
$step2[$name] = $definition;
|
||||
$step2[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($step2 as $name => $definition) {
|
||||
$context = array('name' => $name, 'parent' => $this);
|
||||
$this->properties[$name] = typed_data()->create($definition, NULL, $context);
|
||||
foreach ($step2 as $name) {
|
||||
$this->properties[$name] = typed_data()->getPropertyInstance($this, $name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,14 +79,19 @@ abstract class FieldItemBase extends TypedData implements IteratorAggregate, Fie
|
|||
*/
|
||||
public function setValue($values) {
|
||||
// Treat the values as property value of the first property, if no array is
|
||||
// given and we only have one property.
|
||||
if (!is_array($values) && count($this->properties) == 1) {
|
||||
// given.
|
||||
if (!is_array($values)) {
|
||||
$keys = array_keys($this->properties);
|
||||
$values = array($keys[0] => $values);
|
||||
}
|
||||
|
||||
foreach ($this->properties as $name => $property) {
|
||||
$property->setValue(isset($values[$name]) ? $values[$name] : NULL);
|
||||
if (isset($values[$name])) {
|
||||
$property->setValue($values[$name]);
|
||||
}
|
||||
else {
|
||||
$property->setValue(NULL);
|
||||
}
|
||||
}
|
||||
// @todo: Throw an exception for invalid values once conversion is
|
||||
// totally completed.
|
||||
|
@ -178,35 +166,6 @@ abstract class FieldItemBase extends TypedData implements IteratorAggregate, Fie
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setName().
|
||||
*/
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getParent().
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Field\FieldInterface
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setParent().
|
||||
*/
|
||||
public function setParent($parent) {
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ComplexDataInterface::getProperties().
|
||||
|
@ -249,7 +208,12 @@ abstract class FieldItemBase extends TypedData implements IteratorAggregate, Fie
|
|||
*/
|
||||
public function getPropertyDefinition($name) {
|
||||
$definitions = $this->getPropertyDefinitions();
|
||||
return isset($definitions[$name]) ? $definitions[$name] : FALSE;
|
||||
if (isset($definitions[$name])) {
|
||||
return $definitions[$name];
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,7 +235,7 @@ abstract class FieldItemBase extends TypedData implements IteratorAggregate, Fie
|
|||
foreach ($this->properties as $name => $property) {
|
||||
$this->properties[$name] = clone $property;
|
||||
if ($property instanceof ContextAwareInterface) {
|
||||
$this->properties[$name]->setParent($this);
|
||||
$this->properties[$name]->setContext($name, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use Drupal\Core\Entity\Field\FieldItemBase;
|
|||
class BooleanItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* Field definitions of the contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
|
|
|
@ -15,7 +15,7 @@ use Drupal\Core\Entity\Field\FieldItemBase;
|
|||
class DateItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* Field definitions of the contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
|
|
|
@ -13,13 +13,13 @@ use InvalidArgumentException;
|
|||
/**
|
||||
* Defines the 'entityreference_field' entity field item.
|
||||
*
|
||||
* Required settings (below the definition's 'settings' key) are:
|
||||
* - entity type: The entity type to reference.
|
||||
* Available settings (below the definition's 'settings' key) are:
|
||||
* - entity type: (required) The entity type to reference.
|
||||
*/
|
||||
class EntityReferenceItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* Field definitions of the contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
|
@ -71,8 +71,11 @@ class EntityReferenceItem extends FieldItemBase {
|
|||
if (isset($values['value'])) {
|
||||
$this->properties['value']->setValue($values['value']);
|
||||
}
|
||||
elseif (isset($values['entity'])) {
|
||||
$this->properties['entity']->setValue($values['entity']);
|
||||
}
|
||||
else {
|
||||
$this->properties['entity']->setValue(isset($values['entity']) ? $values['entity'] : NULL);
|
||||
$this->properties['entity']->setValue(NULL);
|
||||
}
|
||||
unset($values['entity'], $values['value']);
|
||||
if ($values) {
|
||||
|
|
|
@ -7,11 +7,9 @@
|
|||
|
||||
namespace Drupal\Core\Entity\Field\Type;
|
||||
|
||||
use Drupal\Core\TypedData\Type\TypedData;
|
||||
use Drupal\Core\TypedData\AccessibleInterface;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareTypedData;
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
use InvalidArgumentException;
|
||||
|
@ -19,7 +17,7 @@ use InvalidArgumentException;
|
|||
/**
|
||||
* Makes translated entity properties available via the Field API.
|
||||
*/
|
||||
class EntityTranslation extends TypedData implements IteratorAggregate, AccessibleInterface, ComplexDataInterface, ContextAwareInterface {
|
||||
class EntityTranslation extends ContextAwareTypedData implements IteratorAggregate, AccessibleInterface, ComplexDataInterface {
|
||||
|
||||
/**
|
||||
* The array of translated properties, each being an instance of
|
||||
|
@ -29,20 +27,6 @@ class EntityTranslation extends TypedData implements IteratorAggregate, Accessib
|
|||
*/
|
||||
protected $properties = array();
|
||||
|
||||
/**
|
||||
* The language code of the translation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode;
|
||||
|
||||
/**
|
||||
* The parent entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Whether the entity translation acts in strict mode.
|
||||
*
|
||||
|
@ -72,37 +56,6 @@ class EntityTranslation extends TypedData implements IteratorAggregate, Accessib
|
|||
$this->strict = $strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
// The name of the translation is the language code.
|
||||
return $this->langcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setName().
|
||||
*/
|
||||
public function setName($name) {
|
||||
// The name of the translation is the language code.
|
||||
$this->langcode = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getParent().
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setParent().
|
||||
*/
|
||||
public function setParent($parent) {
|
||||
$this->parent = $parent;
|
||||
}
|
||||
/**
|
||||
* Implements TypedDataInterface::getValue().
|
||||
*/
|
||||
|
@ -186,7 +139,12 @@ class EntityTranslation extends TypedData implements IteratorAggregate, Accessib
|
|||
*/
|
||||
public function getPropertyDefinition($name) {
|
||||
$definitions = $this->getPropertyDefinitions();
|
||||
return isset($definitions[$name]) ? $definitions[$name] : FALSE;
|
||||
if (isset($definitions[$name])) {
|
||||
return $definitions[$name];
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,7 +193,10 @@ class EntityTranslation extends TypedData implements IteratorAggregate, Accessib
|
|||
*/
|
||||
public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL) {
|
||||
$method = $operation . 'Access';
|
||||
return entity_access_controller($this->parent->entityType())->$method($this->parent, $this->langcode, $account);
|
||||
// @todo Add a way to set and get the langcode so that's more obvious what
|
||||
// we're doing here.
|
||||
$langocde = substr($this->getName(), 1);
|
||||
return entity_access_controller($this->parent->entityType())->$method($this->parent, $langocde, $account);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
namespace Drupal\Core\Entity\Field\Type;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\TypedData\Type\TypedData;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareTypedData;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
|
@ -36,21 +36,7 @@ use InvalidArgumentException;
|
|||
* - id source: If used as computed property, the ID property used to load
|
||||
* the entity object.
|
||||
*/
|
||||
class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataInterface, ContextAwareInterface {
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The parent data structure.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $parent;
|
||||
class EntityWrapper extends ContextAwareTypedData implements IteratorAggregate, ComplexDataInterface {
|
||||
|
||||
/**
|
||||
* The referenced entity type.
|
||||
|
@ -67,10 +53,10 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
|
|||
protected $id;
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::__construct().
|
||||
* Overrides ContextAwareTypedData::__construct().
|
||||
*/
|
||||
public function __construct(array $definition) {
|
||||
$this->definition = $definition + array('constraints' => array());
|
||||
public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
parent::__construct($definition, $name, $parent);
|
||||
$this->entityType = isset($this->definition['constraints']['entity type']) ? $this->definition['constraints']['entity type'] : NULL;
|
||||
}
|
||||
|
||||
|
@ -120,8 +106,10 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
|
|||
* Implements TypedDataInterface::getString().
|
||||
*/
|
||||
public function getString() {
|
||||
$entity = $this->getValue();
|
||||
return $entity ? $entity->label() : '';
|
||||
if ($entity = $this->getValue()) {
|
||||
return $entity->label();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,17 +123,20 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
|
|||
* Implements IteratorAggregate::getIterator().
|
||||
*/
|
||||
public function getIterator() {
|
||||
$entity = $this->getValue();
|
||||
return $entity ? $entity->getIterator() : new ArrayIterator(array());
|
||||
if ($entity = $this->getValue()) {
|
||||
return $entity->getIterator();
|
||||
}
|
||||
return new ArrayIterator(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ComplexDataInterface::get().
|
||||
*/
|
||||
public function get($property_name) {
|
||||
$entity = $this->getValue();
|
||||
// @todo: Allow navigating through the tree without data as well.
|
||||
return $entity ? $entity->get($property_name) : NULL;
|
||||
if ($entity = $this->getValue()) {
|
||||
return $entity->get($property_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,40 +146,14 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
|
|||
$this->get($property_name)->setValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setName().
|
||||
*/
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getParent().
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setParent().
|
||||
*/
|
||||
public function setParent($parent) {
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ComplexDataInterface::getProperties().
|
||||
*/
|
||||
public function getProperties($include_computed = FALSE) {
|
||||
$entity = $this->getValue();
|
||||
return $entity ? $entity->getProperties($include_computed) : array();
|
||||
if ($entity = $this->getValue()) {
|
||||
return $entity->getProperties($include_computed);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +161,12 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
|
|||
*/
|
||||
public function getPropertyDefinition($name) {
|
||||
$definitions = $this->getPropertyDefinitions();
|
||||
return isset($definitions[$name]) ? $definitions[$name] : FALSE;
|
||||
if (isset($definitions[$name])) {
|
||||
return $definitions[$name];
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,8 +181,10 @@ class EntityWrapper extends TypedData implements IteratorAggregate, ComplexDataI
|
|||
* Implements ComplexDataInterface::getPropertyValues().
|
||||
*/
|
||||
public function getPropertyValues() {
|
||||
$entity = $this->getValue();
|
||||
return $entity ? $entity->getPropertyValues() : array();
|
||||
if ($entity = $this->getValue()) {
|
||||
return $entity->getPropertyValues();
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
namespace Drupal\Core\Entity\Field\Type;
|
||||
|
||||
use Drupal\Core\Entity\Field\FieldInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\Type\TypedData;
|
||||
use Drupal\user\Plugin\Core\Entity\User;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\Core\TypedData\ContextAwareTypedData;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
use InvalidArgumentException;
|
||||
|
@ -26,21 +27,7 @@ use InvalidArgumentException;
|
|||
*
|
||||
* @see \Drupal\Core\Entity\Field\FieldInterface
|
||||
*/
|
||||
class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
||||
|
||||
/**
|
||||
* The entity field name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The parent entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $parent;
|
||||
class Field extends ContextAwareTypedData implements IteratorAggregate, FieldInterface {
|
||||
|
||||
/**
|
||||
* Numerically indexed array of field items, implementing the
|
||||
|
@ -51,21 +38,33 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
protected $list = array();
|
||||
|
||||
/**
|
||||
* Flag to indicate if this field has been set.
|
||||
*
|
||||
* @var bool
|
||||
* Overrides ContextAwareTypedData::__construct().
|
||||
*/
|
||||
protected $isset = FALSE;
|
||||
public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
parent::__construct($definition, $name, $parent);
|
||||
// Always initialize one empty item as usually that will be needed. That
|
||||
// way prototypes created by
|
||||
// \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance() will
|
||||
// already have one field item ready for use after cloning.
|
||||
$this->list[0] = $this->createItem(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::getValue().
|
||||
*/
|
||||
public function getValue() {
|
||||
$values = array();
|
||||
foreach ($this->list as $delta => $item) {
|
||||
$values[$delta] = !$item->isEmpty() ? $item->getValue() : NULL;
|
||||
if (isset($this->list)) {
|
||||
$values = array();
|
||||
foreach ($this->list as $delta => $item) {
|
||||
if (!$item->isEmpty()) {
|
||||
$values[$delta] = $item->getValue();
|
||||
}
|
||||
else {
|
||||
$values[$delta] = NULL;
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,19 +74,18 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
* An array of values of the field items.
|
||||
*/
|
||||
public function setValue($values) {
|
||||
$this->isset = TRUE;
|
||||
if (isset($values) && $values !== array()) {
|
||||
if (!isset($values) || $values === array()) {
|
||||
$this->list = $values;
|
||||
}
|
||||
else {
|
||||
// Support passing in only the value of the first item.
|
||||
if (!is_array($values) || !is_numeric(current(array_keys($values)))) {
|
||||
$values = array(0 => $values);
|
||||
}
|
||||
|
||||
if (!is_array($values)) {
|
||||
throw new InvalidArgumentException("An entity field requires a numerically indexed array of items as value.");
|
||||
}
|
||||
// Clear the values of properties for which no value has been passed.
|
||||
foreach (array_diff_key($this->list, $values) as $delta => $item) {
|
||||
unset($this->list[$delta]);
|
||||
if (isset($this->list)) {
|
||||
$this->list = array_intersect_key($this->list, $values);
|
||||
}
|
||||
|
||||
// Set the values.
|
||||
|
@ -96,24 +94,13 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
throw new InvalidArgumentException('Unable to set a value with a non-numeric delta in a list.');
|
||||
}
|
||||
elseif (!isset($this->list[$delta])) {
|
||||
$this->list[$delta] = $this->createItem($value);
|
||||
$this->list[$delta] = $this->createItem($delta, $value);
|
||||
}
|
||||
else {
|
||||
$this->list[$delta]->setValue($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->list = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this field as not set.
|
||||
*/
|
||||
public function unsetValue() {
|
||||
$this->list = array();
|
||||
$this->isset = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,10 +110,12 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
*/
|
||||
public function getString() {
|
||||
$strings = array();
|
||||
foreach ($this->list() as $item) {
|
||||
$strings[] = $item->getString();
|
||||
if (isset($this->list)) {
|
||||
foreach ($this->list() as $item) {
|
||||
$strings[] = $item->getString();
|
||||
}
|
||||
return implode(', ', array_filter($strings));
|
||||
}
|
||||
return implode(', ', array_filter($strings));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,14 +129,16 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
* Implements ArrayAccess::offsetExists().
|
||||
*/
|
||||
public function offsetExists($offset) {
|
||||
return array_key_exists($offset, $this->list);
|
||||
return isset($this->list) && array_key_exists($offset, $this->list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess::offsetUnset().
|
||||
*/
|
||||
public function offsetUnset($offset) {
|
||||
unset($this->list[$offset]);
|
||||
if (isset($this->list)) {
|
||||
unset($this->list[$offset]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,7 +151,7 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
// Allow getting not yet existing items as well.
|
||||
// @todo: Maybe add a public createItem() method in addition?
|
||||
elseif (!isset($this->list[$offset])) {
|
||||
$this->list[$offset] = $this->createItem();
|
||||
$this->list[$offset] = $this->createItem($offset);
|
||||
}
|
||||
return $this->list[$offset];
|
||||
}
|
||||
|
@ -170,9 +161,15 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
*
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
*/
|
||||
protected function createItem($value = NULL) {
|
||||
$context = array('parent' => $this);
|
||||
return typed_data()->create(array('list' => FALSE) + $this->definition, $value, $context);
|
||||
protected function createItem($offset = 0, $value = NULL) {
|
||||
return typed_data()->getPropertyInstance($this, $offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ListInterface::getItemDefinition().
|
||||
*/
|
||||
public function getItemDefinition() {
|
||||
return array('list' => FALSE) + $this->definition;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,44 +196,17 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
* Implements IteratorAggregate::getIterator().
|
||||
*/
|
||||
public function getIterator() {
|
||||
return new ArrayIterator($this->list);
|
||||
if (isset($this->list)) {
|
||||
return new ArrayIterator($this->list);
|
||||
}
|
||||
return new ArrayIterator(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Countable::count().
|
||||
*/
|
||||
public function count() {
|
||||
return count($this->list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setName().
|
||||
*/
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getParent().
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setParent().
|
||||
*/
|
||||
public function setParent($parent) {
|
||||
$this->parent = $parent;
|
||||
return isset($this->list) ? count($this->list) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -257,7 +227,7 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
* Delegate.
|
||||
*/
|
||||
public function __get($property_name) {
|
||||
return $this->offsetGet(0)->__get($property_name);
|
||||
return $this->offsetGet(0)->get($property_name)->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,14 +242,13 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
*/
|
||||
public function __set($property_name, $value) {
|
||||
$this->offsetGet(0)->__set($property_name, $value);
|
||||
$this->isset = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate.
|
||||
*/
|
||||
public function __isset($property_name) {
|
||||
return $this->isset && $this->offsetGet(0)->__isset($property_name);
|
||||
return $this->offsetGet(0)->__isset($property_name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -293,29 +262,27 @@ class Field extends TypedData implements IteratorAggregate, FieldInterface {
|
|||
* Implements ListInterface::isEmpty().
|
||||
*/
|
||||
public function isEmpty() {
|
||||
foreach ($this->list as $item) {
|
||||
if (!$item->isEmpty()) {
|
||||
return FALSE;
|
||||
if (isset($this->list)) {
|
||||
foreach ($this->list as $item) {
|
||||
if (!$item->isEmpty()) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this field has been set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valueIsSet() {
|
||||
return $this->isset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a deep clone.
|
||||
*/
|
||||
public function __clone() {
|
||||
foreach ($this->list as $delta => $property) {
|
||||
$this->list[$delta] = clone $property;
|
||||
if (isset($this->list)) {
|
||||
foreach ($this->list as $delta => $property) {
|
||||
$this->list[$delta] = clone $property;
|
||||
if ($property instanceof ContextAwareInterface) {
|
||||
$this->list[$delta]->setContext($delta, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ use Drupal\Core\Entity\Field\FieldItemBase;
|
|||
class IntegerItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* Field definitions of the contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
|
|
|
@ -16,9 +16,9 @@ use InvalidArgumentException;
|
|||
class LanguageItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* Array of property definitions of contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see PropertyEntityReferenceItem::getPropertyDefinitions()
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -61,8 +61,11 @@ class LanguageItem extends FieldItemBase {
|
|||
if (!empty($values['value'])) {
|
||||
$this->properties['value']->setValue($values['value']);
|
||||
}
|
||||
elseif (isset($values['language'])) {
|
||||
$this->properties['language']->setValue($values['language']);
|
||||
}
|
||||
else {
|
||||
$this->properties['language']->setValue(isset($values['language']) ? $values['language'] : NULL);
|
||||
$this->properties['language']->setValue(NULL);
|
||||
}
|
||||
unset($values['language'], $values['value']);
|
||||
if ($values) {
|
||||
|
|
|
@ -15,7 +15,7 @@ use Drupal\Core\Entity\Field\FieldItemBase;
|
|||
class StringItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* Field definitions of the contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
|
|
|
@ -12,6 +12,9 @@ use Traversable;
|
|||
/**
|
||||
* Interface for complex data; i.e. data containing named and typed properties.
|
||||
*
|
||||
* The name of a property has to be a valid PHP variable name, starting with
|
||||
* an alphabetic character.
|
||||
*
|
||||
* This is implemented by entities as well as by field item classes of
|
||||
* entities.
|
||||
*
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\Core\TypedData\ContextAwareInterface.
|
||||
* Contains \Drupal\Core\TypedData\ContextAwareInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\TypedData;
|
||||
|
@ -22,37 +22,49 @@ interface ContextAwareInterface {
|
|||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Sets the name of a property or item.
|
||||
*
|
||||
* This method is supposed to be used by the parental data structure in order
|
||||
* to provide appropriate context only.
|
||||
*
|
||||
* @param string $name
|
||||
* The name to set for a property or item.
|
||||
*
|
||||
* @see ContextAwareInterface::getName()
|
||||
*/
|
||||
public function setName($name);
|
||||
|
||||
/**
|
||||
* Returns the parent data structure; i.e. either complex data or a list.
|
||||
*
|
||||
* @return Drupal\Core\TypedData\ComplexDataInterface|Drupal\Core\TypedData\ListInterface
|
||||
* The parent data structure; either complex data or a list.
|
||||
* @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface
|
||||
* The parent data structure, either complex data or a list; or NULL if this
|
||||
* is the root of the typed data tree.
|
||||
*/
|
||||
public function getParent();
|
||||
|
||||
/**
|
||||
* Sets the parent of a property or item.
|
||||
* Returns the root of the typed data tree.
|
||||
*
|
||||
* This method is supposed to be used by the parental data structure in order
|
||||
* to provide appropriate context only.
|
||||
* Returns the root data for a tree of typed data objects; e.g. for an entity
|
||||
* field item the root of the tree is its parent entity object.
|
||||
*
|
||||
* @param mixed $parent
|
||||
* The parent data structure; either complex data or a list.
|
||||
*
|
||||
* @see ContextAwareInterface::getParent()
|
||||
* @return \Drupal\Core\TypedData\ComplexDataInterface|\Drupal\Core\TypedData\ListInterface
|
||||
* The root data structure, either complex data or a list.
|
||||
*/
|
||||
public function setParent($parent);
|
||||
public function getRoot();
|
||||
|
||||
/**
|
||||
* Returns the property path of the data.
|
||||
*
|
||||
* The trail of property names relative to the root of the typed data tree,
|
||||
* separated by dots; e.g. 'field_text.0.format'.
|
||||
*
|
||||
* @return string
|
||||
* The property path relative to the root of the typed tree, or an empty
|
||||
* string if this is the root.
|
||||
*/
|
||||
public function getPropertyPath();
|
||||
|
||||
/**
|
||||
* Sets the context of a property or item via a context aware parent.
|
||||
*
|
||||
* This method is supposed to be called by the factory only.
|
||||
*
|
||||
* @param string $name
|
||||
* (optional) The name of the property or the delta of the list item,
|
||||
* or NULL if it is the root of a typed data tree. Defaults to NULL.
|
||||
* @param \Drupal\Core\TypedData\ContextAwareInterface $parent
|
||||
* (optional) The parent object of the data property, or NULL if it is the
|
||||
* root of a typed data tree. Defaults to NULL.
|
||||
*/
|
||||
public function setContext($name = NULL, ContextAwareInterface $parent = NULL);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\TypedData\ContextAwareTypedData.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\TypedData;
|
||||
|
||||
/**
|
||||
* An abstract base class for context aware typed data.
|
||||
*
|
||||
* This implementation requires parent typed data objects to implement the
|
||||
* ContextAwareInterface also, such that the context can be derived from the
|
||||
* parents.
|
||||
*
|
||||
* Classes deriving from this base class have to declare $value
|
||||
* or override getValue() or setValue().
|
||||
*/
|
||||
abstract class ContextAwareTypedData extends TypedData implements ContextAwareInterface {
|
||||
|
||||
/**
|
||||
* The property name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The parent typed data object.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\ContextAwareInterface
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Constructs a TypedData object given its definition and context.
|
||||
*
|
||||
* @param array $definition
|
||||
* The data definition.
|
||||
* @param string $name
|
||||
* (optional) The name of the created property, or NULL if it is the root
|
||||
* of a typed data tree. Defaults to NULL.
|
||||
* @param \Drupal\Core\TypedData\ContextAwareInterface $parent
|
||||
* (optional) The parent object of the data property, or NULL if it is the
|
||||
* root of a typed data tree. Defaults to NULL.
|
||||
*
|
||||
* @see Drupal\Core\TypedData\TypedDataManager::create()
|
||||
*/
|
||||
public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
$this->definition = $definition;
|
||||
$this->setContext($name, $parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setContext().
|
||||
*/
|
||||
public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
$this->parent = $parent;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getRoot().
|
||||
*/
|
||||
public function getRoot() {
|
||||
if (isset($this->parent)) {
|
||||
return $this->parent->getRoot();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getPropertyPath().
|
||||
*/
|
||||
public function getPropertyPath() {
|
||||
if (isset($this->parent)) {
|
||||
$prefix = $this->parent->getPropertyPath();
|
||||
return (strlen($prefix) ? $prefix . '.' : '') . $this->name;
|
||||
}
|
||||
elseif (isset($this->name)) {
|
||||
return $this->name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getParent().
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Field\FieldInterface
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::validate().
|
||||
*/
|
||||
public function validate() {
|
||||
// @todo: Implement validate() method.
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\Core\TypedData\ListInterface.
|
||||
* Contains \Drupal\Core\TypedData\ListInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\TypedData;
|
||||
|
@ -29,4 +29,12 @@ interface ListInterface extends ArrayAccess, Countable, Traversable {
|
|||
* TRUE if the list is empty, FALSE otherwise.
|
||||
*/
|
||||
public function isEmpty();
|
||||
|
||||
/**
|
||||
* Gets the definition of a contained item.
|
||||
*
|
||||
* @return array
|
||||
* The data definition of contained items.
|
||||
*/
|
||||
public function getItemDefinition();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@ use InvalidArgumentException;
|
|||
* http://php.net/manual/en/language.types.resource.php. For setting the value
|
||||
* a PHP file resource or a (absolute) stream resource URI may be passed.
|
||||
*/
|
||||
class Binary extends TypedData implements TypedDataInterface {
|
||||
class Binary extends TypedData {
|
||||
|
||||
/**
|
||||
* The file resource URI.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* The boolean data type.
|
||||
|
@ -15,7 +15,7 @@ use Drupal\Core\TypedData\TypedDataInterface;
|
|||
* The plain value of a boolean is a regular PHP boolean. For setting the value
|
||||
* any PHP variable that casts to a boolean may be passed.
|
||||
*/
|
||||
class Boolean extends TypedData implements TypedDataInterface {
|
||||
class Boolean extends TypedData {
|
||||
|
||||
/**
|
||||
* The data value.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,7 @@ use InvalidArgumentException;
|
|||
* class will work, including a DateTime object, a timestamp, a string
|
||||
* date, or an array of date parts.
|
||||
*/
|
||||
class Date extends TypedData implements TypedDataInterface {
|
||||
class Date extends TypedData {
|
||||
|
||||
/**
|
||||
* The data value.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
use DateInterval;
|
||||
use InvalidArgumentException;
|
||||
|
||||
|
@ -19,7 +19,7 @@ use InvalidArgumentException;
|
|||
* supported by DateInterval::__construct, or an integer in seconds may be
|
||||
* passed.
|
||||
*/
|
||||
class Duration extends TypedData implements TypedDataInterface {
|
||||
class Duration extends TypedData {
|
||||
|
||||
/**
|
||||
* The data value.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* The float data type.
|
||||
|
@ -15,7 +15,7 @@ use Drupal\Core\TypedData\TypedDataInterface;
|
|||
* The plain value of a float is a regular PHP float. For setting the value
|
||||
* any PHP variable that casts to a float may be passed.
|
||||
*/
|
||||
class Float extends TypedData implements TypedDataInterface {
|
||||
class Float extends TypedData {
|
||||
|
||||
/**
|
||||
* The data value.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* The integer data type.
|
||||
|
@ -15,7 +15,7 @@ use Drupal\Core\TypedData\TypedDataInterface;
|
|||
* The plain value of an integer is a regular PHP integer. For setting the value
|
||||
* any PHP variable that casts to an integer may be passed.
|
||||
*/
|
||||
class Integer extends TypedData implements TypedDataInterface {
|
||||
class Integer extends TypedData {
|
||||
|
||||
/**
|
||||
* The data value.
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use InvalidArgumentException;
|
||||
use Drupal\Core\TypedData\ContextAwareTypedData;
|
||||
|
||||
/**
|
||||
* Defines the 'language' data type.
|
||||
|
@ -25,21 +24,7 @@ use InvalidArgumentException;
|
|||
* - langcode source: If used as computed property, the langcode property used
|
||||
* to load the language object.
|
||||
*/
|
||||
class Language extends TypedData implements TypedDataInterface, ContextAwareInterface {
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The parent data structure.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $parent;
|
||||
class Language extends ContextAwareTypedData {
|
||||
|
||||
/**
|
||||
* The language code of the language if no 'langcode source' is used.
|
||||
|
@ -48,41 +33,15 @@ class Language extends TypedData implements TypedDataInterface, ContextAwareInte
|
|||
*/
|
||||
protected $langcode;
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setName().
|
||||
*/
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getParent().
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setParent().
|
||||
*/
|
||||
public function setParent($parent) {
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::getValue().
|
||||
*/
|
||||
public function getValue() {
|
||||
$source = $this->getLanguageCodeSource();
|
||||
$langcode = $source ? $source->getValue() : $this->langcode;
|
||||
return $langcode ? language_load($langcode) : NULL;
|
||||
if ($langcode) {
|
||||
return language_load($langcode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* The string data type.
|
||||
|
@ -15,7 +15,7 @@ use Drupal\Core\TypedData\TypedDataInterface;
|
|||
* The plain value of a string is a regular PHP string. For setting the value
|
||||
* any PHP variable that casts to a string may be passed.
|
||||
*/
|
||||
class String extends TypedData implements TypedDataInterface {
|
||||
class String extends TypedData {
|
||||
|
||||
/**
|
||||
* The data value.
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* The URI data type.
|
||||
*
|
||||
* The plain value of a URI is an absolute URI represented as PHP string.
|
||||
*/
|
||||
class Uri extends TypedData implements TypedDataInterface {
|
||||
class Uri extends TypedData {
|
||||
|
||||
/**
|
||||
* The data value.
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\Core\TypedData\Type\TypedData.
|
||||
* Contains \Drupal\Core\TypedData\TypedData.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\TypedData\Type;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
namespace Drupal\Core\TypedData;
|
||||
|
||||
/**
|
||||
* The abstract base class for typed data.
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\TypedData;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Drupal\Component\Plugin\Factory\DefaultFactory;
|
||||
use Drupal\Component\Plugin\Exception\PluginException;
|
||||
|
||||
|
@ -25,28 +26,35 @@ class TypedDataFactory extends DefaultFactory {
|
|||
* The id of a plugin, i.e. the data type.
|
||||
* @param array $configuration
|
||||
* The plugin configuration, i.e. the data definition.
|
||||
* @param string $name
|
||||
* (optional) If a property or list item is to be created, the name of the
|
||||
* property or the delta of the list item.
|
||||
* @param mixed $parent
|
||||
* (optional) If a property or list item is to be created, the parent typed
|
||||
* data object implementing either the ListInterface or the
|
||||
* ComplexDataInterface.
|
||||
*
|
||||
* @return Drupal\Core\TypedData\TypedDataInterface
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
*/
|
||||
public function createInstance($plugin_id, array $configuration) {
|
||||
public function createInstance($plugin_id, array $configuration, $name = NULL, $parent = NULL) {
|
||||
$type_definition = $this->discovery->getDefinition($plugin_id);
|
||||
|
||||
// Allow per-data definition overrides of the used classes and generally
|
||||
// default to the data type definition.
|
||||
$definition = $configuration + $type_definition;
|
||||
if (!isset($type_definition)) {
|
||||
throw new InvalidArgumentException(format_string('Invalid data type %plugin_id has been given.', array('%plugin_id' => $plugin_id)));
|
||||
}
|
||||
|
||||
if (empty($definition['list'])) {
|
||||
if (empty($definition['class'])) {
|
||||
throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
|
||||
}
|
||||
$plugin_class = $definition['class'];
|
||||
// Allow per-data definition overrides of the used classes.
|
||||
$key = empty($configuration['list']) ? 'class' : 'list class';
|
||||
if (isset($configuration[$key])) {
|
||||
$class = $configuration[$key];
|
||||
}
|
||||
else {
|
||||
if (empty($definition['list class'])) {
|
||||
throw new PluginException(sprintf('The plugin (%s) did not specify a list instance class.', $plugin_id));
|
||||
}
|
||||
$plugin_class = $definition['list class'];
|
||||
elseif (isset($type_definition[$key])) {
|
||||
$class = $type_definition[$key];
|
||||
}
|
||||
return new $plugin_class($definition, $plugin_id, $this->discovery);
|
||||
|
||||
if (!isset($class)) {
|
||||
throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id));
|
||||
}
|
||||
return new $class($configuration, $name, $parent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\Core\TypedData\TypedDataManager.
|
||||
* Contains \Drupal\Core\TypedData\TypedDataManager.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\TypedData;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Drupal\Component\Plugin\PluginManagerBase;
|
||||
use Drupal\Core\Plugin\Discovery\CacheDecorator;
|
||||
use Drupal\Core\Plugin\Discovery\HookDiscovery;
|
||||
|
@ -16,6 +17,13 @@ use Drupal\Core\Plugin\Discovery\HookDiscovery;
|
|||
*/
|
||||
class TypedDataManager extends PluginManagerBase {
|
||||
|
||||
/**
|
||||
* An array of typed data property prototypes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $prototypes = array();
|
||||
|
||||
public function __construct() {
|
||||
$this->discovery = new CacheDecorator(new HookDiscovery('data_type_info'), 'typed_data:types');
|
||||
$this->factory = new TypedDataFactory($this->discovery);
|
||||
|
@ -28,11 +36,18 @@ class TypedDataManager extends PluginManagerBase {
|
|||
* The id of a plugin, i.e. the data type.
|
||||
* @param array $configuration
|
||||
* The plugin configuration, i.e. the data definition.
|
||||
* @param string $name
|
||||
* (optional) If a property or list item is to be created, the name of the
|
||||
* property or the delta of the list item.
|
||||
* @param mixed $parent
|
||||
* (optional) If a property or list item is to be created, the parent typed
|
||||
* data object implementing either the ListInterface or the
|
||||
* ComplexDataInterface.
|
||||
*
|
||||
* @return Drupal\Core\TypedData\TypedDataInterface
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
*/
|
||||
public function createInstance($plugin_id, array $configuration) {
|
||||
return $this->factory->createInstance($plugin_id, $configuration);
|
||||
public function createInstance($plugin_id, array $configuration, $name = NULL, $parent = NULL) {
|
||||
return $this->factory->createInstance($plugin_id, $configuration, $name, $parent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,42 +85,126 @@ class TypedDataManager extends PluginManagerBase {
|
|||
* @param mixed $value
|
||||
* (optional) The data value. If set, it has to match one of the supported
|
||||
* data type format as documented for the data type classes.
|
||||
* @param array $context
|
||||
* (optional) An array describing the context of the data object, e.g. its
|
||||
* name or parent data structure. The context should be passed if a typed
|
||||
* data object is created as part of a data structure. The following keys
|
||||
* are supported:
|
||||
* - name: The name associated with the data.
|
||||
* - parent: The parent object containing the data. Must be an instance of
|
||||
* Drupal\Core\TypedData\ComplexDataInterface or
|
||||
* Drupal\Core\TypedData\ListInterface.
|
||||
* @param string $name
|
||||
* (optional) If a property or list item is to be created, the name of the
|
||||
* property or the delta of the list item.
|
||||
* @param mixed $parent
|
||||
* (optional) If a property or list item is to be created, the parent typed
|
||||
* data object implementing either the ListInterface or the
|
||||
* ComplexDataInterface.
|
||||
*
|
||||
* @return Drupal\Core\TypedData\TypedDataInterface
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
*
|
||||
* @see typed_data()
|
||||
* @see Drupal\Core\TypedData\Type\Integer
|
||||
* @see Drupal\Core\TypedData\Type\Float
|
||||
* @see Drupal\Core\TypedData\Type\String
|
||||
* @see Drupal\Core\TypedData\Type\Boolean
|
||||
* @see Drupal\Core\TypedData\Type\Duration
|
||||
* @see Drupal\Core\TypedData\Type\Date
|
||||
* @see Drupal\Core\TypedData\Type\Uri
|
||||
* @see Drupal\Core\TypedData\Type\Binary
|
||||
* @see Drupal\Core\Entity\Field\EntityWrapper
|
||||
* @see \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()
|
||||
* @see \Drupal\Core\TypedData\Type\Integer
|
||||
* @see \Drupal\Core\TypedData\Type\Float
|
||||
* @see \Drupal\Core\TypedData\Type\String
|
||||
* @see \Drupal\Core\TypedData\Type\Boolean
|
||||
* @see \Drupal\Core\TypedData\Type\Duration
|
||||
* @see \Drupal\Core\TypedData\Type\Date
|
||||
* @see \Drupal\Core\TypedData\Type\Uri
|
||||
* @see \Drupal\Core\TypedData\Type\Binary
|
||||
* @see \Drupal\Core\Entity\Field\EntityWrapper
|
||||
*/
|
||||
function create(array $definition, $value = NULL, array $context = array()) {
|
||||
$wrapper = $this->createInstance($definition['type'], $definition);
|
||||
public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL) {
|
||||
$wrapper = $this->factory->createInstance($definition['type'], $definition, $name, $parent);
|
||||
if (isset($value)) {
|
||||
$wrapper->setValue($value);
|
||||
}
|
||||
if ($wrapper instanceof ContextAwareInterface) {
|
||||
if (isset($context['name'])) {
|
||||
$wrapper->setName($context['name']);
|
||||
}
|
||||
if (isset($context['parent'])) {
|
||||
$wrapper->setParent($context['parent']);
|
||||
}
|
||||
}
|
||||
return $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Component\Plugin\PluginManagerInterface::getInstance().
|
||||
*
|
||||
* @param array $options
|
||||
* An array of options with the following keys:
|
||||
* - object: The parent typed data object, implementing the
|
||||
* ContextAwareInterface and either the ListInterface or the
|
||||
* ComplexDataInterface.
|
||||
* - property: The name of the property to instantiate, or the delta of the
|
||||
* the list item to instantiate.
|
||||
* - value: The value to set. If set, it has to match one of the supported
|
||||
* data type formats as documented by the data type classes.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* If the given property is not known, or the passed object does not
|
||||
* implement the ListInterface or the ComplexDataInterface.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
* The new property instance.
|
||||
*
|
||||
* @see \Drupal\Core\TypedData\TypedDataManager::getPropertyInstance()
|
||||
*/
|
||||
public function getInstance(array $options) {
|
||||
return $this->getPropertyInstance($options['object'], $options['property'], $options['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a typed data instance for a property of a given typed data object.
|
||||
*
|
||||
* This method will use prototyping for fast and efficient instantiation of
|
||||
* many property objects with the same property path; e.g.,
|
||||
* when multiple comments are used comment_body.0.value needs to be
|
||||
* instantiated very often.
|
||||
* Prototyping is done by the root object's data type and the given
|
||||
* property path, i.e. all property instances having the same property path
|
||||
* and inheriting from the same data type are prototyped.
|
||||
*
|
||||
* @param \Drupal\Core\TypedData\ContextAwareInterface $object
|
||||
* The parent typed data object, implementing the ContextAwareInterface and
|
||||
* either the ListInterface or the ComplexDataInterface.
|
||||
* @param string $property_name
|
||||
* The name of the property to instantiate, or the delta of an list item.
|
||||
* @param mixed $value
|
||||
* (optional) The data value. If set, it has to match one of the supported
|
||||
* data type formats as documented by the data type classes.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* If the given property is not known, or the passed object does not
|
||||
* implement the ListInterface or the ComplexDataInterface.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
* The new property instance.
|
||||
*
|
||||
* @see \Drupal\Core\TypedData\TypedDataManager::create()
|
||||
*/
|
||||
public function getPropertyInstance(ContextAwareInterface $object, $property_name, $value = NULL) {
|
||||
$key = $object->getRoot()->getType() . ':' . $object->getPropertyPath() . '.';
|
||||
// If we are creating list items, we always use 0 in the key as all list
|
||||
// items look the same.
|
||||
$key .= is_numeric($property_name) ? 0 : $property_name;
|
||||
|
||||
// Make sure we have a prototype. Then, clone the prototype and set object
|
||||
// specific values, i.e. the value and the context.
|
||||
if (!isset($this->prototypes[$key])) {
|
||||
if ($object instanceof ComplexDataInterface) {
|
||||
$definition = $object->getPropertyDefinition($property_name);
|
||||
}
|
||||
elseif ($object instanceof ListInterface) {
|
||||
$definition = $object->getItemDefinition();
|
||||
}
|
||||
else {
|
||||
throw new InvalidArgumentException("The passed object has to either implement the ComplexDataInterface or the ListInterface.");
|
||||
}
|
||||
// Make sure we have got a valid definition.
|
||||
if (!$definition) {
|
||||
throw new InvalidArgumentException('Property ' . check_plain($property_name) . ' is unknown.');
|
||||
}
|
||||
|
||||
$this->prototypes[$key] = $this->create($definition, NULL, $property_name, $object);
|
||||
}
|
||||
|
||||
$property = clone $this->prototypes[$key];
|
||||
// Update the parent relationship if necessary.
|
||||
if ($property instanceof ContextAwareInterface) {
|
||||
$property->setContext($property_name, $object);
|
||||
}
|
||||
// Set the passed data value.
|
||||
if (isset($value)) {
|
||||
$property->setValue($value);
|
||||
}
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,14 @@ class JsonldEntityNormalizer extends JsonldNormalizerBase implements Denormalize
|
|||
$values['langcode'] = language(LANGUAGE_TYPE_CONTENT)->langcode;
|
||||
}
|
||||
$entity = entity_create($typed_data_ids['entity_type'], $values);
|
||||
// Make sure all empty entity fields default to NULL, so that afterwards it
|
||||
// is possible to determine which fields were part of the data (even if they
|
||||
// are empty).
|
||||
foreach ($entity as $name => $field) {
|
||||
if ($field->isEmpty()) {
|
||||
$field->setValue(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// For each attribute in the JSON-LD, add the values as fields to the newly
|
||||
// created entity. It is assumed that the JSON attribute names are the same
|
||||
|
|
|
@ -2076,9 +2076,9 @@ abstract class WebTestBase extends TestBase {
|
|||
// Assert the definition of the wrapper.
|
||||
$this->assertTrue($data instanceof \Drupal\Core\TypedData\TypedDataInterface, 'Typed data object is an instance of the typed data interface.');
|
||||
$definition = $data->getDefinition();
|
||||
$this->assertTrue(!empty($definition['label']), $definition['label'] . ' data definition was returned.');
|
||||
$this->assertTrue(!empty($definition['type']), format_string('!type data definition was returned.', array('!type' => $definition['type'])));
|
||||
// Assert that the correct type was constructed.
|
||||
$this->assertEqual($data->getType(), $type, $definition['label'] . ' object returned type.');
|
||||
$this->assertEqual($data->getType(), $type, format_string('!type object returned type.', array('!type' => $definition['type'])));
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
@ -221,10 +221,12 @@ class EntityFieldTest extends WebTestBase {
|
|||
$this->assertIdentical(count($entity->name), 0, 'Name field contains no items.');
|
||||
$this->assertIdentical($entity->name->getValue(), array(), 'Name field value is an empty array.');
|
||||
|
||||
$entity->name->value = 'foo';
|
||||
$this->assertTrue($entity->name->value, 'foo', 'Name field set.');
|
||||
// Test removing all list items by setting it to NULL.
|
||||
$entity->name = NULL;
|
||||
$this->assertIdentical(count($entity->name), 0, 'Name field contains no items.');
|
||||
$this->assertIdentical($entity->name->getValue(), array(), 'Name field value is an empty array.');
|
||||
$this->assertNull($entity->name->getValue(), 'Name field value is NULL.');
|
||||
|
||||
// Test get and set field values.
|
||||
$entity->name = 'foo';
|
||||
|
@ -319,6 +321,30 @@ class EntityFieldTest extends WebTestBase {
|
|||
|
||||
// @todo: Once the user entity has definitions, continue testing getting
|
||||
// them from the $userref_values['entity'] property.
|
||||
|
||||
// Make sure provided contextual information is right.
|
||||
$this->assertIdentical($entity->getRoot(), $entity, 'Entity is root object.');
|
||||
$this->assertEqual($entity->getPropertyPath(), '');
|
||||
$this->assertEqual($entity->getName(), '');
|
||||
$this->assertEqual($entity->getParent(), NULL);
|
||||
|
||||
$field = $entity->user_id;
|
||||
$this->assertIdentical($field->getRoot(), $entity, 'Entity is root object.');
|
||||
$this->assertEqual($field->getPropertyPath(), 'user_id');
|
||||
$this->assertEqual($field->getName(), 'user_id');
|
||||
$this->assertIdentical($field->getParent(), $entity, 'Parent object matches.');
|
||||
|
||||
$field_item = $field[0];
|
||||
$this->assertIdentical($field_item->getRoot(), $entity, 'Entity is root object.');
|
||||
$this->assertEqual($field_item->getPropertyPath(), 'user_id.0');
|
||||
$this->assertEqual($field_item->getName(), '0');
|
||||
$this->assertIdentical($field_item->getParent(), $field, 'Parent object matches.');
|
||||
|
||||
$item_value = $field_item->get('entity');
|
||||
$this->assertIdentical($item_value->getRoot(), $entity, 'Entity is root object.');
|
||||
$this->assertEqual($item_value->getPropertyPath(), 'user_id.0.entity');
|
||||
$this->assertEqual($item_value->getName(), 'entity');
|
||||
$this->assertIdentical($item_value->getParent(), $field_item, 'Parent object matches.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,30 +48,38 @@ class EntityTestStorageController extends DatabaseStorageControllerNG {
|
|||
* An array of entity objects implementing the EntityInterface.
|
||||
*/
|
||||
protected function mapFromStorageRecords(array $records, $load_revision = FALSE) {
|
||||
$records = parent::mapFromStorageRecords($records, $load_revision);
|
||||
$property_values = $this->getPropertyValues($records, $load_revision);
|
||||
|
||||
// Load data of translatable properties.
|
||||
$this->attachPropertyData($records, $load_revision);
|
||||
foreach ($records as $id => $record) {
|
||||
$values = isset($property_values[$id]) ? $property_values[$id] : array();
|
||||
|
||||
foreach ($record as $name => $value) {
|
||||
$values[$name][LANGUAGE_DEFAULT][0]['value'] = $value;
|
||||
}
|
||||
$entity = new $this->entityClass($values, $this->entityType);
|
||||
$records[$id] = $entity;
|
||||
}
|
||||
return $records;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches property data in all languages for translatable properties.
|
||||
*/
|
||||
protected function attachPropertyData(&$queried_entities, $load_revision = FALSE) {
|
||||
protected function getPropertyValues($records, $load_revision = FALSE) {
|
||||
$query = db_select('entity_test_property_data', 'data', array('fetch' => PDO::FETCH_ASSOC))
|
||||
->fields('data')
|
||||
->condition('id', array_keys($queried_entities))
|
||||
->condition('id', array_keys($records))
|
||||
->orderBy('data.id');
|
||||
if ($load_revision) {
|
||||
// Get revision id's.
|
||||
$revision_ids = array();
|
||||
foreach ($queried_entities as $id => $entity) {
|
||||
$revision_ids[] = $entity->get('revision_id')->value;
|
||||
foreach ($records as $record) {
|
||||
$revision_ids[] = $record->revision_id;
|
||||
}
|
||||
$query->condition('revision_id', $revision_ids);
|
||||
}
|
||||
$data = $query->execute();
|
||||
$property_values = array();
|
||||
|
||||
foreach ($data as $values) {
|
||||
$id = $values['id'];
|
||||
|
@ -79,9 +87,10 @@ class EntityTestStorageController extends DatabaseStorageControllerNG {
|
|||
// LANGUAGE_DEFAULT as key.
|
||||
$langcode = empty($values['default_langcode']) ? $values['langcode'] : LANGUAGE_DEFAULT;
|
||||
|
||||
$queried_entities[$id]->name[$langcode][0]['value'] = $values['name'];
|
||||
$queried_entities[$id]->user_id[$langcode][0]['value'] = $values['user_id'];
|
||||
$property_values[$id]['name'][$langcode][0]['value'] = $values['name'];
|
||||
$property_values[$id]['user_id'][$langcode][0]['value'] = $values['user_id'];
|
||||
}
|
||||
return $property_values;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,7 +23,7 @@ use Drupal\Core\Annotation\Translation;
|
|||
* form_controller_class = {
|
||||
* "default" = "Drupal\entity_test\EntityTestFormController"
|
||||
* },
|
||||
* translation_controller_class = "Drupal\entity_test\EntityTestTranslationController",
|
||||
* translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
|
||||
* base_table = "entity_test",
|
||||
* data_table = "entity_test_property_data",
|
||||
* revision_table = "entity_test_property_revision",
|
||||
|
@ -74,14 +74,12 @@ class EntityTest extends EntityNG {
|
|||
public $user_id;
|
||||
|
||||
/**
|
||||
* Overrides Entity::__construct().
|
||||
* Initialize the object. Invoked upon construction and wake up.
|
||||
*/
|
||||
public function __construct(array $values, $entity_type) {
|
||||
parent::__construct($values, $entity_type);
|
||||
|
||||
protected function init() {
|
||||
parent::init();
|
||||
// We unset all defined properties, so magic getters apply.
|
||||
unset($this->id);
|
||||
unset($this->langcode);
|
||||
unset($this->uuid);
|
||||
unset($this->revision_id);
|
||||
unset($this->name);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Drupal\text;
|
||||
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\Core\TypedData\Type\String;
|
||||
use Drupal\Core\TypedData\ContextAwareTypedData;
|
||||
use Drupal\Core\TypedData\ReadOnlyException;
|
||||
use InvalidArgumentException;
|
||||
|
||||
|
@ -18,7 +18,7 @@ use InvalidArgumentException;
|
|||
* Required settings (below the definition's 'settings' key) are:
|
||||
* - text source: The text property containing the to be processed text.
|
||||
*/
|
||||
class TextProcessed extends String implements ContextAwareInterface {
|
||||
class TextProcessed extends ContextAwareTypedData {
|
||||
|
||||
/**
|
||||
* The text property.
|
||||
|
@ -35,24 +35,10 @@ class TextProcessed extends String implements ContextAwareInterface {
|
|||
protected $format;
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*
|
||||
* @var string
|
||||
* Overrides ContextAwareTypedData::__construct().
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The parent data structure.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Field\FieldItemInterface
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::__construct().
|
||||
*/
|
||||
public function __construct(array $definition) {
|
||||
$this->definition = $definition;
|
||||
public function __construct(array $definition, $name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
parent::__construct($definition, $name, $parent);
|
||||
|
||||
if (!isset($definition['settings']['text source'])) {
|
||||
throw new InvalidArgumentException("The definition's 'source' key has to specify the name of the text property to be processed.");
|
||||
|
@ -60,39 +46,18 @@ class TextProcessed extends String implements ContextAwareInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getName().
|
||||
* Overrides ContextAwareTypedData::setContext().
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
parent::setContext($name, $parent);
|
||||
if (isset($parent)) {
|
||||
$this->text = $parent->get($this->definition['settings']['text source']);
|
||||
$this->format = $parent->get('format');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setName().
|
||||
*/
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::getParent().
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Field\FieldItemInterface
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ContextAwareInterface::setParent().
|
||||
*/
|
||||
public function setParent($parent) {
|
||||
$this->parent = $parent;
|
||||
$this->text = $parent->get($this->definition['settings']['text source']);
|
||||
$this->format = $parent->get('format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::getValue().
|
||||
* Implements \Drupal\Core\TypedData\TypedDataInterface::getValue().
|
||||
*/
|
||||
public function getValue($langcode = NULL) {
|
||||
|
||||
|
@ -104,21 +69,28 @@ class TextProcessed extends String implements ContextAwareInterface {
|
|||
$entity = $field->getParent();
|
||||
$instance = field_info_instance($entity->entityType(), $field->getName(), $entity->bundle());
|
||||
|
||||
if (!empty($instance['settings']['text_processing']) && $this->format->value) {
|
||||
return check_markup($this->text->value, $this->format->value, $entity->language()->langcode);
|
||||
if (!empty($instance['settings']['text_processing']) && $this->format->getValue()) {
|
||||
return check_markup($this->text->getValue(), $this->format->getValue(), $entity->language()->langcode);
|
||||
}
|
||||
else {
|
||||
// If no format is available, still make sure to sanitize the text.
|
||||
return check_plain($this->text->value);
|
||||
return check_plain($this->text->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements TypedDataInterface::setValue().
|
||||
* Implements \Drupal\Core\TypedData\TypedDataInterface::setValue().
|
||||
*/
|
||||
public function setValue($value) {
|
||||
if (isset($value)) {
|
||||
throw new ReadOnlyException('Unable to set a computed property.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\TypedDataInterface::validate().
|
||||
*/
|
||||
public function validate() {
|
||||
// @todo: Implement.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@ namespace Drupal\text\Type;
|
|||
use Drupal\Core\Entity\Field\FieldItemBase;
|
||||
|
||||
/**
|
||||
* Defines the 'text_item' and 'text_long_item' entity field items.
|
||||
* Defines the 'text_field' and 'text_long_field' entity field items.
|
||||
*/
|
||||
class TextItem extends FieldItemBase {
|
||||
|
||||
/**
|
||||
* Field definitions of the contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
namespace Drupal\text\Type;
|
||||
|
||||
/**
|
||||
* Defines the 'text_with_summary' entity field item.
|
||||
* Defines the 'text_with_summary_field' entity field item.
|
||||
*/
|
||||
class TextSummaryItem extends TextItem {
|
||||
|
||||
/**
|
||||
* Field definitions of the contained properties.
|
||||
* Definitions of the contained properties.
|
||||
*
|
||||
* @see self::getPropertyDefinitions()
|
||||
*
|
||||
|
|
|
@ -2,21 +2,20 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\translation_entity\EntityTranslationController.
|
||||
* Contains \Drupal\translation_entity\EntityTranslationControllerNG.
|
||||
*/
|
||||
|
||||
namespace Drupal\entity_test;
|
||||
namespace Drupal\translation_entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\translation_entity\EntityTranslationController;
|
||||
|
||||
/**
|
||||
* Test entity translation controller.
|
||||
*/
|
||||
class EntityTestTranslationController extends EntityTranslationController {
|
||||
class EntityTranslationControllerNG extends EntityTranslationController {
|
||||
|
||||
/**
|
||||
* Overrides EntityTranslationControllerInterface::removeTranslation().
|
||||
* Overrides EntityTranslationController::removeTranslation().
|
||||
*/
|
||||
public function removeTranslation(EntityInterface $entity, $langcode) {
|
||||
$translation = $entity->getTranslation($langcode);
|
||||
|
@ -24,5 +23,4 @@ class EntityTestTranslationController extends EntityTranslationController {
|
|||
$translation->$property_name = array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -292,7 +292,7 @@ abstract class EntityTranslationUITest extends WebTestBase {
|
|||
* The translation object to act on.
|
||||
*/
|
||||
protected function getTranslation(EntityInterface $entity, $langcode) {
|
||||
return $entity instanceof EntityNG ? $entity->getTranslation($langcode) : $entity;
|
||||
return $entity instanceof EntityNG ? $entity->getTranslation($langcode, FALSE) : $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\views_ui;
|
|||
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\TypedData\ContextAwareInterface;
|
||||
use Drupal\views\Plugin\views\query\Sql;
|
||||
use Drupal\views\Plugin\Core\Entity\View;
|
||||
use Drupal\views\ViewStorageInterface;
|
||||
|
@ -1080,4 +1081,52 @@ class ViewUI implements ViewStorageInterface {
|
|||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::getBCEntity().
|
||||
*/
|
||||
public function getBCEntity() {
|
||||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Entity\EntityInterface::getOriginalEntity().
|
||||
*/
|
||||
public function getOriginalEntity() {
|
||||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getName().
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getRoot().
|
||||
*/
|
||||
public function getRoot() {
|
||||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getPropertyPath().
|
||||
*/
|
||||
public function getPropertyPath() {
|
||||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::getParent().
|
||||
*/
|
||||
public function getParent() {
|
||||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\TypedData\ContextAwareInterface::setContext().
|
||||
*/
|
||||
public function setContext($name = NULL, ContextAwareInterface $parent = NULL) {
|
||||
return $this->__call(__FUNCTION__, func_get_args());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue