Skip to content
Snippets Groups Projects
Commit 1f9a06c6 authored by Angie Byron's avatar Angie Byron
Browse files

Issue #2087393 by amateescu: Remove LegacyField once all field types converted.

parent 074937a2
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
......@@ -42,10 +42,6 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
parent::__construct('Plugin/Field/FieldType', $namespaces, 'Drupal\Core\Field\Annotation\FieldType');
$this->alterInfo($module_handler, 'field_info');
$this->setCacheBackend($cache_backend, $language_manager, 'field_types_plugins');
// @todo Remove once all core field types have been converted (see
// http://drupal.org/node/2014671).
$this->discovery = new LegacyFieldTypeDiscoveryDecorator($this->discovery, $module_handler);
}
/**
......
<?php
/**
* @file
* Contains \Drupal\Core\Field\LegacyFieldTypeDiscoveryDecorator.
*/
namespace Drupal\Core\Field;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
/**
* Custom decorator to add legacy field types.
*
* Legacy field types are discovered through the old hook_field_info() hook,
* and handled by the Drupal\field\Plugin\Field\FieldType\LegacyConfigFieldItem class.
*
* @todo Remove once all core field types have been converted (see
* http://drupal.org/node/2014671).
*/
class LegacyFieldTypeDiscoveryDecorator implements DiscoveryInterface {
/**
* The decorated discovery object.
*
* @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
*/
protected $decorated;
/**
* Creates a \Drupal\Core\Field\LegacyFieldTypeDiscoveryDecorator object.
*
* @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
* The parent object implementing DiscoveryInterface that is being
* decorated.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(DiscoveryInterface $decorated, ModuleHandlerInterface $module_handler) {
$this->decorated = $decorated;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public function getDefinition($plugin_id) {
$definitions = $this->getDefinitions();
return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
}
/**
* {@inheritdoc}
*/
public function getDefinitions() {
$definitions = $this->decorated->getDefinitions();
// We cannot use HookDiscovery, since it uses
// \Drupal::moduleHandler()->getImplementations(), which
// throws exceptions during upgrades.
foreach (array_keys($this->moduleHandler->getModuleList()) as $module) {
$function = $module . '_field_info';
if (function_exists($function)) {
foreach ($function() as $plugin_id => $definition) {
$definition['id'] = $plugin_id;
$definition['provider'] = $module;
$definition['configurable'] = TRUE;
$definition += array('list_class' => '\Drupal\Core\Field\Plugin\Field\FieldType\LegacyConfigFieldItemList');
$definitions[$plugin_id] = $definition;
}
}
}
return $definitions;
}
}
<?php
/**
* @file
* Contains \Drupal\field\Plugin\Field\FieldType\LegacyConfigFieldItem.
*/
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\PrepareCacheInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Field\ConfigFieldItemBase;
use Drupal\field\FieldInstanceInterface;
/**
* Plugin implementation for legacy field types.
*
* This special implementation acts as a temporary BC layer for field types
* that have not been converted to Plugins, and bridges new methods to the
* old-style hook_field_*() callbacks.
*
* This class is not discovered by the annotations reader, but referenced by
* the Drupal\field\Plugin\Discovery\LegacyDiscoveryDecorator.
*
* @todo Remove once all core field types have been converted (see
* http://drupal.org/node/2014671).
*/
abstract class LegacyConfigFieldItem extends ConfigFieldItemBase implements PrepareCacheInterface {
/**
* {@inheritdoc}
*/
public static function schema(FieldDefinitionInterface $field_definition) {
$definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field_definition->type);
$module = $definition['provider'];
module_load_install($module);
$callback = "{$module}_field_schema";
if (function_exists($callback)) {
return $callback($field_definition);
}
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$callback = $this->getLegacyCallback('is_empty');
// Make sure the array received by the legacy callback includes computed
// properties.
$item = $this->getValue(TRUE);
// The previous hook was never called on an empty item, but
// ContentEntityBase always creates a FieldItem element for an empty field.
return empty($item) || $callback($item, $this->getFieldDefinition()->getType());
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, array &$form_state, $has_data) {
if ($callback = $this->getLegacyCallback('settings_form')) {
// hook_field_settings_form() used to receive the $instance (not actually
// needed), and the value of field_has_data().
return $callback($this->getFieldInstance()->getField(), $this->getFieldInstance(), $has_data);
}
return array();
}
/**
* {@inheritdoc}
*/
public function instanceSettingsForm(array $form, array &$form_state) {
if ($callback = $this->getLegacyCallback('instance_settings_form')) {
return $callback($this->getFieldInstance()->getField(), $this->getFieldInstance(), $form_state);
}
return array();
}
/**
* Massages loaded field values before they enter the field cache.
*
* This implements the prepareCache() method defined in PrepareCacheInterface
* even if the class does explicitly implements it, so as to preserve
* the optimizations of only creating Field and FieldItem objects and invoking
* the method if are actually needed.
*
* @see \Drupal\Core\Entity\DatabaseStorageController::invokeFieldItemPrepareCache()
*/
public function getCacheData() {
if ($callback = $this->getLegacyCallback('load')) {
$entity = $this->getEntity();
$entity_id = $entity->id();
// hook_field_load() receives items keyed by entity id, and alters then by
// reference.
$items = array($entity_id => array(0 => $this->getValue(TRUE)));
$args = array(
$entity->entityType(),
array($entity_id => $entity),
$this->getFieldInstance()->getField(),
array($entity_id => $this->getFieldInstance()),
$this->getLangcode(),
&$items,
EntityStorageControllerInterface::FIELD_LOAD_CURRENT,
);
call_user_func_array($callback, $args);
$this->setValue($items[$entity_id][0]);
return $items[$entity_id][0];
}
return $this->getValue();
}
/**
* Returns options provided via the legacy callback hook_options_list().
*
* @todo: Convert all legacy callback implementations to methods.
*
* @see \Drupal\Core\TypedData\AllowedValuesInterface
*/
public function getSettableOptions() {
$definition = $this->getPluginDefinition();
$callback = "{$definition['provider']}_options_list";
if (function_exists($callback)) {
return $callback($this->getFieldDefinition(), $this->getEntity());
}
}
/**
* Returns the legacy callback for a given field type "hook".
*
* @param string $hook
* The name of the hook, e.g. 'settings_form', 'is_empty'.
*
* @return string|null
* The name of the legacy callback, or NULL if it does not exist.
*/
protected function getLegacyCallback($hook) {
$definition = $this->getPluginDefinition();
$module = $definition['provider'];
$callback = "{$module}_field_{$hook}";
if (function_exists($callback)) {
return $callback;
}
}
/**
* Returns the field instance.
*
* @return \Drupal\field\Entity\FieldInstanceInterface
* The field instance.
*/
protected function getFieldInstance() {
$instance = $this->getFieldDefinition();
if (!($instance instanceof FieldInstanceInterface)) {
throw new \UnexpectedValueException('LegacyConfigFieldItem::getFieldInstance() called for a field whose definition is not a field instance.');
}
return $instance;
}
}
<?php
/**
* @file
* Contains \Drupal\field\Plugin\Field\FieldType\LegacyConfigFieldItemList.
*/
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\ConfigFieldItemList;
use Drupal\field\FieldInstanceInterface;
use Symfony\Component\Validator\ConstraintViolation;
/**
* Field class for legacy field types.
*
* This acts as a temporary BC layer for field types that have not been
* converted to Plugins, and bridges new methods to the old-style hook_field_*()
* callbacks.
*
* This class is not discovered by the annotations reader, but referenced by
* the Drupal\field\Plugin\Discovery\LegacyDiscoveryDecorator.
*
* @todo Remove once all core field types have been converted (see
* http://drupal.org/node/2014671).
*/
class LegacyConfigFieldItemList extends ConfigFieldItemList {
/**
* {@inheritdoc}
*/
public function validate() {
$violations = parent::validate();
// Filter out empty items (legacy hook_field_validate() implementations
// used to receive pruned items).
$this->filterEmptyValues();
$legacy_errors = array();
$this->legacyCallback('validate', array(&$legacy_errors));
$langcode = $this->getLangcode();
$field_name = $this->getFieldDefinition()->getName();
if (isset($legacy_errors[$field_name][$langcode])) {
foreach ($legacy_errors[$field_name][$langcode] as $delta => $item_errors) {
foreach ($item_errors as $item_error) {
// We do not have the information about which column triggered the
// error, so assume the first column...
$property_names = $this->getFieldDefinition()->getPropertyNames();
$property_name = $property_names[0];
$violations->add(new ConstraintViolation($item_error['message'], $item_error['message'], array(), $this, $delta . '.' . $property_name, $this->offsetGet($delta)->get($property_name)->getValue(), NULL, $item_error['error']));
}
}
}
return $violations;
}
/**
* {@inheritdoc}
*/
public function preSave() {
// Filter out empty items.
$this->filterEmptyValues();
$this->legacyCallback('presave');
}
/**
* {@inheritdoc}
*/
public function insert() {
$this->legacyCallback('insert');
}
/**
* {@inheritdoc}
*/
public function update() {
$this->legacyCallback('update');
}
/**
* {@inheritdoc}
*/
public function delete() {
$this->legacyCallback('delete');
}
/**
* {@inheritdoc}
*/
public function deleteRevision() {
$this->legacyCallback('delete_revision');
}
/**
* Calls the legacy callback for a given field type "hook", if it exists.
*
* @param string $hook
* The name of the hook, e.g. 'presave', 'validate'.
*/
protected function legacyCallback($hook, $args = array()) {
$type_definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getFieldDefinition()->getType());
$module = $type_definition['provider'];
$callback = "{$module}_field_{$hook}";
if (function_exists($callback)) {
// We need to remove the empty "prototype" item here.
// @todo Revisit after http://drupal.org/node/1988492.
$this->filterEmptyValues();
// Legacy callbacks alter $items by reference.
$items = (array) $this->getValue(TRUE);
$args = array_merge(array(
$this->getEntity(),
$this->getFieldInstance()->getField(),
$this->getFieldInstance(),
$this->getLangcode(),
&$items
), $args);
call_user_func_array($callback, $args);
$this->setValue($items);
}
}
/**
* Returns the field instance.
*
* @return \Drupal\field\FieldInstanceInterface
* The field instance.
*/
protected function getFieldInstance() {
$instance = $this->getFieldDefinition();
if (!($instance instanceof FieldInstanceInterface)) {
throw new \UnexpectedValueException('LegacyConfigFieldItemList::getFieldInstance() called for a field whose definition is not a field instance.');
}
return $instance;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment