Commit 38bf424d authored by Dries's avatar Dries

Issue #2021817 by effulgentsia, yched: Make widgets / formatters work on...

Issue #2021817 by effulgentsia, yched: Make widgets / formatters work on EntityNG Field value objects.
parent f5cc9308
......@@ -555,7 +555,7 @@ function entity_get_form(EntityInterface $entity, $operation = 'default', array
* so the builder function for such forms needs to implement the required
* functionality instead of calling this function.
*/
function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state) {
function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state, array $options = array()) {
$info = entity_get_info($entity_type);
// Copy top-level form values that are not for fields to entity properties,
......@@ -576,7 +576,7 @@ function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_st
// Copy field values to the entity.
if ($info['fieldable']) {
field_attach_extract_form_values($entity, $form, $form_state);
field_attach_extract_form_values($entity, $form, $form_state, $options);
}
}
......
......@@ -430,9 +430,9 @@ public function isDefaultFormLangcode(array $form_state) {
* Updates the form language to reflect any change to the entity language.
*
* @param array $form_state
* A keyed array containing the current state of the form.
* A reference to a keyed array containing the current state of the form.
*/
protected function updateFormLangcode(array $form_state) {
protected function updateFormLangcode(array &$form_state) {
// Update the form language as it might have changed.
if (isset($form_state['values']['langcode']) && $this->isDefaultFormLangcode($form_state)) {
$form_state['langcode'] = $form_state['values']['langcode'];
......@@ -487,7 +487,7 @@ public function buildEntity(array $form, array &$form_state) {
$form_state['controller'] = $this;
// @todo Move entity_form_submit_build_entity() here.
// @todo Exploit the Field API to process the submitted entity field.
entity_form_submit_build_entity($entity->entityType(), $entity, $form, $form_state);
entity_form_submit_build_entity($entity->entityType(), $entity, $form, $form_state, array('langcode' => $this->getFormLangcode($form_state)));
return $entity;
}
......
......@@ -77,7 +77,7 @@ public function buildEntity(array $form, array &$form_state) {
// Invoke field API for copying field values.
if ($info['fieldable']) {
field_attach_extract_form_values($entity, $form, $form_state);
field_attach_extract_form_values($entity, $form, $form_state, array('langcode' => $this->getFormLangcode($form_state)));
}
return $entity;
}
......
......@@ -130,6 +130,7 @@ public function __isset($name) {
*/
public function __unset($name) {
$this->set($name, NULL);
unset($this->values[$name]);
}
/**
......
......@@ -14,6 +14,7 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Entity\Field\FieldDefinitionInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\field\Plugin\Type\Formatter\FormatterBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -95,7 +96,7 @@ public static function create(ContainerInterface $container, array $configuratio
/**
* {@inheritdoc}
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
public function viewElements(EntityInterface $entity, $langcode, FieldInterface $items) {
$elements = array();
......@@ -104,10 +105,10 @@ public function viewElements(EntityInterface $entity, $langcode, array $items) {
$formatted_date = '';
$iso_date = '';
if (!empty($item['date'])) {
if (!empty($item->date)) {
// The date was created and verified during field_load(), so it is safe
// to use without further inspection.
$date = $item['date'];
$date = $item->date;
// Create the ISO date in Universal Time.
$iso_date = $date->format("Y-m-d\TH:i:s") . 'Z';
......
......@@ -11,6 +11,7 @@
use Drupal\Core\Annotation\Translation;
use Drupal\field\Plugin\Type\Formatter\FormatterBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\Core\Datetime\DrupalDateTime;
/**
......@@ -30,17 +31,17 @@ class DateTimePlainFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
public function viewElements(EntityInterface $entity, $langcode, FieldInterface $items) {
$elements = array();
foreach ($items as $delta => $item) {
$output = '';
if (!empty($item['date'])) {
if (!empty($item->date)) {
// The date was created and verified during field_load(), so it is safe
// to use without further inspection.
$date = $item['date'];
$date = $item->date;
$date->setTimeZone(timezone_open(drupal_get_user_timezone()));
$format = DATETIME_DATETIME_STORAGE_FORMAT;
if ($this->getFieldSetting('datetime_type') == 'date') {
......
......@@ -12,6 +12,7 @@
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldDefinitionInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\field\Plugin\PluginSettingsBase;
use Drupal\field\FieldInstanceInterface;
use Drupal\Core\Datetime\DrupalDateTime;
......@@ -61,7 +62,7 @@ public function defaultValueFunction() {
/**
* {@inheritdoc}
*/
public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
public function formElement(FieldInterface $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
$date_order = $this->getSetting('date_order');
$time_type = $this->getSetting('time_type');
$increment = $this->getSetting('increment');
......@@ -129,8 +130,8 @@ public function formElement(array $items, $delta, array $element, $langcode, arr
// validator will not have access to the field definition.
$element['value']['#date_storage_format'] = $storage_format;
if (!empty($items[$delta]['date'])) {
$date = $items[$delta]['date'];
if (!empty($items[$delta]->date)) {
$date = $items[$delta]->date;
// The date was created and verified during field_load(), so it is safe to
// use without further inspection.
$date->setTimezone( new \DateTimeZone($element['value']['#date_timezone']));
......
......@@ -12,6 +12,7 @@
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldDefinitionInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\field\Plugin\PluginSettingsBase;
use Drupal\field\FieldInstanceInterface;
use Drupal\Core\Datetime\DrupalDateTime;
......@@ -65,7 +66,7 @@ public function defaultValueFunction() {
/**
* {@inheritdoc}
*/
public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
public function formElement(FieldInterface $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
$format_type = datetime_default_format_type();
// We are nesting some sub-elements inside the parent, so we need a wrapper.
......@@ -118,8 +119,8 @@ public function formElement(array $items, $delta, array $element, $langcode, arr
$element['value']['#date_element_format'] = $element_format;
$element['value']['#date_storage_format'] = $storage_format;
if (!empty($items[$delta]['date'])) {
$date = $items[$delta]['date'];
if (!empty($items[$delta]->date)) {
$date = $items[$delta]->date;
// The date was created and verified during field_load(), so it is safe to
// use without further inspection.
$date->setTimezone(new \DateTimeZone($element['value']['#date_timezone']));
......
......@@ -11,6 +11,7 @@
use Drupal\Core\Annotation\Translation;
use Drupal\field\Plugin\Type\Formatter\FormatterBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldInterface;
/**
* Plugin implementation of the 'email_mailto' formatter.
......@@ -29,14 +30,14 @@ class MailToFormatter extends FormatterBase {
/**
* Implements Drupal\field\Plugin\Type\Formatter\FormatterInterface::viewElements().
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
public function viewElements(EntityInterface $entity, $langcode, FieldInterface $items) {
$elements = array();
foreach ($items as $delta => $item) {
$elements[$delta] = array(
'#type' => 'link',
'#title' => $item['value'],
'#href' => 'mailto:' . $item['value'],
'#title' => $item->value,
'#href' => 'mailto:' . $item->value,
);
}
......
......@@ -9,6 +9,7 @@
use Drupal\field\Annotation\FieldWidget;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\field\Plugin\Type\Widget\WidgetBase;
/**
......@@ -60,10 +61,10 @@ public function settingsSummary() {
/**
* Implements Drupal\field\Plugin\Type\Widget\WidgetInterface::formElement().
*/
public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
public function formElement(FieldInterface $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
$element['value'] = $element + array(
'#type' => 'email',
'#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
'#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
'#placeholder' => $this->getSetting('placeholder'),
);
return $element;
......
......@@ -10,6 +10,7 @@
use Drupal\field\Annotation\FieldFormatter;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\entity_reference\RecursiveRenderingException;
use Drupal\entity_reference\Plugin\field\formatter\EntityReferenceFormatterBase;
......@@ -79,7 +80,7 @@ public function settingsSummary() {
/**
* {@inheritdoc}
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
public function viewElements(EntityInterface $entity, $langcode, FieldInterface $items) {
// Remove un-accessible items.
parent::viewElements($entity, $langcode, $items);
......@@ -95,17 +96,17 @@ public function viewElements(EntityInterface $entity, $langcode, array $items) {
static $depth = 0;
$depth++;
if ($depth > 20) {
throw new RecursiveRenderingException(format_string('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity_type, '@entity_id' => $item['target_id'])));
throw new RecursiveRenderingException(format_string('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity_type, '@entity_id' => $item->target_id)));
}
if (!empty($item['target_id'])) {
$entity = clone $item['entity'];
if (!empty($item->target_id)) {
$entity = clone $item->entity;
unset($entity->content);
$elements[$delta] = entity_view($entity, $view_mode, $langcode);
if (empty($links) && isset($result[$delta][$target_type][$item['target_id']]['links'])) {
if (empty($links) && isset($result[$delta][$target_type][$item->target_id]['links'])) {
// Hide the element links.
$elements[$delta][$target_type][$item['target_id']]['links']['#access'] = FALSE;
$elements[$delta][$target_type][$item->target_id]['links']['#access'] = FALSE;
}
}
else {
......
......@@ -10,6 +10,7 @@
use Drupal\field\Annotation\FieldFormatter;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\field\Plugin\Type\Formatter\FormatterBase;
/**
......@@ -24,18 +25,18 @@ abstract class EntityReferenceFormatterBase extends FormatterBase {
* values, as other may want to act on those values, even if they can
* not be accessed.
*/
public function prepareView(array $entities, $langcode, array &$items) {
public function prepareView(array $entities, $langcode, array $items) {
$target_ids = array();
$revision_ids = array();
// Collect every possible entity attached to any of the entities.
foreach ($entities as $id => $entity) {
foreach ($items[$id] as $delta => $item) {
if (!empty($item['revision_id'])) {
$revision_ids[] = $item['revision_id'];
if (!empty($item->revision_id)) {
$revision_ids[] = $item->revision_id;
}
elseif (!empty($item['target_id'])) {
$target_ids[] = $item['target_id'];
elseif (!empty($item->target_id)) {
$target_ids[] = $item->target_id;
}
}
}
......@@ -63,8 +64,8 @@ public function prepareView(array $entities, $langcode, array &$items) {
$rekey = FALSE;
foreach ($items[$id] as $delta => $item) {
// If we have a revision ID, the key uses it as well.
$identifier = !empty($item['revision_id']) ? $item['target_id'] . ':' . $item['revision_id'] : $item['target_id'];
if ($item['target_id'] !== 0) {
$identifier = !empty($item->revision_id) ? $item->target_id . ':' . $item->revision_id : $item->target_id;
if ($item->target_id !== 0) {
if (!isset($target_entities[$identifier])) {
// The entity no longer exists, so remove the key.
$rekey = TRUE;
......@@ -73,7 +74,7 @@ public function prepareView(array $entities, $langcode, array &$items) {
}
$entity = $target_entities[$identifier];
$items[$id][$delta]['entity'] = $entity;
$item->entity = $entity;
if (!$entity->access('view')) {
continue;
......@@ -84,7 +85,7 @@ public function prepareView(array $entities, $langcode, array &$items) {
}
// Mark item as accessible.
$items[$id][$delta]['access'] = TRUE;
$item->access = TRUE;
}
if ($rekey) {
......@@ -99,10 +100,10 @@ public function prepareView(array $entities, $langcode, array &$items) {
*
* @see \Drupal\entity_reference\Plugin\field\formatter\EntityReferenceFormatterBase::viewElements().
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
public function viewElements(EntityInterface $entity, $langcode, FieldInterface $items) {
// Remove un-accessible items.
foreach ($items as $delta => $item) {
if (empty($item['access'])) {
if (empty($item->access)) {
unset($items[$delta]);
}
}
......
......@@ -10,6 +10,7 @@
use Drupal\field\Annotation\FieldFormatter;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\entity_reference\Plugin\field\formatter\EntityReferenceFormatterBase;
/**
......@@ -30,12 +31,12 @@ class EntityReferenceIdFormatter extends EntityReferenceFormatterBase {
/**
* Overrides \Drupal\entity_reference\Plugin\field\formatter\EntityReferenceFormatterBase::viewElements().
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
public function viewElements(EntityInterface $entity, $langcode, FieldInterface $items) {
$elements = array();
foreach ($items as $delta => $item) {
if (!empty($item['entity']) && !empty($item['target_id'])) {
$elements[$delta] = array('#markup' => check_plain($item['target_id']));
if (!empty($item->entity) && !empty($item->target_id)) {
$elements[$delta] = array('#markup' => check_plain($item->target_id));
}
}
......
......@@ -10,6 +10,7 @@
use Drupal\field\Annotation\FieldFormatter;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\entity_reference\Plugin\field\formatter\EntityReferenceFormatterBase;
/**
......@@ -55,14 +56,14 @@ public function settingsSummary() {
/**
* {@inheritdoc}
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
public function viewElements(EntityInterface $entity, $langcode, FieldInterface $items) {
// Remove un-accessible items.
parent::viewElements($entity, $langcode, $items);
$elements = array();
foreach ($items as $delta => $item) {
if ($entity = $item['entity']) {
if ($entity = $item->entity) {
$label = $entity->label();
// If the link is to be displayed and the entity has a uri,
// display a link.
......
......@@ -9,6 +9,7 @@
use Drupal\field\Annotation\FieldWidget;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\entity_reference\Plugin\field\widget\AutocompleteWidgetBase;
/**
......@@ -39,14 +40,14 @@ class AutocompleteWidget extends AutocompleteWidgetBase {
/**
* {@inheritdoc}
*/
public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
public function formElement(FieldInterface $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
// We let the Field API handles multiple values for us, only take care of
// the one matching our delta.
if (isset($items[$delta])) {
$items = array($items[$delta]);
$items->setValue(array($items[$delta]->getValue()));
}
else {
$items = array();
$items->setValue(array());
}
return parent::formElement($items, $delta, $element, $langcode, $form, $form_state);
......
......@@ -9,6 +9,7 @@
use Drupal\Component\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\field\Plugin\Type\Widget\WidgetBase;
use Symfony\Component\Validator\ConstraintViolationInterface;
......@@ -69,7 +70,7 @@ public function settingsSummary() {
/**
* {@inheritdoc}
*/
public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
public function formElement(FieldInterface $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
global $user;
$entity = $element['#entity'];
......@@ -115,13 +116,17 @@ public function elementValidate($element, &$form_state, $form) { }
/**
* Gets the entity labels.
*/
protected function getLabels(array $items) {
protected function getLabels(FieldInterface $items) {
if ($items->isEmpty()) {
return array();
}
$entity_ids = array();
$entity_labels = array();
// Build an array of entity IDs.
foreach ($items as $item) {
$entity_ids[] = $item['target_id'];
$entity_ids[] = $item->target_id;
}
// Load those entities and loop through them to extract their labels.
......
......@@ -177,7 +177,8 @@ function field_invoke_method($method, $target_function, EntityInterface $entity,
$langcodes = _field_language_suggestion($available_langcodes, $options['langcode'], $field_name);
foreach ($langcodes as $langcode) {
$items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
$items = $entity->getTranslation($langcode)->get($field_name);
$items->filterEmptyValues();
$result = $target->$method($entity, $langcode, $items, $a, $b);
......@@ -191,12 +192,6 @@ function field_invoke_method($method, $target_function, EntityInterface $entity,
$return[] = $result;
}
}
// Populate $items back in the field values, but avoid replacing missing
// fields with an empty array (those are not equivalent on update).
if ($items !== array() || isset($entity->{$field_name}[$langcode])) {
$entity->{$field_name}[$langcode] = $items;
}
}
}
}
......@@ -288,7 +283,9 @@ function field_invoke_method_multiple($method, $target_function, array $entities
foreach ($langcodes as $langcode) {
// Group the entities and items corresponding to the current field.
$grouped_entities[$instance_id][$langcode][$id] = $entities[$id];
$grouped_items[$instance_id][$langcode][$id] = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
$items = $entity->getTranslation($langcode)->get($field_name);
$items->filterEmptyValues();
$grouped_items[$instance_id][$langcode][$id] = $items;
}
}
}
......@@ -301,7 +298,7 @@ function field_invoke_method_multiple($method, $target_function, array $entities
$field_name = $instance['field_name'];
// Iterate over all the field translations.
foreach ($grouped_items[$instance_id] as $langcode => &$items) {
foreach ($grouped_items[$instance_id] as $langcode => $items) {
$entities = $grouped_entities[$instance_id][$langcode];
$results = $grouped_targets[$instance_id]->$method($entities, $langcode, $items, $a, $b);
......@@ -319,16 +316,6 @@ function field_invoke_method_multiple($method, $target_function, array $entities
}
}
}
// Populate field values back in the entities, but avoid replacing missing
// fields with an empty array (those are not equivalent on update).
foreach ($grouped_entities[$instance_id] as $langcode => $entities) {
foreach ($entities as $id => $entity) {
if ($grouped_items[$instance_id][$langcode][$id] !== array() || isset($entity->{$field_name}[$langcode])) {
$entity->{$field_name}[$langcode] = $grouped_items[$instance_id][$langcode][$id];
}
}
}
}
return $return;
......
......@@ -803,24 +803,11 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options
if ($formatter) {
$display_langcode = field_language($entity, $field_name, $langcode);
// Get the items.
if ($entity->getNGEntity() instanceof EntityNG) {
$items = $entity->getTranslation($display_langcode)->get($field_name);
$definition = $entity->getPropertyDefinition($field_name);
}
else {
$definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $bundle);
$definition = $definitions[$field_name];
$itemsBC = isset($entity->{$field_name}[$display_langcode]) ? $entity->{$field_name}[$display_langcode] : array();
$items = \Drupal::typedData()->create($definitions[$field_name], $itemsBC, $field_name, $entity);
}
// Invoke the formatter's prepareView() and view() methods.
$items = $entity->getNGEntity()->getTranslation($display_langcode)->get($field_name);
$id = $entity->id();
$itemsBC_multi = array($id => $items->getValue());
$formatter->prepareView(array($id => $entity), $display_langcode, $itemsBC_multi);
$itemsBC = $itemsBC_multi[$id];
$result = $formatter->view($entity, $display_langcode, $itemsBC);
$formatter->prepareView(array($id => $entity), $display_langcode, array($id => $items));
$result = $formatter->view($entity, $display_langcode, $items);
// Invoke hook_field_attach_view_alter() to let other modules alter the
// renderable array, as in a full field_attach_view() execution.
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldDefinitionInterface;
use Drupal\Core\Entity\Field\FieldInterface;
use Drupal\field\FieldInstanceInterface;
use Drupal\field\Plugin\PluginSettingsBase;
......@@ -73,7 +74,7 @@ public function __construct($plugin_id, array $plugin_definition, FieldDefinitio
/**
* {@inheritdoc}
*/
public function view(EntityInterface $entity, $langcode, array $items) {
public function view(EntityInterface $entity, $langcode, FieldInterface $items) {
$addition = array();
$elements = $this->viewElements($entity, $langcode, $items);
......@@ -93,7 +94,7 @@ public function view(EntityInterface $entity, $langcode, array $items) {
'#entity_type' => $entity_type,
'#bundle' => $entity->bundle(),
'#object' => $entity,
'#items' => $items,
'#items' => $items->getValue(TRUE),
'#formatter' => $this->getPluginId(),
);
......@@ -120,7 +121,7 @@ public function settingsSummary() {
/**
* {@inheritdoc}
*/
public function prepareView(array $entities, $langcode, array &$items) { }
public function prepareView(array $entities, $langcode, array $items) { }
/**
* Returns whether the currently logged in user has access to the field.
......