Move all files to 2017/
This commit is contained in:
parent
ac7370f67f
commit
2875863330
15717 changed files with 0 additions and 0 deletions
146
2017/web/core/modules/field/src/ConfigImporterFieldPurger.php
Normal file
146
2017/web/core/modules/field/src/ConfigImporterFieldPurger.php
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Config\ConfigImporter;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityStorage;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Processes field purges before a configuration synchronization.
|
||||
*/
|
||||
class ConfigImporterFieldPurger {
|
||||
|
||||
/**
|
||||
* Processes fields targeted for purge as part of a configuration sync.
|
||||
*
|
||||
* This takes care of deleting the field if necessary, and purging the data on
|
||||
* the fly.
|
||||
*
|
||||
* @param array $context
|
||||
* The batch context.
|
||||
* @param \Drupal\Core\Config\ConfigImporter $config_importer
|
||||
* The config importer.
|
||||
*/
|
||||
public static function process(array &$context, ConfigImporter $config_importer) {
|
||||
if (!isset($context['sandbox']['field'])) {
|
||||
static::initializeSandbox($context, $config_importer);
|
||||
}
|
||||
|
||||
// Get the list of field storages to purge.
|
||||
$field_storages = static::getFieldStoragesToPurge($context['sandbox']['field']['extensions'], $config_importer->getUnprocessedConfiguration('delete'));
|
||||
// Get the first field storage to process.
|
||||
$field_storage = reset($field_storages);
|
||||
if (!isset($context['sandbox']['field']['current_storage_id']) || $context['sandbox']['field']['current_storage_id'] != $field_storage->id()) {
|
||||
$context['sandbox']['field']['current_storage_id'] = $field_storage->id();
|
||||
// If the storage has not been deleted yet we need to do that. This is the
|
||||
// case when the storage deletion is staged.
|
||||
if (!$field_storage->isDeleted()) {
|
||||
$field_storage->delete();
|
||||
}
|
||||
}
|
||||
field_purge_batch($context['sandbox']['field']['purge_batch_size'], $field_storage->getUniqueStorageIdentifier());
|
||||
$context['sandbox']['field']['current_progress']++;
|
||||
$fields_to_delete_count = count(static::getFieldStoragesToPurge($context['sandbox']['field']['extensions'], $config_importer->getUnprocessedConfiguration('delete')));
|
||||
if ($fields_to_delete_count == 0) {
|
||||
$context['finished'] = 1;
|
||||
}
|
||||
else {
|
||||
$context['finished'] = $context['sandbox']['field']['current_progress'] / $context['sandbox']['field']['steps_to_delete'];
|
||||
$context['message'] = \Drupal::translation()->translate('Purging field @field_label', ['@field_label' => $field_storage->label()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the batch context sandbox for processing field deletions.
|
||||
*
|
||||
* This calculates the number of steps necessary to purge all the field data
|
||||
* and saves data for later use.
|
||||
*
|
||||
* @param array $context
|
||||
* The batch context.
|
||||
* @param \Drupal\Core\Config\ConfigImporter $config_importer
|
||||
* The config importer.
|
||||
*/
|
||||
protected static function initializeSandbox(array &$context, ConfigImporter $config_importer) {
|
||||
$context['sandbox']['field']['purge_batch_size'] = \Drupal::config('field.settings')->get('purge_batch_size');
|
||||
// Save the future list of installed extensions to limit the amount of times
|
||||
// the configuration is read from disk.
|
||||
$context['sandbox']['field']['extensions'] = $config_importer->getStorageComparer()->getSourceStorage()->read('core.extension');
|
||||
|
||||
$context['sandbox']['field']['steps_to_delete'] = 0;
|
||||
$fields = static::getFieldStoragesToPurge($context['sandbox']['field']['extensions'], $config_importer->getUnprocessedConfiguration('delete'));
|
||||
foreach ($fields as $field) {
|
||||
$row_count = \Drupal::entityManager()->getStorage($field->getTargetEntityTypeId())
|
||||
->countFieldData($field);
|
||||
if ($row_count > 0) {
|
||||
// The number of steps to delete each field is determined by the
|
||||
// purge_batch_size setting. For example if the field has 9 rows and the
|
||||
// batch size is 10 then this will add 1 step to $number_of_steps.
|
||||
$how_many_steps = ceil($row_count / $context['sandbox']['field']['purge_batch_size']);
|
||||
$context['sandbox']['field']['steps_to_delete'] += $how_many_steps;
|
||||
}
|
||||
}
|
||||
// Each field possibly needs one last field_purge_batch() call to remove the
|
||||
// last field and the field storage itself.
|
||||
$context['sandbox']['field']['steps_to_delete'] += count($fields);
|
||||
|
||||
$context['sandbox']['field']['current_progress'] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of fields to purge before configuration synchronization.
|
||||
*
|
||||
* If, during a configuration synchronization, a field is being deleted and
|
||||
* the module that provides the field type is being uninstalled then the field
|
||||
* data must be purged before the module is uninstalled. Also, if deleted
|
||||
* fields exist whose field types are provided by modules that are being
|
||||
* uninstalled their data need to be purged too.
|
||||
*
|
||||
* @param array $extensions
|
||||
* The list of extensions that will be enabled after the configuration
|
||||
* synchronization has finished.
|
||||
* @param array $deletes
|
||||
* The configuration that will be deleted by the configuration
|
||||
* synchronization.
|
||||
*
|
||||
* @return \Drupal\field\Entity\FieldStorageConfig[]
|
||||
* An array of field storages that need purging before configuration can be
|
||||
* synchronized.
|
||||
*/
|
||||
public static function getFieldStoragesToPurge(array $extensions, array $deletes) {
|
||||
$providers = array_keys($extensions['module']);
|
||||
$providers[] = 'core';
|
||||
$storages_to_delete = [];
|
||||
|
||||
// Gather fields that will be deleted during configuration synchronization
|
||||
// where the module that provides the field type is also being uninstalled.
|
||||
$field_storage_ids = [];
|
||||
foreach ($deletes as $config_name) {
|
||||
$field_storage_config_prefix = \Drupal::entityManager()->getDefinition('field_storage_config')->getConfigPrefix();
|
||||
if (strpos($config_name, $field_storage_config_prefix . '.') === 0) {
|
||||
$field_storage_ids[] = ConfigEntityStorage::getIDFromConfigName($config_name, $field_storage_config_prefix);
|
||||
}
|
||||
}
|
||||
if (!empty($field_storage_ids)) {
|
||||
$field_storages = \Drupal::entityQuery('field_storage_config')
|
||||
->condition('id', $field_storage_ids, 'IN')
|
||||
->condition('module', $providers, 'NOT IN')
|
||||
->execute();
|
||||
if (!empty($field_storages)) {
|
||||
$storages_to_delete = FieldStorageConfig::loadMultiple($field_storages);
|
||||
}
|
||||
}
|
||||
|
||||
// Gather deleted fields from modules that are being uninstalled.
|
||||
/** @var \Drupal\field\FieldStorageConfigInterface[] $deleted_storage_definitions */
|
||||
$deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions();
|
||||
foreach ($deleted_storage_definitions as $field_storage_definition) {
|
||||
if ($field_storage_definition instanceof FieldStorageConfigInterface && !in_array($field_storage_definition->getTypeProvider(), $providers)) {
|
||||
$storages_to_delete[$field_storage_definition->id()] = $field_storage_definition;
|
||||
}
|
||||
}
|
||||
return $storages_to_delete;
|
||||
}
|
||||
|
||||
}
|
||||
380
2017/web/core/modules/field/src/Entity/FieldConfig.php
Normal file
380
2017/web/core/modules/field/src/Entity/FieldConfig.php
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityStorageInterface;
|
||||
use Drupal\Core\Field\FieldConfigBase;
|
||||
use Drupal\Core\Field\FieldException;
|
||||
use Drupal\field\FieldStorageConfigInterface;
|
||||
use Drupal\field\FieldConfigInterface;
|
||||
|
||||
/**
|
||||
* Defines the Field entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "field_config",
|
||||
* label = @Translation("Field"),
|
||||
* label_collection = @Translation("Fields"),
|
||||
* label_singular = @Translation("field"),
|
||||
* label_plural = @Translation("fields"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count field",
|
||||
* plural = "@count fields",
|
||||
* ),
|
||||
* handlers = {
|
||||
* "access" = "Drupal\field\FieldConfigAccessControlHandler",
|
||||
* "storage" = "Drupal\field\FieldConfigStorage"
|
||||
* },
|
||||
* config_prefix = "field",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label"
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "field_name",
|
||||
* "entity_type",
|
||||
* "bundle",
|
||||
* "label",
|
||||
* "description",
|
||||
* "required",
|
||||
* "translatable",
|
||||
* "default_value",
|
||||
* "default_value_callback",
|
||||
* "settings",
|
||||
* "field_type",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class FieldConfig extends FieldConfigBase implements FieldConfigInterface {
|
||||
|
||||
/**
|
||||
* Flag indicating whether the field is deleted.
|
||||
*
|
||||
* The delete() method marks the field as "deleted" and removes the
|
||||
* corresponding entry from the config storage, but keeps its definition in
|
||||
* the state storage while field data is purged by a separate
|
||||
* garbage-collection process.
|
||||
*
|
||||
* Deleted fields stay out of the regular entity lifecycle (notably, their
|
||||
* values are not populated in loaded entities, and are not saved back).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $deleted = FALSE;
|
||||
|
||||
/**
|
||||
* The associated FieldStorageConfig entity.
|
||||
*
|
||||
* @var \Drupal\field\Entity\FieldStorageConfig
|
||||
*/
|
||||
protected $fieldStorage;
|
||||
|
||||
/**
|
||||
* Constructs a FieldConfig object.
|
||||
*
|
||||
* In most cases, Field entities are created via
|
||||
* FieldConfig::create($values), where $values is the same
|
||||
* parameter as in this constructor.
|
||||
*
|
||||
* @param array $values
|
||||
* An array of field properties, keyed by property name. The
|
||||
* storage associated with the field can be specified either with:
|
||||
* - field_storage: the FieldStorageConfigInterface object,
|
||||
* or by referring to an existing field storage in the current configuration
|
||||
* with:
|
||||
* - field_name: The field name.
|
||||
* - entity_type: The entity type.
|
||||
* Additionally, a 'bundle' property is required to indicate the entity
|
||||
* bundle to which the field is attached to. Other array elements will be
|
||||
* used to set the corresponding properties on the class; see the class
|
||||
* property documentation for details.
|
||||
*
|
||||
* @see entity_create()
|
||||
*/
|
||||
public function __construct(array $values, $entity_type = 'field_config') {
|
||||
// Allow either an injected FieldStorageConfig object, or a field_name and
|
||||
// entity_type.
|
||||
if (isset($values['field_storage'])) {
|
||||
if (!$values['field_storage'] instanceof FieldStorageConfigInterface) {
|
||||
throw new FieldException('Attempt to create a configurable field for a non-configurable field storage.');
|
||||
}
|
||||
$field_storage = $values['field_storage'];
|
||||
$values['field_name'] = $field_storage->getName();
|
||||
$values['entity_type'] = $field_storage->getTargetEntityTypeId();
|
||||
// The internal property is fieldStorage, not field_storage.
|
||||
unset($values['field_storage']);
|
||||
$values['fieldStorage'] = $field_storage;
|
||||
}
|
||||
else {
|
||||
if (empty($values['field_name'])) {
|
||||
throw new FieldException('Attempt to create a field without a field_name.');
|
||||
}
|
||||
if (empty($values['entity_type'])) {
|
||||
throw new FieldException("Attempt to create a field '{$values['field_name']}' without an entity_type.");
|
||||
}
|
||||
}
|
||||
// 'bundle' is required in either case.
|
||||
if (empty($values['bundle'])) {
|
||||
throw new FieldException("Attempt to create a field '{$values['field_name']}' without a bundle.");
|
||||
}
|
||||
|
||||
parent::__construct($values, $entity_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postCreate(EntityStorageInterface $storage) {
|
||||
parent::postCreate($storage);
|
||||
|
||||
// Validate that we have a valid storage for this field. This throws an
|
||||
// exception if the storage is invalid.
|
||||
$this->getFieldStorageDefinition();
|
||||
|
||||
// 'Label' defaults to the field name (mostly useful for fields created in
|
||||
// tests).
|
||||
if (empty($this->label)) {
|
||||
$this->label = $this->getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\Core\Entity\Entity::preSave().
|
||||
*
|
||||
* @throws \Drupal\Core\Field\FieldException
|
||||
* If the field definition is invalid.
|
||||
* @throws \Drupal\Core\Entity\EntityStorageException
|
||||
* In case of failures at the configuration storage level.
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
$entity_manager = \Drupal::entityManager();
|
||||
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
||||
|
||||
$storage_definition = $this->getFieldStorageDefinition();
|
||||
|
||||
// Filter out unknown settings and make sure all settings are present, so
|
||||
// that a complete field definition is passed to the various hooks and
|
||||
// written to config.
|
||||
$default_settings = $field_type_manager->getDefaultFieldSettings($storage_definition->getType());
|
||||
$this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings;
|
||||
|
||||
if ($this->isNew()) {
|
||||
// Notify the entity storage.
|
||||
$entity_manager->onFieldDefinitionCreate($this);
|
||||
}
|
||||
else {
|
||||
// Some updates are always disallowed.
|
||||
if ($this->entity_type != $this->original->entity_type) {
|
||||
throw new FieldException("Cannot change an existing field's entity_type.");
|
||||
}
|
||||
if ($this->bundle != $this->original->bundle) {
|
||||
throw new FieldException("Cannot change an existing field's bundle.");
|
||||
}
|
||||
if ($storage_definition->uuid() != $this->original->getFieldStorageDefinition()->uuid()) {
|
||||
throw new FieldException("Cannot change an existing field's storage.");
|
||||
}
|
||||
// Notify the entity storage.
|
||||
$entity_manager->onFieldDefinitionUpdate($this, $this->original);
|
||||
}
|
||||
|
||||
parent::preSave($storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
parent::calculateDependencies();
|
||||
// Mark the field_storage_config as a dependency.
|
||||
$this->addDependency('config', $this->getFieldStorageDefinition()->getConfigDependencyName());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preDelete(EntityStorageInterface $storage, array $fields) {
|
||||
/** @var \Drupal\Core\Field\DeletedFieldsRepositoryInterface $deleted_fields_repository */
|
||||
$deleted_fields_repository = \Drupal::service('entity_field.deleted_fields_repository');
|
||||
$entity_type_manager = \Drupal::entityTypeManager();
|
||||
|
||||
parent::preDelete($storage, $fields);
|
||||
|
||||
// Keep the field definitions in the deleted fields repository so we can use
|
||||
// them later during field_purge_batch().
|
||||
/** @var \Drupal\field\FieldConfigInterface $field */
|
||||
foreach ($fields as $field) {
|
||||
// Only mark a field for purging if there is data. Otherwise, just remove
|
||||
// it.
|
||||
$target_entity_storage = $entity_type_manager->getStorage($field->getTargetEntityTypeId());
|
||||
if (!$field->deleted && $target_entity_storage instanceof FieldableEntityStorageInterface && $target_entity_storage->countFieldData($field->getFieldStorageDefinition(), TRUE)) {
|
||||
$field = clone $field;
|
||||
$field->deleted = TRUE;
|
||||
$field->fieldStorage = NULL;
|
||||
$deleted_fields_repository->addFieldDefinition($field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function postDelete(EntityStorageInterface $storage, array $fields) {
|
||||
// Clear the cache upfront, to refresh the results of getBundles().
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
|
||||
// Notify the entity storage.
|
||||
foreach ($fields as $field) {
|
||||
if (!$field->deleted) {
|
||||
\Drupal::entityManager()->onFieldDefinitionDelete($field);
|
||||
}
|
||||
}
|
||||
|
||||
// If this is part of a configuration synchronization then the following
|
||||
// configuration updates are not necessary.
|
||||
$entity = reset($fields);
|
||||
if ($entity->isSyncing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the associated field storages if they are not used anymore and are
|
||||
// not persistent.
|
||||
$storages_to_delete = [];
|
||||
foreach ($fields as $field) {
|
||||
$storage_definition = $field->getFieldStorageDefinition();
|
||||
if (!$field->deleted && !$field->isUninstalling() && $storage_definition->isDeletable()) {
|
||||
// Key by field UUID to avoid deleting the same storage twice.
|
||||
$storages_to_delete[$storage_definition->uuid()] = $storage_definition;
|
||||
}
|
||||
}
|
||||
if ($storages_to_delete) {
|
||||
\Drupal::entityManager()->getStorage('field_storage_config')->delete($storages_to_delete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function linkTemplates() {
|
||||
$link_templates = parent::linkTemplates();
|
||||
if (\Drupal::moduleHandler()->moduleExists('field_ui')) {
|
||||
$link_templates["{$this->entity_type}-field-edit-form"] = 'entity.field_config.' . $this->entity_type . '_field_edit_form';
|
||||
$link_templates["{$this->entity_type}-storage-edit-form"] = 'entity.field_config.' . $this->entity_type . '_storage_edit_form';
|
||||
$link_templates["{$this->entity_type}-field-delete-form"] = 'entity.field_config.' . $this->entity_type . '_field_delete_form';
|
||||
|
||||
if (isset($link_templates['config-translation-overview'])) {
|
||||
$link_templates["config-translation-overview.{$this->entity_type}"] = "entity.field_config.config_translation_overview.{$this->entity_type}";
|
||||
}
|
||||
}
|
||||
return $link_templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function urlRouteParameters($rel) {
|
||||
$parameters = parent::urlRouteParameters($rel);
|
||||
$entity_type = \Drupal::entityManager()->getDefinition($this->entity_type);
|
||||
$bundle_parameter_key = $entity_type->getBundleEntityType() ?: 'bundle';
|
||||
$parameters[$bundle_parameter_key] = $this->bundle;
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isDeleted() {
|
||||
return $this->deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFieldStorageDefinition() {
|
||||
if (!$this->fieldStorage) {
|
||||
$field_storage_definition = NULL;
|
||||
|
||||
$field_storage_definitions = $this->entityManager()->getFieldStorageDefinitions($this->entity_type);
|
||||
if (isset($field_storage_definitions[$this->field_name])) {
|
||||
$field_storage_definition = $field_storage_definitions[$this->field_name];
|
||||
}
|
||||
// If this field has been deleted, try to find its field storage
|
||||
// definition in the deleted fields repository.
|
||||
elseif ($this->deleted) {
|
||||
$deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions();
|
||||
foreach ($deleted_storage_definitions as $deleted_storage_definition) {
|
||||
if ($deleted_storage_definition->getName() === $this->field_name) {
|
||||
$field_storage_definition = $deleted_storage_definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$field_storage_definition) {
|
||||
throw new FieldException("Attempt to create a field {$this->field_name} that does not exist on entity type {$this->entity_type}.");
|
||||
}
|
||||
if (!$field_storage_definition instanceof FieldStorageConfigInterface) {
|
||||
throw new FieldException("Attempt to create a configurable field of non-configurable field storage {$this->field_name}.");
|
||||
}
|
||||
$this->fieldStorage = $field_storage_definition;
|
||||
}
|
||||
|
||||
return $this->fieldStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isDisplayConfigurable($context) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDisplayOptions($display_context) {
|
||||
// Hide configurable fields by default.
|
||||
return ['region' => 'hidden'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isReadOnly() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isComputed() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUniqueIdentifier() {
|
||||
return $this->uuid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a field config entity based on the entity type and field name.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* ID of the entity type.
|
||||
* @param string $bundle
|
||||
* Bundle name.
|
||||
* @param string $field_name
|
||||
* Name of the field.
|
||||
*
|
||||
* @return static
|
||||
* The field config entity if one exists for the provided field
|
||||
* name, otherwise NULL.
|
||||
*/
|
||||
public static function loadByName($entity_type_id, $bundle, $field_name) {
|
||||
return \Drupal::entityManager()->getStorage('field_config')->load($entity_type_id . '.' . $bundle . '.' . $field_name);
|
||||
}
|
||||
|
||||
}
|
||||
846
2017/web/core/modules/field/src/Entity/FieldStorageConfig.php
Normal file
846
2017/web/core/modules/field/src/Entity/FieldStorageConfig.php
Normal file
|
|
@ -0,0 +1,846 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityStorageInterface;
|
||||
use Drupal\Core\Field\FieldException;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\TypedData\OptionsProviderInterface;
|
||||
use Drupal\field\FieldStorageConfigInterface;
|
||||
|
||||
/**
|
||||
* Defines the Field storage configuration entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "field_storage_config",
|
||||
* label = @Translation("Field storage"),
|
||||
* label_collection = @Translation("Field storages"),
|
||||
* label_singular = @Translation("field storage"),
|
||||
* label_plural = @Translation("field storages"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count field storage",
|
||||
* plural = "@count field storages",
|
||||
* ),
|
||||
* handlers = {
|
||||
* "access" = "Drupal\field\FieldStorageConfigAccessControlHandler",
|
||||
* "storage" = "Drupal\field\FieldStorageConfigStorage"
|
||||
* },
|
||||
* config_prefix = "storage",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "id"
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "field_name",
|
||||
* "entity_type",
|
||||
* "type",
|
||||
* "settings",
|
||||
* "module",
|
||||
* "locked",
|
||||
* "cardinality",
|
||||
* "translatable",
|
||||
* "indexes",
|
||||
* "persist_with_no_fields",
|
||||
* "custom_storage",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigInterface {
|
||||
|
||||
/**
|
||||
* The maximum length of the field name, in characters.
|
||||
*
|
||||
* For fields created through Field UI, this includes the 'field_' prefix.
|
||||
*/
|
||||
const NAME_MAX_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* The field ID.
|
||||
*
|
||||
* The ID consists of 2 parts: the entity type and the field name.
|
||||
*
|
||||
* Example: node.body, user.field_main_image.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The field name.
|
||||
*
|
||||
* This is the name of the property under which the field values are placed in
|
||||
* an entity: $entity->{$field_name}. The maximum length is
|
||||
* Field:NAME_MAX_LENGTH.
|
||||
*
|
||||
* Example: body, field_main_image.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $field_name;
|
||||
|
||||
/**
|
||||
* The name of the entity type the field can be attached to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entity_type;
|
||||
|
||||
/**
|
||||
* The field type.
|
||||
*
|
||||
* Example: text, integer.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* The name of the module that provides the field type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $module;
|
||||
|
||||
/**
|
||||
* Field-type specific settings.
|
||||
*
|
||||
* An array of key/value pairs, The keys and default values are defined by the
|
||||
* field type.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $settings = [];
|
||||
|
||||
/**
|
||||
* The field cardinality.
|
||||
*
|
||||
* The maximum number of values the field can hold. Possible values are
|
||||
* positive integers or
|
||||
* FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED. Defaults to 1.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $cardinality = 1;
|
||||
|
||||
/**
|
||||
* Flag indicating whether the field is translatable.
|
||||
*
|
||||
* Defaults to TRUE.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $translatable = TRUE;
|
||||
|
||||
/**
|
||||
* Flag indicating whether the field is available for editing.
|
||||
*
|
||||
* If TRUE, some actions not available though the UI (but are still possible
|
||||
* through direct API manipulation):
|
||||
* - field settings cannot be changed,
|
||||
* - new fields cannot be created
|
||||
* - existing fields cannot be deleted.
|
||||
* Defaults to FALSE.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $locked = FALSE;
|
||||
|
||||
/**
|
||||
* Flag indicating whether the field storage should be deleted when orphaned.
|
||||
*
|
||||
* By default field storages for configurable fields are removed when there
|
||||
* are no remaining fields using them. If multiple modules provide bundles
|
||||
* which need to use the same field storage then setting this to TRUE will
|
||||
* preserve the field storage regardless of what happens to the bundles. The
|
||||
* classic use case for this is node body field storage since Book, Forum, the
|
||||
* Standard profile and bundle (node type) creation through the UI all use
|
||||
* same field storage.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $persist_with_no_fields = FALSE;
|
||||
|
||||
/**
|
||||
* A boolean indicating whether or not the field item uses custom storage.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $custom_storage = FALSE;
|
||||
|
||||
/**
|
||||
* The custom storage indexes for the field data storage.
|
||||
*
|
||||
* This set of indexes is merged with the "default" indexes specified by the
|
||||
* field type in hook_field_schema() to determine the actual set of indexes
|
||||
* that get created.
|
||||
*
|
||||
* The indexes are defined using the same definition format as Schema API
|
||||
* index specifications. Only columns that are part of the field schema, as
|
||||
* defined by the field type in hook_field_schema(), are allowed.
|
||||
*
|
||||
* Some storage backends might not support indexes, and discard that
|
||||
* information.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $indexes = [];
|
||||
|
||||
/**
|
||||
* Flag indicating whether the field is deleted.
|
||||
*
|
||||
* The delete() method marks the field as "deleted" and removes the
|
||||
* corresponding entry from the config storage, but keeps its definition in
|
||||
* the state storage while field data is purged by a separate
|
||||
* garbage-collection process.
|
||||
*
|
||||
* Deleted fields stay out of the regular entity lifecycle (notably, their
|
||||
* values are not populated in loaded entities, and are not saved back).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $deleted = FALSE;
|
||||
|
||||
/**
|
||||
* The field schema.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $schema;
|
||||
|
||||
/**
|
||||
* An array of field property definitions.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\DataDefinitionInterface[]
|
||||
*
|
||||
* @see \Drupal\Core\TypedData\ComplexDataDefinitionInterface::getPropertyDefinitions()
|
||||
*/
|
||||
protected $propertyDefinitions;
|
||||
|
||||
/**
|
||||
* Static flag set to prevent recursion during field deletes.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $inDeletion = FALSE;
|
||||
|
||||
/**
|
||||
* Constructs a FieldStorageConfig object.
|
||||
*
|
||||
* In most cases, Field entities are created via
|
||||
* FieldStorageConfig::create($values)), where $values is the same parameter
|
||||
* as in this constructor.
|
||||
*
|
||||
* @param array $values
|
||||
* An array of field properties, keyed by property name. Most array
|
||||
* elements will be used to set the corresponding properties on the class;
|
||||
* see the class property documentation for details. Some array elements
|
||||
* have special meanings and a few are required. Special elements are:
|
||||
* - name: required. As a temporary Backwards Compatibility layer right now,
|
||||
* a 'field_name' property can be accepted in place of 'id'.
|
||||
* - entity_type: required.
|
||||
* - type: required.
|
||||
*
|
||||
* @see entity_create()
|
||||
*/
|
||||
public function __construct(array $values, $entity_type = 'field_storage_config') {
|
||||
// Check required properties.
|
||||
if (empty($values['field_name'])) {
|
||||
throw new FieldException('Attempt to create a field storage without a field name.');
|
||||
}
|
||||
if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $values['field_name'])) {
|
||||
throw new FieldException("Attempt to create a field storage {$values['field_name']} with invalid characters. Only lowercase alphanumeric characters and underscores are allowed, and only lowercase letters and underscore are allowed as the first character");
|
||||
}
|
||||
if (empty($values['type'])) {
|
||||
throw new FieldException("Attempt to create a field storage {$values['field_name']} with no type.");
|
||||
}
|
||||
if (empty($values['entity_type'])) {
|
||||
throw new FieldException("Attempt to create a field storage {$values['field_name']} with no entity_type.");
|
||||
}
|
||||
|
||||
parent::__construct($values, $entity_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function id() {
|
||||
return $this->getTargetEntityTypeId() . '.' . $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\Core\Entity\Entity::preSave().
|
||||
*
|
||||
* @throws \Drupal\Core\Field\FieldException
|
||||
* If the field definition is invalid.
|
||||
* @throws \Drupal\Core\Entity\EntityStorageException
|
||||
* In case of failures at the configuration storage level.
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
// Clear the derived data about the field.
|
||||
unset($this->schema);
|
||||
|
||||
// Filter out unknown settings and make sure all settings are present, so
|
||||
// that a complete field definition is passed to the various hooks and
|
||||
// written to config.
|
||||
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
||||
$default_settings = $field_type_manager->getDefaultStorageSettings($this->type);
|
||||
$this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings;
|
||||
|
||||
if ($this->isNew()) {
|
||||
$this->preSaveNew($storage);
|
||||
}
|
||||
else {
|
||||
$this->preSaveUpdated($storage);
|
||||
}
|
||||
|
||||
parent::preSave($storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares saving a new field definition.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage.
|
||||
*
|
||||
* @throws \Drupal\Core\Field\FieldException
|
||||
* If the field definition is invalid.
|
||||
*/
|
||||
protected function preSaveNew(EntityStorageInterface $storage) {
|
||||
$entity_manager = \Drupal::entityManager();
|
||||
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
||||
|
||||
// Assign the ID.
|
||||
$this->id = $this->id();
|
||||
|
||||
// Field name cannot be longer than FieldStorageConfig::NAME_MAX_LENGTH
|
||||
// characters. We use mb_strlen() because the DB layer assumes that column
|
||||
// widths are given in characters rather than bytes.
|
||||
if (mb_strlen($this->getName()) > static::NAME_MAX_LENGTH) {
|
||||
throw new FieldException('Attempt to create a field storage with an name longer than ' . static::NAME_MAX_LENGTH . ' characters: ' . $this->getName());
|
||||
}
|
||||
|
||||
// Disallow reserved field names.
|
||||
$disallowed_field_names = array_keys($entity_manager->getBaseFieldDefinitions($this->getTargetEntityTypeId()));
|
||||
if (in_array($this->getName(), $disallowed_field_names)) {
|
||||
throw new FieldException("Attempt to create field storage {$this->getName()} which is reserved by entity type {$this->getTargetEntityTypeId()}.");
|
||||
}
|
||||
|
||||
// Check that the field type is known.
|
||||
$field_type = $field_type_manager->getDefinition($this->getType(), FALSE);
|
||||
if (!$field_type) {
|
||||
throw new FieldException("Attempt to create a field storage of unknown type {$this->getType()}.");
|
||||
}
|
||||
$this->module = $field_type['provider'];
|
||||
|
||||
// Notify the entity manager.
|
||||
$entity_manager->onFieldStorageDefinitionCreate($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
parent::calculateDependencies();
|
||||
// Ensure the field is dependent on the providing module.
|
||||
$this->addDependency('module', $this->getTypeProvider());
|
||||
// Ask the field type for any additional storage dependencies.
|
||||
// @see \Drupal\Core\Field\FieldItemInterface::calculateStorageDependencies()
|
||||
$definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getType(), FALSE);
|
||||
$this->addDependencies($definition['class']::calculateStorageDependencies($this));
|
||||
|
||||
// Ensure the field is dependent on the provider of the entity type.
|
||||
$entity_type = \Drupal::entityManager()->getDefinition($this->entity_type);
|
||||
$this->addDependency('module', $entity_type->getProvider());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares saving an updated field definition.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage.
|
||||
*/
|
||||
protected function preSaveUpdated(EntityStorageInterface $storage) {
|
||||
$module_handler = \Drupal::moduleHandler();
|
||||
$entity_manager = \Drupal::entityManager();
|
||||
|
||||
// Some updates are always disallowed.
|
||||
if ($this->getType() != $this->original->getType()) {
|
||||
throw new FieldException("Cannot change the field type for an existing field storage.");
|
||||
}
|
||||
if ($this->getTargetEntityTypeId() != $this->original->getTargetEntityTypeId()) {
|
||||
throw new FieldException("Cannot change the entity type for an existing field storage.");
|
||||
}
|
||||
|
||||
// See if any module forbids the update by throwing an exception. This
|
||||
// invokes hook_field_storage_config_update_forbid().
|
||||
$module_handler->invokeAll('field_storage_config_update_forbid', [$this, $this->original]);
|
||||
|
||||
// Notify the entity manager. A listener can reject the definition
|
||||
// update as invalid by raising an exception, which stops execution before
|
||||
// the definition is written to config.
|
||||
$entity_manager->onFieldStorageDefinitionUpdate($this, $this->original);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
if ($update) {
|
||||
// Invalidate the render cache for all affected entities.
|
||||
$entity_manager = \Drupal::entityManager();
|
||||
$entity_type = $this->getTargetEntityTypeId();
|
||||
if ($entity_manager->hasHandler($entity_type, 'view_builder')) {
|
||||
$entity_manager->getViewBuilder($entity_type)->resetCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preDelete(EntityStorageInterface $storage, array $field_storages) {
|
||||
/** @var \Drupal\Core\Field\DeletedFieldsRepositoryInterface $deleted_fields_repository */
|
||||
$deleted_fields_repository = \Drupal::service('entity_field.deleted_fields_repository');
|
||||
|
||||
// Set the static flag so that we don't delete field storages whilst
|
||||
// deleting fields.
|
||||
static::$inDeletion = TRUE;
|
||||
|
||||
// Delete or fix any configuration that is dependent, for example, fields.
|
||||
parent::preDelete($storage, $field_storages);
|
||||
|
||||
// Keep the field storage definitions in the deleted fields repository so we
|
||||
// can use them later during field_purge_batch().
|
||||
/** @var \Drupal\field\FieldStorageConfigInterface $field_storage */
|
||||
foreach ($field_storages as $field_storage) {
|
||||
// Only mark a field for purging if there is data. Otherwise, just remove
|
||||
// it.
|
||||
$target_entity_storage = \Drupal::entityTypeManager()->getStorage($field_storage->getTargetEntityTypeId());
|
||||
if (!$field_storage->deleted && $target_entity_storage instanceof FieldableEntityStorageInterface && $target_entity_storage->countFieldData($field_storage, TRUE)) {
|
||||
$storage_definition = clone $field_storage;
|
||||
$storage_definition->deleted = TRUE;
|
||||
$deleted_fields_repository->addFieldStorageDefinition($storage_definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function postDelete(EntityStorageInterface $storage, array $fields) {
|
||||
// Notify the storage.
|
||||
foreach ($fields as $field) {
|
||||
if (!$field->deleted) {
|
||||
\Drupal::entityManager()->onFieldStorageDefinitionDelete($field);
|
||||
$field->deleted = TRUE;
|
||||
}
|
||||
}
|
||||
// Unset static flag.
|
||||
static::$inDeletion = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSchema() {
|
||||
if (!isset($this->schema)) {
|
||||
// Get the schema from the field item class.
|
||||
$class = $this->getFieldItemClass();
|
||||
$schema = $class::schema($this);
|
||||
// Fill in default values for optional entries.
|
||||
$schema += [
|
||||
'columns' => [],
|
||||
'unique keys' => [],
|
||||
'indexes' => [],
|
||||
'foreign keys' => [],
|
||||
];
|
||||
|
||||
// Merge custom indexes with those specified by the field type. Custom
|
||||
// indexes prevail.
|
||||
$schema['indexes'] = $this->indexes + $schema['indexes'];
|
||||
|
||||
$this->schema = $schema;
|
||||
}
|
||||
|
||||
return $this->schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasCustomStorage() {
|
||||
return $this->custom_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isBaseField() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getColumns() {
|
||||
$schema = $this->getSchema();
|
||||
// A typical use case for the method is to iterate on the columns, while
|
||||
// some other use cases rely on identifying the first column with the key()
|
||||
// function. Since the schema is persisted in the Field object, we take care
|
||||
// of resetting the array pointer so that the former does not interfere with
|
||||
// the latter.
|
||||
reset($schema['columns']);
|
||||
return $schema['columns'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBundles() {
|
||||
if (!$this->isDeleted()) {
|
||||
$map = \Drupal::entityManager()->getFieldMap();
|
||||
if (isset($map[$this->getTargetEntityTypeId()][$this->getName()]['bundles'])) {
|
||||
return $map[$this->getTargetEntityTypeId()][$this->getName()]['bundles'];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName() {
|
||||
return $this->field_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isDeleted() {
|
||||
return $this->deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTypeProvider() {
|
||||
return $this->module;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSettings() {
|
||||
// @todo FieldTypePluginManager maintains its own static cache. However, do
|
||||
// some CPU and memory profiling to see if it's worth statically caching
|
||||
// $field_type_info, or the default field storage and field settings,
|
||||
// within $this.
|
||||
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
||||
|
||||
$settings = $field_type_manager->getDefaultStorageSettings($this->getType());
|
||||
return $this->settings + $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSetting($setting_name) {
|
||||
// @todo See getSettings() about potentially statically caching this.
|
||||
// We assume here that one call to array_key_exists() is more efficient
|
||||
// than calling getSettings() when all we need is a single setting.
|
||||
if (array_key_exists($setting_name, $this->settings)) {
|
||||
return $this->settings[$setting_name];
|
||||
}
|
||||
$settings = $this->getSettings();
|
||||
if (array_key_exists($setting_name, $settings)) {
|
||||
return $settings[$setting_name];
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSetting($setting_name, $value) {
|
||||
$this->settings[$setting_name] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSettings(array $settings) {
|
||||
$this->settings = $settings + $this->settings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isTranslatable() {
|
||||
return $this->translatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isRevisionable() {
|
||||
// All configurable fields are revisionable.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setTranslatable($translatable) {
|
||||
$this->translatable = $translatable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProvider() {
|
||||
return 'field';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLabel() {
|
||||
return $this->label();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCardinality() {
|
||||
/** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
|
||||
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
|
||||
$definition = $field_type_manager->getDefinition($this->getType());
|
||||
$enforced_cardinality = isset($definition['cardinality']) ? $definition['cardinality'] : NULL;
|
||||
|
||||
// Enforced cardinality is a positive integer or -1.
|
||||
if ($enforced_cardinality !== NULL && $enforced_cardinality < 1 && $enforced_cardinality !== FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
|
||||
throw new FieldException("Invalid enforced cardinality '$enforced_cardinality'. Allowed values: a positive integer or -1.");
|
||||
}
|
||||
|
||||
return $enforced_cardinality ?: $this->cardinality;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setCardinality($cardinality) {
|
||||
$this->cardinality = $cardinality;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOptionsProvider($property_name, FieldableEntityInterface $entity) {
|
||||
// If the field item class implements the interface, create an orphaned
|
||||
// runtime item object, so that it can be used as the options provider
|
||||
// without modifying the entity being worked on.
|
||||
if (is_subclass_of($this->getFieldItemClass(), OptionsProviderInterface::class)) {
|
||||
$items = $entity->get($this->getName());
|
||||
return \Drupal::service('plugin.manager.field.field_type')->createFieldItem($items, 0);
|
||||
}
|
||||
// @todo: Allow setting custom options provider, see
|
||||
// https://www.drupal.org/node/2002138.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isMultiple() {
|
||||
$cardinality = $this->getCardinality();
|
||||
return ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) || ($cardinality > 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLocked() {
|
||||
return $this->locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setLocked($locked) {
|
||||
$this->locked = $locked;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTargetEntityTypeId() {
|
||||
return $this->entity_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isQueryable() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a field has any data.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field has data for any entity; FALSE otherwise.
|
||||
*/
|
||||
public function hasData() {
|
||||
return \Drupal::entityManager()->getStorage($this->entity_type)->countFieldData($this, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the magic __sleep() method.
|
||||
*
|
||||
* Using the Serialize interface and serialize() / unserialize() methods
|
||||
* breaks entity forms in PHP 5.4.
|
||||
* @todo Investigate in https://www.drupal.org/node/2074253.
|
||||
*/
|
||||
public function __sleep() {
|
||||
// Only serialize necessary properties, excluding those that can be
|
||||
// recalculated.
|
||||
$properties = get_object_vars($this);
|
||||
unset($properties['schema'], $properties['propertyDefinitions'], $properties['original']);
|
||||
return array_keys($properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConstraints() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConstraint($constraint_name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPropertyDefinition($name) {
|
||||
if (!isset($this->propertyDefinitions)) {
|
||||
$this->getPropertyDefinitions();
|
||||
}
|
||||
if (isset($this->propertyDefinitions[$name])) {
|
||||
return $this->propertyDefinitions[$name];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPropertyDefinitions() {
|
||||
if (!isset($this->propertyDefinitions)) {
|
||||
$class = $this->getFieldItemClass();
|
||||
$this->propertyDefinitions = $class::propertyDefinitions($this);
|
||||
}
|
||||
return $this->propertyDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPropertyNames() {
|
||||
return array_keys($this->getPropertyDefinitions());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMainPropertyName() {
|
||||
$class = $this->getFieldItemClass();
|
||||
return $class::mainPropertyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUniqueStorageIdentifier() {
|
||||
return $this->uuid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to retrieve the field item class.
|
||||
*/
|
||||
protected function getFieldItemClass() {
|
||||
$type_definition = \Drupal::typedDataManager()
|
||||
->getDefinition('field_item:' . $this->getType());
|
||||
return $type_definition['class'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a field config entity based on the entity type and field name.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* ID of the entity type.
|
||||
* @param string $field_name
|
||||
* Name of the field.
|
||||
*
|
||||
* @return static
|
||||
* The field config entity if one exists for the provided field name,
|
||||
* otherwise NULL.
|
||||
*/
|
||||
public static function loadByName($entity_type_id, $field_name) {
|
||||
return \Drupal::entityManager()->getStorage('field_storage_config')->load($entity_type_id . '.' . $field_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isDeletable() {
|
||||
// The field storage is not deleted, is configured to be removed when there
|
||||
// are no fields, the field storage has no bundles, and field storages are
|
||||
// not in the process of being deleted.
|
||||
return !$this->deleted && !$this->persist_with_no_fields && count($this->getBundles()) == 0 && !static::$inDeletion;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIndexes() {
|
||||
return $this->indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setIndexes(array $indexes) {
|
||||
$this->indexes = $indexes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the field config entity type.
|
||||
*
|
||||
* @see \Drupal\field\Entity\FieldConfig
|
||||
*/
|
||||
class FieldConfigAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
// Delegate access control to the underlying field storage config entity:
|
||||
// the field config entity merely handles configuration for a particular
|
||||
// bundle of an entity type, the bulk of the logic and configuration is with
|
||||
// the field storage config entity. Therefore, if an operation is allowed on
|
||||
// a certain field storage config entity, it should also be allowed for all
|
||||
// associated field config entities.
|
||||
// @see \Drupal\Core\Field\FieldDefinitionInterface
|
||||
/** \Drupal\field\FieldConfigInterface $entity */
|
||||
$field_storage_entity = $entity->getFieldStorageDefinition();
|
||||
return $field_storage_entity->access($operation, $account, TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
21
2017/web/core/modules/field/src/FieldConfigInterface.php
Normal file
21
2017/web/core/modules/field/src/FieldConfigInterface.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a field entity.
|
||||
*/
|
||||
interface FieldConfigInterface extends ConfigEntityInterface, FieldDefinitionInterface {
|
||||
|
||||
/**
|
||||
* Gets the deleted flag of the field.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if the field is deleted.
|
||||
*/
|
||||
public function isDeleted();
|
||||
|
||||
}
|
||||
181
2017/web/core/modules/field/src/FieldConfigStorage.php
Normal file
181
2017/web/core/modules/field/src/FieldConfigStorage.php
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
|
||||
use Drupal\Core\Config\Config;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\DeletedFieldsRepositoryInterface;
|
||||
use Drupal\Core\Field\FieldConfigStorageBase;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Component\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* Storage handler for field config.
|
||||
*/
|
||||
class FieldConfigStorage extends FieldConfigStorageBase {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The field type plugin manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypeManager;
|
||||
|
||||
/**
|
||||
* The deleted fields repository.
|
||||
*
|
||||
* @var \Drupal\Core\Field\DeletedFieldsRepositoryInterface
|
||||
*/
|
||||
protected $deletedFieldsRepository;
|
||||
|
||||
/**
|
||||
* Constructs a FieldConfigStorage object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type definition.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
|
||||
* The UUID service.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The field type plugin manager.
|
||||
* @param \Drupal\Core\Field\DeletedFieldsRepositoryInterface $deleted_fields_repository
|
||||
* The deleted fields repository.
|
||||
* @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache
|
||||
* The memory cache.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, DeletedFieldsRepositoryInterface $deleted_fields_repository, MemoryCacheInterface $memory_cache) {
|
||||
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $memory_cache);
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->fieldTypeManager = $field_type_manager;
|
||||
$this->deletedFieldsRepository = $deleted_fields_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('config.factory'),
|
||||
$container->get('uuid'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('entity_field.deleted_fields_repository'),
|
||||
$container->get('entity.memory_cache')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function importDelete($name, Config $new_config, Config $old_config) {
|
||||
// If the field storage has been deleted in the same import, the field will
|
||||
// be deleted by then, and there is nothing left to do. Just return TRUE so
|
||||
// that the file does not get written to active store.
|
||||
if (!$old_config->get()) {
|
||||
return TRUE;
|
||||
}
|
||||
return parent::importDelete($name, $new_config, $old_config);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadByProperties(array $conditions = []) {
|
||||
// Include deleted fields if specified in the $conditions parameters.
|
||||
$include_deleted = isset($conditions['include_deleted']) ? $conditions['include_deleted'] : FALSE;
|
||||
unset($conditions['include_deleted']);
|
||||
|
||||
$fields = [];
|
||||
|
||||
// Get fields stored in configuration. If we are explicitly looking for
|
||||
// deleted fields only, this can be skipped, because they will be
|
||||
// retrieved from the deleted fields repository below.
|
||||
if (empty($conditions['deleted'])) {
|
||||
if (isset($conditions['entity_type']) && isset($conditions['bundle']) && isset($conditions['field_name'])) {
|
||||
// Optimize for the most frequent case where we do have a specific ID.
|
||||
$id = $conditions['entity_type'] . '.' . $conditions['bundle'] . '.' . $conditions['field_name'];
|
||||
$fields = $this->loadMultiple([$id]);
|
||||
}
|
||||
else {
|
||||
// No specific ID, we need to examine all existing fields.
|
||||
$fields = $this->loadMultiple();
|
||||
}
|
||||
}
|
||||
|
||||
// Merge deleted fields from the deleted fields repository if needed.
|
||||
if ($include_deleted || !empty($conditions['deleted'])) {
|
||||
$deleted_field_definitions = $this->deletedFieldsRepository->getFieldDefinitions();
|
||||
foreach ($deleted_field_definitions as $id => $field_definition) {
|
||||
if ($field_definition instanceof FieldConfigInterface) {
|
||||
$fields[$id] = $field_definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect matching fields.
|
||||
$matching_fields = [];
|
||||
foreach ($fields as $field) {
|
||||
// Some conditions are checked against the field storage.
|
||||
$field_storage = $field->getFieldStorageDefinition();
|
||||
|
||||
// Only keep the field if it matches all conditions.
|
||||
foreach ($conditions as $key => $value) {
|
||||
// Extract the actual value against which the condition is checked.
|
||||
switch ($key) {
|
||||
case 'field_name':
|
||||
$checked_value = $field_storage->getName();
|
||||
break;
|
||||
|
||||
case 'field_id':
|
||||
case 'field_storage_uuid':
|
||||
$checked_value = $field_storage->uuid();
|
||||
break;
|
||||
|
||||
case 'uuid';
|
||||
$checked_value = $field->uuid();
|
||||
break;
|
||||
|
||||
case 'deleted';
|
||||
$checked_value = $field->isDeleted();
|
||||
break;
|
||||
|
||||
default:
|
||||
$checked_value = $field->get($key);
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip to the next field as soon as one condition does not match.
|
||||
if ($checked_value != $value) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// When returning deleted fields, key the results by UUID since they
|
||||
// can include several fields with the same ID.
|
||||
$key = $include_deleted ? $field->uuid() : $field->id();
|
||||
$matching_fields[$key] = $field;
|
||||
}
|
||||
|
||||
return $matching_fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the field storage config entity type.
|
||||
*
|
||||
* @see \Drupal\field\Entity\FieldStorageConfig
|
||||
*/
|
||||
class FieldStorageConfigAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
/** \Drupal\field\FieldStorageConfigInterface $entity */
|
||||
if ($operation === 'delete') {
|
||||
if ($entity->isLocked()) {
|
||||
return AccessResult::forbidden()->addCacheableDependency($entity);
|
||||
}
|
||||
else {
|
||||
return AccessResult::allowedIfHasPermission($account, 'administer ' . $entity->getTargetEntityTypeId() . ' fields')->addCacheableDependency($entity);
|
||||
}
|
||||
}
|
||||
return AccessResult::allowedIfHasPermission($account, 'administer ' . $entity->getTargetEntityTypeId() . ' fields');
|
||||
}
|
||||
|
||||
}
|
||||
145
2017/web/core/modules/field/src/FieldStorageConfigInterface.php
Normal file
145
2017/web/core/modules/field/src/FieldStorageConfigInterface.php
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a field storage entity.
|
||||
*/
|
||||
interface FieldStorageConfigInterface extends ConfigEntityInterface, FieldStorageDefinitionInterface {
|
||||
|
||||
/**
|
||||
* Returns the field type.
|
||||
*
|
||||
* @return string
|
||||
* The field type, i.e. the id of a field type plugin. For example 'text'.
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* Returns the name of the module providing the field type.
|
||||
*
|
||||
* @return string
|
||||
* The name of the module that provides the field type.
|
||||
*/
|
||||
public function getTypeProvider();
|
||||
|
||||
/**
|
||||
* Returns the list of bundles where the field storage has fields.
|
||||
*
|
||||
* @return array
|
||||
* An array of bundle names.
|
||||
*/
|
||||
public function getBundles();
|
||||
|
||||
/**
|
||||
* Checks if the field storage can be deleted.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field storage can be deleted.
|
||||
*/
|
||||
public function isDeletable();
|
||||
|
||||
/**
|
||||
* Returns whether the field storage is locked or not.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field storage is locked.
|
||||
*/
|
||||
public function isLocked();
|
||||
|
||||
/**
|
||||
* Sets the locked flag.
|
||||
*
|
||||
* @param bool $locked
|
||||
* Sets value of locked flag.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLocked($locked);
|
||||
|
||||
/**
|
||||
* Sets the maximum number of items allowed for the field.
|
||||
*
|
||||
* @param int $cardinality
|
||||
* The cardinality value.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCardinality($cardinality);
|
||||
|
||||
/**
|
||||
* Sets the value for a field setting by name.
|
||||
*
|
||||
* @param string $setting_name
|
||||
* The name of the setting.
|
||||
* @param mixed $value
|
||||
* The value of the setting.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSetting($setting_name, $value);
|
||||
|
||||
/**
|
||||
* Sets field storage settings.
|
||||
*
|
||||
* Note that the method does not unset existing settings not specified in the
|
||||
* incoming $settings array.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* // Given these are the default settings.
|
||||
* $storage_definition->getSettings() === [
|
||||
* 'fruit' => 'apple',
|
||||
* 'season' => 'summer',
|
||||
* ];
|
||||
* // Change only the 'fruit' setting.
|
||||
* $storage_definition->setSettings(['fruit' => 'banana']);
|
||||
* // The 'season' setting persists unchanged.
|
||||
* $storage_definition->getSettings() === [
|
||||
* 'fruit' => 'banana',
|
||||
* 'season' => 'summer',
|
||||
* ];
|
||||
* @endcode
|
||||
*
|
||||
* For clarity, it is preferred to use setSetting() if not all available
|
||||
* settings are supplied.
|
||||
*
|
||||
* @param array $settings
|
||||
* The array of storage settings.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSettings(array $settings);
|
||||
|
||||
/**
|
||||
* Sets whether the field is translatable.
|
||||
*
|
||||
* @param bool $translatable
|
||||
* Whether the field is translatable.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTranslatable($translatable);
|
||||
|
||||
/**
|
||||
* Returns the custom storage indexes for the field data storage.
|
||||
*
|
||||
* @return array
|
||||
* An array of custom indexes.
|
||||
*/
|
||||
public function getIndexes();
|
||||
|
||||
/**
|
||||
* Sets the custom storage indexes for the field data storage..
|
||||
*
|
||||
* @param array $indexes
|
||||
* The array of custom indexes.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setIndexes(array $indexes);
|
||||
|
||||
}
|
||||
181
2017/web/core/modules/field/src/FieldStorageConfigStorage.php
Normal file
181
2017/web/core/modules/field/src/FieldStorageConfigStorage.php
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Component\Uuid\UuidInterface;
|
||||
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityStorage;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\DeletedFieldsRepositoryInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
|
||||
/**
|
||||
* Storage handler for "field storage" configuration entities.
|
||||
*/
|
||||
class FieldStorageConfigStorage extends ConfigEntityStorage {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The field type plugin manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypeManager;
|
||||
|
||||
/**
|
||||
* The deleted fields repository.
|
||||
*
|
||||
* @var \Drupal\Core\Field\DeletedFieldsRepositoryInterface
|
||||
*/
|
||||
protected $deletedFieldsRepository;
|
||||
|
||||
/**
|
||||
* Constructs a FieldStorageConfigStorage object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type definition.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
|
||||
* The UUID service.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The field type plugin manager.
|
||||
* @param \Drupal\Core\Field\DeletedFieldsRepositoryInterface $deleted_fields_repository
|
||||
* The deleted fields repository.
|
||||
* @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache
|
||||
* The memory cache.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, FieldTypePluginManagerInterface $field_type_manager, DeletedFieldsRepositoryInterface $deleted_fields_repository, MemoryCacheInterface $memory_cache) {
|
||||
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $memory_cache);
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->fieldTypeManager = $field_type_manager;
|
||||
$this->deletedFieldsRepository = $deleted_fields_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('config.factory'),
|
||||
$container->get('uuid'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('entity_field.deleted_fields_repository'),
|
||||
$container->get('entity.memory_cache')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadByProperties(array $conditions = []) {
|
||||
// Include deleted fields if specified in the $conditions parameters.
|
||||
$include_deleted = isset($conditions['include_deleted']) ? $conditions['include_deleted'] : FALSE;
|
||||
unset($conditions['include_deleted']);
|
||||
|
||||
/** @var \Drupal\field\FieldStorageConfigInterface[] $storages */
|
||||
$storages = [];
|
||||
|
||||
// Get field storages living in configuration. If we are explicitly looking
|
||||
// for deleted storages only, this can be skipped, because they will be
|
||||
// retrieved from the deleted fields repository below.
|
||||
if (empty($conditions['deleted'])) {
|
||||
if (isset($conditions['entity_type']) && isset($conditions['field_name'])) {
|
||||
// Optimize for the most frequent case where we do have a specific ID.
|
||||
$id = $conditions['entity_type'] . $conditions['field_name'];
|
||||
$storages = $this->loadMultiple([$id]);
|
||||
}
|
||||
else {
|
||||
// No specific ID, we need to examine all existing storages.
|
||||
$storages = $this->loadMultiple();
|
||||
}
|
||||
}
|
||||
|
||||
// Merge deleted field storage definitions from the deleted fields
|
||||
// repository if needed.
|
||||
if ($include_deleted || !empty($conditions['deleted'])) {
|
||||
$deleted_storage_definitions = $this->deletedFieldsRepository->getFieldStorageDefinitions();
|
||||
foreach ($deleted_storage_definitions as $id => $field_storage_definition) {
|
||||
if ($field_storage_definition instanceof FieldStorageConfigInterface) {
|
||||
$storages[$id] = $field_storage_definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect matching fields.
|
||||
$matches = [];
|
||||
foreach ($storages as $field) {
|
||||
foreach ($conditions as $key => $value) {
|
||||
// Extract the actual value against which the condition is checked.
|
||||
$checked_value = $field->get($key);
|
||||
// Skip to the next field as soon as one condition does not match.
|
||||
if ($checked_value != $value) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// When returning deleted fields, key the results by UUID since they can
|
||||
// include several fields with the same ID.
|
||||
$key = $include_deleted ? $field->uuid() : $field->id();
|
||||
$matches[$key] = $field;
|
||||
}
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapFromStorageRecords(array $records) {
|
||||
foreach ($records as $id => &$record) {
|
||||
$class = $this->fieldTypeManager->getPluginClass($record['type']);
|
||||
if (empty($class)) {
|
||||
$config_id = $this->getPrefix() . $id;
|
||||
throw new \RuntimeException("Unable to determine class for field type '{$record['type']}' found in the '$config_id' configuration");
|
||||
}
|
||||
$record['settings'] = $class::storageSettingsFromConfigData($record['settings']);
|
||||
}
|
||||
return parent::mapFromStorageRecords($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapToStorageRecord(EntityInterface $entity) {
|
||||
$record = parent::mapToStorageRecord($entity);
|
||||
$class = $this->fieldTypeManager->getPluginClass($record['type']);
|
||||
$record['settings'] = $class::storageSettingsToConfigData($record['settings']);
|
||||
return $record;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Field\FieldException;
|
||||
|
||||
/**
|
||||
* Exception class thrown by hook_field_storage_config_update_forbid().
|
||||
*/
|
||||
class FieldStorageConfigUpdateForbiddenException extends FieldException {}
|
||||
101
2017/web/core/modules/field/src/FieldUninstallValidator.php
Normal file
101
2017/web/core/modules/field/src/FieldUninstallValidator.php
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
|
||||
/**
|
||||
* Prevents uninstallation of modules providing active field storage.
|
||||
*/
|
||||
class FieldUninstallValidator implements ModuleUninstallValidatorInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The field storage config storage.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
|
||||
*/
|
||||
protected $fieldStorageConfigStorage;
|
||||
|
||||
/**
|
||||
* The field type plugin manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a new FieldUninstallValidator.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
* @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
|
||||
* The field type plugin manager.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, TranslationInterface $string_translation, FieldTypePluginManagerInterface $field_type_manager) {
|
||||
$this->fieldStorageConfigStorage = $entity_type_manager->getStorage('field_storage_config');
|
||||
$this->stringTranslation = $string_translation;
|
||||
$this->fieldTypeManager = $field_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($module) {
|
||||
$reasons = [];
|
||||
if ($field_storages = $this->getFieldStoragesByModule($module)) {
|
||||
// Provide an explanation message (only mention pending deletions if there
|
||||
// remain no actual, non-deleted fields.)
|
||||
$fields_in_use = [];
|
||||
foreach ($field_storages as $field_storage) {
|
||||
if (!$field_storage->isDeleted()) {
|
||||
$fields_in_use[$field_storage->getType()][] = $field_storage->getLabel();
|
||||
}
|
||||
}
|
||||
if (!empty($fields_in_use)) {
|
||||
foreach ($fields_in_use as $field_type => $field_storages) {
|
||||
$field_type_label = $this->getFieldTypeLabel($field_type);
|
||||
$reasons[] = $this->formatPlural(count($fields_in_use[$field_type]), 'The %field_type_label field type is used in the following field: @fields', 'The %field_type_label field type is used in the following fields: @fields', ['%field_type_label' => $field_type_label, '@fields' => implode(', ', $field_storages)]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$reasons[] = $this->t('Fields pending deletion');
|
||||
}
|
||||
}
|
||||
return $reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all field storages for a specified module.
|
||||
*
|
||||
* @param string $module
|
||||
* The module to filter field storages by.
|
||||
*
|
||||
* @return \Drupal\field\FieldStorageConfigInterface[]
|
||||
* An array of field storages for a specified module.
|
||||
*/
|
||||
protected function getFieldStoragesByModule($module) {
|
||||
return $this->fieldStorageConfigStorage->loadByProperties(['module' => $module, 'include_deleted' => TRUE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label for a specified field type.
|
||||
*
|
||||
* @param string $field_type
|
||||
* The field type.
|
||||
*
|
||||
* @return string
|
||||
* The field type label.
|
||||
*/
|
||||
protected function getFieldTypeLabel($field_type) {
|
||||
return $this->fieldTypeManager->getDefinitions()[$field_type]['label'];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\migrate\process\StaticMap;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
|
||||
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "field_type"
|
||||
* )
|
||||
*/
|
||||
class FieldType extends StaticMap implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The cckfield plugin manager.
|
||||
*
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
|
||||
*/
|
||||
protected $cckPluginManager;
|
||||
|
||||
/**
|
||||
* The field plugin manager.
|
||||
*
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface
|
||||
*/
|
||||
protected $fieldPluginManager;
|
||||
|
||||
/**
|
||||
* The migration object.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* Constructs a FieldType plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The plugin configuration.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin definition.
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_plugin_manager
|
||||
* The cckfield plugin manager.
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $field_plugin_manager
|
||||
* The field plugin manager.
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The migration being run.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrateCckFieldPluginManagerInterface $cck_plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, MigrationInterface $migration = NULL) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->cckPluginManager = $cck_plugin_manager;
|
||||
$this->fieldPluginManager = $field_plugin_manager;
|
||||
$this->migration = $migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('plugin.manager.migrate.cckfield'),
|
||||
$container->get('plugin.manager.migrate.field'),
|
||||
$migration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$field_type = is_array($value) ? $value[0] : $value;
|
||||
try {
|
||||
$plugin_id = $this->fieldPluginManager->getPluginIdFromFieldType($field_type, [], $this->migration);
|
||||
return $this->fieldPluginManager->createInstance($plugin_id, [], $this->migration)->getFieldType($row);
|
||||
}
|
||||
catch (PluginNotFoundException $e) {
|
||||
try {
|
||||
$plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, [], $this->migration);
|
||||
return $this->cckPluginManager->createInstance($plugin_id, [], $this->migration)->getFieldType($row);
|
||||
}
|
||||
catch (PluginNotFoundException $e) {
|
||||
return parent::transform($value, $migrate_executable, $row, $destination_property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process;
|
||||
|
||||
@trigger_error('The field_type_defaults process plugin is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use d6_field_type_defaults or d7_field_type_defaults instead. See https://www.drupal.org/node/2944589.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\field\Plugin\migrate\process\d6\FieldTypeDefaults as D6FieldTypeDefaults;
|
||||
|
||||
/**
|
||||
* BC Layer.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "field_type_defaults"
|
||||
* )
|
||||
*
|
||||
* @deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.x.
|
||||
* Use d6_field_type_defaults or d7_field_type_defaults instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2944589
|
||||
*/
|
||||
class FieldTypeDefaults extends D6FieldTypeDefaults {}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface;
|
||||
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Get the value from a method call on a field plugin instance.
|
||||
*
|
||||
* This process plugin will instantiate a field plugin based on the given
|
||||
* field type and then call the given method on it for the return value.
|
||||
*
|
||||
* Available configuration keys:
|
||||
* - source: The source field type to use to instantiate a field plugin.
|
||||
* - method: The method to be called on the field plugin instance.
|
||||
*
|
||||
* If no field plugin for the given field type is found, NULL will be returned.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* @code
|
||||
* process:
|
||||
* type:
|
||||
* plugin: process_field
|
||||
* source: type
|
||||
* method: getFieldType
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
* @see \Drupal\migrate_drupal\Plugin\MigrateFieldInterface;
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "process_field"
|
||||
* )
|
||||
*/
|
||||
class ProcessField extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The cckfield plugin manager.
|
||||
*
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
|
||||
*/
|
||||
protected $cckPluginManager;
|
||||
|
||||
/**
|
||||
* The field plugin manager.
|
||||
*
|
||||
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface
|
||||
*/
|
||||
protected $fieldPluginManager;
|
||||
|
||||
/**
|
||||
* The migration being run.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* Constructs a ProcessField plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The plugin configuration.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin definition.
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_plugin_manager
|
||||
* The cckfield plugin manager.
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $field_plugin_manager
|
||||
* The field plugin manager.
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The migration being run.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrateCckFieldPluginManagerInterface $cck_plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, MigrationInterface $migration = NULL) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->cckPluginManager = $cck_plugin_manager;
|
||||
$this->fieldPluginManager = $field_plugin_manager;
|
||||
$this->migration = $migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('plugin.manager.migrate.cckfield'),
|
||||
$container->get('plugin.manager.migrate.field'),
|
||||
$migration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (!is_string($value)) {
|
||||
throw new MigrateException('The input value must be a string.');
|
||||
}
|
||||
|
||||
if (empty($this->configuration['method'])) {
|
||||
throw new MigrateException('You need to specify the name of a method to be called on the Field plugin.');
|
||||
}
|
||||
$method = $this->configuration['method'];
|
||||
|
||||
try {
|
||||
return $this->callMethodOnFieldPlugin($this->fieldPluginManager, $value, $method, $row);
|
||||
}
|
||||
catch (PluginNotFoundException $e) {
|
||||
try {
|
||||
return $this->callMethodOnFieldPlugin($this->cckPluginManager, $value, $method, $row);
|
||||
}
|
||||
catch (PluginNotFoundException $e) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a field plugin and call a method on it.
|
||||
*
|
||||
* @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $field_plugin_manager
|
||||
* The field plugin manager.
|
||||
* @param string $field_type
|
||||
* The field type for which to get the field plugin.
|
||||
* @param string $method
|
||||
* The method to call on the field plugin.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row from the source to process.
|
||||
*
|
||||
* @return mixed
|
||||
* The return value from the method called on the field plugin.
|
||||
*/
|
||||
protected function callMethodOnFieldPlugin(MigrateFieldPluginManagerInterface $field_plugin_manager, $field_type, $method, Row $row) {
|
||||
$plugin_id = $field_plugin_manager->getPluginIdFromFieldType($field_type, [], $this->migration);
|
||||
$plugin_instance = $field_plugin_manager->createInstance($plugin_id, [], $this->migration);
|
||||
if (!is_callable([$plugin_instance, $method])) {
|
||||
throw new MigrateException('The specified method does not exist or is not callable.');
|
||||
}
|
||||
return call_user_func_array([$plugin_instance, $method], [$row]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Set the default field settings.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "field_formatter_settings_defaults"
|
||||
* )
|
||||
*/
|
||||
class FieldFormatterSettingsDefaults extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Set field formatter settings when the map didn't map: for date
|
||||
* formatters, the fallback format, for everything else, empty array.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
// If the 1 index is set then the map missed.
|
||||
if (isset($value[1])) {
|
||||
$module = $row->getSourceProperty('module');
|
||||
if ($module === 'date') {
|
||||
$value = ['format_type' => 'fallback'];
|
||||
}
|
||||
elseif ($module === 'number') {
|
||||
// We have to do the lookup here in the process plugin because for
|
||||
// number we need to calculated the settings based on the type not just
|
||||
// the module which works well for other field types.
|
||||
return $this->numberSettings($row->getDestinationProperty('options/type'), $value[1]);
|
||||
}
|
||||
else {
|
||||
$value = [];
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* The field type.
|
||||
* @param $format
|
||||
* The format selected for the field on the display.
|
||||
*
|
||||
* @return array
|
||||
* The correct default settings.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateException
|
||||
*/
|
||||
protected function numberSettings($type, $format) {
|
||||
$map = [
|
||||
'number_decimal' => [
|
||||
'us_0' => [
|
||||
'scale' => 0,
|
||||
'decimal_separator' => '.',
|
||||
'thousand_separator' => ',',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'us_1' => [
|
||||
'scale' => 1,
|
||||
'decimal_separator' => '.',
|
||||
'thousand_separator' => ',',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'us_2' => [
|
||||
'scale' => 2,
|
||||
'decimal_separator' => '.',
|
||||
'thousand_separator' => ',',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'be_0' => [
|
||||
'scale' => 0,
|
||||
'decimal_separator' => ',',
|
||||
'thousand_separator' => '.',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'be_1' => [
|
||||
'scale' => 1,
|
||||
'decimal_separator' => ',',
|
||||
'thousand_separator' => '.',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'be_2' => [
|
||||
'scale' => 2,
|
||||
'decimal_separator' => ',',
|
||||
'thousand_separator' => '.',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'fr_0' => [
|
||||
'scale' => 0,
|
||||
'decimal_separator' => ',',
|
||||
'thousand_separator' => ' ',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'fr_1' => [
|
||||
'scale' => 1,
|
||||
'decimal_separator' => ',',
|
||||
'thousand_separator' => ' ',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'fr_2' => [
|
||||
'scale' => 2,
|
||||
'decimal_separator' => ',',
|
||||
'thousand_separator' => ' ',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
],
|
||||
'number_integer' => [
|
||||
'us_0' => [
|
||||
'thousand_separator' => ',',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'be_0' => [
|
||||
'thousand_separator' => '.',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
'fr_0' => [
|
||||
'thousand_separator' => ' ',
|
||||
'prefix_suffix' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return isset($map[$type][$format]) ? $map[$type][$format] : [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d6_field_instance_defaults"
|
||||
* )
|
||||
*/
|
||||
class FieldInstanceDefaults extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Set the field instance defaults.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($widget_type, $widget_settings) = $value;
|
||||
$default = [];
|
||||
|
||||
switch ($widget_type) {
|
||||
case 'text_textfield':
|
||||
case 'number':
|
||||
case 'phone_textfield':
|
||||
if (!empty($widget_settings['default_value'][0]['value'])) {
|
||||
$default['value'] = $widget_settings['default_value'][0]['value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'imagefield_widget':
|
||||
// @todo, load the image and populate the defaults.
|
||||
// $default['default_image'] = $widget_settings['default_image'];
|
||||
break;
|
||||
|
||||
case 'date_select':
|
||||
if (!empty($widget_settings['default_value'])) {
|
||||
$default['default_date_type'] = 'relative';
|
||||
$default['default_date'] = $widget_settings['default_value'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'email_textfield':
|
||||
if (!empty($widget_settings['default_value'][0]['email'])) {
|
||||
$default['value'] = $widget_settings['default_value'][0]['email'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'link':
|
||||
if (!empty($widget_settings['default_value'][0]['url'])) {
|
||||
$default['title'] = $widget_settings['default_value'][0]['title'];
|
||||
$default['url'] = $widget_settings['default_value'][0]['url'];
|
||||
$default['options'] = ['attributes' => []];
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!empty($default)) {
|
||||
$default = [$default];
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Determines the settings property and translation for boolean fields.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d6_field_instance_option_translation",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class FieldInstanceOptionTranslation extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($field_type, $global_settings) = $value;
|
||||
|
||||
$option_key = 0;
|
||||
$translation = '';
|
||||
if (isset($global_settings['allowed_values'])) {
|
||||
$list = explode("\n", $global_settings['allowed_values']);
|
||||
$list = array_map('trim', $list);
|
||||
$list = array_filter($list, 'strlen');
|
||||
switch ($field_type) {
|
||||
case 'boolean';
|
||||
$option = preg_replace('/^option_/', '', $row->getSourceProperty('property'));
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$value = $list[$i];
|
||||
$tmp = explode("|", $value);
|
||||
$original_option_key = isset($tmp[0]) ? $tmp[0] : NULL;
|
||||
$option_key = ($i === 0) ? 'off_label' : 'on_label';
|
||||
// Find property with name matching the original option.
|
||||
if ($option == $original_option_key) {
|
||||
$translation = $row->getSourceProperty('translation');
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
return ['settings.' . $option_key, $translation];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d6_field_field_settings"
|
||||
* )
|
||||
*/
|
||||
class FieldInstanceSettings extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Set the field instance defaults.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($widget_type, $widget_settings, $field_settings) = $value;
|
||||
$settings = [];
|
||||
switch ($widget_type) {
|
||||
case 'number':
|
||||
$settings['min'] = $field_settings['min'];
|
||||
$settings['max'] = $field_settings['max'];
|
||||
$settings['prefix'] = $field_settings['prefix'];
|
||||
$settings['suffix'] = $field_settings['suffix'];
|
||||
break;
|
||||
|
||||
case 'link':
|
||||
// $settings['url'] = $widget_settings['default_value'][0]['url'];
|
||||
// D6 has optional, required, value and none. D8 only has disabled (0)
|
||||
// optional (1) and required (2).
|
||||
$map = ['disabled' => 0, 'optional' => 1, 'required' => 2];
|
||||
$settings['title'] = $map[$field_settings['title']];
|
||||
break;
|
||||
|
||||
case 'filefield_widget':
|
||||
$settings['file_extensions'] = $widget_settings['file_extensions'];
|
||||
$settings['file_directory'] = $widget_settings['file_path'];
|
||||
$settings['description_field'] = $field_settings['description_field'];
|
||||
$settings['max_filesize'] = $this->convertSizeUnit($widget_settings['max_filesize_per_file']);
|
||||
break;
|
||||
|
||||
case 'imagefield_widget':
|
||||
$settings['file_extensions'] = $widget_settings['file_extensions'];
|
||||
$settings['file_directory'] = $widget_settings['file_path'];
|
||||
$settings['max_filesize'] = $this->convertSizeUnit($widget_settings['max_filesize_per_file']);
|
||||
$settings['alt_field'] = $widget_settings['alt'];
|
||||
$settings['alt_field_required'] = $widget_settings['custom_alt'];
|
||||
$settings['title_field'] = $widget_settings['title'];
|
||||
$settings['title_field_required'] = $widget_settings['custom_title'];
|
||||
// With nothing entered for min or max resolution in Drupal 6, zero is
|
||||
// stored. For Drupal 8 this should be an empty string.
|
||||
$settings['max_resolution'] = !empty($widget_settings['max_resolution']) ? $widget_settings['max_resolution'] : '';
|
||||
$settings['min_resolution'] = !empty($widget_settings['min_resolution']) ? $widget_settings['min_resolution'] : '';
|
||||
break;
|
||||
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert file size strings into their D8 format.
|
||||
*
|
||||
* D6 stores file size using a "K" for kilobytes and "M" for megabytes where
|
||||
* as D8 uses "KB" and "MB" respectively.
|
||||
*
|
||||
* @param string $size_string
|
||||
* The size string, eg 10M
|
||||
*
|
||||
* @return string
|
||||
* The D8 version of the size string.
|
||||
*/
|
||||
protected function convertSizeUnit($size_string) {
|
||||
$size_unit = substr($size_string, strlen($size_string) - 1);
|
||||
if ($size_unit == "M" || $size_unit == "K") {
|
||||
return $size_string . "B";
|
||||
}
|
||||
return $size_string;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Get the field instance widget settings.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "field_instance_widget_settings"
|
||||
* )
|
||||
*/
|
||||
class FieldInstanceWidgetSettings extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Get the field instance default/mapped widget settings.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($widget_type, $widget_settings) = $value;
|
||||
return $this->getSettings($widget_type, $widget_settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the default D8 and specified D6 settings for a widget type.
|
||||
*
|
||||
* @param string $widget_type
|
||||
* The widget type.
|
||||
* @param array $widget_settings
|
||||
* The widget settings from D6 for this widget.
|
||||
*
|
||||
* @return array
|
||||
* A valid array of settings.
|
||||
*/
|
||||
public function getSettings($widget_type, $widget_settings) {
|
||||
$progress = isset($widget_settings['progress_indicator']) ? $widget_settings['progress_indicator'] : 'throbber';
|
||||
$size = isset($widget_settings['size']) ? $widget_settings['size'] : 60;
|
||||
$rows = isset($widget_settings['rows']) ? $widget_settings['rows'] : 5;
|
||||
|
||||
$settings = [
|
||||
'text_textfield' => [
|
||||
'size' => $size,
|
||||
'placeholder' => '',
|
||||
],
|
||||
'text_textarea' => [
|
||||
'rows' => $rows,
|
||||
'placeholder' => '',
|
||||
],
|
||||
'number' => [
|
||||
'placeholder' => '',
|
||||
],
|
||||
'email_textfield' => [
|
||||
'placeholder' => '',
|
||||
],
|
||||
'link' => [
|
||||
'placeholder_url' => '',
|
||||
'placeholder_title' => '',
|
||||
],
|
||||
'filefield_widget' => [
|
||||
'progress_indicator' => $progress,
|
||||
],
|
||||
'imagefield_widget' => [
|
||||
'progress_indicator' => $progress,
|
||||
'preview_image_style' => 'thumbnail',
|
||||
],
|
||||
'optionwidgets_onoff' => [
|
||||
'display_label' => FALSE,
|
||||
],
|
||||
'phone_textfield' => [
|
||||
'placeholder' => '',
|
||||
],
|
||||
];
|
||||
|
||||
return isset($settings[$widget_type]) ? $settings[$widget_type] : [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Determines the allowed values translation for select lists.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d6_field_option_translation",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class FieldOptionTranslation extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Get the field default/mapped settings.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($field_type, $global_settings) = $value;
|
||||
|
||||
$allowed_values = '';
|
||||
$i = 0;
|
||||
if (isset($global_settings['allowed_values'])) {
|
||||
$list = explode("\n", $global_settings['allowed_values']);
|
||||
$list = array_map('trim', $list);
|
||||
$list = array_filter($list, 'strlen');
|
||||
switch ($field_type) {
|
||||
case 'list_string':
|
||||
case 'list_integer':
|
||||
case 'list_float':
|
||||
// Remove the prefix used in the i18n_strings table for field options
|
||||
// to get the option value.
|
||||
$option = preg_replace('/^option_/', '', $row->getSourceProperty('property'));
|
||||
$i = 0;
|
||||
foreach ($list as $allowed_value) {
|
||||
// Get the key for this allowed value which may be a key|label pair
|
||||
// or or just key.
|
||||
$value = explode("|", $allowed_value);
|
||||
if (isset($value[0]) && ($value[0] == $option)) {
|
||||
$allowed_values = ['label' => $row->getSourceProperty('translation')];
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
return ["settings.allowed_values.$i", $allowed_values];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Get the field settings.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "field_settings"
|
||||
* )
|
||||
*/
|
||||
class FieldSettings extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Get the field default/mapped settings.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
// To maintain backwards compatibility, ensure that $value contains at least
|
||||
// three elements.
|
||||
if (count($value) == 2) {
|
||||
$value[] = NULL;
|
||||
}
|
||||
list($field_type, $global_settings, $original_field_type) = $value;
|
||||
return $this->getSettings($field_type, $global_settings, $original_field_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the default D8 and specified D6 settings.
|
||||
*
|
||||
* @param string $field_type
|
||||
* The destination field type.
|
||||
* @param array $global_settings
|
||||
* The field settings.
|
||||
* @param string $original_field_type
|
||||
* (optional) The original field type before migration.
|
||||
*
|
||||
* @return array
|
||||
* A valid array of settings.
|
||||
*/
|
||||
public function getSettings($field_type, $global_settings, $original_field_type = NULL) {
|
||||
$max_length = isset($global_settings['max_length']) ? $global_settings['max_length'] : '';
|
||||
$max_length = empty($max_length) ? 255 : $max_length;
|
||||
$allowed_values = [];
|
||||
if (isset($global_settings['allowed_values'])) {
|
||||
$list = explode("\n", $global_settings['allowed_values']);
|
||||
$list = array_map('trim', $list);
|
||||
$list = array_filter($list, 'strlen');
|
||||
switch ($field_type) {
|
||||
case 'list_string':
|
||||
case 'list_integer':
|
||||
case 'list_float':
|
||||
foreach ($list as $value) {
|
||||
$value = explode("|", $value);
|
||||
$allowed_values[$value[0]] = isset($value[1]) ? $value[1] : $value[0];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$allowed_values = $list;
|
||||
}
|
||||
}
|
||||
|
||||
$settings = [
|
||||
'text' => [
|
||||
'max_length' => $max_length,
|
||||
],
|
||||
'datetime' => ['datetime_type' => 'datetime'],
|
||||
'list_string' => [
|
||||
'allowed_values' => $allowed_values,
|
||||
],
|
||||
'list_integer' => [
|
||||
'allowed_values' => $allowed_values,
|
||||
],
|
||||
'list_float' => [
|
||||
'allowed_values' => $allowed_values,
|
||||
],
|
||||
'boolean' => [
|
||||
'allowed_values' => $allowed_values,
|
||||
],
|
||||
];
|
||||
|
||||
if ($original_field_type == 'userreference') {
|
||||
return ['target_type' => 'user'];
|
||||
}
|
||||
else {
|
||||
return isset($settings[$field_type]) ? $settings[$field_type] : [];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d6;
|
||||
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Gives us a chance to set per field defaults.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d6_field_type_defaults"
|
||||
* )
|
||||
*/
|
||||
class FieldTypeDefaults extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (is_array($value)) {
|
||||
if ($row->getSourceProperty('module') == 'date') {
|
||||
$value = 'datetime_default';
|
||||
}
|
||||
else {
|
||||
throw new MigrateException(sprintf('Failed to lookup field type %s in the static map.', var_export($value, TRUE)));
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d7;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d7_field_instance_defaults"
|
||||
* )
|
||||
*/
|
||||
class FieldInstanceDefaults extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($default_value, $widget_settings) = $value;
|
||||
$widget_type = $widget_settings['type'];
|
||||
$default_value = $default_value ?: [];
|
||||
|
||||
// In Drupal 7, the default value for email fields is stored in the key
|
||||
// 'email' while in Drupal 8 it is stored in the key 'value'.
|
||||
if ($widget_type == 'email_textfield' && $default_value) {
|
||||
$default_value[0]['value'] = $default_value[0]['email'];
|
||||
unset($default_value[0]['email']);
|
||||
}
|
||||
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d7;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d7_field_instance_settings"
|
||||
* )
|
||||
*/
|
||||
class FieldInstanceSettings extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($instance_settings, $widget_settings, $field_definition) = $value;
|
||||
$widget_type = $widget_settings['type'];
|
||||
|
||||
$field_data = unserialize($field_definition['data']);
|
||||
$field_settings = $field_data['settings'];
|
||||
|
||||
// Get entityreference handler settings from source field configuration.
|
||||
if ($row->getSourceProperty('type') == "entityreference") {
|
||||
$instance_settings['handler'] = 'default:' . $field_settings['target_type'];
|
||||
// Transform the sort settings to D8 structure.
|
||||
$sort = [
|
||||
'field' => '_none',
|
||||
'direction' => 'ASC',
|
||||
];
|
||||
if (!empty(array_filter($field_settings['handler_settings']['sort']))) {
|
||||
if ($field_settings['handler_settings']['sort']['type'] == "property") {
|
||||
$sort = [
|
||||
'field' => $field_settings['handler_settings']['sort']['property'],
|
||||
'direction' => $field_settings['handler_settings']['sort']['direction'],
|
||||
];
|
||||
}
|
||||
elseif ($field_settings['handler_settings']['sort']['type'] == "field") {
|
||||
$sort = [
|
||||
'field' => $field_settings['handler_settings']['sort']['field'],
|
||||
'direction' => $field_settings['handler_settings']['sort']['direction'],
|
||||
];
|
||||
}
|
||||
}
|
||||
if (empty($field_settings['handler_settings']['target_bundles'])) {
|
||||
$field_settings['handler_settings']['target_bundles'] = NULL;
|
||||
}
|
||||
$field_settings['handler_settings']['sort'] = $sort;
|
||||
$instance_settings['handler_settings'] = $field_settings['handler_settings'];
|
||||
}
|
||||
|
||||
switch ($widget_type) {
|
||||
case 'image_image':
|
||||
$settings = $instance_settings;
|
||||
$settings['default_image'] = [
|
||||
'alt' => '',
|
||||
'title' => '',
|
||||
'width' => NULL,
|
||||
'height' => NULL,
|
||||
'uuid' => '',
|
||||
];
|
||||
break;
|
||||
|
||||
default:
|
||||
$settings = $instance_settings;
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d7;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d7_field_settings"
|
||||
* )
|
||||
*/
|
||||
class FieldSettings extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$value = $row->getSourceProperty('settings');
|
||||
|
||||
switch ($row->getSourceProperty('type')) {
|
||||
case 'image':
|
||||
if (!is_array($value['default_image'])) {
|
||||
$value['default_image'] = ['uuid' => ''];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
case 'datestamp':
|
||||
if ($value['granularity']['hour'] === 0
|
||||
&& $value['granularity']['minute'] === 0
|
||||
&& $value['granularity']['second'] === 0) {
|
||||
$value['datetime_type'] = 'date';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'taxonomy_term_reference':
|
||||
$value['target_type'] = 'taxonomy_term';
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\process\d7;
|
||||
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Gives us a chance to set per field defaults.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "d7_field_type_defaults"
|
||||
* )
|
||||
*/
|
||||
class FieldTypeDefaults extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (is_array($value) && isset($value[1])) {
|
||||
return $value[1];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 6 field source from database.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_field",
|
||||
* source_module = "content"
|
||||
* )
|
||||
*/
|
||||
class Field extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('content_node_field', 'cnf')
|
||||
->fields('cnf', [
|
||||
'field_name',
|
||||
'type',
|
||||
'global_settings',
|
||||
'required',
|
||||
'multiple',
|
||||
'db_storage',
|
||||
'module',
|
||||
'db_columns',
|
||||
'active',
|
||||
'locked',
|
||||
])
|
||||
->distinct();
|
||||
// Only import fields which are actually being used.
|
||||
$query->innerJoin('content_node_field_instance', 'cnfi', 'cnfi.field_name = cnf.field_name');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'field_name' => $this->t('Field name'),
|
||||
'type' => $this->t('Type (text, integer, ....)'),
|
||||
'widget_type' => $this->t('An instance-specific widget type'),
|
||||
'global_settings' => $this->t('Global settings. Shared with every field instance.'),
|
||||
'required' => $this->t('Required'),
|
||||
'multiple' => $this->t('Multiple'),
|
||||
'db_storage' => $this->t('DB storage'),
|
||||
'module' => $this->t('Module'),
|
||||
'db_columns' => $this->t('DB Columns'),
|
||||
'active' => $this->t('Active'),
|
||||
'locked' => $this->t('Locked'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
// The instance widget_type helps determine what D8 field type we'll use.
|
||||
// Identify the distinct widget_types being used in D6.
|
||||
$widget_types = $this->select('content_node_field_instance', 'cnfi')
|
||||
->fields('cnfi', ['widget_type'])
|
||||
->condition('field_name', $row->getSourceProperty('field_name'))
|
||||
->distinct()
|
||||
->orderBy('widget_type')
|
||||
->execute()
|
||||
->fetchCol();
|
||||
// Arbitrarily use the first widget_type - if there are multiples, let the
|
||||
// migrator know.
|
||||
$row->setSourceProperty('widget_type', $widget_types[0]);
|
||||
if (count($widget_types) > 1) {
|
||||
$this->migration->getIdMap()->saveMessage(
|
||||
['field_name' => $row->getSourceProperty('field_name')],
|
||||
$this->t('Widget types @types are used in Drupal 6 field instances: widget type @selected_type applied to the Drupal 8 base field', [
|
||||
'@types' => implode(', ', $widget_types),
|
||||
'@selected_type' => $widget_types[0],
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
// Unserialize data.
|
||||
$global_settings = unserialize($row->getSourceProperty('global_settings'));
|
||||
$db_columns = unserialize($row->getSourceProperty('db_columns'));
|
||||
$row->setSourceProperty('global_settings', $global_settings);
|
||||
$row->setSourceProperty('db_columns', $db_columns);
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['field_name'] = [
|
||||
'type' => 'string',
|
||||
'alias' => 'cnf',
|
||||
];
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 6 field instances source from database.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_field_instance",
|
||||
* source_module = "content"
|
||||
* )
|
||||
*/
|
||||
class FieldInstance extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('content_node_field_instance', 'cnfi')->fields('cnfi');
|
||||
if (isset($this->configuration['node_type'])) {
|
||||
$query->condition('cnfi.type_name', $this->configuration['node_type']);
|
||||
}
|
||||
$query->join('content_node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
|
||||
$query->fields('cnf');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'field_name' => $this->t('The machine name of field.'),
|
||||
'type_name' => $this->t('Content type where this field is in use.'),
|
||||
'weight' => $this->t('Weight.'),
|
||||
'label' => $this->t('A name to show.'),
|
||||
'widget_type' => $this->t('Widget type.'),
|
||||
'widget_settings' => $this->t('Serialize data with widget settings.'),
|
||||
'display_settings' => $this->t('Serialize data with display settings.'),
|
||||
'description' => $this->t('A description of field.'),
|
||||
'widget_module' => $this->t('Module that implements widget.'),
|
||||
'widget_active' => $this->t('Status of widget'),
|
||||
'module' => $this->t('The module that provides the field.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
// Unserialize data.
|
||||
$widget_settings = unserialize($row->getSourceProperty('widget_settings'));
|
||||
$display_settings = unserialize($row->getSourceProperty('display_settings'));
|
||||
$global_settings = unserialize($row->getSourceProperty('global_settings'));
|
||||
$row->setSourceProperty('widget_settings', $widget_settings);
|
||||
$row->setSourceProperty('display_settings', $display_settings);
|
||||
$row->setSourceProperty('global_settings', $global_settings);
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids = [
|
||||
'field_name' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'cnfi',
|
||||
],
|
||||
'type_name' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
];
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d6;
|
||||
|
||||
/**
|
||||
* Gets field instance option label translations.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_field_instance_option_translation",
|
||||
* source_module = "i18ncck"
|
||||
* )
|
||||
*/
|
||||
class FieldInstanceOptionTranslation extends FieldOptionTranslation {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = parent::query();
|
||||
$query->join('content_node_field_instance', 'cnfi', 'cnf.field_name = cnfi.field_name');
|
||||
$query->addField('cnfi', 'type_name');
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'type_name' => $this->t('Type (article, page, ....)'),
|
||||
];
|
||||
return parent::fields() + $fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* The field instance per form display source class.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_field_instance_per_form_display",
|
||||
* source_module = "content"
|
||||
* )
|
||||
*/
|
||||
class FieldInstancePerFormDisplay extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initializeIterator() {
|
||||
$rows = [];
|
||||
$result = $this->prepareQuery()->execute();
|
||||
while ($field_row = $result->fetchAssoc()) {
|
||||
$bundle = $field_row['type_name'];
|
||||
$field_name = $field_row['field_name'];
|
||||
|
||||
$index = "$bundle.$field_name";
|
||||
$rows[$index]['type_name'] = $bundle;
|
||||
$rows[$index]['widget_active'] = (bool) $field_row['widget_active'];
|
||||
$rows[$index]['field_name'] = $field_name;
|
||||
$rows[$index]['type'] = $field_row['type'];
|
||||
$rows[$index]['module'] = $field_row['module'];
|
||||
$rows[$index]['weight'] = $field_row['weight'];
|
||||
$rows[$index]['widget_type'] = $field_row['widget_type'];
|
||||
$rows[$index]['widget_settings'] = unserialize($field_row['widget_settings']);
|
||||
$rows[$index]['display_settings'] = unserialize($field_row['display_settings']);
|
||||
}
|
||||
|
||||
return new \ArrayIterator($rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('content_node_field_instance', 'cnfi')
|
||||
->fields('cnfi', [
|
||||
'field_name',
|
||||
'type_name',
|
||||
'weight',
|
||||
'label',
|
||||
'widget_type',
|
||||
'widget_settings',
|
||||
'display_settings',
|
||||
'description',
|
||||
'widget_module',
|
||||
'widget_active',
|
||||
])
|
||||
->fields('cnf', [
|
||||
'type',
|
||||
'module',
|
||||
]);
|
||||
$query->join('content_node_field', 'cnf', 'cnfi.field_name = cnf.field_name');
|
||||
$query->orderBy('cnfi.weight');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'field_name' => $this->t('The machine name of field.'),
|
||||
'type_name' => $this->t('Content type where this field is used.'),
|
||||
'weight' => $this->t('Weight.'),
|
||||
'label' => $this->t('A name to show.'),
|
||||
'widget_type' => $this->t('Widget type.'),
|
||||
'widget_settings' => $this->t('Serialize data with widget settings.'),
|
||||
'display_settings' => $this->t('Serialize data with display settings.'),
|
||||
'description' => $this->t('A description of field.'),
|
||||
'widget_module' => $this->t('Module that implements widget.'),
|
||||
'widget_active' => $this->t('Status of widget'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['type_name']['type'] = 'string';
|
||||
$ids['field_name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\node\Plugin\migrate\source\d6\ViewModeBase;
|
||||
|
||||
/**
|
||||
* The field instance per view mode source class.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_field_instance_per_view_mode",
|
||||
* source_module = "content"
|
||||
* )
|
||||
*/
|
||||
class FieldInstancePerViewMode extends ViewModeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initializeIterator() {
|
||||
$rows = [];
|
||||
$result = $this->prepareQuery()->execute();
|
||||
while ($field_row = $result->fetchAssoc()) {
|
||||
// These are added to every view mode row.
|
||||
$field_row['display_settings'] = unserialize($field_row['display_settings']);
|
||||
$field_row['widget_settings'] = unserialize($field_row['widget_settings']);
|
||||
$bundle = $field_row['type_name'];
|
||||
$field_name = $field_row['field_name'];
|
||||
|
||||
foreach ($this->getViewModes() as $view_mode) {
|
||||
// Append to the return value if the row has display settings for this
|
||||
// view mode and the view mode is neither hidden nor excluded.
|
||||
// @see \Drupal\node\Plugin\migrate\source\d6\ViewMode::initializeIterator()
|
||||
if (isset($field_row['display_settings'][$view_mode]) && $field_row['display_settings'][$view_mode]['format'] != 'hidden' && empty($field_row['display_settings'][$view_mode]['exclude'])) {
|
||||
$index = $view_mode . "." . $bundle . "." . $field_name;
|
||||
$rows[$index]['entity_type'] = 'node';
|
||||
$rows[$index]['view_mode'] = $view_mode;
|
||||
$rows[$index]['type_name'] = $bundle;
|
||||
$rows[$index]['field_name'] = $field_name;
|
||||
$rows[$index]['type'] = $field_row['type'];
|
||||
$rows[$index]['module'] = $field_row['module'];
|
||||
$rows[$index]['weight'] = $field_row['weight'];
|
||||
$rows[$index]['label'] = $field_row['display_settings']['label']['format'];
|
||||
$rows[$index]['display_settings'] = $field_row['display_settings'][$view_mode];
|
||||
$rows[$index]['widget_settings'] = $field_row['widget_settings'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new \ArrayIterator($rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('content_node_field_instance', 'cnfi')
|
||||
->fields('cnfi', [
|
||||
'field_name',
|
||||
'type_name',
|
||||
'weight',
|
||||
'label',
|
||||
'display_settings',
|
||||
'widget_settings',
|
||||
])
|
||||
->fields('cnf', [
|
||||
'type',
|
||||
'module',
|
||||
]);
|
||||
$query->join('content_node_field', 'cnf', 'cnfi.field_name = cnf.field_name');
|
||||
$query->orderBy('cnfi.weight');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'field_name' => $this->t('The machine name of field.'),
|
||||
'type_name' => $this->t('Content type where this field is used.'),
|
||||
'weight' => $this->t('Weight.'),
|
||||
'label' => $this->t('A name to show.'),
|
||||
'widget_type' => $this->t('Widget type.'),
|
||||
'widget_settings' => $this->t('Serialize data with widget settings.'),
|
||||
'display_settings' => $this->t('Serialize data with display settings.'),
|
||||
'description' => $this->t('A description of field.'),
|
||||
'widget_module' => $this->t('Module that implements widget.'),
|
||||
'widget_active' => $this->t('Status of widget'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['type_name']['type'] = 'string';
|
||||
$ids['view_mode']['type'] = 'string';
|
||||
$ids['entity_type']['type'] = 'string';
|
||||
$ids['field_name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d6;
|
||||
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Gets field label and description translations.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_field_instance_label_description_translation",
|
||||
* source_module = "i18ncck"
|
||||
* )
|
||||
*/
|
||||
class FieldLabelDescriptionTranslation extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Get translations for field labels and descriptions.
|
||||
$query = $this->select('i18n_strings', 'i18n')
|
||||
->fields('i18n', ['property', 'objectid', 'type'])
|
||||
->fields('lt', ['lid', 'translation', 'language'])
|
||||
->condition('i18n.type', 'field')
|
||||
->isNotNull('language')
|
||||
->isNotNull('translation');
|
||||
$condition = $query->orConditionGroup()
|
||||
->condition('property', 'widget_label')
|
||||
->condition('property', 'widget_description');
|
||||
$query->condition($condition);
|
||||
$query->leftJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'property' => $this->t('Profile field ID.'),
|
||||
'lid' => $this->t('Locales target language ID.'),
|
||||
'language' => $this->t('Language for this field.'),
|
||||
'translation' => $this->t('Translation of either the title or explanation.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['property']['type'] = 'string';
|
||||
$ids['language']['type'] = 'string';
|
||||
$ids['lid']['type'] = 'integer';
|
||||
$ids['lid']['alias'] = 'lt';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d6;
|
||||
|
||||
/**
|
||||
* Gets field option label translations.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d6_field_option_translation",
|
||||
* source_module = "i18ncck"
|
||||
* )
|
||||
*/
|
||||
class FieldOptionTranslation extends Field {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Get the fields that have field options translations.
|
||||
$query = $this->select('i18n_strings', 'i18n')
|
||||
->fields('i18n')
|
||||
->fields('lt', [
|
||||
'translation',
|
||||
'language',
|
||||
'plid',
|
||||
'plural',
|
||||
'i18n_status',
|
||||
])
|
||||
->condition('i18n.type', 'field')
|
||||
->condition('property', 'option\_%', 'LIKE')
|
||||
->isNotNull('translation');
|
||||
$query->leftJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
|
||||
$query->leftjoin('content_node_field', 'cnf', 'cnf.field_name = i18n.objectid');
|
||||
$query->addField('cnf', 'field_name');
|
||||
$query->addField('cnf', 'global_settings');
|
||||
// Minimise changes to the d6_field_option_translation.yml, which is copied
|
||||
// from d6_field.yml, by ensuring the 'type' property is from
|
||||
// content_node_field table.
|
||||
$query->addField('cnf', 'type');
|
||||
$query->addField('i18n', 'type', 'i18n_type');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'property' => $this->t('Option ID.'),
|
||||
'objectid' => $this->t('Object ID'),
|
||||
'objectindex' => $this->t('Integer value of Object ID'),
|
||||
'format' => $this->t('The input format used by this string'),
|
||||
'lid' => $this->t('Source string ID'),
|
||||
'language' => $this->t('Language code'),
|
||||
'translation' => $this->t('Translation of the option'),
|
||||
'plid' => $this->t('Parent lid'),
|
||||
'plural' => $this->t('Plural index number in case of plural strings'),
|
||||
];
|
||||
return parent::fields() + $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return parent::getIds() +
|
||||
[
|
||||
'language' => ['type' => 'string'],
|
||||
'property' => ['type' => 'string'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 7 field source from database.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* This class is marked as internal and should not be extended. Use
|
||||
* Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase instead.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_field",
|
||||
* source_module = "field_sql_storage"
|
||||
* )
|
||||
*/
|
||||
class Field extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('field_config', 'fc')
|
||||
->distinct()
|
||||
->fields('fc')
|
||||
->fields('fci', ['entity_type'])
|
||||
->condition('fc.active', 1)
|
||||
->condition('fc.storage_active', 1)
|
||||
->condition('fc.deleted', 0)
|
||||
->condition('fci.deleted', 0);
|
||||
$query->join('field_config_instance', 'fci', 'fc.id = fci.field_id');
|
||||
|
||||
// If the Drupal 7 Title module is enabled, we don't want to migrate the
|
||||
// fields it provides. The values of those fields will be migrated to the
|
||||
// base fields they were replacing.
|
||||
if ($this->moduleExists('title')) {
|
||||
$title_fields = [
|
||||
'title_field',
|
||||
'name_field',
|
||||
'description_field',
|
||||
'subject_field',
|
||||
];
|
||||
$query->condition('fc.field_name', $title_fields, 'NOT IN');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'id' => $this->t('The field ID.'),
|
||||
'field_name' => $this->t('The field name.'),
|
||||
'type' => $this->t('The field type.'),
|
||||
'module' => $this->t('The module that implements the field type.'),
|
||||
'active' => $this->t('The field status.'),
|
||||
'storage_type' => $this->t('The field storage type.'),
|
||||
'storage_module' => $this->t('The module that implements the field storage type.'),
|
||||
'storage_active' => $this->t('The field storage status.'),
|
||||
'locked' => $this->t('Locked'),
|
||||
'data' => $this->t('The field data.'),
|
||||
'cardinality' => $this->t('Cardinality'),
|
||||
'translatable' => $this->t('Translatable'),
|
||||
'deleted' => $this->t('Deleted'),
|
||||
'instances' => $this->t('The field instances.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row, $keep = TRUE) {
|
||||
foreach (unserialize($row->getSourceProperty('data')) as $key => $value) {
|
||||
$row->setSourceProperty($key, $value);
|
||||
}
|
||||
|
||||
$instances = $this->select('field_config_instance', 'fci')
|
||||
->fields('fci')
|
||||
->condition('field_name', $row->getSourceProperty('field_name'))
|
||||
->condition('entity_type', $row->getSourceProperty('entity_type'))
|
||||
->execute()
|
||||
->fetchAll();
|
||||
$row->setSourceProperty('instances', $instances);
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'field_name' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'fc',
|
||||
],
|
||||
'entity_type' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'fci',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Drupal 7 field instances source from database.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* This class is marked as internal and should not be extended. Use
|
||||
* Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase instead.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_field_instance",
|
||||
* source_module = "field"
|
||||
* )
|
||||
*/
|
||||
class FieldInstance extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('field_config_instance', 'fci')
|
||||
->fields('fci')
|
||||
->fields('fc', ['type', 'translatable'])
|
||||
->condition('fc.active', 1)
|
||||
->condition('fc.storage_active', 1)
|
||||
->condition('fc.deleted', 0)
|
||||
->condition('fci.deleted', 0);
|
||||
$query->join('field_config', 'fc', 'fci.field_id = fc.id');
|
||||
|
||||
// Optionally filter by entity type and bundle.
|
||||
if (isset($this->configuration['entity_type'])) {
|
||||
$query->condition('fci.entity_type', $this->configuration['entity_type']);
|
||||
|
||||
if (isset($this->configuration['bundle'])) {
|
||||
$query->condition('fci.bundle', $this->configuration['bundle']);
|
||||
}
|
||||
}
|
||||
|
||||
// If the Drupal 7 Title module is enabled, we don't want to migrate the
|
||||
// fields it provides. The values of those fields will be migrated to the
|
||||
// base fields they were replacing.
|
||||
if ($this->moduleExists('title')) {
|
||||
$title_fields = [
|
||||
'title_field',
|
||||
'name_field',
|
||||
'description_field',
|
||||
'subject_field',
|
||||
];
|
||||
$query->condition('fc.field_name', $title_fields, 'NOT IN');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initializeIterator() {
|
||||
$results = $this->prepareQuery()->execute()->fetchAll();
|
||||
|
||||
// Group all instances by their base field.
|
||||
$instances = [];
|
||||
foreach ($results as $result) {
|
||||
$instances[$result['field_id']][] = $result;
|
||||
}
|
||||
|
||||
// Add the array of all instances using the same base field to each row.
|
||||
$rows = [];
|
||||
foreach ($results as $result) {
|
||||
$result['instances'] = $instances[$result['field_id']];
|
||||
$rows[] = $result;
|
||||
}
|
||||
|
||||
return new \ArrayIterator($rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return [
|
||||
'id' => $this->t('The field instance ID.'),
|
||||
'field_id' => $this->t('The field ID.'),
|
||||
'field_name' => $this->t('The field name.'),
|
||||
'entity_type' => $this->t('The entity type.'),
|
||||
'bundle' => $this->t('The entity bundle.'),
|
||||
'data' => $this->t('The field instance data.'),
|
||||
'deleted' => $this->t('Deleted'),
|
||||
'type' => $this->t('The field type'),
|
||||
'instances' => $this->t('The field instances.'),
|
||||
'field_definition' => $this->t('The field definition.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
foreach (unserialize($row->getSourceProperty('data')) as $key => $value) {
|
||||
$row->setSourceProperty($key, $value);
|
||||
}
|
||||
|
||||
$field_definition = $this->select('field_config', 'fc')
|
||||
->fields('fc')
|
||||
->condition('id', $row->getSourceProperty('field_id'))
|
||||
->execute()
|
||||
->fetch();
|
||||
$row->setSourceProperty('field_definition', $field_definition);
|
||||
|
||||
$translatable = FALSE;
|
||||
if ($row->getSourceProperty('entity_type') == 'node') {
|
||||
$language_content_type_bundle = (int) $this->variableGet('language_content_type_' . $row->getSourceProperty('bundle'), 0);
|
||||
// language_content_type_[bundle] may be
|
||||
// - 0: no language support
|
||||
// - 1: language assignment support
|
||||
// - 2: node translation support
|
||||
// - 4: entity translation support
|
||||
if ($language_content_type_bundle === 2 || ($language_content_type_bundle === 4 && $row->getSourceProperty('translatable'))) {
|
||||
$translatable = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This is not a node entity. Get the translatable value from the source
|
||||
// field_config table.
|
||||
$field_data = unserialize($field_definition['data']);
|
||||
$translatable = $field_data['translatable'];
|
||||
}
|
||||
$row->setSourceProperty('translatable', $translatable);
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'entity_type' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'fci',
|
||||
],
|
||||
'bundle' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'fci',
|
||||
],
|
||||
'field_name' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'fci',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count($refresh = FALSE) {
|
||||
return $this->initializeIterator()->count();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d7;
|
||||
|
||||
/**
|
||||
* The field instance per form display source class.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_field_instance_per_form_display",
|
||||
* source_module = "field"
|
||||
* )
|
||||
*/
|
||||
class FieldInstancePerFormDisplay extends FieldInstance {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'bundle' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
'field_name' => [
|
||||
'type' => 'string',
|
||||
'alias' => 'fci',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d7;
|
||||
|
||||
/**
|
||||
* The field instance per view mode source class.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_field_instance_per_view_mode",
|
||||
* source_module = "field"
|
||||
* )
|
||||
*/
|
||||
class FieldInstancePerViewMode extends FieldInstance {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initializeIterator() {
|
||||
$instances = parent::initializeIterator();
|
||||
|
||||
$rows = [];
|
||||
foreach ($instances->getArrayCopy() as $instance) {
|
||||
$data = unserialize($instance['data']);
|
||||
foreach ($data['display'] as $view_mode => $formatter) {
|
||||
$rows[] = array_merge($instance, [
|
||||
'view_mode' => $view_mode,
|
||||
'formatter' => $formatter,
|
||||
]);
|
||||
}
|
||||
}
|
||||
return new \ArrayIterator($rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return array_merge(parent::fields(), [
|
||||
'view_mode' => $this->t('The original machine name of the view mode.'),
|
||||
'formatter' => $this->t('The formatter settings.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'entity_type' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
'bundle' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
'view_mode' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
'field_name' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Plugin\migrate\source\d7;
|
||||
|
||||
/**
|
||||
* The view mode source class.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_view_mode",
|
||||
* source_module = "field"
|
||||
* )
|
||||
*/
|
||||
class ViewMode extends FieldInstance {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initializeIterator() {
|
||||
$instances = parent::initializeIterator();
|
||||
|
||||
$rows = [];
|
||||
foreach ($instances->getArrayCopy() as $instance) {
|
||||
$data = unserialize($instance['data']);
|
||||
foreach (array_keys($data['display']) as $view_mode) {
|
||||
$key = $instance['entity_type'] . '.' . $view_mode;
|
||||
$rows[$key] = array_merge($instance, [
|
||||
'view_mode' => $view_mode,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return new \ArrayIterator($rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return array_merge(parent::fields(), [
|
||||
'view_mode' => $this->t('The view mode ID.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return [
|
||||
'entity_type' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
'view_mode' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
// @codingStandardsIgnoreFile
|
||||
|
||||
/**
|
||||
* This file was generated via php core/scripts/generate-proxy-class.php 'Drupal\field\FieldUninstallValidator' "core/modules/field/src".
|
||||
*/
|
||||
|
||||
namespace Drupal\field\ProxyClass {
|
||||
|
||||
/**
|
||||
* Provides a proxy class for \Drupal\field\FieldUninstallValidator.
|
||||
*
|
||||
* @see \Drupal\Component\ProxyBuilder
|
||||
*/
|
||||
class FieldUninstallValidator implements \Drupal\Core\Extension\ModuleUninstallValidatorInterface
|
||||
{
|
||||
|
||||
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
|
||||
/**
|
||||
* The id of the original proxied service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $drupalProxyOriginalServiceId;
|
||||
|
||||
/**
|
||||
* The real proxied service, after it was lazy loaded.
|
||||
*
|
||||
* @var \Drupal\field\FieldUninstallValidator
|
||||
*/
|
||||
protected $service;
|
||||
|
||||
/**
|
||||
* The service container.
|
||||
*
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Constructs a ProxyClass Drupal proxy object.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
|
||||
* The container.
|
||||
* @param string $drupal_proxy_original_service_id
|
||||
* The service ID of the original service.
|
||||
*/
|
||||
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy loads the real service from the container.
|
||||
*
|
||||
* @return object
|
||||
* Returns the constructed real service.
|
||||
*/
|
||||
protected function lazyLoadItself()
|
||||
{
|
||||
if (!isset($this->service)) {
|
||||
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
|
||||
}
|
||||
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($module)
|
||||
{
|
||||
return $this->lazyLoadItself()->validate($module);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStringTranslation(\Drupal\Core\StringTranslation\TranslationInterface $translation)
|
||||
{
|
||||
return $this->lazyLoadItself()->setStringTranslation($translation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Tests\EntityReference;
|
||||
|
||||
use Drupal\Tests\field\Traits\EntityReferenceTestTrait as nonDeprecatedEntityReferenceTestTrait;
|
||||
|
||||
/**
|
||||
* Provides common functionality for the EntityReference test classes.
|
||||
*
|
||||
* @deprecated in Drupal 8.6.2 for removal before 9.0.0. Use
|
||||
* Drupal\Tests\field\Traits\EntityReferenceTestTrait instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2998888
|
||||
*/
|
||||
trait EntityReferenceTestTrait {
|
||||
|
||||
use nonDeprecatedEntityReferenceTestTrait;
|
||||
|
||||
}
|
||||
68
2017/web/core/modules/field/src/Tests/FieldTestBase.php
Normal file
68
2017/web/core/modules/field/src/Tests/FieldTestBase.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Tests;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Parent class for Field API tests.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\field\Functional\FieldTestBase instead.
|
||||
*/
|
||||
abstract class FieldTestBase extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Generate random values for a field_test field.
|
||||
*
|
||||
* @param $cardinality
|
||||
* Number of values to generate.
|
||||
* @return
|
||||
* An array of random values, in the format expected for field values.
|
||||
*/
|
||||
public function _generateTestFieldValues($cardinality) {
|
||||
$values = [];
|
||||
for ($i = 0; $i < $cardinality; $i++) {
|
||||
// field_test fields treat 0 as 'empty value'.
|
||||
$values[$i]['value'] = mt_rand(1, 127);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a field has the expected values in an entity.
|
||||
*
|
||||
* This function only checks a single column in the field values.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to test.
|
||||
* @param $field_name
|
||||
* The name of the field to test
|
||||
* @param $expected_values
|
||||
* The array of expected values.
|
||||
* @param $langcode
|
||||
* (Optional) The language code for the values. Defaults to
|
||||
* \Drupal\Core\Language\LanguageInterface::LANGCODE_DEFAULT.
|
||||
* @param $column
|
||||
* (Optional) The name of the column to check. Defaults to 'value'.
|
||||
*/
|
||||
public function assertFieldValues(EntityInterface $entity, $field_name, $expected_values, $langcode = LanguageInterface::LANGCODE_DEFAULT, $column = 'value') {
|
||||
// Re-load the entity to make sure we have the latest changes.
|
||||
$storage = $this->container->get('entity_type.manager')
|
||||
->getStorage($entity->getEntityTypeId());
|
||||
$storage->resetCache([$entity->id()]);
|
||||
$e = $storage->load($entity->id());
|
||||
|
||||
$field = $values = $e->getTranslation($langcode)->$field_name;
|
||||
// Filter out empty values so that they don't mess with the assertions.
|
||||
$field->filterEmptyItems();
|
||||
$values = $field->getValue();
|
||||
$this->assertEqual(count($values), count($expected_values), 'Expected number of values were saved.');
|
||||
foreach ($expected_values as $key => $value) {
|
||||
$this->assertEqual($values[$key][$column], $value, format_string('Value @value was saved correctly.', ['@value' => $value]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\field\Tests\Views;
|
||||
|
||||
@trigger_error(__NAMESPACE__ . '\FieldTestBase is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\field\Functional\Views\FieldTestBase. See https://www.drupal.org/node/2971931.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\views\Tests\ViewTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Provides some helper methods for testing fieldapi integration into views.
|
||||
*
|
||||
* @todo Test on a generic entity not on a node. What has to be tested:
|
||||
* - Make sure that every wanted field is added to the according entity type.
|
||||
* - Make sure the joins are done correctly.
|
||||
* - Use basic fields and make sure that the full wanted object is built.
|
||||
* - Use relationships between different entity types, for example node and
|
||||
* the node author(user).
|
||||
*
|
||||
* @deprecated in Drupal 8.6.0. Will be removed before Drupal 9.0.0. Use
|
||||
* \Drupal\Tests\field\Functional\Views\FieldTestBase instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2989020
|
||||
*/
|
||||
abstract class FieldTestBase extends ViewTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'field_test_views'];
|
||||
|
||||
/**
|
||||
* Stores the field definitions used by the test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fieldStorages;
|
||||
|
||||
/**
|
||||
* Stores the fields of the field storage. They have the same keys as the
|
||||
* field storages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fields;
|
||||
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
// Ensure the page node type exists.
|
||||
NodeType::create([
|
||||
'type' => 'page',
|
||||
'name' => 'page',
|
||||
])->save();
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['field_test_views']);
|
||||
}
|
||||
|
||||
public function setUpFieldStorages($amount = 3, $type = 'string') {
|
||||
// Create three fields.
|
||||
$field_names = [];
|
||||
for ($i = 0; $i < $amount; $i++) {
|
||||
$field_names[$i] = 'field_name_' . $i;
|
||||
$this->fieldStorages[$i] = FieldStorageConfig::create([
|
||||
'field_name' => $field_names[$i],
|
||||
'entity_type' => 'node',
|
||||
'type' => $type,
|
||||
]);
|
||||
$this->fieldStorages[$i]->save();
|
||||
}
|
||||
return $field_names;
|
||||
}
|
||||
|
||||
public function setUpFields($bundle = 'page') {
|
||||
foreach ($this->fieldStorages as $key => $field_storage) {
|
||||
$this->fields[$key] = FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => $bundle,
|
||||
]);
|
||||
$this->fields[$key]->save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in a new issue