diff --git a/core/includes/database.inc b/core/includes/database.inc index 75f6a96..67c879e 100644 --- a/core/includes/database.inc +++ b/core/includes/database.inc @@ -680,6 +680,18 @@ function db_rename_table($table, $new_name) { } /** + * Copies the structure of a table. + * + * @param string $source + * The name of the table to be copied. + * @param string $destination + * The name for the new table. + */ +function db_copy_table($source, $destination) { + return Database::getConnection()->schema()->copyTable($source, $destination); +} + +/** * Drops a table. * * @param $table diff --git a/core/includes/entity.inc b/core/includes/entity.inc index 7822d7a..04a4130 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -102,6 +102,8 @@ function entity_get_bundles($entity_type = NULL) { */ function entity_invoke_bundle_hook($hook, $entity_type, $bundle, $bundle_new = NULL) { entity_info_cache_clear(); + $method = 'handleBundle' . ucfirst($hook); + Drupal::entityManager()->getStorageController($entity_type)->$method($bundle, $bundle_new); Drupal::moduleHandler()->invokeAll('entity_bundle_' . $hook, array($entity_type, $bundle, $bundle_new)); } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php index 14d3f18..0d9bd71 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php @@ -75,4 +75,14 @@ public function setStatus($status); */ public function status(); + /** + * Retrieves the exportable properties of the entity. + * + * These are the values that get saved into config. + * + * @return array + * An array of exportable properties and their values. + */ + public function getExportProperties(); + } diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index ce7e04f..c9069b1 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -759,7 +759,7 @@ public function truncate($table, array $options = array()) { * * This method will lazy-load the appropriate schema library file. * - * @return Drupal\Core\Database\Schema + * @return \Drupal\Core\Database\Schema * The database Schema object for this connection. */ public function schema() { diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php index 5788bef..f4ad9a7 100644 --- a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php +++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php @@ -327,6 +327,15 @@ public function dropTable($table) { return TRUE; } + /** + * {@inheritdoc} + */ + public function copyTable($source, $destination) { + parent::copyTable($source, $destination); + $info = $this->getPrefixInfo($destination); + return $this->connection->query('CREATE TABLE `' . $info['table'] . '` LIKE {' . $source . '}'); + } + public function addField($table, $field, $spec, $keys_new = array()) { if (!$this->tableExists($table)) { throw new SchemaObjectDoesNotExistException(t("Cannot add field @table.@field: table doesn't exist.", array('@field' => $field, '@table' => $table))); diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php index e2798e1..e6a3ba8 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php @@ -348,6 +348,15 @@ function renameTable($table, $new_name) { $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $prefixInfo['table']); } + /** + * {@inheritdoc} + */ + public function copyTable($source, $destination) { + parent::copyTable($source, $destination); + $info = $this->getPrefixInfo($destination); + return $this->connection->query('CREATE TABLE `' . $info['table'] . '` (LIKE {' . $source . '} INCLUDING ALL)'); + } + public function dropTable($table) { if (!$this->tableExists($table)) { return FALSE; diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php index f8050cd..24dbe19 100644 --- a/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php +++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Schema.php @@ -272,6 +272,14 @@ public function renameTable($table, $new_name) { } } + /** + * {@inheritdoc} + */ + public function copyTable($source, $destination) { + parent::copyTable($source, $destination); + $this->createTable($destination, $this->introspectSchema($source)); + } + public function dropTable($table) { if (!$this->tableExists($table)) { return FALSE; diff --git a/core/lib/Drupal/Core/Database/Schema.php b/core/lib/Drupal/Core/Database/Schema.php index 7b884f7..2a24ced 100644 --- a/core/lib/Drupal/Core/Database/Schema.php +++ b/core/lib/Drupal/Core/Database/Schema.php @@ -408,6 +408,31 @@ public function fieldExists($table, $column) { abstract public function dropTable($table); /** + * Copies the structure of a table without copying the content. + * + * @param string $source + * The name of the table to be used as source. + * @param string $destination + * The name of the table to be used as destination. + * + * @return \Drupal\Core\Database\StatementInterface + * The result of the executed query. + * + * @throws \Drupal\Core\Database\SchemaObjectExistsException + * Thrown when the source table does not exist. + * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException + * Thrown when the destination table already exists. + */ + public function copyTable($source, $destination) { + if (!$this->tableExists($source)) { + throw new SchemaObjectDoesNotExistException(t("Cannot copy @source to @destination: table @source doesn't exist.", array('@source' => $source, '@destination' => $destination))); + } + if ($this->tableExists($destination)) { + throw new SchemaObjectExistsException(t("Cannot copy @source to @destination: table @destination already exists.", array('@source' => $source, '@destination' => $destination))); + } + } + + /** * Add a new field to a table. * * @param $table diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php index 5eeb637..5f30a58 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php @@ -7,13 +7,15 @@ namespace Drupal\Core\Entity; -use Drupal\Core\Language\Language; -use PDO; -use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Database\Connection; use Drupal\Core\Entity\Query\QueryInterface; -use Drupal\Component\Uuid\Uuid; use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Database\Connection; +use Drupal\Component\Uuid\Uuid; +use Drupal\field\FieldInfo; +use Drupal\field\FieldUpdateForbiddenException; +use Drupal\field\FieldInterface; +use Drupal\field\FieldInstanceInterface; +use Drupal\field\Plugin\Core\Entity\Field; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -24,7 +26,7 @@ * This class can be used as-is by most simple entity types. Entity types * requiring special handling can extend the class. */ -class DatabaseStorageController extends EntityStorageControllerBase { +class DatabaseStorageController extends FieldableEntityStorageControllerBase { /** * Name of entity's revision database table field, if it supports revisions. @@ -59,13 +61,21 @@ class DatabaseStorageController extends EntityStorageControllerBase { protected $database; /** + * The field info object. + * + * @var \Drupal\field\FieldInfo + */ + protected $fieldInfo; + + /** * {@inheritdoc} */ public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { return new static( $entity_type, $entity_info, - $container->get('database') + $container->get('database'), + $container->get('field.info') ); } @@ -78,11 +88,14 @@ public static function createInstance(ContainerInterface $container, $entity_typ * An array of entity info for the entity type. * @param \Drupal\Core\Database\Connection $database * The database connection to be used. + * @param \Drupal\field\FieldInfo $field_info + * The field info service. */ - public function __construct($entity_type, array $entity_info, Connection $database) { + public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info) { parent::__construct($entity_type, $entity_info); $this->database = $database; + $this->fieldInfo = $field_info; // Check if the entity type supports IDs. if (isset($this->entityInfo['entity_keys']['id'])) { @@ -143,7 +156,7 @@ public function loadMultiple(array $ids = NULL) { // We provide the necessary arguments for PDO to create objects of the // specified entity class. // @see Drupal\Core\Entity\EntityInterface::__construct() - $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); + $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); } $queried_entities = $query_result->fetchAllAssoc($this->idKey); } @@ -196,7 +209,7 @@ public function loadRevision($revision_id) { // We provide the necessary arguments for PDO to create objects of the // specified entity class. // @see Drupal\Core\Entity\EntityInterface::__construct() - $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); + $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); } $queried_entities = $query_result->fetchAllAssoc($this->idKey); @@ -335,14 +348,9 @@ protected function buildQuery($ids, $revision_id = FALSE) { * (optional) TRUE if the revision should be loaded, defaults to FALSE. */ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { - // Attach fields. + // Attach field values. if ($this->entityInfo['fieldable']) { - if ($load_revision) { - field_attach_load_revision($this->entityType, $queried_entities); - } - else { - field_attach_load($this->entityType, $queried_entities); - } + $this->fieldLoad($queried_entities, $load_revision ? FIELD_LOAD_REVISION : FIELD_LOAD_CURRENT); } // Call hook_entity_load(). @@ -490,7 +498,7 @@ public function save(EntityInterface $entity) { /** * Saves an entity revision. * - * @param Drupal\Core\Entity\EntityInterface $entity + * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. */ protected function saveRevision(EntityInterface $entity) { @@ -528,42 +536,676 @@ protected function saveRevision(EntityInterface $entity) { } /** - * Invokes a hook on behalf of the entity. + * {@inheritdoc} + */ + public function baseFieldDefinitions() { + // @todo: Define abstract once all entity types have been converted. + return array(); + } + + /** + * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::getQueryServiceName(). + */ + public function getQueryServiceName() { + return 'entity.query.sql'; + } + + /** + * {@inheritdoc} + */ + protected function doFieldLoad($entities, $age) { + $load_current = $age == FIELD_LOAD_CURRENT; + + // Collect entities ids and bundles. + $bundles = array(); + $ids = array(); + foreach ($entities as $key => $entity) { + $bundles[$entity->bundle()] = TRUE; + $ids[] = $load_current ? $key : $entity->getRevisionId(); + } + + // Collect impacted fields. + $fields = array(); + foreach ($bundles as $bundle => $v) { + foreach ($this->fieldInfo->getBundleInstances($this->entityType, $bundle) as $field_name => $instance) { + $fields[$field_name] = $instance->getField(); + } + } + + // Load field data. + foreach ($fields as $field_name => $field) { + $table = $load_current ? static::_fieldTableName($field) : static::_fieldRevisionTableName($field); + + $results = $this->database->select($table, 't') + ->fields('t') + ->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN') + ->condition('langcode', field_available_languages($this->entityType, $field), 'IN') + ->orderBy('delta') + ->condition('deleted', 0) + ->execute(); + + $delta_count = array(); + foreach ($results as $row) { + if (!isset($delta_count[$row->entity_id][$row->langcode])) { + $delta_count[$row->entity_id][$row->langcode] = 0; + } + + if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field['cardinality']) { + $item = array(); + // For each column declared by the field, populate the item from the + // prefixed database column. + foreach ($field['columns'] as $column => $attributes) { + $column_name = static::_fieldColumnName($field, $column); + // Unserialize the value if specified in the column schema. + $item[$column] = (!empty($attributes['serialize'])) ? unserialize($row->$column_name) : $row->$column_name; + } + + // Add the item to the field values for the entity. + $entities[$row->entity_id]->{$field_name}[$row->langcode][] = $item; + $delta_count[$row->entity_id][$row->langcode]++; + } + } + } + } + + /** + * {@inheritdoc} + */ + protected function doFieldInsert(EntityInterface $entity) { + $this->doFieldWrite($entity, FALSE); + } + + /** + * {@inheritdoc} + */ + protected function doFieldUpdate(EntityInterface $entity) { + $this->doFieldWrite($entity, TRUE); + } + + /** + * Performs the actual write on behalf of doFieldInsert / doFieldUpdate. * - * @param $hook - * One of 'presave', 'insert', 'update', 'predelete', 'delete', or - * 'revision_delete'. - * @param $entity - * The entity object. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity being written. + * @param bool $update + * TRUE when running an update, FALSE when running an insert. */ - protected function invokeHook($hook, EntityInterface $entity) { - $function = 'field_attach_' . $hook; - // @todo: field_attach_delete_revision() is named the wrong way round, - // consider renaming it. - if ($function == 'field_attach_revision_delete') { - $function = 'field_attach_delete_revision'; + protected function doFieldWrite(EntityInterface $entity, $update) { + $vid = $entity->getRevisionId(); + $id = $entity->id(); + $bundle = $entity->bundle(); + $entity_type = $entity->entityType(); + if (!isset($vid)) { + $vid = $id; } - if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { - $function($entity); + + foreach ($this->fieldInfo->getBundleInstances($entity_type, $bundle) as $field_name => $instance) { + $field = $instance->getField(); + $table_name = static::_fieldTableName($field); + $revision_name = static::_fieldRevisionTableName($field); + + $all_langcodes = field_available_languages($entity_type, $field); + $field_langcodes = array_intersect($all_langcodes, array_keys((array) $entity->$field_name)); + + // Delete and insert, rather than update, in case a value was added. + if ($update) { + // Delete language codes present in the incoming $entity->$field_name. + // Delete all language codes if $entity->$field_name is empty. + $langcodes = !empty($entity->$field_name) ? $field_langcodes : $all_langcodes; + if ($langcodes) { + // Only overwrite the field's base table if saving the default revision + // of an entity. + if ($entity->isDefaultRevision()) { + $this->database->delete($table_name) + ->condition('entity_id', $id) + ->condition('langcode', $langcodes, 'IN') + ->execute(); + } + $this->database->delete($revision_name) + ->condition('entity_id', $id) + ->condition('revision_id', $vid) + ->condition('langcode', $langcodes, 'IN') + ->execute(); + } + } + + // Prepare the multi-insert query. + $do_insert = FALSE; + $columns = array('entity_id', 'revision_id', 'bundle', 'delta', 'langcode'); + foreach ($field['columns'] as $column => $attributes) { + $columns[] = static::_fieldColumnName($field, $column); + } + $query = $this->database->insert($table_name)->fields($columns); + $revision_query = $this->database->insert($revision_name)->fields($columns); + + foreach ($field_langcodes as $langcode) { + $items = (array) $entity->{$field_name}[$langcode]; + $delta_count = 0; + foreach ($items as $delta => $item) { + // We now know we have someting to insert. + $do_insert = TRUE; + $record = array( + 'entity_id' => $id, + 'revision_id' => $vid, + 'bundle' => $bundle, + 'delta' => $delta, + 'langcode' => $langcode, + ); + foreach ($field['columns'] as $column => $attributes) { + $column_name = static::_fieldColumnName($field, $column); + $value = isset($item[$column]) ? $item[$column] : NULL; + // Serialize the value if specified in the column schema. + $record[$column_name] = (!empty($attributes['serialize'])) ? serialize($value) : $value; + } + $query->values($record); + if (isset($vid)) { + $revision_query->values($record); + } + + if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) { + break; + } + } + } + + // Execute the query if we have values to insert. + if ($do_insert) { + // Only overwrite the field's base table if saving the default revision + // of an entity. + if ($entity->isDefaultRevision()) { + $query->execute(); + } + $revision_query->execute(); + } } - // Invoke the hook. - module_invoke_all($this->entityType . '_' . $hook, $entity); - // Invoke the respective entity-level hook. - module_invoke_all('entity_' . $hook, $entity, $this->entityType); } /** * {@inheritdoc} */ - public function baseFieldDefinitions() { - // @todo: Define abstract once all entity types have been converted. - return array(); + protected function doFieldDelete(EntityInterface $entity) { + foreach ($this->fieldInfo->getBundleInstances($entity->getType(), $entity->bundle()) as $instance) { + $field = $instance->getField(); + $table_name = static::_fieldTableName($field); + $revision_name = static::_fieldRevisionTableName($field); + $this->database->delete($table_name) + ->condition('entity_id', $entity->id()) + ->execute(); + $this->database->delete($revision_name) + ->condition('entity_id', $entity->id()) + ->execute(); + } } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::getQueryServiceName(). + * {@inheritdoc} */ - public function getQueryServiceName() { - return 'entity.query.sql'; + protected function doFieldRevisionDelete(EntityInterface $entity) { + $vid = $entity->getRevisionId(); + if (isset($vid)) { + foreach ($this->fieldInfo->getBundleInstances($entity->getType(), $entity->bundle()) as $instance) { + $revision_name = static::_fieldRevisionTableName($instance->getField()); + $this->database->delete($revision_name) + ->condition('entity_id', $entity->id()) + ->condition('revision_id', $vid) + ->execute(); + } + } + } + + /** + * {@inheritdoc} + */ + public function handleFieldCreate(FieldInterface $field) { + $schema = $this->_fieldSqlSchema($field); + foreach ($schema as $name => $table) { + $this->database->schema()->createTable($name, $table); + } } + + /** + * {@inheritdoc} + */ + public function handleFieldUpdate(FieldInterface $field, FieldInterface $original) { + if (!$field->hasData()) { + // There is no data. Re-create the tables completely. + + if ($this->database->supportsTransactionalDDL()) { + // If the database supports transactional DDL, we can go ahead and rely + // on it. If not, we will have to rollback manually if something fails. + $transaction = $this->database->startTransaction(); + } + + try { + $original_schema = $this->_fieldSqlSchema($original); + foreach ($original_schema as $name => $table) { + $this->database->schema()->dropTable($name, $table); + } + $schema = $this->_fieldSqlSchema($field); + foreach ($schema as $name => $table) { + $this->database->schema()->createTable($name, $table); + } + } + catch (\Exception $e) { + if ($this->database->supportsTransactionalDDL()) { + $transaction->rollback(); + } + else { + // Recreate tables. + $original_schema = $this->_fieldSqlSchema($original); + foreach ($original_schema as $name => $table) { + if (!$this->database->schema()->tableExists($name)) { + $this->database->schema()->createTable($name, $table); + } + } + } + throw $e; + } + } + else { + if ($field['columns'] != $original['columns']) { + throw new FieldUpdateForbiddenException("The SQL storage cannot change the schema for an existing field with data."); + } + // There is data, so there are no column changes. Drop all the prior + // indexes and create all the new ones, except for all the priors that + // exist unchanged. + $table = static::_fieldTableName($original); + $revision_table = static::_fieldRevisionTableName($original); + + $schema = $field->getSchema(); + $original_schema = $original->getSchema(); + + foreach ($original_schema['indexes'] as $name => $columns) { + if (!isset($schema['indexes'][$name]) || $columns != $schema['indexes'][$name]) { + $real_name = static::_fieldIndexName($field, $name); + $this->database->schema()->dropIndex($table, $real_name); + $this->database->schema()->dropIndex($revision_table, $real_name); + } + } + $table = static::_fieldTableName($field); + $revision_table = static::_fieldRevisionTableName($field); + foreach ($schema['indexes'] as $name => $columns) { + if (!isset($original_schema['indexes'][$name]) || $columns != $original_schema['indexes'][$name]) { + $real_name = static::_fieldIndexName($field, $name); + $real_columns = array(); + foreach ($columns as $column_name) { + // Indexes can be specified as either a column name or an array with + // column name and length. Allow for either case. + if (is_array($column_name)) { + $real_columns[] = array( + static::_fieldColumnName($field, $column_name[0]), + $column_name[1], + ); + } + else { + $real_columns[] = static::_fieldColumnName($field, $column_name); + } + } + $this->database->schema()->addIndex($table, $real_name, $real_columns); + $this->database->schema()->addIndex($revision_table, $real_name, $real_columns); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function handleFieldDelete(FieldInterface $field) { + // Mark all data associated with the field for deletion. + $field['deleted'] = FALSE; + $table = static::_fieldTableName($field); + $revision_table = static::_fieldRevisionTableName($field); + $this->database->update($table) + ->fields(array('deleted' => 1)) + ->execute(); + + // Move the table to a unique name while the table contents are being + // deleted. + $field['deleted'] = TRUE; + $new_table = static::_fieldTableName($field); + $revision_new_table = static::_fieldRevisionTableName($field); + $this->database->schema()->renameTable($table, $new_table); + $this->database->schema()->renameTable($revision_table, $revision_new_table); + } + + /** + * {@inheritdoc} + */ + public function handleInstanceDelete(FieldInstanceInterface $instance) { + $field = $instance->getField(); + $table_name = static::_fieldTableName($field); + $revision_name = static::_fieldRevisionTableName($field); + $this->database->update($table_name) + ->fields(array('deleted' => 1)) + ->condition('bundle', $instance['bundle']) + ->execute(); + $this->database->update($revision_name) + ->fields(array('deleted' => 1)) + ->condition('bundle', $instance['bundle']) + ->execute(); + } + + /** + * {@inheritdoc} + */ + public function handleBundleRename($bundle, $bundle_new) { + // We need to account for deleted or inactive fields and instances. + $instances = field_read_instances(array('entity_type' => $this->entityType, 'bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE)); + foreach ($instances as $instance) { + $field = $instance->getField(); + if ($field['storage']['type'] == 'field_sql_storage') { + $table_name = static::_fieldTableName($field); + $revision_name = static::_fieldRevisionTableName($field); + $this->database->update($table_name) + ->fields(array('bundle' => $bundle_new)) + ->condition('bundle', $bundle) + ->execute(); + $this->database->update($revision_name) + ->fields(array('bundle' => $bundle_new)) + ->condition('bundle', $bundle) + ->execute(); + } + } + } + + /** + * {@inheritdoc} + */ + public function fieldPurgeData(EntityInterface $entity, FieldInstanceInterface $instance) { + parent::fieldPurgeData($entity, $instance); + $field = $instance->getField(); + $table_name = static::_fieldTableName($field); + $revision_name = static::_fieldRevisionTableName($field); + $this->database->delete($table_name) + ->condition('entity_id', $entity->id()) + ->execute(); + $this->database->delete($revision_name) + ->condition('entity_id', $entity->id()) + ->execute(); + } + + /** + * {@inheritdoc} + */ + protected function fieldValues(EntityInterface $entity, FieldInstanceInterface $instance) { + $field = $instance->getField(); + $columns = array(); + foreach ($field->getColumns() as $column_name => $data) { + $columns[] = static::_fieldColumnName($field, $column_name); + } + return $this->database->select(static::_fieldTableName($field), 't') + ->fields('t', $columns) + ->condition('entity_id', $entity->id()) + ->execute() + ->fetchAll(); + } + + /** + * {@inheritdoc} + */ + public function fieldPurge(FieldInterface $field) { + $table_name = static::_fieldTableName($field); + $revision_name = static::_fieldRevisionTableName($field); + $this->database->schema()->dropTable($table_name); + $this->database->schema()->dropTable($revision_name); + } + + /** + * Gets the SQL table schema. + * + * @private Calling this function circumvents the entity system and is + * strongly discouraged. This function is not considered part of the public + * API and modules relying on it might break even in minor releases. + * + * @param \Drupal\field\FieldInterface $field + * The field object + * @param array $schema + * The field schema array. Mandatory for upgrades, omit otherwise. + * + * @return array + * The same as a hook_schema() implementation for the data and the + * revision tables. + * + * @see hook_schema() + */ + public static function _fieldSqlSchema(FieldInterface $field, array $schema = NULL) { + if ($field['deleted']) { + $description_current = "Data storage for deleted field {$field['id']} ({$field['entity_type']}, {$field['field_name']})."; + $description_revision = "Revision archive storage for deleted field {$field['id']} ({$field['entity_type']}, {$field['field_name']})."; + } + else { + $description_current = "Data storage for {$field['entity_type']} field {$field['field_name']}."; + $description_revision = "Revision archive storage for {$field['entity_type']} field {$field['field_name']}."; + } + + $current = array( + 'description' => $description_current, + 'fields' => array( + 'bundle' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The field instance bundle to which this row belongs, used when deleting a field instance', + ), + 'deleted' => array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'A boolean indicating whether this data item has been deleted' + ), + 'entity_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The entity id this data is attached to', + ), + 'revision_id' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned', + ), + 'langcode' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The language code for this data item.', + ), + 'delta' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'description' => 'The sequence number for this data item, used for multi-value fields', + ), + ), + 'primary key' => array('entity_id', 'deleted', 'delta', 'langcode'), + 'indexes' => array( + 'bundle' => array('bundle'), + 'deleted' => array('deleted'), + 'entity_id' => array('entity_id'), + 'revision_id' => array('revision_id'), + 'langcode' => array('langcode'), + ), + ); + + if (!$schema) { + $schema = $field->getSchema(); + } + + // Add field columns. + foreach ($schema['columns'] as $column_name => $attributes) { + $real_name = static::_fieldColumnName($field, $column_name); + $current['fields'][$real_name] = $attributes; + } + + // Add indexes. + foreach ($schema['indexes'] as $index_name => $columns) { + $real_name = static::_fieldIndexName($field, $index_name); + foreach ($columns as $column_name) { + // Indexes can be specified as either a column name or an array with + // column name and length. Allow for either case. + if (is_array($column_name)) { + $current['indexes'][$real_name][] = array( + static::_fieldColumnName($field, $column_name[0]), + $column_name[1], + ); + } + else { + $current['indexes'][$real_name][] = static::_fieldColumnName($field, $column_name); + } + } + } + + // Add foreign keys. + foreach ($schema['foreign keys'] as $specifier => $specification) { + $real_name = static::_fieldIndexName($field, $specifier); + $current['foreign keys'][$real_name]['table'] = $specification['table']; + foreach ($specification['columns'] as $column_name => $referenced) { + $sql_storage_column = static::_fieldColumnName($field, $column_name); + $current['foreign keys'][$real_name]['columns'][$sql_storage_column] = $referenced; + } + } + + // Construct the revision table. + $revision = $current; + $revision['description'] = $description_revision; + $revision['primary key'] = array('entity_id', 'revision_id', 'deleted', 'delta', 'langcode'); + $revision['fields']['revision_id']['not null'] = TRUE; + $revision['fields']['revision_id']['description'] = 'The entity revision id this data is attached to'; + + return array( + static::_fieldTableName($field) => $current, + static::_fieldRevisionTableName($field) => $revision, + ); + } + + /** + * Generates a table name for a field data table. + * + * @private Calling this function circumvents the entity system and is + * strongly discouraged. This function is not considered part of the public + * API and modules relying on it might break even in minor releases. Only + * call this function to write a query that \Drupal::entityQuery() does not + * support. Always call entity_load() before using the data found in the + * table. + * + * @param \Drupal\field\FieldInterface $field + * The field object. + * + * @return string + * A string containing the generated name for the database table. + * + */ + static public function _fieldTableName(FieldInterface $field) { + if ($field['deleted']) { + // When a field is a deleted, the table is renamed to + // {field_deleted_data_FIELD_UUID}. To make sure we don't end up with + // table names longer than 64 characters, we hash the uuid and return the + // first 10 characters so we end up with a short unique ID. + return "field_deleted_data_" . substr(hash('sha256', $field['uuid']), 0, 10); + } + else { + return static::_truncateFieldTableName("{$field->entity_type}__{$field->name}", $field->uuid); + } + } + + /** + * Generates a table name for a field revision archive table. + * + * @private Calling this function circumvents the entity system and is + * strongly discouraged. This function is not considered part of the public + * API and modules relying on it might break even in minor releases. Only + * call this function to write a query that Drupal::entityQuery() does not + * support. Always call entity_load() before using the data found in the + * table. + * + * @param \Drupal\field\Plugin\Core\Entity\FieldInterface $field + * The field object. + * + * @return string + * A string containing the generated name for the database table. + */ + static public function _fieldRevisionTableName(FieldInterface $field) { + if ($field['deleted']) { + // When a field is a deleted, the table is renamed to + // {field_deleted_revision_FIELD_UUID}. To make sure we don't end up with + // table names longer than 64 characters, we hash the uuid and return the + // first 10 characters so we end up with a short unique ID. + return "field_deleted_revision_" . substr(hash('sha256', $field['uuid']), 0, 10); + } + else { + return static::_truncateFieldTableName("{$field->entity_type}_revision__{$field->name}", $field->uuid); + } + } + + /** + * Generates a safe and unanbiguous field table name for a condidate name. + * + * The method accounts for a maximum table name length of 64 characters, and + * adds a hash of the field UUID for disambiguation. + * + * @param string $table_name + * The candidate table name. + * @param string $field_uuid + * The UUID of the field. + * + * @return string + * The final table name. + */ + static protected function _truncateFieldTableName($table_name, $field_uuid) { + // Limit the string to 48 characters, keeping a 16 characters margin for db + // prefixes. + if (strlen($table_name) > 48) { + $table_name = substr($table_name, 0, 38) . substr(hash('sha256', $field_uuid), 0, 10); + } + return $table_name; + } + + /** + * Generates an index name for a field data table. + * + * @private Calling this function circumvents the entity system and is + * strongly discouraged. This function is not considered part of the public + * API and modules relying on it might break even in minor releases. + * + * @param \Drupal\field\Plugin\Core\Entity\FieldInterface $field + * The field structure + * @param string $index + * The name of the index. + * + * @return string + * A string containing a generated index name for a field data table that is + * unique among all other fields. + */ + static public function _fieldIndexName(FieldInterface $field, $index) { + return $field->getFieldName() . '_' . $index; + } + + /** + * Generates a column name for a field data table. + * + * @private Calling this function circumvents the entity system and is + * strongly discouraged. This function is not considered part of the public + * API and modules relying on it might break even in minor releases. Only + * call this function to write a query that \Drupal::entityQuery() does not + * support. Always call entity_load() before using the data found in the + * table. + * + * @param \Drupal\field\Plugin\Core\Entity\FieldInterface $field + * The field object. + * @param string $column + * The name of the column. + * + * @return string + * A string containing a generated column name for a field data table that is + * unique among all other fields. + */ + static public function _fieldColumnName(FieldInterface $field, $column) { + return in_array($column, Field::getReservedColumns()) ? $column : $field->getFieldName() . '_' . $column; + } + } diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php index 143a2ab..a2bf5d6 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity; use Drupal\Core\Language\Language; +use Drupal\field\FieldInfo; use PDO; use Drupal\Core\Entity\Query\QueryInterface; @@ -53,8 +54,8 @@ class DatabaseStorageControllerNG extends DatabaseStorageController { /** * Overrides DatabaseStorageController::__construct(). */ - public function __construct($entity_type, array $entity_info, Connection $database) { - parent::__construct($entity_type,$entity_info, $database); + public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info) { + parent::__construct($entity_type,$entity_info, $database, $field_info); $this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE; $this->entityClass = $this->entityInfo['class']; diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index ec05c1a..770b486 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -333,8 +333,7 @@ public function getTranslationLanguages($include_default = TRUE) { // Go through translatable properties and determine all languages for // which translated values are available. foreach (field_info_instances($this->entityType, $this->bundle()) as $field_name => $instance) { - $field = field_info_field($field_name); - if (field_is_translatable($this->entityType, $field) && isset($this->$field_name)) { + if (field_is_translatable($this->entityType, $instance->getField()) && isset($this->$field_name)) { foreach (array_filter($this->$field_name) as $langcode => $value) { $languages[$langcode] = TRUE; } diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php index ceb09de..b9e3da5 100644 --- a/core/lib/Drupal/Core/Entity/EntityFormController.php +++ b/core/lib/Drupal/Core/Entity/EntityFormController.php @@ -295,6 +295,7 @@ protected function actions(array $form, array &$form_state) { */ public function validate(array $form, array &$form_state) { $entity = $this->buildEntity($form, $form_state); + $entity_type = $entity->entityType(); $entity_langcode = $entity->language()->id; $violations = array(); @@ -311,9 +312,9 @@ public function validate(array $form, array &$form_state) { else { // For BC entities, iterate through each field instance and // instantiate NG items objects manually. - $definitions = \Drupal::entityManager()->getFieldDefinitions($entity->entityType(), $entity->bundle()); - foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $field_name => $instance) { - $langcode = field_is_translatable($entity->entityType(), $instance->getField()) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED; + $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $entity->bundle()); + foreach (field_info_instances($entity_type, $entity->bundle()) as $field_name => $instance) { + $langcode = field_is_translatable($entity_type, $instance->getField()) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED; // Create the field object. $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array(); @@ -330,7 +331,7 @@ public function validate(array $form, array &$form_state) { // Map errors back to form elements. if ($violations) { foreach ($violations as $field_name => $field_violations) { - $langcode = field_is_translatable($entity->entityType(), field_info_field($field_name)) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED; + $langcode = field_is_translatable($entity_type , field_info_field($entity_type, $field_name)) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED; $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state); $field_state['constraint_violations'] = $field_violations; field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state); @@ -459,9 +460,8 @@ protected function submitEntityLanguage(array $form, array &$form_state) { $current_langcode = $this->isDefaultFormLangcode($form_state) ? $form_state['values']['langcode'] : $this->getFormLangcode($form_state); foreach (field_info_instances($entity_type, $entity->bundle()) as $instance) { - $field_name = $instance['field_name']; - $field = field_info_field($field_name); - + $field = $instance->getField(); + $field_name = $field->name; if (isset($form[$field_name]['#language'])) { $previous_langcode = $form[$field_name]['#language']; diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index a662259..7a807ac 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -88,6 +88,15 @@ class EntityManager extends PluginManagerBase { protected $fieldDefinitions; /** + * The root paths. + * + * @see \Drupal\Core\Entity\EntityManager::__construct(). + * + * @var \Traversable + */ + protected $namespaces; + + /** * Constructs a new Entity plugin manager. * * @param \Traversable $namespaces @@ -104,21 +113,45 @@ class EntityManager extends PluginManagerBase { */ public function __construct(\Traversable $namespaces, ContainerInterface $container, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManager $language_manager) { // Allow the plugin definition to be altered by hook_entity_info_alter(). - $annotation_namespaces = array( - 'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib', - ); $this->moduleHandler = $module_handler; $this->cache = $cache; $this->languageManager = $language_manager; + $this->namespaces = $namespaces; - $this->discovery = new AnnotatedClassDiscovery('Plugin/Core/Entity', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\EntityType'); + $this->doDiscovery($namespaces); + $this->factory = new DefaultFactory($this->discovery); + $this->container = $container; + } + + protected function doDiscovery($namespaces) { + $annotation_namespaces = array( + 'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib', + ); + $this->discovery = new AnnotatedClassDiscovery('Plugin\Core/Entity', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\EntityType'); $this->discovery = new InfoHookDecorator($this->discovery, 'entity_info'); $this->discovery = new AlterDecorator($this->discovery, 'entity_info'); $this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE)); + } - $this->factory = new DefaultFactory($this->discovery); - $this->container = $container; + /** + * Add more namespaces to the entity manager. + * + * This is usually only necessary for uninstall purposes. + * + * @todo Remove this method, along with doDiscovery(), when + * https://drupal.org/node/1199946 is fixed. + * + * @param \Traversable $namespaces + * + * @see comment_uninstall() + */ + public function addNamespaces(\Traversable $namespaces) { + reset($this->namespaces); + $iterator = new \AppendIterator; + $iterator->append(new \IteratorIterator($this->namespaces)); + $iterator->append($namespaces); + $this->doDiscovery($iterator); } /** @@ -153,6 +186,9 @@ public function hasController($entity_type, $controller_type) { */ public function getControllerClass($entity_type, $controller_type, $nested = NULL) { $definition = $this->getDefinition($entity_type); + if (!$definition) { + throw new \InvalidArgumentException(sprintf('The %s entity type does not exist.', $entity_type)); + } $definition = $definition['controllers']; if (!$definition) { throw new \InvalidArgumentException(sprintf('The entity type (%s) does not exist.', $entity_type)); diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php index 988afa7..22eb472 100644 --- a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php +++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php @@ -234,6 +234,22 @@ public function invokeFieldItemPrepareCache(EntityInterface $entity) { } /** + * Invokes a hook on behalf of the entity. + * + * @param string $hook + * One of 'presave', 'insert', 'update', 'predelete', 'delete', or + * 'revision_delete'. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + */ + protected function invokeHook($hook, EntityInterface $entity) { + // Invoke the hook. + module_invoke_all($this->entityType . '_' . $hook, $entity); + // Invoke the respective entity-level hook. + module_invoke_all('entity_' . $hook, $entity, $this->entityType); + } + + /** * Checks translation statuses and invoke the related hooks if needed. * * @param \Drupal\Core\Entity\EntityInterface $entity diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php new file mode 100644 index 0000000..e278af3 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php @@ -0,0 +1,310 @@ +entityInfo['fieldable']) && method_exists($this, $method)) { + $this->$method($entity); + } + parent::invokeHook($hook, $entity); + } + + /** + * Loads fields for the current revisions of a group of entities. + * + * Loads all fields for each entity object in a group of a single entity type. + * The loaded field values are added directly to the entity objects. + * + * @param array $entities + * An array of entities for which to load fields, keyed by entity ID. + * @param int $age + * FIELD_LOAD_CURRENT to load the most recent revision for all fields, or + * FIELD_LOAD_REVISION to load the version indicated by each entity. + */ + protected function fieldLoad($entities, $age) { + if (empty($entities)) { + return; + } + + // Only the most current revision of non-deleted fields for cacheable entity + // types can be cached. + $load_current = $age == FIELD_LOAD_CURRENT; + $info = entity_get_info($this->entityType); + $use_cache = $load_current && $info['field_cache']; + + // Ensure we are working with a BC mode entity. + foreach ($entities as $id => $entity) { + $entities[$id] = $entity->getBCEntity(); + } + + // Assume all entities will need to be queried. Entities found in the cache + // will be removed from the list. + $queried_entities = $entities; + + // Fetch available entities from cache, if applicable. + if ($use_cache) { + // Build the list of cache entries to retrieve. + $cids = array(); + foreach ($entities as $id => $entity) { + $cids[] = "field:{$this->entityType}:$id"; + } + $cache = cache('field')->getMultiple($cids); + // Put the cached field values back into the entities and remove them from + // the list of entities to query. + foreach ($entities as $id => $entity) { + $cid = "field:{$this->entityType}:$id"; + if (isset($cache[$cid])) { + unset($queried_entities[$id]); + foreach ($cache[$cid]->data as $field_name => $values) { + $entity->$field_name = $values; + } + } + } + } + + // Fetch other entities from their storage location. + if ($queried_entities) { + // The invoke order is: + // - Entity storage controller's doFieldLoad() method + // - Field class's prepareCache() method. + // - hook_field_attach_load() + + // Let the storage controller actually load the values. + $this->doFieldLoad($queried_entities, $age); + + // Invoke the field type's prepareCache() method. + foreach ($queried_entities as $entity) { + \Drupal::entityManager() + ->getStorageController($this->entityType) + ->invokeFieldItemPrepareCache($entity); + } + + // Invoke hook_field_attach_load(): let other modules act on loading the + // entity. + \Drupal::moduleHandler()->invokeAll('field_attach_load', array($this->entityType, $queried_entities, $age)); + + // Build cache data. + if ($use_cache) { + foreach ($queried_entities as $id => $entity) { + $data = array(); + $instances = field_info_instances($this->entityType, $entity->bundle()); + foreach ($instances as $instance) { + $data[$instance['field_name']] = $queried_entities[$id]->{$instance['field_name']}; + } + $cid = "field:{$this->entityType}:$id"; + cache('field')->set($cid, $data); + } + } + } + } + + /** + * Save field data for a new entity. + * + * The passed-in entity must already contain its id and (if applicable) + * revision id attributes. + * + * It should be enough to override doFieldInsert() instead of this method. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity with fields to save. + */ + protected function fieldInsert(EntityInterface $entity) { + // Ensure we are working with a BC mode entity. + $entity = $entity->getBCEntity(); + + $this->doFieldInsert($entity); + } + + /** + * Saves field data for an existing entity. + * + * It should be enough to override doFieldUpdate() instead of this method. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity with fields to save. + */ + protected function fieldUpdate(EntityInterface $entity) { + // Ensure we are working with a BC mode entity. + $entity = $entity->getBCEntity(); + + $this->doFieldUpdate($entity); + + $entity_info = $entity->entityInfo(); + if ($entity_info['field_cache']) { + cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id()); + } + } + + /** + * Deletes field data for an existing entity. + * + * This deletes all revisions of field data for the entity. + * + * It should be enough to override doFieldDelete() instead of this method. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity whose field data to delete. + */ + protected function fieldDelete(EntityInterface $entity) { + // Ensure we are working with a BC mode entity. + $entity = $entity->getBCEntity(); + + $this->doFieldDelete($entity); + + $entity_info = $entity->entityInfo(); + if ($entity_info['field_cache']) { + cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id()); + } + } + + /** + * Delete field data for a single revision of an existing entity. + * + * The passed $entity must have a revision ID attribute. + * + * It should be enough to override doFieldRevisionDelete() instead of this + * method. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity with fields to save. + */ + protected function fieldRevisionDelete(EntityInterface $entity) { + $this->dofieldRevisionDelete($entity->getBCEntity()); + } + + /** + * Load configurable fields from storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + */ + protected function doFieldLoad($queried_entities, $age) { } + + /** + * Insert configurable fields into storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + */ + protected function doFieldInsert(EntityInterface $entity) { } + + /** + * Update configurable fields in storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + */ + protected function doFieldUpdate(EntityInterface $entity) { } + + /** + * Delete configurable fields from storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + */ + protected function doFieldDelete(EntityInterface $entity) { } + + /** + * Delete specific revision of configurable fields from storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + */ + protected function doFieldRevisionDelete(EntityInterface $entity) { } + + /** + * {@inheritdoc} + */ + public function handleFieldCreate(FieldInterface $field) { } + + /** + * {@inheritdoc} + */ + public function handleFieldUpdate(FieldInterface $field, FieldInterface $original) { } + + /** + * {@inheritdoc} + */ + public function handleFieldDelete(FieldInterface $field) { } + + /** + * {@inheritdoc} + */ + public function handleInstanceCreate(FieldInstanceInterface $instance) { } + + /** + * {@inheritdoc} + */ + public function handleInstanceUpdate(FieldInstanceInterface $instance, FieldInstanceInterface $orignal) { } + + /** + * {@inheritdoc} + */ + public function handleInstanceDelete(FieldInstanceInterface $instance) { } + + /** + * {@inheritdoc} + */ + public function handleBundleCreate($bundle) { } + + /** + * {@inheritdoc} + */ + public function handleBundleRename($bundle, $bundle_new) { } + + /** + * {@inheritdoc} + */ + public function handleBundleDelete($bundle) { } + + /** + * {@inheritdoc} + */ + public function fieldPurgeData(EntityInterface $entity, FieldInstanceInterface $instance) { + $values = $this->fieldValues($entity, $instance); + $field = $instance->getField(); + foreach ($values as $value) { + $definition = _field_generate_entity_field_definition($field, $instance); + $items = \Drupal::typedData()->create($definition, $value, $field->getFieldName(), $entity); + $items->delete(); + } + } + + /** + * Gets the field values for a single field of a single entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * @param \Drupal\field\FieldInstanceInterface $instance + * The field instance. + * + * @return array + * The field values. + */ + protected function fieldValues(EntityInterface $entity, FieldInstanceInterface $instance) { + return array(); + } + + /** + * {@inheritdoc} + */ + public function fieldPurge(FieldInterface $field) { } + +} diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php new file mode 100644 index 0000000..71cb93d --- /dev/null +++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php @@ -0,0 +1,106 @@ +ensureFieldTable($index_prefix, $field, $type, $langcode, $base_table, $entity_id_field, $field_id_field); - $sql_column = _field_sql_storage_columnname($field['field_name'], $column); + $sql_column = DatabaseStorageController::_fieldColumnName($field, $column); } // This is an entity property (non-configurable field). else { @@ -242,12 +243,12 @@ protected function ensureEntityTable($index_prefix, $property, $type, $langcode, protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $base_table, $entity_id_field, $field_id_field) { $field_name = $field['field_name']; if (!isset($this->fieldTables[$index_prefix . $field_name])) { - $table = $this->sqlQuery->getMetaData('age') == FIELD_LOAD_CURRENT ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field); + $table = $this->sqlQuery->getMetaData('age') == FIELD_LOAD_CURRENT ? DatabaseStorageController::_fieldTableName($field) : DatabaseStorageController::_fieldRevisionTableName($field); if ($field['cardinality'] != 1) { $this->sqlQuery->addMetaData('simple_query', FALSE); } $entity_type = $this->sqlQuery->getMetaData('entity_type'); - $this->fieldTables[$index_prefix . $field_name] = $this->addJoin($type, $table, "%alias.$field_id_field = $base_table.$entity_id_field AND %alias.entity_type = '$entity_type'", $langcode); + $this->fieldTables[$index_prefix . $field_name] = $this->addJoin($type, $table, "%alias.$field_id_field = $base_table.$entity_id_field", $langcode); } return $this->fieldTables[$index_prefix . $field_name]; } diff --git a/core/modules/block/block.install b/core/modules/block/block.install index 3c1755f..4363ef8 100644 --- a/core/modules/block/block.install +++ b/core/modules/block/block.install @@ -35,6 +35,10 @@ function block_update_dependencies() { $dependencies['block'][8005] = array( 'user' => 8016, ); + // Migrate custom blocks after field storage has been reorganized. + $dependencies['block'][8008] = array( + 'field' => 8006, + ); return $dependencies; } @@ -247,9 +251,9 @@ function block_update_8008() { // First, create the body field. $body_field = array( - 'id' => 'block_body', + 'name' => 'block_body', + 'entity_type' => 'custom_block', 'type' => 'text_with_summary', - 'entity_types' => array('custom_block'), 'module' => 'text', 'cardinality' => 1, 'schema' => array( @@ -283,8 +287,8 @@ function block_update_8008() { ); _update_8003_field_create_field($body_field); + $instance = array( - 'id' => 'custom_block.basic.block_body', 'entity_type' => 'custom_block', 'bundle' => 'basic', 'label' => 'Block body', @@ -338,7 +342,7 @@ function block_update_8008() { ); // This is a core update and no contrib modules are enabled yet, so // we can assume default field storage for a faster update. - _update_8000_field_sql_storage_write('custom_block', 'basic', $block->bid, $block->bid, 'block_body', $data); + _update_8006_field_write_data_sql('custom_block', 'basic', $block->bid, $block->bid, 'block_body', $data); $sandbox['last'] = $block->bid; $sandbox['count'] += 1; diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module index 2752ee8..7ae5a8f 100644 --- a/core/modules/block/custom_block/custom_block.module +++ b/core/modules/block/custom_block/custom_block.module @@ -181,13 +181,13 @@ function custom_block_entity_bundle_info() { */ function custom_block_add_body_field($block_type_id, $label = 'Block body') { // Add or remove the body field, as needed. - $field = field_info_field('block_body'); + $field = field_info_field('custom_block', 'block_body'); $instance = field_info_instance('custom_block', 'block_body', $block_type_id); if (empty($field)) { $field = entity_create('field_entity', array( - 'field_name' => 'block_body', + 'name' => 'block_body', + 'entity_type' => 'custom_block', 'type' => 'text_with_summary', - 'entity_types' => array('custom_block'), )); $field->save(); } diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php index 0698234..5fb5330 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php @@ -16,7 +16,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageControllerNG class, * adding required special handling for custom block entities. */ -class CustomBlockStorageController extends DatabaseStorageControllerNG implements EntityStorageControllerInterface { +class CustomBlockStorageController extends DatabaseStorageControllerNG { /** * Overrides \Drupal\Core\Entity\DatabaseStorageController::attachLoad(). diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php index da5ac4f..b2de855 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php @@ -65,13 +65,14 @@ public function testBlockFields() { // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => drupal_strtolower($this->randomName()), + 'name' => drupal_strtolower($this->randomName()), + 'entity_type' => 'custom_block', 'type' => 'link', 'cardinality' => 2, )); $this->field->save(); $this->instance = entity_create('field_instance', array( - 'field_name' => $this->field->id(), + 'field_name' => $this->field->name, 'entity_type' => 'custom_block', 'bundle' => 'link', 'settings' => array( diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install index efaf9f3..04e1291 100644 --- a/core/modules/comment/comment.install +++ b/core/modules/comment/comment.install @@ -12,6 +12,10 @@ function comment_uninstall() { // Remove variables. variable_del('comment_block_count'); $node_types = array_keys(node_type_get_types()); + Drupal::entityManager()->addNamespaces(new ArrayIterator(array( + 'Drupal\comment' => DRUPAL_ROOT . '/core/modules/comment/lib', + ))); + drupal_classloader_register('comment', 'core/modules/comment'); foreach ($node_types as $node_type) { entity_invoke_bundle_hook('delete', 'comment', 'comment_node_' . $node_type); variable_del('comment_' . $node_type); diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index b38892d..6944d8a 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -322,11 +322,11 @@ function comment_node_type_delete($info) { */ function _comment_body_field_create($info) { // Create the field if needed. - if (!field_read_field('comment_body', array('include_inactive' => TRUE))) { + if (!field_read_field('comment', 'comment_body', array('include_inactive' => TRUE))) { $field = entity_create('field_entity', array( - 'field_name' => 'comment_body', + 'name' => 'comment_body', 'type' => 'text_long', - 'entity_types' => array('comment'), + 'entity_type' => 'comment', )); $field->save(); } diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php index 8928f4f..f9d25f1 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php @@ -45,7 +45,7 @@ function testCommentDefaultFields() { } // Check that the 'comment_body' field is deleted. - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $this->assertTrue(empty($field), 'The comment_body field was deleted'); // Create a new content type. @@ -54,7 +54,7 @@ function testCommentDefaultFields() { // Check that the 'comment_body' field exists and has an instance on the // new comment bundle. - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $this->assertTrue($field, 'The comment_body field exists'); $instances = field_info_instances('comment'); $this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), format_string('The comment_body field is present for comments on type @type', array('@type' => $type_name))); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php index 84a080e..4064b22 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php @@ -71,7 +71,7 @@ function setUp() { $this->drupalPost("user/" . $admin_user->id() . "/edit", $edit, t('Save')); // Make comment body translatable. - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $field['translatable'] = TRUE; $field->save(); $this->assertTrue(field_is_translatable('comment', $field), 'Comment body is translatable.'); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php index 296a3e2..e935ca6 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php @@ -63,7 +63,7 @@ protected function getTranslatorPermissions() { */ function setupTestFields() { parent::setupTestFields(); - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $field['translatable'] = TRUE; $field->save(); } diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php index 48e749f..127a611 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php @@ -42,7 +42,7 @@ protected function setUp() { */ function testCommentUninstallWithField() { // Ensure that the field exists before uninstallation. - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $this->assertNotNull($field, 'The comment_body field exists.'); // Uninstall the comment module which should trigger field deletion. @@ -50,7 +50,7 @@ function testCommentUninstallWithField() { $this->container->get('module_handler')->uninstall(array('comment')); // Check that the field is now deleted. - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $this->assertNull($field, 'The comment_body field has been deleted.'); } @@ -60,12 +60,12 @@ function testCommentUninstallWithField() { */ function testCommentUninstallWithoutField() { // Manually delete the comment_body field before module uninstallation. - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $this->assertNotNull($field, 'The comment_body field exists.'); $field->delete(); // Check that the field is now deleted. - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $this->assertNull($field, 'The comment_body field has been deleted.'); // Ensure that uninstallation succeeds even if the field has already been diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php index 79f22a9..6d4ff98 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php @@ -21,7 +21,7 @@ class ConfigLocaleOverride extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('locale', 'config_test', 'user', 'language', 'system'); + public static $modules = array('locale', 'config_test', 'user', 'language', 'system', 'field'); public static function getInfo() { return array( diff --git a/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php b/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php index c9e2e5d..271acfd 100644 --- a/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php +++ b/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php @@ -21,7 +21,7 @@ class MessageEntityTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('system', 'contact'); + public static $modules = array('system', 'contact', 'field'); public static function getInfo() { return array( diff --git a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php index 166a64b..18e70af 100644 --- a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php +++ b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php @@ -7,6 +7,7 @@ namespace Drupal\contact\Tests\Views; +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\views\Tests\ViewTestBase; /** @@ -40,13 +41,14 @@ protected function setUp() { parent::setUp(); $this->field = entity_create('field_entity', array( - 'field_name' => strtolower($this->randomName()), + 'name' => strtolower($this->randomName()), + 'entity_type' => 'contact_message', 'type' => 'text' )); $this->field->save(); entity_create('field_instance', array( - 'field_name' => $this->field->id(), + 'field_name' => $this->field->name, 'entity_type' => 'contact_message', 'bundle' => 'contact_message', ))->save(); @@ -58,14 +60,14 @@ protected function setUp() { * Tests the views data generation. */ public function testViewsData() { - $table_name = _field_sql_storage_tablename($this->field); + $table_name = DatabaseStorageController::_fieldTableName($this->field); $data = $this->container->get('views.views_data')->get($table_name); // Test that the expected data array is returned. $expected = array('', '_value', '_format'); $this->assertEqual(count($data), count($expected), 'The expected amount of array keys were found.'); foreach ($expected as $suffix) { - $this->assertTrue(isset($data[$this->field->id() . $suffix])); + $this->assertTrue(isset($data[$this->field->name . $suffix])); } $this->assertTrue(empty($data['table']['join']), 'The field is not joined to the non existent contact message base table.'); } diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc index 63e71fc..a4186ba 100644 --- a/core/modules/content_translation/content_translation.admin.inc +++ b/core/modules/content_translation/content_translation.admin.inc @@ -95,7 +95,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$ // @todo Exploit field definitions once all core entities and field // types are migrated to the Entity Field API. foreach ($fields as $field_name => $instance) { - $field = field_info_field($field_name); + $field = $instance->getField(); $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array( '#label' => $instance['label'], '#type' => 'checkbox', @@ -326,7 +326,7 @@ function _content_translation_update_field_translatability($settings) { foreach ($bundle_settings['fields'] as $field_name => $translatable) { // If a field is enabled for translation for at least one instance we // need to mark it as translatable. - $fields[$field_name] = $translatable || !empty($fields[$field_name]); + $fields[$entity_type][$field_name] = $translatable || !empty($fields[$entity_type][$field_name]); } } // @todo Store non-configurable field settings to be able to alter their @@ -335,22 +335,24 @@ function _content_translation_update_field_translatability($settings) { } $operations = array(); - foreach ($fields as $field_name => $translatable) { - $field = field_info_field($field_name); - if ($field['translatable'] != $translatable) { - // If a field is untranslatable, it can have no data except under - // Language::LANGCODE_NOT_SPECIFIED. Thus we need a field to be translatable before - // we convert data to the entity language. Conversely we need to switch - // data back to Language::LANGCODE_NOT_SPECIFIED before making a field - // untranslatable lest we lose information. - $field_operations = array( - array('content_translation_translatable_switch', array($translatable, $field_name)), - ); - if ($field->hasData()) { - $field_operations[] = array('content_translation_translatable_batch', array($translatable, $field_name)); - $field_operations = $translatable ? $field_operations : array_reverse($field_operations); + foreach ($fields as $entity_type => $entity_type_fields) { + foreach ($entity_type_fields as $field_name => $translatable) { + $field = field_info_field($entity_type, $field_name); + if ($field['translatable'] != $translatable) { + // If a field is untranslatable, it can have no data except under + // Language::LANGCODE_NOT_SPECIFIED. Thus we need a field to be translatable before + // we convert data to the entity language. Conversely we need to switch + // data back to Language::LANGCODE_NOT_SPECIFIED before making a field + // untranslatable lest we lose information. + $field_operations = array( + array('content_translation_translatable_switch', array($translatable, $entity_type, $field_name)), + ); + if ($field->hasData()) { + $field_operations[] = array('content_translation_translatable_batch', array($translatable, $field_name)); + $field_operations = $translatable ? $field_operations : array_reverse($field_operations); + } + $operations = array_merge($operations, $field_operations); } - $operations = array_merge($operations, $field_operations); } } @@ -374,11 +376,13 @@ function _content_translation_update_field_translatability($settings) { * @param bool $translatable * Indicator of whether the field should be made translatable (TRUE) or * untranslatble (FALSE). + * @param string $entity_type + * Field entity type. * @param string $field_name * Field machine name. */ -function content_translation_translatable_switch($translatable, $field_name) { - $field = field_info_field($field_name); +function content_translation_translatable_switch($translatable, $entity_type, $field_name) { + $field = field_info_field($entity_type, $field_name); if ($field['translatable'] !== $translatable) { $field['translatable'] = $translatable; $field->save(); @@ -395,10 +399,6 @@ function content_translation_translatable_switch($translatable, $field_name) { * Field machine name. */ function content_translation_translatable_batch($translatable, $field_name, &$context) { - $field = field_info_field($field_name); - $column = isset($field['columns']['value']) ? 'value' : key($field['columns']); - $query_field = "$field_name.$column"; - // Determine the entity types to act on. $entity_types = array(); foreach (field_info_instances() as $entity_type => $info) { @@ -417,6 +417,10 @@ function content_translation_translatable_batch($translatable, $field_name, &$co $context['sandbox']['max'] = 0; foreach ($entity_types as $entity_type) { + $field = field_info_field($entity_type, $field_name); + $column = isset($field['columns']['value']) ? 'value' : key($field['columns']); + $query_field = "$field_name.$column"; + // How many entities will need processing? $query = Drupal::entityQuery($entity_type); $count = $query @@ -444,6 +448,9 @@ function content_translation_translatable_batch($translatable, $field_name, &$co $info = entity_get_info($entity_type); $offset = $context['sandbox']['progress_entity_type'][$entity_type]; $query = Drupal::entityQuery($entity_type); + $field = field_info_field($entity_type, $field_name); + $column = isset($field['columns']['value']) ? 'value' : key($field['columns']); + $query_field = "$field_name.$column"; $result = $query ->exists($query_field) ->sort($info['entity_keys']['id']) diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index 56d9508..ba5c9f5 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -200,7 +200,7 @@ function content_translation_menu() { } } - $items['admin/config/regional/content_translation/translatable/%'] = array( + $items['admin/config/regional/content_translation/translatable/%/%'] = array( 'title' => 'Confirm change in translatability.', 'description' => 'Confirm page for changing field translatability.', 'route_name' => 'content_translation_translatable', @@ -621,7 +621,7 @@ function content_translation_form_alter(array &$form, array &$form_state) { else { foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { $field_name = $instance['field_name']; - $field = field_info_field($field_name); + $field = $instance->getField(); $form[$field_name]['#multilingual'] = !empty($field['translatable']); } } @@ -808,6 +808,7 @@ function content_translation_field_extra_fields() { */ function content_translation_form_field_ui_field_edit_form_alter(array &$form, array &$form_state, $form_id) { $field = $form['#field']; + $entity_type = $field['entity_type']; $field_name = $field['field_name']; $translatable = $field['translatable']; $label = t('Field translation'); @@ -821,7 +822,7 @@ function content_translation_form_field_ui_field_edit_form_alter(array &$form, a '#type' => 'link', '#prefix' => t('This field has data in existing content.') . ' ', '#title' => !$translatable ? t('Enable translation') : t('Disable translation'), - '#href' => 'admin/config/regional/content_translation/translatable/' . $field_name, + '#href' => "admin/config/regional/content_translation/translatable/$entity_type/$field_name", '#options' => array('query' => drupal_get_destination()), '#access' => user_access('administer content translation'), ), @@ -1022,7 +1023,7 @@ function content_translation_save_settings($settings) { // Store whether fields have translation enabled or not. if (!empty($bundle_settings['columns'])) { foreach ($bundle_settings['columns'] as $field_name => $column_settings) { - $field = field_info_field($field_name); + $field = field_info_field($entity_type, $field_name); $instance = field_info_instance($entity_type, $field_name, $bundle); if ($field['translatable']) { $instance['settings']['translation_sync'] = $column_settings; diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc index e277791..966d259 100644 --- a/core/modules/content_translation/content_translation.pages.inc +++ b/core/modules/content_translation/content_translation.pages.inc @@ -40,8 +40,7 @@ function content_translation_overview(EntityInterface $entity) { // Determine whether the current entity is translatable. $translatable = FALSE; foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { - $field_name = $instance['field_name']; - $field = field_info_field($field_name); + $field = $instance->getField(); if ($field['translatable']) { $translatable = TRUE; break; @@ -246,7 +245,7 @@ function content_translation_prepare_translation(EntityInterface $entity, Langua else { $instances = field_info_instances($entity->entityType(), $entity->bundle()); foreach ($instances as $field_name => $instance) { - $field = field_info_field($field_name); + $field = $instance->getField(); if (!empty($field['translatable'])) { $value = $entity->get($field_name); $value[$target->id] = isset($value[$source->id]) ? $value[$source->id] : array(); diff --git a/core/modules/content_translation/content_translation.routing.yml b/core/modules/content_translation/content_translation.routing.yml index d7d55a1..64f210c 100644 --- a/core/modules/content_translation/content_translation.routing.yml +++ b/core/modules/content_translation/content_translation.routing.yml @@ -1,5 +1,5 @@ content_translation_translatable: - pattern: 'admin/config/regional/content_translation/translatable/{field_name}' + pattern: 'admin/config/regional/content_translation/translatable/{entity_type}/{field_name}' defaults: _form: 'Drupal\content_translation\Form\TranslatableForm' requirements: diff --git a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php index 08cc693..56892de 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php @@ -51,7 +51,7 @@ public function removeTranslation(EntityInterface $entity, $langcode) { // Remove field translations. foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { $field_name = $instance['field_name']; - $field = field_info_field($field_name); + $field = $instance->getField(); if ($field['translatable']) { $entity->{$field_name}[$langcode] = array(); } diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php b/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php index bdeb983..ceb771c 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php @@ -8,7 +8,8 @@ namespace Drupal\content_translation\Form; use Drupal\Core\Form\ConfirmFormBase; -use Drupal\field\Field; +use Drupal\field\Plugin\Core\Entity\Field; +use Drupal\field\field as FieldInfo; /** * Provides a confirm form for changing translatable status on translation @@ -19,9 +20,9 @@ class TranslatableForm extends ConfirmFormBase { /** * The field info we are changing translatable status on. * - * @var array. + * @var \Drupal\field\Plugin\Core\Entity\Field */ - protected $fieldInfo; + protected $field; /** * The field name we are changing translatable @@ -42,7 +43,7 @@ public function getFormID() { * {@inheritdoc} */ public function getQuestion() { - if ($field['translatable']) { + if ($this->field['translatable']) { $question = t('Are you sure you want to disable translation for the %name field?', array('%name' => $this->fieldName)); } else { @@ -58,7 +59,7 @@ public function getDescription() { $description = t('By submitting this form these changes will apply to the %name field everywhere it is used.', array('%name' => $this->fieldName) ); - $description .= $this->fieldInfo['translatable'] ? "
" . t("All the existing translations of this field will be deleted.
This action cannot be undone.") : ''; + $description .= $this->field['translatable'] ? "
" . t("All the existing translations of this field will be deleted.
This action cannot be undone.") : ''; return $description; } @@ -71,12 +72,14 @@ public function getCancelPath() { /** * {@inheritdoc} + * @param string $entity_type + * The entity type. * @param string $field_name * The field name. */ - public function buildForm(array $form, array &$form_state, $field_name = NULL) { + public function buildForm(array $form, array &$form_state, $entity_type = NULL, $field_name = NULL) { $this->fieldName = $field_name; - $this->fieldInfo = Field::fieldInfo($field_name); + $this->fieldInfo = FieldInfo::fieldInfo()->getField($entity_type, $field_name); return parent::buildForm($form, $form_state); } @@ -127,6 +130,7 @@ public function submitForm(array &$form, array &$form_state) { array( 'content_translation_translatable_switch', array( !$translatable, + $this->field['entity_type'], $this->fieldName, ), ), diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php index c17bd06..f4e2f13 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php @@ -89,7 +89,7 @@ function testSettingsUI() { ); $this->assertSettings('comment', 'comment_node_article', TRUE, $edit); field_info_cache_clear(); - $field = field_info_field('comment_body'); + $field = field_info_field('comment', 'comment_body'); $this->assertTrue($field['translatable'], 'Comment body is translatable.'); // Test that language settings are correctly stored. diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php index 54d234e..c813790 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php @@ -57,7 +57,8 @@ protected function setupTestFields() { $this->cardinality = 3; entity_create('field_entity', array( - 'field_name' => $this->fieldName, + 'name' => $this->fieldName, + 'entity_type' => $this->entityType, 'type' => 'image', 'cardinality' => $this->cardinality, 'translatable' => TRUE, diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php index b635c45..0ea5ae6 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php @@ -162,8 +162,9 @@ protected function setupTestFields() { $this->fieldName = 'field_test_et_ui_test'; entity_create('field_entity', array( - 'field_name' => $this->fieldName, + 'name' => $this->fieldName, 'type' => 'text', + 'entity_type' => $this->entityType, 'cardinality' => 1, 'translatable' => TRUE, ))->save(); diff --git a/core/modules/datetime/lib/Drupal/datetime/Tests/DateTimeItemTest.php b/core/modules/datetime/lib/Drupal/datetime/Tests/DateTimeItemTest.php index 16731a2..f755730 100644 --- a/core/modules/datetime/lib/Drupal/datetime/Tests/DateTimeItemTest.php +++ b/core/modules/datetime/lib/Drupal/datetime/Tests/DateTimeItemTest.php @@ -36,8 +36,9 @@ public function setUp() { // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => 'field_datetime', + 'name' => 'field_datetime', 'type' => 'datetime', + 'entity_type' => 'entity_test', 'settings' => array('datetime_type' => 'date'), )); $this->field->save(); diff --git a/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php index af66e0d..3c739be 100644 --- a/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php +++ b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php @@ -57,13 +57,14 @@ function setUp() { // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => drupal_strtolower($this->randomName()), + 'name' => drupal_strtolower($this->randomName()), + 'entity_type' => 'entity_test', 'type' => 'datetime', 'settings' => array('datetime_type' => 'date'), )); $this->field->save(); $this->instance = entity_create('field_instance', array( - 'field_name' => $this->field->id(), + 'field_name' => $this->field->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', 'settings' => array( @@ -73,7 +74,7 @@ function setUp() { $this->instance->save(); entity_get_form_display($this->instance->entity_type, $this->instance->bundle, 'default') - ->setComponent($this->field->id(), array( + ->setComponent($this->field->name, array( 'type' => 'datetime_default', )) ->save(); @@ -84,7 +85,7 @@ function setUp() { 'settings' => array('format_type' => 'medium'), ); entity_get_display($this->instance->entity_type, $this->instance->bundle, 'full') - ->setComponent($this->field->id(), $this->display_options) + ->setComponent($this->field->name, $this->display_options) ->save(); } @@ -92,7 +93,7 @@ function setUp() { * Tests date field functionality. */ function testDateField() { - $field_name = $this->field->id(); + $field_name = $this->field->name; // Display creation form. $this->drupalGet('entity_test/add'); @@ -160,7 +161,7 @@ function testDateField() { * Tests date and time field. */ function testDatetimeField() { - $field_name = $this->field->id(); + $field_name = $this->field->name; // Change the field to a datetime field. $this->field['settings']['datetime_type'] = 'datetime'; $this->field->save(); @@ -229,7 +230,7 @@ function testDatetimeField() { * Tests Date List Widget functionality. */ function testDatelistWidget() { - $field_name = $this->field->id(); + $field_name = $this->field->name; // Change the field to a datetime field. $this->field->settings['datetime_type'] = 'datetime'; $this->field->save(); @@ -299,7 +300,7 @@ function testDefaultValue() { // Change the field to a datetime field. $this->field->settings['datetime_type'] = 'datetime'; $this->field->save(); - $field_name = $this->field->id(); + $field_name = $this->field->name; // Set the default value to 'now'. $this->instance->settings['default_value'] = 'now'; @@ -341,7 +342,7 @@ function testInvalidField() { // Change the field to a datetime field. $this->field->settings['datetime_type'] = 'datetime'; $this->field->save(); - $field_name = $this->field->id(); + $field_name = $this->field->name; // Display creation form. $this->drupalGet('entity_test/add'); diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php index 9559be7..01dcf0a 100644 --- a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php +++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php @@ -42,7 +42,8 @@ public function access(Route $route, Request $request) { * {@inheritdoc} */ public function accessEditEntityField(EntityInterface $entity, $field_name) { - return $entity->access('update') && ($field = field_info_field($field_name)) && field_access('edit', $field, $entity->entityType(), $entity); + $entity_type = $entity->entityType(); + return $entity->access('update') && ($field = field_info_field($entity_type, $field_name)) && field_access('edit', $field, $entity_type, $entity); } /** diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php index 649f033..a7d38af 100644 --- a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php +++ b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php @@ -19,7 +19,7 @@ class EditTestBase extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('system', 'entity', 'entity_test', 'field', 'field_sql_storage', 'field_test', 'number', 'text', 'edit'); + public static $modules = array('system', 'entity', 'entity_test', 'field', 'field_test', 'number', 'text', 'edit'); /** * Sets the default field storage backend for fields created during tests. */ @@ -55,7 +55,8 @@ function setUp() { function createFieldWithInstance($field_name, $type, $cardinality, $label, $instance_settings, $widget_type, $widget_settings, $formatter_type, $formatter_settings) { $field = $field_name . '_field'; $this->$field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => $type, 'cardinality' => $cardinality, )); diff --git a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php index 2d76d76..25e599b 100644 --- a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php +++ b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php @@ -62,7 +62,8 @@ function testEmailField() { // Create a field with settings to validate. $field_name = drupal_strtolower($this->randomName()); $this->field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'email', )); $this->field->save(); diff --git a/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php b/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php index 7e72163..b4a1bfe 100644 --- a/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php +++ b/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php @@ -36,7 +36,8 @@ public function setUp() { // Create an email field and instance for validation. entity_create('field_entity', array( - 'field_name' => 'field_email', + 'name' => 'field_email', + 'entity_type' => 'entity_test', 'type' => 'email', ))->save(); entity_create('field_instance', array( diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php index 6a1c9de..128bc7c 100644 --- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php +++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php @@ -209,7 +209,7 @@ public function setComponent($name, array $options = array()) { } if ($instance = field_info_instance($this->targetEntityType, $name, $this->bundle)) { - $field = field_info_field($instance['field_name']); + $field = $instance->getField(); $options = $this->pluginManager->prepareConfiguration($field['type'], $options); // Clear the persisted plugin, if any. diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php index fdeaa1b..637489b 100644 --- a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php +++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php @@ -131,7 +131,7 @@ public function testExtraFieldComponent() { * Tests the behavior of a field component within an EntityDisplay object. */ public function testFieldComponent() { - $this->enableModules(array('field_sql_storage', 'field_test')); + $this->enableModules(array('field_test')); $display = entity_create('entity_display', array( 'targetEntityType' => 'entity_test', @@ -142,7 +142,8 @@ public function testFieldComponent() { $field_name = 'test_field'; // Create a field and an instance. $field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'test_field' )); $field->save(); @@ -202,7 +203,7 @@ public function testFieldComponent() { * Tests renaming and deleting a bundle. */ public function testRenameDeleteBundle() { - $this->enableModules(array('field_sql_storage', 'field_test', 'node', 'system', 'text')); + $this->enableModules(array('field_test', 'node', 'system', 'text')); $this->installSchema('system', array('variable')); $this->installSchema('node', array('node')); @@ -239,12 +240,13 @@ public function testRenameDeleteBundle() { * Tests deleting field instance. */ public function testDeleteFieldInstance() { - $this->enableModules(array('field_sql_storage', 'field_test')); + $this->enableModules(array('field_test')); $field_name = 'test_field'; // Create a field and an instance. $field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'test_field' )); $field->save(); diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php index 8d7df46..595ac74 100644 --- a/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php +++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php @@ -53,7 +53,7 @@ public function testEntityGetFromDisplay() { * Tests the behavior of a field component within an EntityFormDisplay object. */ public function testFieldComponent() { - $this->enableModules(array('field_sql_storage', 'field_test')); + $this->enableModules(array('field_test')); $form_display = entity_create('entity_form_display', array( 'targetEntityType' => 'entity_test', @@ -64,7 +64,8 @@ public function testFieldComponent() { // Create a field and an instance. $field_name = 'test_field'; $field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'test_field' )); $field->save(); diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module index 52bb75f..31ace31 100644 --- a/core/modules/entity_reference/entity_reference.module +++ b/core/modules/entity_reference/entity_reference.module @@ -50,7 +50,7 @@ function entity_reference_field_info() { function entity_reference_entity_field_info_alter(&$info, $entity_type) { foreach (field_info_instances($entity_type) as $bundle_name => $instances) { foreach ($instances as $field_name => $instance) { - $field = field_info_field($field_name); + $field = $instance->getField(); if ($field['type'] != 'entity_reference') { continue; } @@ -165,7 +165,7 @@ function entity_reference_field_entity_update(FieldInterface $field) { return; } - $field_name = $field->id(); + $field_name = $field->getFieldName(); foreach ($field->bundles() as $entity_type => $bundles) { foreach ($bundles as $bundle) { @@ -394,14 +394,14 @@ function entity_reference_create_instance($entity_type, $bundle, $field_name, $f } // Look for or add the specified field to the requested entity bundle. - $field = field_info_field($field_name); + $field = field_info_field($entity_type, $field_name); $instance = field_info_instance($entity_type, $field_name, $bundle); if (empty($field)) { $field = array( - 'field_name' => $field_name, + 'name' => $field_name, 'type' => 'entity_reference', - 'entity_types' => array($entity_type), + 'entity_type' => $entity_type, 'settings' => array( 'target_type' => $target_entity_type, ), diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php index b6099f1..644304a 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php @@ -69,7 +69,7 @@ public static function create(ContainerInterface $container) { * The matched labels as json. */ public function handleAutocomplete(Request $request, $type, $field_name, $entity_type, $bundle_name, $entity_id) { - if (!$field = field_info_field($field_name)) { + if (!$field = field_info_field($entity_type, $field_name)) { throw new AccessDeniedHttpException(); } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php index de4729c..ab8886d 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php @@ -108,7 +108,7 @@ public static function settingsForm(&$field, &$instance) { $fields = drupal_map_assoc(drupal_schema_fields_sql($entity_info['base_table'])); foreach (field_info_instances($field['settings']['target_type']) as $bundle_instances) { foreach ($bundle_instances as $instance_name => $instance_info) { - $field_info = field_info_field($instance_name); + $field_info = $instance_info->getField(); foreach ($field_info['columns'] as $column_name => $column_info) { $fields[$instance_name . '.' . $column_name] = t('@label (@column)', array('@label' => $instance_info['label'], '@column' => $column_name)); } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php index f5f74d0..6cccb4d 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php @@ -36,12 +36,13 @@ function setUp() { $this->referenced_type = $referenced->type; entity_create('field_entity', array( + 'name' => 'test_field', + 'entity_type' => 'node', 'translatable' => FALSE, 'entity_types' => array(), 'settings' => array( 'target_type' => 'node', ), - 'field_name' => 'test_field', 'type' => 'entity_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, ))->save(); diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php index 8c17fd6..2a50949 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php @@ -7,6 +7,7 @@ namespace Drupal\entity_reference\Tests; +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\Field\FieldInterface; use Drupal\Core\Entity\Field\FieldItemInterface; use Drupal\Core\Language\Language; @@ -110,16 +111,16 @@ public function testEntityReferenceItem() { * Tests foreign key support. */ public function testEntityReferenceFieldSchema() { - $field = field_info_field('field_test_taxonomy'); + $field = field_info_field('entity_test', 'field_test_taxonomy'); $foreign_key_column_name = 'target_id'; // Grab the SQL schema and verify that the 'foreign keys' are present. - $schemas = _field_sql_storage_schema($field); - $schema = $schemas[_field_sql_storage_tablename($field)]; + $schemas = DatabaseStorageController::_fieldSqlSchema($field); + $schema = $schemas[DatabaseStorageController::_fieldTableName($field)]; $this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema.'); $foreign_key = reset($schema['foreign keys']); - $foreign_key_column = _field_sql_storage_columnname($field['field_name'], $foreign_key_column_name); + $foreign_key_column = DatabaseStorageController::_fieldColumnName($field, $foreign_key_column_name); $this->assertEqual($foreign_key['table'], 'taxonomy_term_data', 'Foreign key table name preserved in the schema.'); $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'tid', 'Foreign key column name preserved in the schema.'); @@ -127,10 +128,10 @@ public function testEntityReferenceFieldSchema() { // foreign key is present. $field_name = 'field_test_vocabulary'; entity_reference_create_instance('entity_test', 'entity_test', $field_name, 'Test vocabulary reference', 'taxonomy_vocabulary'); - $field = field_info_field($field_name); + $field = field_info_field('entity_test', $field_name); - $schemas = _field_sql_storage_schema($field); - $schema = $schemas[_field_sql_storage_tablename($field)]; + $schemas = DatabaseStorageController::_fieldSqlSchema($field); + $schema = $schemas[DatabaseStorageController::_fieldTableName($field)]; $this->assertFalse(isset($schema['foreign keys']), 'There is no foreign key in the schema.'); } } diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php index 1482d4e..746e6b8 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php @@ -24,7 +24,7 @@ public static function getInfo() { ); } - public static $modules = array('node', 'comment', 'entity_reference'); + public static $modules = array('node', 'comment', 'entity_reference', 'entity_test'); function setUp() { parent::setUp(); @@ -61,19 +61,20 @@ protected function assertReferenceable(FieldDefinitionInterface $field_definitio public function testNodeHandler() { // Create a field and instance. $field = entity_create('field_entity', array( + 'name' => 'test_field', + 'entity_type' => 'entity_test', 'translatable' => FALSE, 'entity_types' => array(), 'settings' => array( 'target_type' => 'node', ), - 'field_name' => 'test_field', 'type' => 'entity_reference', 'cardinality' => '1', )); $field->save(); $instance = entity_create('field_instance', array( 'field_name' => 'test_field', - 'entity_type' => 'test_entity', + 'entity_type' => 'entity_test', 'bundle' => 'test_bundle', 'settings' => array( 'handler' => 'default', @@ -205,19 +206,19 @@ public function testNodeHandler() { public function testUserHandler() { // Create a field and instance. $field = entity_create('field_entity', array( + 'name' => 'test_field', + 'entity_type' => 'entity_test', 'translatable' => FALSE, - 'entity_types' => array(), 'settings' => array( 'target_type' => 'user', ), - 'field_name' => 'test_field', 'type' => 'entity_reference', 'cardinality' => '1', )); $field->save(); $instance = entity_create('field_instance', array( 'field_name' => 'test_field', - 'entity_type' => 'test_entity', + 'entity_type' => 'entity_test', 'bundle' => 'test_bundle', 'settings' => array( 'handler' => 'default', @@ -351,19 +352,20 @@ public function testUserHandler() { public function testCommentHandler() { // Create a field and instance. $field = entity_create('field_entity', array( + 'name' => 'test_field', + 'entity_type' => 'entity_test', 'translatable' => FALSE, 'entity_types' => array(), 'settings' => array( 'target_type' => 'comment', ), - 'field_name' => 'test_field', 'type' => 'entity_reference', 'cardinality' => '1', )); $field->save(); $instance = entity_create('field_instance', array( 'field_name' => 'test_field', - 'entity_type' => 'test_entity', + 'entity_type' => 'entity_test', 'bundle' => 'test_bundle', 'settings' => array( 'handler' => 'default', diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php index b44c54d..6ed2ace 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php @@ -22,7 +22,7 @@ public static function getInfo() { ); } - public static $modules = array('node', 'entity_reference'); + public static $modules = array('node', 'entity_reference', 'entity_test'); function setUp() { parent::setUp(); @@ -37,7 +37,8 @@ function setUp() { public function testSort() { // Add text field to entity, to sort by. entity_create('field_entity', array( - 'field_name' => 'field_text', + 'name' => 'field_text', + 'entity_type' => 'node', 'type' => 'text', 'entity_types' => array('node'), ))->save(); @@ -54,19 +55,19 @@ public function testSort() { // Create a field and instance. $field = entity_create('field_entity', array( + 'name' => 'test_field', + 'entity_type' => 'entity_test', 'translatable' => FALSE, - 'entity_types' => array(), 'settings' => array( 'target_type' => 'node', ), - 'field_name' => 'test_field', 'type' => 'entity_reference', 'cardinality' => 1, )); $field->save(); $instance = entity_create('field_instance', array( 'field_name' => 'test_field', - 'entity_type' => 'test_entity', + 'entity_type' => 'entity_test', 'bundle' => 'test_bundle', 'settings' => array( 'handler' => 'default', diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php index cad4bd8..9c615e8 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php @@ -14,7 +14,7 @@ */ class SelectionTest extends WebTestBase { - public static $modules = array('views', 'entity_reference', 'entity_reference_test'); + public static $modules = array('views', 'entity_reference', 'entity_reference_test', 'entity_test'); public static function getInfo() { return array( @@ -41,19 +41,19 @@ public function testSelectionHandler() { // Create a field and instance. $field = entity_create('field_entity', array( + 'name' => 'test_field', + 'entity_type' => 'entity_test', 'translatable' => FALSE, - 'entity_types' => array(), 'settings' => array( 'target_type' => 'node', ), - 'field_name' => 'test_field', 'type' => 'entity_reference', 'cardinality' => '1', )); $field->save(); $instance = entity_create('field_instance', array( 'field_name' => 'test_field', - 'entity_type' => 'test_entity', + 'entity_type' => 'entity_test', 'bundle' => 'test_bundle', 'settings' => array( 'handler' => 'views', diff --git a/core/modules/field/config/field.settings.yml b/core/modules/field/config/field.settings.yml index 5ca0000..6b569a9 100644 --- a/core/modules/field/config/field.settings.yml +++ b/core/modules/field/config/field.settings.yml @@ -1,3 +1,2 @@ -default_storage: field_sql_storage language_fallback: '1' purge_batch_size: 10 diff --git a/core/modules/field/config/schema/field.schema.yml b/core/modules/field/config/schema/field.schema.yml index 1b23198..2a942ea 100644 --- a/core/modules/field/config/schema/field.schema.yml +++ b/core/modules/field/config/schema/field.schema.yml @@ -4,9 +4,6 @@ field.settings: type: mapping label: 'Field settings' mapping: - default_storage: - type: string - label: 'The default storage backend for a field' language_fallback: type: boolean label: 'Whether the field display falls back to global language fallback configuration' @@ -30,6 +27,9 @@ field.field.*: langcode: type: string label: 'Default language' + entity_type: + type: string + label: 'Entity type' type: type: string label: 'Type' @@ -41,28 +41,6 @@ field.field.*: active: type: boolean label: 'Active' - entity_types: - type: sequence - label: 'Allowed entity types' - sequence: - - type: string - label: 'Entity type' - storage: - type: mapping - label: 'Storage' - mapping: - type: - type: string - label: 'Type' - settings: - type: field_storage.[%parent.type].settings - label: 'Settings' - module: - type: string - label: 'Module' - active: - type: boolean - label: 'Active' locked: type: boolean label: 'Locked' @@ -101,9 +79,6 @@ field.instance.*.*.*: field_uuid: type: string label: 'Field UUID' - entity_type: - type: string - label: 'Allowed entity types' bundle: type: string label: 'Bundle' diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php index 312ebb5..084790a 100644 --- a/core/modules/field/field.api.php +++ b/core/modules/field/field.api.php @@ -810,7 +810,7 @@ function hook_field_storage_write(\Drupal\Core\Entity\EntityInterface $entity, $ function hook_field_storage_delete(\Drupal\Core\Entity\EntityInterface $entity, $fields) { foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { if (isset($fields[$instance['field_id']])) { - $field = field_info_field_by_id($instance['field_id']); + $field = $instance->getField(); field_sql_storage_field_storage_purge($entity, $field, $instance); } } @@ -1050,7 +1050,7 @@ function hook_field_storage_delete_field($field) { * The instance being deleted. */ function hook_field_storage_delete_instance($instance) { - $field = field_info_field($instance['field_name']); + $field = $instance->getField(); $table_name = _field_sql_storage_tablename($field); $revision_name = _field_sql_storage_revision_tablename($field); db_update($table_name) diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc index 5bab381..bf13405 100644 --- a/core/modules/field/field.attach.inc +++ b/core/modules/field/field.attach.inc @@ -13,45 +13,6 @@ use Drupal\Core\Entity\Field\PrepareCacheInterface; /** - * @defgroup field_storage Field Storage API - * @{ - * Implements a storage engine for Field API data. - * - * The Field Attach API uses the Field Storage API to perform all "database - * access". Each Field Storage API hook function defines a primitive database - * operation such as read, write, or delete. The default field storage module, - * field_sql_storage.module, uses the local SQL database to implement these - * operations, but alternative field storage backends can choose to represent - * the data in SQL differently or use a completely different storage mechanism - * such as a cloud-based database. - * - * Each field defines which storage backend it uses. The Drupal configuration - * 'field.settings.default_storage' identifies the storage backend used by - * default. - * - * See @link field Field API @endlink for information about the other parts of - * the Field API. - */ - -/** - * Argument for an update operation. - * - * This is used in hook_field_storage_write when updating an existing entity. - */ -const FIELD_STORAGE_UPDATE = 'update'; - -/** - * Argument for an insert operation. - * - * This is used in hook_field_storage_write when inserting a new entity. - */ -const FIELD_STORAGE_INSERT = 'insert'; - -/** - * @} End of "defgroup field_storage". - */ - -/** * @defgroup field_attach Field Attach API * @{ * Operates on Field API data attached to Drupal entities. @@ -170,7 +131,7 @@ function field_invoke_method($method, $target_function, EntityInterface $entity, $target = call_user_func($target_function, $instance); if (method_exists($target, $method)) { - $field = field_info_field_by_id($instance['field_id']); + $field = $instance->getField(); $field_name = $field['field_name']; // Determine the list of languages to iterate on. @@ -277,7 +238,7 @@ function field_invoke_method_multiple($method, $target_function, array $entities // Unless a language code suggestion is provided we iterate on all the // available language codes. - $field = field_info_field_by_id($instance['field_id']); + $field = $instance->getField(); $available_langcodes = field_available_languages($entity_type, $field); $langcode = !empty($options['langcode'][$id]) ? $options['langcode'][$id] : $options['langcode']; $langcodes = _field_language_suggestion($available_langcodes, $langcode, $field_name); @@ -527,215 +488,6 @@ function field_attach_form(EntityInterface $entity, &$form, &$form_state, $langc } /** - * Loads fields for the current revisions of a group of entities. - * - * Loads all fields for each entity object in a group of a single entity type. - * The loaded field values are added directly to the entity objects. - * - * field_attach_load() is automatically called by the default entity controller - * class, and thus, in most cases, doesn't need to be explicitly called by the - * entity type module. - * - * @param $entity_type - * The type of entities in $entities; e.g., 'node' or 'user'. - * @param $entities - * An array of entities for which to load fields, keyed by entity ID. Each - * entity needs to have its 'bundle', 'id' and (if applicable) 'revision' keys - * filled in. The function adds the loaded field data directly in the entity - * objects of the $entities array. - * @param $age - * FIELD_LOAD_CURRENT to load the most recent revision for all fields, or - * FIELD_LOAD_REVISION to load the version indicated by each entity. Defaults - * to FIELD_LOAD_CURRENT; use field_attach_load_revision() instead of passing - * FIELD_LOAD_REVISION. - * @param $options - * An associative array of additional options, with the following keys: - * - instance: A field instance entity, If provided, only values for the - * corresponding field will be loaded, and no cache is written. This - * option is only supported when all $entities are within the same bundle. - * - * @deprecated as of Drupal 8.0. Use the entity system instead. - */ -function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $options = array()) { - $load_current = $age == FIELD_LOAD_CURRENT; - $load_deleted = !empty($options['instance']->deleted); - - // Merge default options. - $options += array('instance' => NULL); - // Set options for hook invocations. - $hook_options = array( - 'deleted' => $load_deleted, - ); - if ($options['instance']) { - $hook_options['field_id'] = $options['instance']->field_uuid; - } - - $info = entity_get_info($entity_type); - // Only the most current revision of non-deleted fields for cacheable entity - // types can be cached. - $cache_read = $load_current && $info['field_cache'] && !$load_deleted; - // In addition, do not write to the cache when loading a single field. - $cache_write = $cache_read && !isset($options['instance']); - - if (empty($entities)) { - return; - } - - // Ensure we are working with a BC mode entity. - foreach ($entities as $id => $entity) { - $entities[$id] = $entity->getBCEntity(); - } - - // Assume all entities will need to be queried. Entities found in the cache - // will be removed from the list. - $queried_entities = $entities; - - // Fetch available entities from cache, if applicable. - if ($cache_read) { - // Build the list of cache entries to retrieve. - $cids = array(); - foreach ($entities as $id => $entity) { - $cids[] = "field:$entity_type:$id"; - } - $cache = cache('field')->getMultiple($cids); - // Put the cached field values back into the entities and remove them from - // the list of entities to query. - foreach ($entities as $id => $entity) { - $cid = "field:$entity_type:$id"; - if (isset($cache[$cid])) { - unset($queried_entities[$id]); - foreach ($cache[$cid]->data as $field_name => $values) { - $entity->$field_name = $values; - } - } - } - } - - // Fetch other entities from their storage location. - if ($queried_entities) { - // The invoke order is: - // - hook_field_storage_pre_load() - // - storage backend's hook_field_storage_load() - // - Field class's prepareCache() method. - // - hook_field_attach_load() - - // Invoke hook_field_storage_pre_load(): let any module load field - // data before the storage engine, accumulating along the way. - $skip_fields = array(); - foreach (Drupal::moduleHandler()->getImplementations('field_storage_pre_load') as $module) { - $function = $module . '_field_storage_pre_load'; - $function($entity_type, $queried_entities, $age, $skip_fields, $hook_options); - } - - // Collect the storage backends used by the remaining fields in the entities. - $storages = array(); - foreach ($queried_entities as $entity) { - $id = $entity->id(); - $vid = $entity->getRevisionId(); - - // Determine the list of field instances to work on. - if ($options['instance']) { - $instances = array($options['instance']); - } - else { - $instances = field_info_instances($entity_type, $entity->bundle()); - } - - foreach ($instances as $instance) { - $field = $instance->getField(); - $field_name = $field->id(); - if (!isset($queried_entities[$id]->{$field_name})) { - $queried_entities[$id]->{$field_name} = array(); - } - if (!isset($skip_fields[$field->uuid])) { - $storages[$field->storage['type']][$field->uuid][] = $load_current ? $id : $vid; - } - } - } - - // Invoke hook_field_storage_load() on the relevant storage backends. - foreach ($storages as $storage => $fields) { - $storage_info = field_info_storage_types($storage); - module_invoke($storage_info['module'], 'field_storage_load', $entity_type, $queried_entities, $age, $fields, $hook_options); - } - - // Invoke the field type's prepareCache() method. - if (empty($options['instance'])) { - foreach ($queried_entities as $entity) { - \Drupal::entityManager() - ->getStorageController($entity_type) - ->invokeFieldItemPrepareCache($entity); - } - } - else { - // Do not rely on invokeFieldItemPrepareCache(), which only works on - // fields listed in getFieldDefinitions(), and will fail if we are loading - // values for a deleted field. Instead, generate FieldItem objects - // directly, and call their prepareCache() method. - foreach ($queried_entities as $entity) { - $field = $options['instance']->getField(); - $field_name = $field->id(); - // Call the prepareCache() method on each item. - foreach ($entity->{$field_name} as $langcode => $values) { - $definition = _field_generate_entity_field_definition($field, $options['instance']); - $items = \Drupal::typedData()->create($definition, $values, $field_name, $entity); - foreach ($items as $item) { - if ($item instanceof PrepareCacheInterface) { - $item->prepareCache(); - } - } - $entity->{$field_name}[$langcode] = $items->getValue(); - } - } - } - - // Invoke hook_field_attach_load(): let other modules act on loading the - // entity. - Drupal::moduleHandler()->invokeAll('field_attach_load', $entity_type, $queried_entities, $age, $options); - - // Build cache data. - if ($cache_write) { - foreach ($queried_entities as $id => $entity) { - $data = array(); - $instances = field_info_instances($entity_type, $entity->bundle()); - foreach ($instances as $instance) { - $data[$instance['field_name']] = $queried_entities[$id]->{$instance['field_name']}; - } - $cid = "field:$entity_type:$id"; - cache('field')->set($cid, $data); - } - } - } -} - -/** - * Loads all fields for previous versions of a group of entities. - * - * Loading different versions of the same entities is not supported, and should - * be done by separate calls to the function. - * - * field_attach_load_revision() is automatically called by the default entity - * controller class, and thus, in most cases, doesn't need to be explicitly - * called by the entity type module. - * - * @param $entity_type - * The type of entities in $entities; e.g. 'node' or 'user'. - * @param $entities - * An array of entities for which to load fields, keyed by entity ID. Each - * entity needs to have its 'bundle', 'id' and (if applicable) 'revision' keys - * filled. The function adds the loaded field data directly in the entity - * objects of the $entities array. - * @param $options - * An associative array of additional options. See field_attach_load() for - * details. - * - * @deprecated as of Drupal 8.0. Use the entity system instead. - */ -function field_attach_load_revision($entity_type, $entities, $options = array()) { - return field_attach_load($entity_type, $entities, FIELD_LOAD_REVISION, $options); -} - -/** * Performs field validation against form-submitted field values. * * There are two levels of validation for fields in forms: widget validation and @@ -772,6 +524,7 @@ function field_attach_form_validate(EntityInterface $entity, $form, &$form_state return; } + $entity_type = $entity->entityType(); $has_violations = FALSE; foreach ($entity as $field_name => $field) { $definition = $field->getDefinition(); @@ -781,7 +534,7 @@ function field_attach_form_validate(EntityInterface $entity, $form, &$form_state $has_violations = TRUE; // Place violations in $form_state. - $langcode = field_is_translatable($entity->entityType(), field_info_field($field_name)) ? $entity->language()->id : Language::LANGCODE_NOT_SPECIFIED; + $langcode = field_is_translatable($entity_type, field_info_field($entity_type, $field_name)) ? $entity->language()->id : Language::LANGCODE_NOT_SPECIFIED; $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state); $field_state['constraint_violations'] = $field_violations; field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state); @@ -833,159 +586,6 @@ function field_attach_extract_form_values(EntityInterface $entity, $form, &$form } /** - * Save field data for a new entity. - * - * The passed-in entity must already contain its id and (if applicable) - * revision id attributes. - * Default values (if any) will be saved for fields not present in the - * $entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity with fields to save. - * @return - * Default values (if any) will be added to the $entity parameter for fields - * it leaves unspecified. - * - * @deprecated as of Drupal 8.0. Use the entity system instead. - */ -function field_attach_insert(EntityInterface $entity) { - // Ensure we are working with a BC mode entity. - $entity = $entity->getBCEntity(); - - // Let any module insert field data before the storage engine, accumulating - // saved fields along the way. - $skip_fields = array(); - foreach (Drupal::moduleHandler()->getImplementations('field_storage_pre_insert') as $module) { - $function = $module . '_field_storage_pre_insert'; - $function($entity, $skip_fields); - } - - // Collect the storage backends used by the remaining fields in the entities. - $storages = array(); - foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { - $field = field_info_field_by_id($instance['field_id']); - $field_id = $field['uuid']; - $field_name = $field['field_name']; - if (!empty($entity->$field_name)) { - // Collect the storage backend if the field has not been written yet. - if (!isset($skip_fields[$field_id])) { - $storages[$field['storage']['type']][$field_id] = $field_id; - } - } - } - - // Field storage backends save any remaining unsaved fields. - foreach ($storages as $storage => $fields) { - $storage_info = field_info_storage_types($storage); - module_invoke($storage_info['module'], 'field_storage_write', $entity, FIELD_STORAGE_INSERT, $fields); - } -} - -/** - * Saves field data for an existing entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity with fields to save. - * - * @deprecated as of Drupal 8.0. Use the entity system instead. - */ -function field_attach_update(EntityInterface $entity) { - // Ensure we are working with a BC mode entity. - $entity = $entity->getBCEntity(); - - // Let any module update field data before the storage engine, accumulating - // saved fields along the way. - $skip_fields = array(); - foreach (Drupal::moduleHandler()->getImplementations('field_storage_pre_update') as $module) { - $function = $module . '_field_storage_pre_update'; - $function($entity, $skip_fields); - } - - // Collect the storage backends used by the remaining fields in the entities. - $storages = array(); - foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { - $field = field_info_field_by_id($instance['field_id']); - $field_id = $field['uuid']; - // Collect the storage backend if the field has not been written yet. - if (!isset($skip_fields[$field_id])) { - $storages[$field['storage']['type']][$field_id] = $field_id; - } - } - - // Field storage backends save any remaining unsaved fields. - foreach ($storages as $storage => $fields) { - $storage_info = field_info_storage_types($storage); - module_invoke($storage_info['module'], 'field_storage_write', $entity, FIELD_STORAGE_UPDATE, $fields); - } - - $entity_info = $entity->entityInfo(); - if ($entity_info['field_cache']) { - cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id()); - } -} - -/** - * Deletes field data for an existing entity. This deletes all revisions of - * field data for the entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity whose field data to delete. - * - * @deprecated as of Drupal 8.0. Use the entity system instead. - */ -function field_attach_delete(EntityInterface $entity) { - // Ensure we are working with a BC mode entity. - $entity = $entity->getBCEntity(); - - // Collect the storage backends used by the fields in the entities. - $storages = array(); - foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { - $field = field_info_field_by_id($instance['field_id']); - $field_id = $field['uuid']; - $storages[$field['storage']['type']][$field_id] = $field_id; - } - - // Field storage backends delete their data. - foreach ($storages as $storage => $fields) { - $storage_info = field_info_storage_types($storage); - module_invoke($storage_info['module'], 'field_storage_delete', $entity, $fields); - } - - $entity_info = $entity->entityInfo(); - if ($entity_info['field_cache']) { - cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id()); - } -} - -/** - * Delete field data for a single revision of an existing entity. The passed - * entity must have a revision ID attribute. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity with fields to save. - * - * @deprecated as of Drupal 8.0. Use the entity system instead. - */ -function field_attach_delete_revision(EntityInterface $entity) { - // Ensure we are working with a BC mode entity. - $entity = $entity->getBCEntity(); - - // Collect the storage backends used by the fields in the entities. - $storages = array(); - foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { - $field = field_info_field_by_id($instance['field_id']); - $field_id = $field['uuid']; - $storages[$field['storage']['type']][$field_id] = $field_id; - } - - // Field storage backends delete their data. - foreach ($storages as $storage => $fields) { - $storage_info = field_info_storage_types($storage); - module_invoke($storage_info['module'], 'field_storage_delete_revision', $entity, $fields); - } -} - -/** * Prepares field data prior to display. * * This function lets field types and formatters load additional data needed for diff --git a/core/modules/field/field.crud.inc b/core/modules/field/field.crud.inc index c66fd54..dbed308 100644 --- a/core/modules/field/field.crud.inc +++ b/core/modules/field/field.crud.inc @@ -32,6 +32,8 @@ * This function will not return deleted fields. Use field_read_fields() instead * for this purpose. * + * @param $entity_type + * The entity type. * @param $field_name * The field name to read. * @param array $include_additional @@ -45,8 +47,8 @@ * @deprecated as of Drupal 8.0. Use * entity_load('field_entity', 'field_name'). */ -function field_read_field($field_name, $include_additional = array()) { - $fields = field_read_fields(array('field_name' => $field_name), $include_additional); +function field_read_field($entity_type, $field_name, $include_additional = array()) { + $fields = field_read_fields(array('entity_type' => $entity_type, 'name' => $field_name), $include_additional); return $fields ? current($fields) : FALSE; } @@ -254,7 +256,7 @@ function field_purge_batch($batch_size) { 'bundle' => $instance['bundle'], ); // field_purge_data() will need the field array. - $field = field_info_field_by_id($instance['field_id']); + $field = $instance->getField(); // Retrieve some entities. $query = $factory->get($entity_type) ->condition('id:' . $field['uuid'] . '.deleted', 1) @@ -264,21 +266,12 @@ function field_purge_batch($batch_size) { $query->condition($info[$entity_type]['entity_keys']['bundle'], $ids->bundle); } $results = $query->execute(); - if ($results) { - $entities = array(); foreach ($results as $revision_id => $entity_id) { - // This might not be the revision id if the entity type does not support - // revisions but _field_create_entity_from_ids() checks that and - // disregards this value so there is no harm setting it. $ids->revision_id = $revision_id; $ids->entity_id = $entity_id; - $entities[$entity_id] = _field_create_entity_from_ids($ids); - } - field_attach_load($entity_type, $entities, FIELD_LOAD_CURRENT, array('instance' => $instance)); - foreach ($entities as $entity) { - // Purge the data for the entity. - field_purge_data($entity, $field, $instance); + $entity = _field_create_entity_from_ids($ids); + Drupal::entityManager()->getStorageController($instance->entity_type)->fieldPurgeData($entity, $instance); } } else { @@ -299,37 +292,6 @@ function field_purge_batch($batch_size) { } /** - * Purges the field data for a single field on a single pseudo-entity. - * - * This is basically the same as field_attach_delete() except it only applies to - * a single field. The entity itself is not being deleted, and it is quite - * possible that other field data will remain attached to it. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The pseudo-entity whose field data is being purged. - * @param $field - * The (possibly deleted) field whose data is being purged. - * @param $instance - * The deleted field instance whose data is being purged. - */ -function field_purge_data(EntityInterface $entity, $field, $instance) { - foreach ($entity->{$field->id()} as $value) { - $definition = _field_generate_entity_field_definition($field, $instance); - $items = \Drupal::typedData()->create($definition, $value, $field->id(), $entity); - $items->delete(); - } - - // Tell the field storage system to purge the data. - module_invoke($field['storage']['module'], 'field_storage_purge', $entity, $field, $instance); - - // Let other modules act on purging the data. - foreach (Drupal::moduleHandler()->getImplementations('field_attach_purge') as $module) { - $function = $module . '_field_attach_purge'; - $function($entity, $field, $instance); - } -} - -/** * Purges a field instance record from the database. * * This function assumes all data for the instance has already been purged and @@ -340,7 +302,7 @@ function field_purge_data(EntityInterface $entity, $field, $instance) { */ function field_purge_instance($instance) { // Notify the storage engine. - $field = field_info_field_by_id($instance['field_id']); + $field = $instance->getField(); module_invoke($field['storage']['module'], 'field_storage_purge_instance', $instance); $state = Drupal::state(); diff --git a/core/modules/field/field.info.inc b/core/modules/field/field.info.inc index 824d74e..2bdb147 100644 --- a/core/modules/field/field.info.inc +++ b/core/modules/field/field.info.inc @@ -42,77 +42,10 @@ function field_info_cache_clear() { Drupal::typedData()->clearCachedDefinitions(); Drupal::service('plugin.manager.entity.field.field_type')->clearCachedDefinitions(); - _field_info_collate_types_reset(); Field::fieldInfo()->flush(); } /** - * Collates all information on field types, widget types and related structures. - * - * @return - * An associative array containing: - * - 'storage types': Array of hook_field_storage_info() results, keyed by - * storage type names. Each element has the following components: label, - * description, and settings from hook_field_storage_info(), as well as - * module, giving the module that exposes the storage type. - * - * @see _field_info_collate_types_reset() - */ -function _field_info_collate_types() { - $language_interface = language(Language::TYPE_INTERFACE); - - // Use the advanced drupal_static() pattern, since this is called very often. - static $drupal_static_fast; - - if (!isset($drupal_static_fast)) { - $drupal_static_fast['field_info_collate_types'] = &drupal_static(__FUNCTION__); - } - $info = &$drupal_static_fast['field_info_collate_types']; - - // The _info() hooks invoked below include translated strings, so each - // language is cached separately. - $langcode = $language_interface->id; - - if (!isset($info)) { - if ($cached = cache('field')->get("field_info_types:$langcode")) { - $info = $cached->data; - } - else { - $info = array( - 'storage types' => array(), - ); - - // Populate storage types. - foreach (Drupal::moduleHandler()->getImplementations('field_storage_info') as $module) { - $storage_types = (array) module_invoke($module, 'field_storage_info'); - foreach ($storage_types as $name => $storage_info) { - // Provide defaults. - $storage_info += array( - 'settings' => array(), - ); - $info['storage types'][$name] = $storage_info; - $info['storage types'][$name]['module'] = $module; - } - } - drupal_alter('field_storage_info', $info['storage types']); - - cache('field')->set("field_info_types:$langcode", $info, CacheBackendInterface::CACHE_PERMANENT, array('field_info_types' => TRUE)); - } - } - - return $info; -} - -/** - * Clears collated information on field and widget types and related structures. - */ -function _field_info_collate_types_reset() { - drupal_static_reset('_field_info_collate_types'); - // Clear all languages. - cache('field')->deleteTags(array('field_info_types' => TRUE)); -} - -/** * Determines the behavior of a widget with respect to an operation. * * @param string $op @@ -141,18 +74,20 @@ function field_behaviors_widget($op, $instance) { * The function only returns active, non deleted fields. * * @return - * An array keyed by field name. Each value is an array with two entries: - * - type: The field type. - * - bundles: The bundles in which the field appears, as an array with entity - * types as keys and the array of bundle names as values. + * An array keyed by entity type. Each value is an array which keys are + * field names and value is an array with two entries: + * - type: The field type. + * - bundles: The bundles in which the field appears. * Example: * @code * array( - * 'body' => array( - * 'bundles' => array( - * 'node' => array('page', 'article'), + * 'node' => array( + * 'body' => array( + * 'bundles' => array( + * 'page', 'article' + * ), + * 'type' => 'text_with_summary', * ), - * 'type' => 'text_with_summary', * ), * ); * @endcode @@ -240,31 +175,6 @@ function field_info_formatter_types($formatter_type = NULL) { } /** - * Returns information about field storage from hook_field_storage_info(). - * - * @param $storage_type - * (optional) A storage type name. If omitted, all storage types will be - * returned. - * - * @return - * Either a storage type description, as provided by - * hook_field_storage_info(), or an array of all existing storage types, keyed - * by storage type name. - */ -function field_info_storage_types($storage_type = NULL) { - $info = _field_info_collate_types(); - $storage_types = $info['storage types']; - if ($storage_type) { - if (isset($storage_types[$storage_type])) { - return $storage_types[$storage_type]; - } - } - else { - return $storage_types; - } -} - -/** * Returns all field definitions. * * Use of this function should be avoided when possible, since it loads and @@ -296,8 +206,10 @@ function field_info_fields() { } /** - * Returns data about an individual field, given a field name. + * Returns data about an individual field. * + * @param $entity_type + * The entity type. * @param $field_name * The name of the field to retrieve. $field_name can only refer to a * non-deleted, active field. For deleted fields, use @@ -315,8 +227,8 @@ function field_info_fields() { * @deprecated as of Drupal 8.0. Use * Field::fieldInfo()->getField($field_name). */ -function field_info_field($field_name) { - return Field::fieldInfo()->getField($field_name); +function field_info_field($entity_type, $field_name) { + return Field::fieldInfo()->getField($entity_type, $field_name); } /** @@ -564,21 +476,5 @@ function field_info_formatter_settings($type) { } /** - * Returns a field storage type's default settings. - * - * @param $type - * A field storage type name. - * - * @return - * The storage type's default settings, as provided by - * hook_field_storage_info(), or an empty array if type or settings are - * undefined. - */ -function field_info_storage_settings($type) { - $info = field_info_storage_types($type); - return isset($info['settings']) ? $info['settings'] : array(); -} - -/** * @} End of "defgroup field_info". */ diff --git a/core/modules/field/field.install b/core/modules/field/field.install index c46346a..2898fea 100644 --- a/core/modules/field/field.install +++ b/core/modules/field/field.install @@ -6,6 +6,7 @@ */ use Drupal\Component\Uuid\Uuid; +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\field\Plugin\Core\Entity\Field; /** @@ -29,8 +30,8 @@ function _update_8003_field_create_field(array &$field_config) { // Merge in default values. $field_config += array( + 'id' => $field_config['entity_type'] . '.' . $field_config['name'], 'uuid' => $uuid->generate(), - 'entity_types' => array(), 'cardinality' => 1, 'translatable' => FALSE, 'locked' => FALSE, @@ -41,14 +42,6 @@ function _update_8003_field_create_field(array &$field_config) { 'langcode' => 'und', ); - // Set the storage. - $field_config['storage'] = array( - 'type' => 'field_sql_storage', - 'module' => 'field_sql_storage', - 'active' => TRUE, - 'settings' => array(), - ); - // Save in config. Drupal::config('field.field.' . $field_config['id']) ->setData($field_config) @@ -56,15 +49,17 @@ function _update_8003_field_create_field(array &$field_config) { // Create storage for the field. This requires a field entity, but cannot use // the regular entity_create() function here. - $field_entity = new Field($field_config); - field_sql_storage_field_storage_create_field($field_entity); + $schema = DatabaseStorageController::_fieldSqlSchema(new Field($field_config), $field_config['schema']); + foreach ($schema as $name => $table) { + db_create_table($name, $table); + } } /** * Writes a field instance directly to configuration. * * Upgrades using this function need to use hook_update_dependencies() to ensure - * they get executed after field_update_8003(). + * they get executed after field_update_8003(). * * @param array $field_config * An array of field properties. @@ -78,6 +73,7 @@ function _update_8003_field_create_instance(array $field_config, array &$instanc // Merge in defaults. $instance_config += array( + 'id' => $instance_config['entity_type'] . '.' . $instance_config['bundle'] . '.' . $field_config['name'], 'description' => '', 'required' => FALSE, 'uuid' => $uuid->generate(), @@ -98,6 +94,67 @@ function _update_8003_field_create_instance(array $field_config, array &$instanc } /** + * Writes field data directly to SQL storage. + * + * @param string $entity_type + * @param string $bundle + * @param int $entity_id + * @param int $revision_id + * @param int $field_name + * @param array $data + * + * @ingroup update_api + */ +function _update_8006_field_write_data_sql($entity_type, $bundle, $entity_id, $revision_id, $field_name, array $data) { + $field_config = Drupal::config("field.field.$entity_type.$field_name"); + $field = new Field($field_config); + + $table_name = DatabaseStorageController::_fieldTableName($field); + $revision_name = DatabaseStorageController::_fieldRevisionTableName($field); + + db_delete($table_name) + ->condition('entity_id', $entity_id) + ->execute(); + db_delete($revision_name) + ->condition('entity_id', $entity_id) + ->condition('revision_id', $revision_id) + ->execute(); + + $columns = array(); + foreach ($data as $langcode => $items) { + foreach ($items as $delta => $item) { + $record = array( + 'entity_id' => $entity_id, + 'revision_id' => $revision_id, + 'bundle' => $bundle, + 'delta' => $delta, + 'langcode' => $langcode, + ); + foreach ($item as $column => $value) { + $record[DatabaseStorageController::_fieldColumnName($field_name, $column)] = $value; + } + + $records[] = $record; + // Record the columns used. + $columns += $record; + } + } + + if ($columns) { + $query = db_insert($table_name)->fields(array_keys($columns)); + $revision_query = db_insert($revision_name)->fields(array_keys($columns)); + foreach ($records as $record) { + $query->values($record); + if ($revision_id) { + $revision_query->values($record); + } + } + $query->execute(); + $revision_query->execute(); + } +} + +/** * @addtogroup updates-7.x-to-8.x * @{ */ @@ -255,27 +312,22 @@ function field_update_8003() { $field_data = array(); // Migrate field definitions. - $records = db_query("SELECT * FROM {field_config}")->fetchAll(PDO::FETCH_ASSOC); + $records = db_query("SELECT DISTINCT entity_type, fc.* FROM {field_config} fc INNER JOIN {field_config_instance} fci ON fc.id = fci.field_id")->fetchAll(PDO::FETCH_ASSOC); foreach ($records as $record) { $record['data'] = unserialize($record['data']); $config = array( - 'id' => $record['field_name'], + 'id' => $record['entity_type'] . '.' . $record['field_name'], + 'name' => $record['field_name'], 'uuid' => $uuid->generate(), 'type' => $record['type'], 'module' => $record['module'], 'active' => $record['active'], + 'entity_type' => $record['entity_type'], 'settings' => $record['data']['settings'], - 'storage' => array( - 'type' => $record['storage_type'], - 'module' => $record['storage_module'], - 'active' => $record['storage_active'], - 'settings' => $record['data']['storage']['settings'], - ), 'locked' => $record['locked'], 'cardinality' => $record['cardinality'], 'translatable' => $record['translatable'], - 'entity_types' => $record['data']['entity_types'], 'indexes' => $record['data']['indexes'] ?: array(), 'status' => 1, 'langcode' => 'und', @@ -295,19 +347,17 @@ function field_update_8003() { else { $config['deleted'] = TRUE; $deleted_fields[$config['uuid']] = $config; - // Additionally, rename the data tables for deleted fields. Technically - // this would belong in an update in field_sql_storage.module, but it is - // easier to do it now, when the old numeric ID is available. - if ($config['storage']['type'] == 'field_sql_storage') { - $field = new Field($config); - $tables = array( - "field_deleted_data_{$record['id']}" => _field_sql_storage_tablename($field), - "field_deleted_revision_{$record['id']}" => _field_sql_storage_revision_tablename($field), - ); - foreach ($tables as $table_old => $table_new) { - if (db_table_exists($table_old)) { - db_rename_table($table_old, $table_new); - } + // This will not be saved but the DatabaseStorageController helpers need + // the field object. + $field = new Field($config); + // Additionally, rename the data tables for deleted fields. + $tables = array( + "field_deleted_data_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldTableName($field), + "field_deleted_revision_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldRevisionTableName($field), + ); + foreach ($tables as $table_old => $table_new) { + if (db_table_exists($table_old)) { + db_rename_table($table_old, $table_new); } } } @@ -371,14 +421,13 @@ function field_update_8003() { } /** - * Moves field_storage_default and field_language_fallback to config. + * Moves field_language_fallback to config. * * @ingroup config_upgrade */ function field_update_8004() { update_variable_set('field_language_fallback', TRUE); update_variables_to_config('field.settings', array( - 'field_storage_default' => 'default_storage', 'field_language_fallback' => 'language_fallback', )); } @@ -416,6 +465,106 @@ function field_update_8005() { ->save(); } + +/** + * Splits the field storage tables by entity type and also migrate langcode. + */ +function field_update_8006(&$sandbox) { + // Get field definitions from config, and deleted fields from state system. + $config_names = config_get_storage_names_with_prefix('field.field'); + $deleted_fields = Drupal::state()->get('field.field.deleted') ?: array(); + // Ditch UUID keys, we will iterate through deleted fields using a numeric + // index. + $deleted_fields = array_values($deleted_fields); + + if (empty($config_names) && empty($deleted_fields)) { + return; + } + + if (!isset($sandbox['index'])) { + $sandbox['index'] = 0; + $sandbox['max'] = count($config_names) + count($deleted_fields); + } + + // Retrieve the next field definition. When the index exceeds the number of + // 'configuration' fields, use it to iterate on deleted fields. + if (isset($config_names[$sandbox['index']])) { + $field_config = Drupal::config($config_names[$sandbox['index']])->get(); + } + else { + $field_config = $deleted_fields[$sandbox['index'] - count($config_names)]; + } + + // Prepare updated schema data structures. + $field = new Field($field_config); + $tables = array( + array( + 'old_table' => 'field_data_' . $field_config['name'], + 'new_table' => DatabaseStorageController::_fieldTableName($field), + 'primary_key' => array( + 'entity_id', + 'deleted', + 'delta', + 'langcode', + ), + ), + array( + 'old_table' => 'field_revision_' . $field_config['name'], + 'new_table' => DatabaseStorageController::_fieldRevisionTableName($field), + 'primary_key' => array( + 'entity_id', + 'revision_id', + 'deleted', + 'delta', + 'langcode', + ), + ), + ); + + // Move the field data to the new table. + foreach ($tables as $table_data) { + // Split data from the old "per field" table to the new "per entity type and + // field" table. + $new_table = $table_data['new_table']; + $original_table = empty($field_config['deleted']) ? $table_data['old_table'] : 'old_' . $new_table; + if (db_table_exists($original_table)) { + // Create the new table, with the same schema as the old one. + if (!db_table_exists($new_table)) { + db_copy_table($original_table, $new_table); + } + // Copy relevant rows. + $from_query = db_select($original_table, 'original') + ->fields('original') + ->condition('entity_type', $field_config['entity_type']); + db_insert($new_table) + ->from($from_query) + ->execute(); + // Drop the 'entity_type' column and previous primary key. + db_drop_primary_key($new_table); + db_drop_field($new_table, 'entity_type'); + // Rename 'language' to 'langcode'. Tables created during the upgrade + // before this update function might already have the langcode column. + if (db_field_exists($new_table, 'language')) { + db_drop_index($new_table, 'language'); + db_change_field($new_table, 'language', 'langcode', array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + )); + db_add_index($new_table, 'langcode', array('langcode')); + } + // Create new primary key. + db_add_primary_key($new_table, $table_data['primary_key']); + } + } + + $sandbox['index']++; + $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['index'] / $sandbox['max']); +} + + + /** * @} End of "addtogroup updates-7.x-to-8.x". * The next series of updates should start at 9000. diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 3203f2e..a619fe0 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -259,7 +259,7 @@ function field_populate_default_values(EntityInterface $entity, $langcode = NULL $entity_type = $entity->entityType(); $langcode = $langcode ?: $entity->language()->id; foreach (field_info_instances($entity_type, $entity->bundle()) as $field_name => $instance) { - $field = field_info_field($field_name); + $field = $instance->getField(); $field_langcode = field_is_translatable($entity_type, $field) ? $langcode : Language::LANGCODE_NOT_SPECIFIED; // We need to preserve existing values. if (empty($entity->{$field_name}) || !array_key_exists($field_langcode, $entity->{$field_name})) { @@ -310,7 +310,7 @@ function field_entity_field_info($entity_type) { function _field_generate_entity_field_definition(FieldInterface $field, FieldInstanceInterface $instance = NULL) { // @todo: Allow for adding field type settings. $definition = array( - 'label' => t('Field !name', array('!name' => $field->id())), + 'label' => t('Field !name', array('!name' => $field->name)), 'type' => 'field_item:' . $field->type, 'list' => TRUE, 'configurable' => TRUE, @@ -422,24 +422,8 @@ function field_sync_field_status() { // modules. $changed = array(); $modules = $module_handler->getModuleList(); - foreach ($modules as $module => $module_info) { - // Collect storage backends exposed by the module. - $storage_types = (array) $module_handler->invoke($module, 'field_storage_info'); - - if ($storage_types) { - foreach ($fields as $uuid => &$field) { - // Associate storage backends. - if (isset($storage_types[$field['storage']['type']]) && ($field['storage']['module'] !== $module || !$field['storage']['active'])) { - $field['storage']['module'] = $module; - $field['storage']['active'] = TRUE; - $changed[$uuid] = $field; - } - } - } - } - $field_types = Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions(); - // Set fields with missing field type or storage modules to inactive. + // Set fields with missing field type modules to inactive. foreach ($fields as $uuid => &$field) { // Associate field types. if (isset($field_types[$field['type']]) && ($field['module'] != $field_types[$field['type']]['provider'] || !$field['active'])) { @@ -451,11 +435,6 @@ function field_sync_field_status() { $field['active'] = FALSE; $changed[$uuid] = $field; } - // Disassociate storage backends. - if (!isset($modules[$field['storage']['module']]) && $field['storage']['active']) { - $field['storage']['active'] = FALSE; - $changed[$uuid] = $field; - } } // Store the updated field definitions. @@ -467,8 +446,6 @@ function field_sync_field_status() { Drupal::config('field.field.' . $field['id']) ->set('module', $field['module']) ->set('active', $field['active']) - ->set('storage.module', $field['storage']['module']) - ->set('storage.active', $field['storage']['active']) ->save(); } } @@ -699,7 +676,7 @@ function field_view_value(EntityInterface $entity, $field_name, $item, $display // Ensure we are working with a BC mode entity. $entity = $entity->getBCEntity(); - if ($field = field_info_field($field_name)) { + if ($field = field_info_field($entity->entityType(), $field_name)) { // Determine the langcode that will be used by language fallback. $langcode = field_language($entity, $field_name, $langcode); @@ -789,7 +766,7 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options $view_mode = '_custom'; // hook_field_attach_display_alter() needs to receive the 'prepared' // $display_options, so we cannot let preparation happen internally. - $field = field_info_field($field_name); + $field = field_info_field($entity_type, $field_name); $formatter_manager = drupal_container()->get('plugin.manager.field.formatter'); $display_options = $formatter_manager->prepareConfiguration($field['type'], $display_options); $formatter = $formatter_manager->getInstance(array( diff --git a/core/modules/field/field.views.inc b/core/modules/field/field.views.inc index e5dea3b..96154d5 100644 --- a/core/modules/field/field.views.inc +++ b/core/modules/field/field.views.inc @@ -8,30 +8,30 @@ */ use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\field\FieldInterface; /** * Implements hook_views_data(). * - * Field modules can implement hook_field_views_data() to override - * the default behavior for adding fields. + * Field modules can implement hook_field_views_data() to override the default + * behavior for adding fields. */ function field_views_data() { $data = array(); + $module_handler = Drupal::moduleHandler(); foreach (field_info_fields() as $field) { - if ($field['storage']['type'] != 'field_sql_storage') { - continue; - } - - $module = $field['module']; - $result = (array) module_invoke($module, 'field_views_data', $field); + if ($sql_entity_types = _field_views_get_sql_entity_types($field)) { + $result = (array) $module_handler->invoke($field['module'], 'field_views_data', array($field, $sql_entity_types)); - if (empty($result)) { - $result = field_views_field_default_views_data($field); - } - Drupal::moduleHandler()->alter('field_views_data', $result, $field, $module); + if (empty($result)) { + $result = field_views_field_default_views_data($field, $sql_entity_types); + } + $module_handler->alter('field_views_data', $result, $field, $sql_entity_types); - if (is_array($result)) { - $data = NestedArray::mergeDeep($result, $data); + if (is_array($result)) { + $data = NestedArray::mergeDeep($result, $data); + } } } @@ -48,15 +48,39 @@ function field_views_data() { */ function field_views_data_alter(&$data) { foreach (field_info_fields() as $field) { - if ($field['storage']['type'] != 'field_sql_storage') { - continue; + if ($sql_entity_types = _field_views_get_sql_entity_types($field)) { + $function = $field['module'] . '_field_views_data_views_data_alter'; + if (function_exists($function)) { + $function($data, $field, $sql_entity_types); + } } + } +} - $function = $field['module'] . '_field_views_data_views_data_alter'; - if (function_exists($function)) { - $function($data, $field); +/** + * Returns the SQL-based entity types where the field appears in. + * + * @param \Drupal\field\FieldInterface $field + * The field definition. + * + * @return array + * The array of entity types using DatabaseStorageController where the field + * appears in. + */ +function _field_views_get_sql_entity_types(FieldInterface $field) { + $sql_entity_types = array(); + $entity_manager = Drupal::entityManager(); + foreach ($field['bundles'] as $entity_type => $bundles) { + try { + if ($entity_manager->getStorageController($entity_type) instanceof DatabaseStorageController) { + $sql_entity_types[] = $entity_type; + } + } + catch (\InvalidArgumentException $e) { + // Disabled entity type, nothing to do. } } + return $sql_entity_types; } /** @@ -88,19 +112,32 @@ function field_views_field_label($field_name) { /** * Default views data implementation for a field. + * + * @param \Drupal\field\FieldInterface $field + * The field definition. + * @param array $sql_entity_types + * The array of SQL-based entity types where the field appears in. + * + * @return array + * The default views data for the field. */ -function field_views_field_default_views_data($field) { +function field_views_field_default_views_data(FieldInterface $field, $sql_entity_types) { + // If the field had no instances in the SQL storage then there is nothing to be done. + if (!$sql_entity_types) { + return array(); + } + $field_types = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions(); // Check the field module is available. if (!isset($field_types[$field['type']])) { - return; + return array(); } $data = array(); - $current_table = _field_sql_storage_tablename($field); - $revision_table = _field_sql_storage_revision_tablename($field); + $current_table = DatabaseStorageController::_fieldTableName($field); + $revision_table = DatabaseStorageController::_fieldRevisionTableName($field); // The list of entity:bundle that this field is used in. $bundles_names = array(); @@ -113,35 +150,36 @@ function field_views_field_default_views_data($field) { $group_name = count($field['bundles']) > 1 ? t('Field') : NULL; // Build the relationships between the field table and the entity tables. - foreach ($field['bundles'] as $entity => $bundles) { - $entity_info = entity_get_info($entity); - $groups[$entity] = $entity_info['label']; + $entity_manager = Drupal::entityManager(); + foreach ($sql_entity_types as $entity_type) { + $entity_info = $entity_manager->getDefinition($entity_type); + $groups[$entity_type] = $entity_info['label']; // Override Node to Content. - if ($groups[$entity] == t('Node')) { - $groups[$entity] = t('Content'); + if ($groups[$entity_type] == t('Node')) { + $groups[$entity_type] = t('Content'); } // If only one bundle use this as the default name. if (empty($group_name)) { - $group_name = $groups[$entity]; + $group_name = $groups[$entity_type]; } if (!isset($entity_info['base_table'])) { continue; } - $entity_tables[$entity_info['base_table']] = $entity; - $current_tables[$entity] = $entity_info['base_table']; + $entity_tables[$entity_info['base_table']] = $entity_type; + $current_tables[$entity_type] = $entity_info['base_table']; if (isset($entity_info['revision_table'])) { - $entity_tables[$entity_info['revision_table']] = $entity; - $revision_tables[$entity] = $entity_info['revision_table']; + $entity_tables[$entity_info['revision_table']] = $entity_type; + $revision_tables[$entity_type] = $entity_info['revision_table']; } $data[$current_table]['table']['join'][$entity_info['base_table']] = array( 'left_field' => $entity_info['entity_keys']['id'], 'field' => 'entity_id', 'extra' => array( - array('field' => 'entity_type', 'value' => $entity), + array('field' => 'entity_type', 'value' => $entity_type), array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE), ), ); @@ -151,7 +189,7 @@ function field_views_field_default_views_data($field) { 'left_field' => $entity_info['entity_keys']['revision'], 'field' => 'revision_id', 'extra' => array( - array('field' => 'entity_type', 'value' => $entity), + array('field' => 'entity_type', 'value' => $entity_type), array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE), ), ); @@ -159,8 +197,8 @@ function field_views_field_default_views_data($field) { $supports_revisions = TRUE; } - foreach ($bundles as $bundle) { - $bundles_names[] = t('@entity:@bundle', array('@entity' => $entity, '@bundle' => $bundle)); + foreach ($field['bundles'][$entity_type] as $bundle) { + $bundles_names[] = t('@entity:@bundle', array('@entity' => $entity_type, '@bundle' => $bundle)); } } @@ -172,7 +210,7 @@ function field_views_field_default_views_data($field) { $add_fields = array('delta', 'langcode', 'bundle'); foreach ($field['columns'] as $column_name => $attributes) { - $add_fields[] = _field_sql_storage_columnname($field['field_name'], $column_name); + $add_fields[] = DatabaseStorageController::_fieldColumnName($field, $column_name); } // Note: we don't have a label available here, because we are at the field @@ -243,6 +281,7 @@ function field_views_field_default_views_data($field) { 'table' => $table, 'id' => 'field', 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], // Provide a real field for group by. 'real field' => $column . '_' . $real_field, 'additional fields' => $add_fields, @@ -296,10 +335,11 @@ function field_views_field_default_views_data($field) { else { $group = t('@group (historical data)', array('@group' => $group_name)); } - $column_real_name = $field['storage_details']['sql'][$type][$table][$column]; + $column_real_name = DatabaseStorageController::_fieldColumnName($field, $column); // Load all the fields from the table by default. - $additional_fields = array_values($field['storage_details']['sql'][$type][$table]); + $field_sql_schema = DatabaseStorageController::_fieldSqlSchema($field); + $additional_fields = array_keys($field_sql_schema[$current_table]['fields']); $data[$table][$column_real_name] = array( 'group' => $group, @@ -341,6 +381,7 @@ function field_views_field_default_views_data($field) { 'id' => $argument, 'additional fields' => $additional_fields, 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], 'empty field name' => t('- No value -'), ); $data[$table][$column_real_name]['filter'] = array( @@ -349,6 +390,7 @@ function field_views_field_default_views_data($field) { 'id' => $filter, 'additional fields' => $additional_fields, 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], 'allow empty' => TRUE, ); if (!empty($allow_sort)) { @@ -358,6 +400,7 @@ function field_views_field_default_views_data($field) { 'id' => $sort, 'additional fields' => $additional_fields, 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], ); } @@ -382,6 +425,7 @@ function field_views_field_default_views_data($field) { 'additional fields' => $additional_fields, 'empty field name' => t('- No value -'), 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], ); $data[$table]['delta']['filter'] = array( 'field' => 'delta', @@ -389,6 +433,7 @@ function field_views_field_default_views_data($field) { 'id' => 'numeric', 'additional fields' => $additional_fields, 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], 'allow empty' => TRUE, ); $data[$table]['delta']['sort'] = array( @@ -397,6 +442,7 @@ function field_views_field_default_views_data($field) { 'id' => 'standard', 'additional fields' => $additional_fields, 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], ); } @@ -421,6 +467,7 @@ function field_views_field_default_views_data($field) { 'additional fields' => $additional_fields, 'empty field name' => t('- No value -'), 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], ); $data[$table]['language']['filter'] = array( 'field' => 'language', @@ -428,6 +475,7 @@ function field_views_field_default_views_data($field) { 'id' => 'language', 'additional fields' => $additional_fields, 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], 'allow empty' => TRUE, ); $data[$table]['language']['sort'] = array( @@ -436,6 +484,7 @@ function field_views_field_default_views_data($field) { 'id' => 'standard', 'additional fields' => $additional_fields, 'field_name' => $field['field_name'], + 'entity_type' => $field['entity_type'], ); } } @@ -447,8 +496,8 @@ function field_views_field_default_views_data($field) { /** * Have a different filter handler for lists. This should allow to select values of the list. */ -function list_field_views_data($field) { - $data = field_views_field_default_views_data($field); +function list_field_views_data($field, $sql_entity_types) { + $data = field_views_field_default_views_data($field, $sql_entity_types); foreach ($data as $table_name => $table_data) { foreach ($table_data as $field_name => $field_data) { if (isset($field_data['filter']) && $field_name != 'delta') { diff --git a/core/modules/field/lib/Drupal/field/FieldInfo.php b/core/modules/field/lib/Drupal/field/FieldInfo.php index 2639c25..096841d 100644 --- a/core/modules/field/lib/Drupal/field/FieldInfo.php +++ b/core/modules/field/lib/Drupal/field/FieldInfo.php @@ -165,10 +165,10 @@ public function flush() { * Collects a lightweight map of fields across bundles. * * @return - * An array keyed by field name. Each value is an array with two entries: + * An array keyed by entity type. Each value is an array which keys are + * field names and value is an array with two entries: * - type: The field type. - * - bundles: The bundles in which the field appears, as an array with - * entity types as keys and the array of bundle names as values. + * - bundles: The bundles in which the field appears. */ public function getFieldMap() { // Read from the "static" cache. @@ -191,7 +191,7 @@ public function getFieldMap() { // Get active fields. foreach (config_get_storage_names_with_prefix('field.field.') as $config_id) { $field_config = $this->config->get($config_id)->get(); - if ($field_config['active'] && $field_config['storage']['active']) { + if ($field_config['active']) { $fields[$field_config['uuid']] = $field_config; } } @@ -203,8 +203,8 @@ public function getFieldMap() { // entity types. if (isset($fields[$field_uuid])) { $field = $fields[$field_uuid]; - $map[$field['id']]['bundles'][$instance_config['entity_type']][] = $instance_config['bundle']; - $map[$field['id']]['type'] = $field['type']; + $map[$instance_config['entity_type']][$field['name']]['bundles'][] = $instance_config['bundle']; + $map[$instance_config['entity_type']][$field['name']]['type'] = $field['type']; } } @@ -244,7 +244,7 @@ public function getFields() { // Fill the name/ID map. foreach ($this->fieldsById as $field) { if (!$field['deleted']) { - $this->fieldIdsByName[$field['id']] = $field['uuid']; + $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid']; } } @@ -280,7 +280,7 @@ public function getInstances($entity_type = NULL) { $this->getFields(); foreach (field_read_instances() as $instance) { - $field = $this->getField($instance['field_name']); + $field = $this->getField($instance['entity_type'], $instance['field_name']); $instance = $this->prepareInstance($instance, $field['type']); $this->bundleInstances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance; } @@ -305,36 +305,38 @@ public function getInstances($entity_type = NULL) { * * This method only retrieves active, non-deleted fields. * - * @param $field_name + * @param string $entity_type + * The entity type. + * @param string $field_name * The field name. * * @return * The field definition, or NULL if no field was found. */ - public function getField($field_name) { + public function getField($entity_type, $field_name) { // Read from the "static" cache. - if (isset($this->fieldIdsByName[$field_name])) { - $field_id = $this->fieldIdsByName[$field_name]; + if (isset($this->fieldIdsByName[$entity_type][$field_name])) { + $field_id = $this->fieldIdsByName[$entity_type][$field_name]; return $this->fieldsById[$field_id]; } - if (isset($this->unknownFields[$field_name])) { + if (isset($this->unknownFields[$entity_type][$field_name])) { return; } // Do not check the (large) persistent cache, but read the definition. // Cache miss: read from definition. - if ($field = field_read_field($field_name)) { + if ($field = entity_load('field_entity', $entity_type . '.' . $field_name)) { $field = $this->prepareField($field); // Save in the "static" cache. $this->fieldsById[$field['uuid']] = $field; - $this->fieldIdsByName[$field['field_name']] = $field['uuid']; + $this->fieldIdsByName[$entity_type][$field_name] = $field['uuid']; return $field; } else { - $this->unknownFields[$field_name] = TRUE; + $this->unknownFields[$entity_type][$field_name] = TRUE; } } @@ -369,7 +371,7 @@ public function getFieldById($field_id) { // Store in the static cache. $this->fieldsById[$field['uuid']] = $field; if (!$field['deleted']) { - $this->fieldIdsByName[$field['field_name']] = $field['uuid']; + $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid']; } return $field; @@ -411,7 +413,7 @@ public function getBundleInstances($entity_type, $bundle) { if (!isset($this->fieldsById[$field['uuid']])) { $this->fieldsById[$field['uuid']] = $field; if (!$field['deleted']) { - $this->fieldIdsByName[$field['field_name']] = $field['uuid']; + $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid']; } } } @@ -431,39 +433,42 @@ public function getBundleInstances($entity_type, $bundle) { // Cache miss: collect from the definitions. $instances = array(); + $field_map = $this->getFieldMap(); // Do not return anything for unknown entity types. - if (entity_get_info($entity_type)) { + if (entity_get_info($entity_type) && !empty($field_map[$entity_type])) { // Collect names of fields and instances involved in the bundle, using the // field map. The field map is already filtered to active, non-deleted // fields and instances, so those are kept out of the persistent caches. $config_ids = array(); - foreach ($this->getFieldMap() as $field_name => $field_data) { - if (isset($field_data['bundles'][$entity_type]) && in_array($bundle, $field_data['bundles'][$entity_type])) { - $config_ids[$field_name] = "$entity_type.$bundle.$field_name"; + foreach ($field_map[$entity_type] as $field_name => $field_data) { + if (in_array($bundle, $field_data['bundles'])) { + $config_ids["$entity_type.$field_name"] = "$entity_type.$bundle.$field_name"; } } // Load and prepare the corresponding fields and instances entities. if ($config_ids) { + // Place the fields in our global "static". $loaded_fields = entity_load_multiple('field_entity', array_keys($config_ids)); - $loaded_instances = entity_load_multiple('field_instance', array_values($config_ids)); - - foreach ($loaded_instances as $instance) { - $field = $loaded_fields[$instance['field_name']]; - - $instance = $this->prepareInstance($instance, $field['type']); - $instances[$field['field_name']] = $instance; - - // If the field is not in our global "static" list yet, add it. + foreach ($loaded_fields as $field) { if (!isset($this->fieldsById[$field['uuid']])) { $field = $this->prepareField($field); $this->fieldsById[$field['uuid']] = $field; - $this->fieldIdsByName[$field['field_name']] = $field['uuid']; + $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid']; } } + + // Then collect the instances. + $loaded_instances = entity_load_multiple('field_instance', array_values($config_ids)); + foreach ($loaded_instances as $instance) { + $field = $instance->getField(); + + $instance = $this->prepareInstance($instance, $field['type']); + $instances[$field['field_name']] = $instance; + } } } @@ -565,7 +570,6 @@ public function getBundleExtraFields($entity_type, $bundle) { public function prepareField($field) { // Make sure all expected field settings are present. $field['settings'] += $this->fieldTypeManager->getDefaultSettings($field['type']); - $field['storage']['settings'] += field_info_storage_settings($field['storage']['type']); return $field; } diff --git a/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php b/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php index f9ce249..2649c6a 100644 --- a/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php +++ b/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php @@ -136,7 +136,6 @@ public function loadByProperties(array $conditions = array()) { // Translate "do not include inactive fields" into actual conditions. if (!$include_inactive) { $conditions['field.active'] = TRUE; - $conditions['field.storage.active'] = TRUE; } // Collect matching instances. @@ -155,17 +154,13 @@ public function loadByProperties(array $conditions = array()) { // Extract the actual value against which the condition is checked. switch ($key) { case 'field_name': - $checked_value = $field->id; + $checked_value = $field->name; break; case 'field.active': $checked_value = $field->active; break; - case 'field.storage.active': - $checked_value = $field->storage['active']; - break; - case 'field_id': $checked_value = $instance->field_uuid; break; diff --git a/core/modules/field/lib/Drupal/field/FieldInterface.php b/core/modules/field/lib/Drupal/field/FieldInterface.php index 132bc39..8d7edd8 100644 --- a/core/modules/field/lib/Drupal/field/FieldInterface.php +++ b/core/modules/field/lib/Drupal/field/FieldInterface.php @@ -45,34 +45,6 @@ public function getSchema(); public function getColumns(); /** - * Returns information about how the storage backend stores the field data. - * - * The content of the returned value depends on the storage backend, and some - * storage backends might provide no information. - * - * It is strongly discouraged to use this information to perform direct write - * operations to the field data storage, bypassing the regular field saving - * APIs. - * - * Example return value for the default field_sql_storage backend: - * - 'sql' - * - FIELD_LOAD_CURRENT - * - Table name (string). - * - Table schema (array) - * - FIELD_LOAD_REVISION - * - Table name (string). - * - Table schema (array). - * - * @return array - * The storage details. - * - The first dimension is a store type (sql, solr, etc). - * - The second dimension indicates the age of the values in the store - * FIELD_LOAD_CURRENT or FIELD_LOAD_REVISION. - * - Other dimensions are specific to the field storage backend. - */ - public function getStorageDetails(); - - /** * Returns the list of bundles where the field has instances. * * @return array diff --git a/core/modules/field/lib/Drupal/field/FieldStorageController.php b/core/modules/field/lib/Drupal/field/FieldStorageController.php index 41efe60..8b0f92e 100644 --- a/core/modules/field/lib/Drupal/field/FieldStorageController.php +++ b/core/modules/field/lib/Drupal/field/FieldStorageController.php @@ -98,9 +98,10 @@ public function loadByProperties(array $conditions = array()) { unset($conditions['include_deleted']); // Get fields stored in configuration. - if (isset($conditions['field_name'])) { + if (isset($conditions['entity_type']) && isset($conditions['field_name'])) { // Optimize for the most frequent case where we do have a specific ID. - $fields = $this->entityManager->getStorageController($this->entityType)->loadMultiple(array($conditions['field_name'])); + $id = $conditions['entity_type'] . $conditions['field_name']; + $fields = $this->entityManager->getStorageController($this->entityType)->loadMultiple(array($id)); } else { // No specific ID, we need to examine all existing fields. @@ -118,7 +119,6 @@ public function loadByProperties(array $conditions = array()) { // Translate "do not include inactive instances" into actual conditions. if (!$include_inactive) { $conditions['active'] = TRUE; - $conditions['storage.active'] = TRUE; } // Collect matching fields. @@ -127,12 +127,8 @@ public function loadByProperties(array $conditions = array()) { foreach ($conditions as $key => $value) { // Extract the actual value against which the condition is checked. switch ($key) { - case 'storage.active': - $checked_value = $field->storage['active']; - break; - case 'field_name'; - $checked_value = $field->id; + $checked_value = $field->name; break; default: diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php index bccc64b..4c5b03b 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php @@ -37,24 +37,35 @@ class Field extends ConfigEntityBase implements FieldInterface { /** - * The maximum length of the field ID (machine name), in characters. + * The maximum length of the field name, in characters. * * For fields created through Field UI, this includes the 'field_' prefix. */ - const ID_MAX_LENGTH = 32; + const NAME_MAX_LENGTH = 32; /** - * The field ID (machine name). + * 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 + */ + public $id; + + /** + * The field name. * * This is the name of the property under which the field values are placed in - * an entity : $entity-{>$field_id}. The maximum length is - * Field:ID_MAX_LENGTH. + * an entity: $entity->{$field_name}. The maximum length is + * Field:NAME_MAX_LENGTH. * * Example: body, field_main_image. * * @var string */ - public $id; + public $name; /** * The field UUID. @@ -66,6 +77,13 @@ class Field extends ConfigEntityBase implements FieldInterface { public $uuid; /** + * The name of the entity type the field can be attached to. + * + * @var string + */ + public $entity_type; + + /** * The field type. * * Example: text, number_integer. @@ -118,16 +136,6 @@ class Field extends ConfigEntityBase implements FieldInterface { public $translatable = FALSE; /** - * The entity types on which the field is allowed to have instances. - * - * If empty or not specified, the field is allowed to have instances in any - * entity type. - * - * @var array - */ - public $entity_types = array(); - - /** * Flag indicating whether the field is available for editing. * * If TRUE, some actions not available though the UI (but are still possible @@ -142,25 +150,6 @@ class Field extends ConfigEntityBase implements FieldInterface { public $locked = FALSE; /** - * The field storage definition. - * - * An array of key/value pairs identifying the storage backend to use for the - * field: - * - type: (string) The storage backend used by the field. Storage backends - * are defined by modules that implement hook_field_storage_info(). - * - settings: (array) A sub-array of key/value pairs of settings. The keys - * and default values are defined by the storage backend in the 'settings' - * entry of hook_field_storage_info(). - * - module: (string, read-only) The name of the module that implements the - * storage backend. - * - active: (integer, read-only) TRUE if the module that implements the - * storage backend is currently enabled, FALSE otherwise. - * - * @var array - */ - public $storage = array(); - - /** * The custom storage indexes for the field data storage. * * This set of indexes is merged with the "default" indexes specified by the @@ -201,13 +190,6 @@ class Field extends ConfigEntityBase implements FieldInterface { protected $schema; /** - * The storage information for the field. - * - * @var array - */ - protected $storageDetails; - - /** * The original field. * * @var \Drupal\field\Plugin\Core\Entity\Field @@ -222,8 +204,9 @@ class Field extends ConfigEntityBase implements FieldInterface { * 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: - * - id: required. As a temporary Backwards Compatibility layer right now, + * - 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. * * In most cases, Field entities are created via @@ -236,22 +219,18 @@ class Field extends ConfigEntityBase implements FieldInterface { */ public function __construct(array $values, $entity_type = 'field_entity') { // Check required properties. - if (empty($values['type'])) { - throw new FieldException('Attempt to create a field with no type.'); - } - // Temporary BC layer: accept both 'id' and 'field_name'. - // @todo $field_name and the handling for it will be removed in - // http://drupal.org/node/1953408. - if (empty($values['field_name']) && empty($values['id'])) { + if (empty($values['name'])) { throw new FieldException('Attempt to create an unnamed field.'); } - if (empty($values['id'])) { - $values['id'] = $values['field_name']; - unset($values['field_name']); - } - if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $values['id'])) { + if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $values['name'])) { throw new FieldException('Attempt to create a field 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 with no type.'); + } + if (empty($values['entity_type'])) { + throw new FieldException('Attempt to create a field with no entity_type.'); + } parent::__construct($values, $entity_type); } @@ -259,18 +238,25 @@ public function __construct(array $values, $entity_type = 'field_entity') { /** * {@inheritdoc} */ + public function id() { + return $this->entity_type . '.' . $this->name; + } + + /** + * {@inheritdoc} + */ public function getExportProperties() { $names = array( 'id', 'uuid', 'status', 'langcode', + 'name', + 'entity_type', 'type', 'settings', 'module', 'active', - 'entity_types', - 'storage', 'locked', 'cardinality', 'translatable', @@ -296,7 +282,7 @@ public function getExportProperties() { */ public function save() { // Clear the derived data about the field. - unset($this->schema, $this->storageDetails); + unset($this->schema); if ($this->isNew()) { return $this->saveNew(); @@ -318,18 +304,20 @@ public function save() { * In case of failures at the configuration storage level. */ protected function saveNew() { - $module_handler = \Drupal::moduleHandler(); $entity_manager = \Drupal::entityManager(); $storage_controller = $entity_manager->getStorageController($this->entityType); - // Field name cannot be longer than Field::ID_MAX_LENGTH characters. We + // Assign the ID. + $this->id = $this->id(); + + // Field name cannot be longer than Field::NAME_MAX_LENGTH characters. We // use drupal_strlen() because the DB layer assumes that column widths // are given in characters rather than bytes. - if (drupal_strlen($this->id) > static::ID_MAX_LENGTH) { + if (drupal_strlen($this->name) > static::NAME_MAX_LENGTH) { throw new FieldException(format_string( - 'Attempt to create a field with an ID longer than @max characters: %id', array( - '@max' => static::ID_MAX_LENGTH, - '%id' => $this->id, + 'Attempt to create a field with an ID longer than @max characters: %name', array( + '@max' => static::NAME_MAX_LENGTH, + '%name' => $this->name, ) )); } @@ -337,17 +325,17 @@ protected function saveNew() { // Ensure the field name is unique (we do not care about deleted fields). if ($prior_field = $storage_controller->load($this->id)) { $message = $prior_field->active ? - 'Attempt to create field name %id which already exists and is active.' : - 'Attempt to create field name %id which already exists, although it is inactive.'; - throw new FieldException(format_string($message, array('%id' => $this->id))); + 'Attempt to create field name %name which already exists and is active.' : + 'Attempt to create field name %name which already exists, although it is inactive.'; + throw new FieldException(format_string($message, array('%name' => $this->name))); } // Disallow reserved field names. This can't prevent all field name // collisions with existing entity properties, but some is better than // none. foreach ($entity_manager->getDefinitions() as $type => $info) { - if (in_array($this->id, $info['entity_keys'])) { - throw new FieldException(format_string('Attempt to create field %id which is reserved by entity type %type.', array('%id' => $this->id, '%type' => $type))); + if (in_array($this->name, $info['entity_keys'])) { + throw new FieldException(format_string('Attempt to create field %name which is reserved by entity type %type.', array('%name' => $this->name, '%type' => $type))); } } @@ -363,23 +351,8 @@ protected function saveNew() { // definition is passed to the various hooks and written to config. $this->settings += $field_type['settings']; - // Provide default storage. - $this->storage += array( - 'type' => variable_get('field_storage_default', 'field_sql_storage'), - 'settings' => array(), - ); - // Check that the storage type is known. - $storage_type = field_info_storage_types($this->storage['type']); - if (!$storage_type) { - throw new FieldException(format_string('Attempt to create a field with unknown storage type %type.', array('%type' => $this->storage['type']))); - } - $this->storage['module'] = $storage_type['module']; - $this->storage['active'] = TRUE; - // Provide default storage settings. - $this->storage['settings'] += $storage_type['settings']; - - // Invoke the storage backend's hook_field_storage_create_field(). - $module_handler->invoke($this->storage['module'], 'field_storage_create_field', array($this)); + // Notify the entity storage controller. + $entity_manager->getStorageController($this->entity_type)->handleFieldCreate($this); // Save the configuration. $result = parent::save(); @@ -401,7 +374,8 @@ protected function saveNew() { */ protected function saveUpdated() { $module_handler = \Drupal::moduleHandler(); - $storage_controller = \Drupal::entityManager()->getStorageController($this->entityType); + $entity_manager = \Drupal::entityManager(); + $storage_controller = $entity_manager->getStorageController($this->entityType); $original = $storage_controller->loadUnchanged($this->id()); $this->original = $original; @@ -410,11 +384,8 @@ protected function saveUpdated() { if ($this->type != $original->type) { throw new FieldException("Cannot change an existing field's type."); } - if ($this->entity_types != $original->entity_types) { - throw new FieldException("Cannot change an existing field's entity_types property."); - } - if ($this->storage['type'] != $original->storage['type']) { - throw new FieldException("Cannot change an existing field's storage type."); + if ($this->entity_type != $original->entity_type) { + throw new FieldException("Cannot change an existing field's entity_type."); } // Make sure all settings are present, so that a complete field definition @@ -426,11 +397,10 @@ protected function saveUpdated() { // invokes hook_field_update_forbid(). $module_handler->invokeAll('field_update_forbid', array($this, $original)); - // Tell the storage engine to update the field by invoking the - // hook_field_storage_update_field(). The storage engine can reject the - // definition update as invalid by raising an exception, which stops - // execution before the definition is written to config. - $module_handler->invoke($this->storage['module'], 'field_storage_update_field', array($this, $original)); + // Notify the storage controller. The controller can reject the definition + // update as invalid by raising an exception, which stops execution before + // the definition is written to config. + $entity_manager->getStorageController($this->entity_type)->handleFieldUpdate($this, $original); // Save the configuration. $result = parent::save(); @@ -444,16 +414,13 @@ protected function saveUpdated() { */ public function delete() { if (!$this->deleted) { - $module_handler = \Drupal::moduleHandler(); $instance_controller = \Drupal::entityManager()->getStorageController('field_instance'); $state = \Drupal::state(); // Delete all non-deleted instances. $instance_ids = array(); - foreach ($this->getBundles() as $entity_type => $bundles) { - foreach ($bundles as $bundle) { - $instance_ids[] = "$entity_type.$bundle.$this->id"; - } + foreach ($this->getBundles() as $bundle) { + $instance_ids[] = "{$this->entity_type}.$bundle.{$this->name}"; } foreach ($instance_controller->loadMultiple($instance_ids) as $instance) { // By default, FieldInstance::delete() will automatically try to delete @@ -463,9 +430,7 @@ public function delete() { $instance->delete(FALSE); } - // Mark field data for deletion by invoking - // hook_field_storage_delete_field(). - $module_handler->invoke($this->storage['module'], 'field_storage_delete_field', array($this)); + \Drupal::entityManager()->getStorageController($this->entity_type)->handleFieldDelete($this); // Delete the configuration of this field and save the field configuration // in the key_value table so we can use it later during @@ -528,30 +493,11 @@ public function getColumns() { /** * {@inheritdoc} */ - public function getStorageDetails() { - if (!isset($this->storageDetails)) { - $module_handler = \Drupal::moduleHandler(); - - // Collect the storage details from the storage backend, and let other - // modules alter it. This invokes hook_field_storage_details() and - // hook_field_storage_details_alter(). - $details = (array) $module_handler->invoke($this->storage['module'], 'field_storage_details', array($this)); - $module_handler->alter('field_storage_details', $details, $this); - - $this->storageDetails = $details; - } - - return $this->storageDetails; - } - - /** - * {@inheritdoc} - */ public function getBundles() { if (empty($this->deleted)) { $map = field_info_field_map(); - if (isset($map[$this->id]['bundles'])) { - return $map[$this->id]['bundles']; + if (isset($map[$this->entity_type][$this->name]['bundles'])) { + return $map[$this->entity_type][$this->name]['bundles']; } } return array(); @@ -561,7 +507,7 @@ public function getBundles() { * {@inheritdoc} */ public function getFieldName() { - return $this->id; + return $this->name; } /** @@ -664,7 +610,7 @@ public function &offsetGet($offset) { return $this->uuid; case 'field_name': - return $this->id; + return $this->name; case 'columns': $this->getSchema(); @@ -677,10 +623,6 @@ public function &offsetGet($offset) { case 'bundles': $bundles = $this->getBundles(); return $bundles; - - case 'storage_details': - $this->getStorageDetails(); - return $this->storageDetails; } return $this->{$offset}; @@ -738,28 +680,27 @@ public function hasData() { $storage_details = $this->getSchema(); $columns = array_keys($storage_details['columns']); $factory = \Drupal::service('entity.query'); - foreach ($this->getBundles() as $entity_type => $bundle) { - // Entity Query throws an exception if there is no base table. - $entity_info = \Drupal::entityManager()->getDefinition($entity_type); - if (!isset($entity_info['base_table'])) { - continue; - } - $query = $factory->get($entity_type); - $group = $query->orConditionGroup(); - foreach ($columns as $column) { - $group->exists($this->id() . '.' . $column); - } - $result = $query - ->condition($group) - ->count() - ->accessCheck(FALSE) - ->range(0, 1) - ->execute(); - if ($result) { - return TRUE; - } + // Entity Query throws an exception if there is no base table. + $entity_info = \Drupal::entityManager()->getDefinition($this->entity_type); + if (!isset($entity_info['base_table'])) { + continue; + } + $query = $factory->get($this->entity_type); + $group = $query->orConditionGroup(); + foreach ($columns as $column) { + $group->exists($this->name . '.' . $column); + } + $result = $query + ->condition($group) + ->count() + ->accessCheck(FALSE) + ->range(0, 1) + ->execute(); + if ($result) { + return TRUE; } return FALSE; } + } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php index 9628256..489a908 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php @@ -7,6 +7,7 @@ namespace Drupal\field\Plugin\Core\Entity; +use Drupal\Component\Utility\String; use Drupal\Core\Entity\Annotation\EntityType; use Drupal\Core\Annotation\Translation; use Drupal\Core\Config\Entity\ConfigEntityBase; @@ -34,7 +35,7 @@ class FieldInstance extends ConfigEntityBase implements FieldInstanceInterface { /** - * The instance ID (machine name). + * The instance ID. * * The ID consists of 3 parts: the entity type, bundle and the field name. * @@ -234,10 +235,10 @@ class FieldInstance extends ConfigEntityBase implements FieldInstanceInterface { public function __construct(array $values, $entity_type = 'field_instance') { // Accept incoming 'field_name' instead of 'field_uuid', for easier DX on // creation of new instances. - if (isset($values['field_name']) && !isset($values['field_uuid'])) { - $field = field_info_field($values['field_name']); + if (isset($values['field_name']) && isset($values['entity_type']) && !isset($values['field_uuid'])) { + $field = field_info_field($values['entity_type'], $values['field_name']); if (!$field) { - throw new FieldException(format_string('Attempt to create an instance of unknown, disabled, or deleted field @field_id', array('@field_id' => $values['field_name']))); + throw new FieldException(format_string('Attempt to create an instance of field @field_name that does not exist on entity type @entity_type.', array('@field_name' => $values['field_name'], '@entity_type' => $values['entity_type']))); } $values['field_uuid'] = $field->uuid; } @@ -266,16 +267,16 @@ public function __construct(array $values, $entity_type = 'field_instance') { // Check required properties. if (empty($values['entity_type'])) { - throw new FieldException(format_string('Attempt to create an instance of field @field_id without an entity type.', array('@field_id' => $this->field->id))); + throw new FieldException(format_string('Attempt to create an instance of field @field_name without an entity_type.', array('@field_name' => $this->field->name))); } if (empty($values['bundle'])) { - throw new FieldException(format_string('Attempt to create an instance of field @field_id without a bundle.', array('@field_id' => $this->field->id))); + throw new FieldException(format_string('Attempt to create an instance of field @field_name without a bundle.', array('@field_name' => $this->field->name))); } - // 'Label' defaults to the field ID (mostly useful for field instances + // 'Label' defaults to the field name (mostly useful for field instances // created in tests). $values += array( - 'label' => $this->field->id, + 'label' => $this->field->name, ); parent::__construct($values, $entity_type); } @@ -284,7 +285,7 @@ public function __construct(array $values, $entity_type = 'field_instance') { * {@inheritdoc} */ public function id() { - return $this->entity_type . '.' . $this->bundle . '.' . $this->field->id; + return $this->entity_type . '.' . $this->bundle . '.' . $this->field->name; } /** @@ -354,14 +355,9 @@ public function save() { protected function saveNew() { $instance_controller = \Drupal::entityManager()->getStorageController($this->entityType); - // Check that the field can be attached to this entity type. - if (!empty($this->field->entity_types) && !in_array($this->entity_type, $this->field->entity_types)) { - throw new FieldException(format_string('Attempt to create an instance of field @field_id on forbidden entity type @entity_type.', array('@field_id' => $this->field->id, '@entity_type' => $this->entity_type))); - } - // Ensure the field instance is unique within the bundle. if ($prior_instance = $instance_controller->load($this->id())) { - throw new FieldException(format_string('Attempt to create an instance of field @field_id on bundle @bundle that already has an instance of that field.', array('@field_id' => $this->field->id, '@bundle' => $this->bundle))); + throw new FieldException(format_string('Attempt to create an instance of field %name on bundle @bundle that already has an instance of that field.', array('%name' => $this->field->name, '@bundle' => $this->bundle))); } // Set the field UUID. @@ -409,6 +405,9 @@ protected function saveUpdated() { // Ensure default values are present. $this->prepareSave(); + // Notify the entity storage controller. + \Drupal::entityManager()->getStorageController($this->entity_type)->handleInstanceUpdate($this, $original); + // Save the configuration. $result = parent::save(); field_cache_clear(); @@ -436,7 +435,6 @@ protected function prepareSave() { */ public function delete($field_cleanup = TRUE) { if (!$this->deleted) { - $module_handler = \Drupal::moduleHandler(); $state = \Drupal::state(); // Delete the configuration of this instance and save the configuration @@ -450,16 +448,15 @@ public function delete($field_cleanup = TRUE) { parent::delete(); + // Notify the entity storage controller. + \Drupal::entityManager()->getStorageController($this->entity_type)->handleInstanceDelete($this); + // Clear the cache. field_cache_clear(); - // Mark instance data for deletion by invoking - // hook_field_storage_delete_instance(). - $module_handler->invoke($this->field->storage['module'], 'field_storage_delete_instance', array($this)); - // Remove the instance from the entity form displays. if ($form_display = entity_load('entity_form_display', $this->entity_type . '.' . $this->bundle . '.default')) { - $form_display->removeComponent($this->field->id())->save(); + $form_display->removeComponent($this->field->name)->save(); } // Remove the instance from the entity displays. @@ -469,7 +466,7 @@ public function delete($field_cleanup = TRUE) { $ids[] = $this->entity_type . '.' . $this->bundle . '.' . $view_mode; } foreach (entity_load_multiple('entity_display', $ids) as $display) { - $display->removeComponent($this->field->id())->save(); + $display->removeComponent($this->field->name)->save(); } // Delete the field itself if we just deleted its last instance. @@ -490,7 +487,7 @@ public function getField() { * {@inheritdoc} */ public function getFieldName() { - return $this->field->id; + return $this->field->name; } /** @@ -584,7 +581,7 @@ public function &offsetGet($offset) { return $this->field_uuid; } if ($offset == 'field_name') { - return $this->field->id; + return $this->field->name; } return $this->{$offset}; } diff --git a/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigField.php b/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigField.php index 31e65ca..da703fa 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigField.php +++ b/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigField.php @@ -42,8 +42,8 @@ public function validate() { $entity = $this->getParent(); $langcode = $entity->language()->id; - if (isset($legacy_errors[$this->getInstance()->getField()->id()][$langcode])) { - foreach ($legacy_errors[$this->getInstance()->getField()->id()][$langcode] as $delta => $item_errors) { + if (isset($legacy_errors[$this->getInstance()->getField()->name][$langcode])) { + foreach ($legacy_errors[$this->getInstance()->getField()->name][$langcode] as $delta => $item_errors) { foreach ($item_errors as $item_error) { // We do not have the information about which column triggered the // error, so assume the first column... diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php b/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php index d6ddcac..75b7252 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php +++ b/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php @@ -35,7 +35,7 @@ class FieldList extends Numeric { public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { parent::init($view, $display, $options); - $field = field_info_field($this->definition['field_name']); + $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']); $this->allowed_values = options_allowed_values($field); } diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php b/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php index 0c34d1b..83e24d9 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php +++ b/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php @@ -35,7 +35,7 @@ class ListString extends String { public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { parent::init($view, $display, $options); - $field = field_info_field($this->definition['field_name']); + $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']); $this->allowed_values = options_allowed_values($field); } diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php index fdfea10..a0e8f6e 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php +++ b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php @@ -7,8 +7,9 @@ namespace Drupal\field\Plugin\views\field; -use Drupal\Core\Language\Language; +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Language\Language; use Drupal\field\Plugin\Type\Formatter\FormatterPluginManager; use Drupal\views\ViewExecutable; use Drupal\views\Plugin\views\display\DisplayPluginBase; @@ -111,7 +112,7 @@ public static function create(ContainerInterface $container, array $configuratio public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { parent::init($view, $display, $options); - $this->field_info = $field = field_info_field($this->definition['field_name']); + $this->field_info = $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']); $this->multiple = FALSE; $this->limit_values = FALSE; @@ -286,7 +287,8 @@ public function clickSort($order) { } $this->ensureMyTable(); - $column = _field_sql_storage_columnname($this->definition['field_name'], $this->options['click_sort_column']); + $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']); + $column = DatabaseStorageController::_fieldColumnName($field, $this->options['click_sort_column']); if (!isset($this->aliases[$column])) { // Column is not in query; add a sort on it (without adding the column). $this->aliases[$column] = $this->tableAlias . '.' . $column; @@ -298,7 +300,7 @@ protected function defineOptions() { $options = parent::defineOptions(); // defineOptions runs before init/construct, so no $this->field_info - $field = field_info_field($this->definition['field_name']); + $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']); $field_type = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinition($field['type']); $column_names = array_keys($field['columns']); $default_column = ''; diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php b/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php index cfd2f6c..2b1d57c 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php +++ b/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php @@ -20,7 +20,7 @@ class FieldList extends ManyToOne { public function getValueOptions() { - $field = field_info_field($this->definition['field_name']); + $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']); $this->value_options = list_allowed_values($field); } diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php b/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php index 481105f..3103945 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php +++ b/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php @@ -28,7 +28,7 @@ class EntityReverse extends RelationshipPluginBase { public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { parent::init($view, $display, $options); - $this->field_info = field_info_field($this->definition['field_name']); + $this->field_info = field_info_field($this->definition['entity_type'], $this->definition['field_name']); } /** diff --git a/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php b/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php index c74d426..7b021e2 100644 --- a/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php @@ -14,7 +14,7 @@ class ActiveTest extends FieldTestBase { * * @var array */ - public static $modules = array('field_test'); + public static $modules = array('field_test', 'entity_test'); public static function getInfo() { return array( @@ -28,62 +28,28 @@ public static function getInfo() { * Test that fields are properly marked active or inactive. */ function testActive() { - $field_definition = array( - 'field_name' => 'field_1', + $field_name = 'field_1'; + entity_create('field_entity', array( + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'test_field', - // For this test, we need a storage backend provided by a different - // module than field_test.module. - 'storage' => array( - 'type' => 'field_sql_storage', - ), - ); - entity_create('field_entity', $field_definition)->save(); - - // Test disabling and enabling: - // - the field type module, - // - the storage module, - // - both. - $this->_testActiveHelper($field_definition, array('field_test')); - $this->_testActiveHelper($field_definition, array('field_sql_storage')); - $this->_testActiveHelper($field_definition, array('field_test', 'field_sql_storage')); - } - - /** - * Helper function for testActive(). - * - * Test dependency between a field and a set of modules. - * - * @param $field_definition - * A field definition. - * @param $modules - * An aray of module names. The field will be tested to be inactive as long - * as any of those modules is disabled. - */ - function _testActiveHelper($field_definition, $modules) { - $field_name = $field_definition['field_name']; - - // Read the field. - $field = field_read_field($field_name); - $this->assertTrue($field_definition <= $field, 'The field was properly read.'); - - module_disable($modules, FALSE); - - $fields = field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE)); - $this->assertTrue(isset($fields[$field_name]) && $field_definition < $field, 'The field is properly read when explicitly fetching inactive fields.'); - - // Re-enable modules one by one, and check that the field is still inactive - // while some modules remain disabled. - while ($modules) { - $field = field_read_field($field_name); - $this->assertTrue(empty($field), format_string('%modules disabled. The field is marked inactive.', array('%modules' => implode(', ', $modules)))); - - $module = array_shift($modules); - module_enable(array($module), FALSE); - } - - // Check that the field is active again after all modules have been - // enabled. - $field = field_read_field($field_name); - $this->assertTrue($field_definition <= $field, 'The field was was marked active.'); + ))->save(); + + // Check that the field is correctly found. + $field = field_read_field('entity_test', $field_name); + $this->assertFalse(empty($field), 'The field was properly read.'); + + // Disable the module providing the field type, and check that the field is + // found only if explicitly requesting inactive fields. + module_disable(array('field_test')); + $field = field_read_field('entity_test', $field_name); + $this->assertTrue(empty($field), 'The field is marked inactive when the field type is absent.'); + $field = field_read_field('entity_test', $field_name, array('include_inactive' => TRUE)); + $this->assertFalse(empty($field), 'The field is properly read when explicitly fetching inactive fields.'); + + // Re-enable the module, and check that the field is active again. + module_enable(array('field_test')); + $field = field_read_field('entity_test', $field_name); + $this->assertFalse(empty($field), 'The field was was marked active.'); } } diff --git a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php index 9637826..8c66ab1 100644 --- a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php @@ -7,10 +7,10 @@ namespace Drupal\field\Tests; -use Drupal\field\Plugin\Core\Entity\FieldInstance; +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\EntityInterface; +use Drupal\field\FieldInterface; -use Drupal\Core\Language\Language; /** * Unit test class for field bulk delete and batch purge functionality. @@ -50,7 +50,7 @@ class BulkDeleteTest extends FieldUnitTestBase { * * @var array */ - protected $entity_type = 'test_entity'; + protected $entity_type = 'entity_test'; public static function getInfo() { return array( @@ -114,14 +114,16 @@ function setUp() { // Create two fields. $field = entity_create('field_entity', array( - 'field_name' => 'bf_1', + 'name' => 'bf_1', + 'entity_type' => $this->entity_type, 'type' => 'test_field', 'cardinality' => 1 )); $field->save(); $this->fields[] = $field; $field = entity_create('field_entity', array( - 'field_name' => 'bf_2', + 'name' => 'bf_2', + 'entity_type' => $this->entity_type, 'type' => 'test_field', 'cardinality' => 4 )); @@ -130,11 +132,10 @@ function setUp() { // For each bundle, create an instance of each field, and 10 // entities with values for each field. - $this->entity_type = 'entity_test'; foreach ($this->bundles as $bundle) { foreach ($this->fields as $field) { entity_create('field_instance', array( - 'field_name' => $field->id(), + 'field_name' => $field->name, 'entity_type' => $this->entity_type, 'bundle' => $bundle, ))->save(); @@ -165,7 +166,7 @@ function setUp() { function testDeleteFieldInstance() { $bundle = reset($this->bundles); $field = reset($this->fields); - $field_name = $field->id(); + $field_name = $field->name; $factory = \Drupal::service('entity.query'); // There are 10 entities of this bundle. @@ -175,7 +176,7 @@ function testDeleteFieldInstance() { $this->assertEqual(count($found), 10, 'Correct number of entities found before deleting'); // Delete the instance. - $instance = field_info_instance($this->entity_type, $field->id(), $bundle); + $instance = field_info_instance($this->entity_type, $field->name, $bundle); $instance->delete(); // The instance still exists, deleted. @@ -198,19 +199,25 @@ function testDeleteFieldInstance() { ->condition("$field_name.deleted", 1) ->sort('id') ->execute(); - $ids = (object) array( - 'entity_type' => 'entity_test', - 'bundle' => $bundle, - ); - $entities = array(); - foreach ($found as $entity_id) { - $ids->entity_id = $entity_id; - $entities[$entity_id] = _field_create_entity_from_ids($ids); - } - field_attach_load($this->entity_type, $entities, FIELD_LOAD_CURRENT, array('instance' => $instance)); $this->assertEqual(count($found), 10, 'Correct number of entities found after deleting'); - foreach ($entities as $id => $entity) { - $this->assertEqual($this->entities[$id]->{$field->id()}->value, $entity->{$field->id()}[Language::LANGCODE_NOT_SPECIFIED][0]['value'], "Entity $id with deleted data loaded correctly"); + $this->assertFalse(array_diff($found, array_keys($this->entities))); + $this->checkFieldTableContents($field); + } + + /** + * Test that the actual stored content didn't change during delete. + * + * @param FieldInterface $field + */ + protected function checkFieldTableContents(FieldInterface $field) { + $schema = DatabaseStorageController::_fieldSqlSchema($field); + $table = DatabaseStorageController::_fieldTableName($field); + $column = DatabaseStorageController::_fieldColumnName($field, 'value'); + $result = db_select($table, 't') + ->fields('t', array_keys($schema[$table]['fields'])) + ->execute(); + foreach ($result as $row) { + $this->assertEqual($this->entities[$row->entity_id]->{$field->name}->value, $row->$column); } } @@ -226,7 +233,7 @@ function testPurgeInstance() { $field = reset($this->fields); // Delete the instance. - $instance = field_info_instance($this->entity_type, $field->id(), $bundle); + $instance = field_info_instance($this->entity_type, $field->name, $bundle); $instance->delete(); // No field hooks were called. @@ -241,19 +248,18 @@ function testPurgeInstance() { // There are $count deleted entities left. $found = \Drupal::entityQuery('entity_test') ->condition('type', $bundle) - ->condition($field->id() . '.deleted', 1) + ->condition($field->name . '.deleted', 1) ->execute(); $this->assertEqual(count($found), $count, 'Correct number of entities found after purging 2'); } // Check hooks invocations. - // hook_field_load() and hook_field_delete() should have been called once - // for each entity in the bundle. + // hook_field_delete() should have been called once for each entity in the + // bundle. $actual_hooks = field_test_memorize(); $hooks = array(); $entities = $this->entities_by_bundles[$bundle]; foreach ($entities as $id => $entity) { - $hooks['field_test_field_load'][] = array($id => $entity); $hooks['field_test_field_delete'][] = $entity; } $this->checkHooksInvocations($hooks, $actual_hooks); @@ -286,7 +292,7 @@ function testPurgeField() { // Delete the first instance. $bundle = reset($this->bundles); - $instance = field_info_instance($this->entity_type, $field->id(), $bundle); + $instance = field_info_instance($this->entity_type, $field->name, $bundle); $instance->delete(); // Assert that hook_field_delete() was not called yet. @@ -297,13 +303,12 @@ function testPurgeField() { field_purge_batch(10); // Check hooks invocations. - // hook_field_load() and hook_field_delete() should have been called once - // for each entity in the bundle. + // hook_field_delete() should have been called once for each entity in the + // bundle. $actual_hooks = field_test_memorize(); $hooks = array(); $entities = $this->entities_by_bundles[$bundle]; foreach ($entities as $id => $entity) { - $hooks['field_test_field_load'][] = array($id => $entity); $hooks['field_test_field_delete'][] = $entity; } $this->checkHooksInvocations($hooks, $actual_hooks); @@ -317,7 +322,7 @@ function testPurgeField() { // Delete the second instance. $bundle = next($this->bundles); - $instance = field_info_instance($this->entity_type, $field->id(), $bundle); + $instance = field_info_instance($this->entity_type, $field->name, $bundle); $instance->delete(); // Assert that hook_field_delete() was not called yet. @@ -332,7 +337,6 @@ function testPurgeField() { $hooks = array(); $entities = $this->entities_by_bundles[$bundle]; foreach ($entities as $id => $entity) { - $hooks['field_test_field_load'][] = array($id => $entity); $hooks['field_test_field_delete'][] = $entity; } $this->checkHooksInvocations($hooks, $actual_hooks); diff --git a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php index 70c2236..fd9c189 100644 --- a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php @@ -37,14 +37,15 @@ public static function getInfo() { */ function testCreateField() { $field_definition = array( - 'field_name' => 'field_2', + 'name' => 'field_2', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); field_test_memorize(); $field = entity_create('field_entity', $field_definition); $field->save(); $mem = field_test_memorize(); - $this->assertIdentical($mem['field_test_field_entity_create'][0][0]['field_name'], $field_definition['field_name'], 'hook_entity_create() called with correct arguments.'); + $this->assertIdentical($mem['field_test_field_entity_create'][0][0]['field_name'], $field_definition['name'], 'hook_entity_create() called with correct arguments.'); $this->assertIdentical($mem['field_test_field_entity_create'][0][0]['type'], $field_definition['type'], 'hook_entity_create() called with correct arguments.'); // Read the configuration. Check against raw configuration data rather than @@ -53,7 +54,9 @@ function testCreateField() { $field_config = \Drupal::config('field.field.' . $field->id())->get(); // Ensure that basic properties are preserved. - $this->assertEqual($field_config['id'], $field_definition['field_name'], 'The field name is properly saved.'); + $this->assertEqual($field_config['name'], $field_definition['name'], 'The field name is properly saved.'); + $this->assertEqual($field_config['entity_type'], $field_definition['entity_type'], 'The field entity type is properly saved.'); + $this->assertEqual($field_config['id'], $field_definition['entity_type'] . '.' . $field_definition['name'], 'The field id is properly saved.'); $this->assertEqual($field_config['type'], $field_definition['type'], 'The field type is properly saved.'); // Ensure that cardinality defaults to 1. @@ -63,9 +66,6 @@ function testCreateField() { $field_type = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinition($field_definition['type']); $this->assertEqual($field_config['settings'], $field_type['settings'], 'Default field settings have been written.'); - // Ensure that default storage was set. - $this->assertEqual($field_config['storage']['type'], config('field.settings')->get('default_storage'), 'The field type is properly saved.'); - // Guarantee that the name is unique. try { entity_create('field_entity', $field_definition)->save(); @@ -78,7 +78,8 @@ function testCreateField() { // Check that field type is required. try { $field_definition = array( - 'field_name' => 'field_1', + 'name' => 'field_1', + 'entity_type' => 'entity_type', ); entity_create('field_entity', $field_definition)->save(); $this->fail(t('Cannot create a field with no type.')); @@ -90,7 +91,8 @@ function testCreateField() { // Check that field name is required. try { $field_definition = array( - 'type' => 'test_field' + 'type' => 'test_field', + 'entity_type' => 'entity_test', ); entity_create('field_entity', $field_definition)->save(); $this->fail(t('Cannot create an unnamed field.')); @@ -98,11 +100,24 @@ function testCreateField() { catch (FieldException $e) { $this->pass(t('Cannot create an unnamed field.')); } + // Check that entity type is required. + try { + $field_definition = array( + 'name' => 'test_field', + 'type' => 'test_field' + ); + entity_create('field_entity', $field_definition)->save(); + $this->fail('Cannot create a field without an entity type.'); + } + catch (FieldException $e) { + $this->pass('Cannot create a field without an entity type.'); + } // Check that field name must start with a letter or _. try { $field_definition = array( - 'field_name' => '2field_2', + 'name' => '2field_2', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); entity_create('field_entity', $field_definition)->save(); @@ -115,7 +130,8 @@ function testCreateField() { // Check that field name must only contain lowercase alphanumeric or _. try { $field_definition = array( - 'field_name' => 'field#_3', + 'name' => 'field#_3', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); entity_create('field_entity', $field_definition)->save(); @@ -128,7 +144,8 @@ function testCreateField() { // Check that field name cannot be longer than 32 characters long. try { $field_definition = array( - 'field_name' => '_12345678901234567890123456789012', + 'name' => '_12345678901234567890123456789012', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); entity_create('field_entity', $field_definition)->save(); @@ -143,7 +160,8 @@ function testCreateField() { try { $field_definition = array( 'type' => 'test_field', - 'field_name' => 'id', + 'name' => 'id', + 'entity_type' => 'entity_test', ); entity_create('field_entity', $field_definition)->save(); $this->fail(t('Cannot create a field bearing the name of an entity key.')); @@ -161,7 +179,8 @@ function testCreateField() { */ function testCreateFieldWithExplicitSchema() { $field_definition = array( - 'field_name' => 'field_2', + 'name' => 'field_2', + 'entity_type' => 'entity_test', 'type' => 'test_field', 'schema' => array( 'dummy' => 'foobar' @@ -172,68 +191,32 @@ function testCreateFieldWithExplicitSchema() { } /** - * Test failure to create a field. - */ - function testCreateFieldFail() { - $field_name = 'duplicate'; - $field_definition = array('field_name' => $field_name, 'type' => 'test_field', 'storage' => array('type' => 'field_test_storage_failure')); - $field = entity_load('field_entity', $field_name); - - // The field does not exist. - $this->assertFalse($field, 'The field does not exist.'); - - // Try to create the field. - try { - entity_create('field_entity', $field_definition)->save(); - $this->assertTrue(FALSE, 'Field creation (correctly) fails.'); - } - catch (\Exception $e) { - $this->assertTrue(TRUE, 'Field creation (correctly) fails.'); - } - - // The field does not exist. - $field = entity_load('field_entity', $field_name); - $this->assertFalse($field, 'The field does not exist.'); - } - - /** - * Tests reading a single field definition. - */ - function testReadField() { - $field_definition = array( - 'field_name' => 'field_1', - 'type' => 'test_field', - ); - entity_create('field_entity', $field_definition)->save(); - - // Read the field back. - $field = field_read_field($field_definition['field_name']); - $this->assertTrue($field_definition < $field, 'The field was properly read.'); - } - - /** * Tests reading field definitions. */ function testReadFields() { $field_definition = array( - 'field_name' => 'field_1', + 'name' => 'field_1', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); - entity_create('field_entity', $field_definition)->save(); + $field = entity_create('field_entity', $field_definition); + $field->save(); + $id = $field->id(); + field_cache_clear(); // Check that 'single column' criteria works. - $fields = field_read_fields(array('field_name' => $field_definition['field_name'])); - $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.'); + $fields = field_read_fields(array('id' => $id)); + $this->assertTrue(count($fields) == 1 && isset($fields[$id]), 'The field was properly read.'); // Check that 'multi column' criteria works. - $fields = field_read_fields(array('field_name' => $field_definition['field_name'], 'type' => $field_definition['type'])); - $this->assertTrue(count($fields) == 1 && isset($fields[$field_definition['field_name']]), 'The field was properly read.'); - $fields = field_read_fields(array('field_name' => $field_definition['field_name'], 'type' => 'foo')); + $fields = field_read_fields(array('id' => $id, 'type' => $field_definition['type'])); + $this->assertTrue(count($fields) == 1 && isset($fields[$id]), 'The field was properly read.'); + $fields = field_read_fields(array('name' => $field_definition['name'], 'type' => 'foo')); $this->assertTrue(empty($fields), 'No field was found.'); // Create an instance of the field. $instance_definition = array( - 'field_name' => $field_definition['field_name'], + 'field_name' => $field_definition['name'], 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ); @@ -246,11 +229,14 @@ function testReadFields() { function testFieldIndexes() { // Check that indexes specified by the field type are used by default. $field_definition = array( - 'field_name' => 'field_1', + 'name' => 'field_1', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); - entity_create('field_entity', $field_definition)->save(); - $field = field_read_field($field_definition['field_name']); + $field = entity_create('field_entity', $field_definition); + $field->save(); + field_cache_clear(); + $field = entity_load('field_entity', $field->id()); $schema = $field->getSchema(); $expected_indexes = array('value' => array('value')); $this->assertEqual($schema['indexes'], $expected_indexes, 'Field type indexes saved by default'); @@ -258,14 +244,17 @@ function testFieldIndexes() { // Check that indexes specified by the field definition override the field // type indexes. $field_definition = array( - 'field_name' => 'field_2', + 'name' => 'field_2', + 'entity_type' => 'entity_test', 'type' => 'test_field', 'indexes' => array( 'value' => array(), ), ); - entity_create('field_entity', $field_definition)->save(); - $field = field_read_field($field_definition['field_name']); + $field = entity_create('field_entity', $field_definition); + $field->save(); + field_cache_clear(); + $field = entity_load('field_entity', $field->id()); $schema = $field->getSchema(); $expected_indexes = array('value' => array()); $this->assertEqual($schema['indexes'], $expected_indexes, 'Field definition indexes override field type indexes'); @@ -273,14 +262,18 @@ function testFieldIndexes() { // Check that indexes specified by the field definition add to the field // type indexes. $field_definition = array( - 'field_name' => 'field_3', + 'name' => 'field_3', + 'entity_type' => 'entity_test', 'type' => 'test_field', 'indexes' => array( 'value_2' => array('value'), ), ); - entity_create('field_entity', $field_definition)->save(); - $field = field_read_field($field_definition['field_name']); + $field = entity_create('field_entity', $field_definition); + $field->save(); + $id = $field->id(); + field_cache_clear(); + $field = entity_load('field_entity', $id); $schema = $field->getSchema(); $expected_indexes = array('value' => array('value'), 'value_2' => array('value')); $this->assertEqual($schema['indexes'], $expected_indexes, 'Field definition indexes are merged with field type indexes'); @@ -293,30 +286,38 @@ function testDeleteField() { // TODO: Also test deletion of the data stored in the field ? // Create two fields (so we can test that only one is deleted). - $this->field = array('field_name' => 'field_1', 'type' => 'test_field'); + $this->field = array( + 'name' => 'field_1', + 'type' => 'test_field', + 'entity_type' => 'entity_test', + ); entity_create('field_entity', $this->field)->save(); - $this->another_field = array('field_name' => 'field_2', 'type' => 'test_field'); + $this->another_field = array( + 'name' => 'field_2', + 'type' => 'test_field', + 'entity_type' => 'entity_test', + ); entity_create('field_entity', $this->another_field)->save(); // Create instances for each. $this->instance_definition = array( - 'field_name' => $this->field['field_name'], + 'field_name' => $this->field['name'], 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ); entity_create('field_instance', $this->instance_definition)->save(); $another_instance_definition = $this->instance_definition; - $another_instance_definition['field_name'] = $this->another_field['field_name']; + $another_instance_definition['field_name'] = $this->another_field['name']; entity_create('field_instance', $another_instance_definition)->save(); // Test that the first field is not deleted, and then delete it. - $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE)); + $field = field_read_field('entity_test', $this->field['name'], array('include_deleted' => TRUE)); $this->assertTrue(!empty($field) && empty($field['deleted']), 'A new field is not marked for deletion.'); - field_info_field($this->field['field_name'])->delete(); + field_info_field('entity_test', $this->field['name'])->delete(); // Make sure that the field is marked as deleted when it is specifically // loaded. - $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE)); + $field = field_read_field('entity_test', $this->field['name'], array('include_deleted' => TRUE)); $this->assertTrue(!empty($field['deleted']), 'A deleted field is marked for deletion.'); // Make sure that this field's instance is marked as deleted when it is @@ -325,7 +326,7 @@ function testDeleteField() { $this->assertTrue(!empty($instance['deleted']), 'An instance for a deleted field is marked for deletion.'); // Try to load the field normally and make sure it does not show up. - $field = field_read_field($this->field['field_name']); + $field = field_read_field('entity_test', $this->field['name']); $this->assertTrue(empty($field), 'A deleted field is not loaded by default.'); // Try to load the instance normally and make sure it does not show up. @@ -333,7 +334,7 @@ function testDeleteField() { $this->assertTrue(empty($instance), 'An instance for a deleted field is not loaded by default.'); // Make sure the other field (and its field instance) are not deleted. - $another_field = field_read_field($this->another_field['field_name']); + $another_field = field_read_field('entity_test', $this->another_field['name']); $this->assertTrue(!empty($another_field) && empty($another_field['deleted']), 'A non-deleted field is not marked for deletion.'); $another_instance = field_read_instance('entity_test', $another_instance_definition['field_name'], $another_instance_definition['bundle']); $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), 'An instance of a non-deleted field is not marked for deletion.'); @@ -342,21 +343,18 @@ function testDeleteField() { // write data into it. entity_create('field_entity', $this->field)->save(); entity_create('field_instance', $this->instance_definition)->save(); - $field = field_read_field($this->field['field_name']); + $field = field_read_field('entity_test', $this->field['name']); $this->assertTrue(!empty($field) && empty($field['deleted']), 'A new field with a previously used name is created.'); $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']); $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new instance for a previously used field name is created.'); // Save an entity with data for the field - $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0)); - $langcode = Language::LANGCODE_NOT_SPECIFIED; + $entity = entity_create('entity_test', array()); $values[0]['value'] = mt_rand(1, 127); $entity->{$field['field_name']}->value = $values[0]['value']; - field_attach_insert($entity); + $entity = $this->entitySaveReload($entity); // Verify the field is present on load - $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0)); - field_attach_load('entity_test', array(0 => $entity)); $this->assertIdentical(count($entity->{$field['field_name']}), count($values), "Data in previously deleted field saves and loads correctly"); foreach ($values as $delta => $value) { $this->assertEqual($entity->{$field['field_name']}[$delta]->value, $values[$delta]['value'], "Data in previously deleted field saves and loads correctly"); @@ -364,7 +362,11 @@ function testDeleteField() { } function testUpdateFieldType() { - $field_definition = array('field_name' => 'field_type', 'type' => 'number_decimal'); + $field_definition = array( + 'name' => 'field_type', + 'entity_type' => 'entity_test', + 'type' => 'number_decimal', + ); $field = entity_create('field_entity', $field_definition); $field->save(); @@ -387,7 +389,8 @@ function testUpdateField() { // systems, it makes a good test case. $cardinality = 4; $field = entity_create('field_entity', array( - 'field_name' => 'field_update', + 'name' => 'field_update', + 'entity_type' => 'entity_test', 'type' => 'test_field', 'cardinality' => $cardinality, )); @@ -400,22 +403,18 @@ function testUpdateField() { $instance->save(); do { - // We need a unique ID for our entity. $cardinality will do. - $id = $cardinality; - $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id)); + $entity = entity_create('entity_test', array()); // Fill in the entity with more values than $cardinality. for ($i = 0; $i < 20; $i++) { - $entity->field_update[$i]->value = $i; + // We can not use $i here because 0 values are filtered out. + $entity->field_update[$i]->value = $i + 1; } - // Save the entity. - field_attach_insert($entity); // Load back and assert there are $cardinality number of values. - $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id)); - field_attach_load('entity_test', array($id => $entity)); - $this->assertEqual(count($entity->field_update), $field->cardinality, 'Cardinality is kept'); + $entity = $this->entitySaveReload($entity); + $this->assertEqual(count($entity->field_update), $field->cardinality); // Now check the values themselves. for ($delta = 0; $delta < $cardinality; $delta++) { - $this->assertEqual($entity->field_update[$delta]->value, $delta, 'Value is kept'); + $this->assertEqual($entity->field_update[$delta]->value, $delta + 1); } // Increase $cardinality and set the field cardinality to the new value. $field->cardinality = ++$cardinality; @@ -428,7 +427,8 @@ function testUpdateField() { */ function testUpdateFieldForbid() { $field = entity_create('field_entity', array( - 'field_name' => 'forbidden', + 'name' => 'forbidden', + 'entity_type' => 'entity_test', 'type' => 'test_field', 'settings' => array( 'changeable' => 0, diff --git a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php index e2fb2f9..3bfc7d2 100644 --- a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php @@ -70,7 +70,8 @@ function setUp() { $this->cardinality = 4; $field = array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test', 'type' => 'test_field', 'cardinality' => $this->cardinality, ); diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php index 16fabe5..eb115dc 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php @@ -52,12 +52,13 @@ function setUp() { $content_type = $content_type_info->type; $field = array( - 'field_name' => 'test_view_field', + 'name' => 'test_view_field', + 'entity_type' => 'node', 'type' => 'text', ); entity_create('field_entity', $field)->save(); $instance = array( - 'field_name' => $field['field_name'], + 'field_name' => $field['name'], 'entity_type' => 'node', 'bundle' => $content_type, ); @@ -66,7 +67,7 @@ function setUp() { // Assign display properties for the 'default' and 'teaser' view modes. foreach (array('default', 'teaser') as $view_mode) { entity_get_display('node', $content_type, $view_mode) - ->setComponent($field['field_name']) + ->setComponent($field['name']) ->save(); } diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php index 4739d5f..03490a5 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php @@ -236,7 +236,7 @@ function testFieldAttachPrepareViewMultiple() { */ function testFieldAttachCache() { // Initialize random values and a test entity. - $entity_init = entity_create('entity_test', array('id' => 1, 'revision_id' => 1, 'type' => $this->instance['bundle'])); + $entity_init = entity_create('entity_test', array('type' => $this->instance['bundle'])); $langcode = Language::LANGCODE_NOT_SPECIFIED; $values = $this->_generateTestFieldValues($this->field['cardinality']); @@ -250,87 +250,72 @@ function testFieldAttachCache() { // Save, and check that no cache entry is present. $entity = clone($entity_init); $entity->{$this->field_name}->setValue($values); - field_attach_insert($entity); - $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on insert'); - - // Load, and check that no cache entry is present. - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); - $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on load'); - + $entity = $this->entitySaveReload($entity); + $cid = "field:$entity_type:" . $entity->id(); + $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on insert and load'); // Cacheable entity type. $entity_type = 'entity_test_cache'; - $cid = "field:$entity_type:" . $entity_init->id(); - $instance_definition = $this->instance_definition; - $instance_definition['entity_type'] = $entity_type; - $instance_definition['bundle'] = $entity_type; - entity_create('field_instance', $instance_definition)->save(); - + $this->createFieldWithInstance('_2', 'entity_test_cache'); entity_info_cache_clear(); $entity_init = entity_create($entity_type, array( - 'id' => 1, - 'revision_id' => 1, 'type' => $entity_type, )); // Check that no initial cache entry is present. + $cid = "field:$entity_type:" . $entity->id(); $this->assertFalse(cache('field')->get($cid), 'Cached: no initial cache entry'); // Save, and check that no cache entry is present. $entity = clone($entity_init); - $entity->{$this->field_name} = $values; - field_attach_insert($entity); + $entity->{$this->field_name_2} = $values; + $entity->save(); + $cid = "field:$entity_type:" . $entity->id(); $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on insert'); - // Load a single field, and check that no cache entry is present. - $entity = clone($entity_init); - $instance = field_info_instance($entity->entityType(), $this->field_name, $entity->bundle()); - field_attach_load($entity_type, array($entity->id() => $entity), FIELD_LOAD_CURRENT, array('instance' => $instance)); - $cache = cache('field')->get($cid); - $this->assertFalse($cache, 'Cached: no cache entry on loading a single field'); - // Load, and check that a cache entry is present with the expected values. - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType()); + $controller->resetCache(); + $controller->load($entity->id()); $cache = cache('field')->get($cid); - $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load'); + $this->assertEqual($cache->data[$this->field_name_2][$langcode], $values, 'Cached: correct cache entry on load'); // Update with different values, and check that the cache entry is wiped. - $values = $this->_generateTestFieldValues($this->field['cardinality']); - $entity = clone($entity_init); - $entity->{$this->field_name} = $values; - field_attach_update($entity); + $values = $this->_generateTestFieldValues($this->field_name_2['cardinality']); + $entity = entity_create($entity_type, array( + 'type' => $entity_type, + 'id' => $entity->id(), + )); + $entity->{$this->field_name_2} = $values; + $entity->save(); $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on update'); // Load, and check that a cache entry is present with the expected values. - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $controller->resetCache(); + $controller->load($entity->id()); $cache = cache('field')->get($cid); - $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load'); + $this->assertEqual($cache->data[$this->field_name_2][$langcode], $values, 'Cached: correct cache entry on load'); // Create a new revision, and check that the cache entry is wiped. - $entity_init = entity_create($entity_type, array( - 'id' => 1, - 'revision_id' => 2, + $entity = entity_create($entity_type, array( 'type' => $entity_type, + 'id' => $entity->id(), )); - $values = $this->_generateTestFieldValues($this->field['cardinality']); - $entity = clone($entity_init); + $values = $this->_generateTestFieldValues($this->field_name_2['cardinality']); $entity->{$this->field_name} = $values; - field_attach_update($entity); - $cache = cache('field')->get($cid); + $entity->setNewRevision(); + $entity->save(); $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on new revision creation'); // Load, and check that a cache entry is present with the expected values. - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $controller->resetCache(); + $controller->load($entity->id()); $cache = cache('field')->get($cid); - $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load'); + $this->assertEqual($cache->data[$this->field_name_2][$langcode], $values, 'Cached: correct cache entry on load'); // Delete, and check that the cache entry is wiped. - field_attach_delete($entity); + $entity->delete(); $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry after delete'); } diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php index e5f28d0..1bd585a 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php @@ -62,26 +62,22 @@ function testFieldAttachSaveLoad() { // TODO : test empty values filtering and "compression" (store consecutive deltas). // Preparation: create three revisions and store them in $revision array. $values = array(); + $entity = entity_create($entity_type, array()); for ($revision_id = 0; $revision_id < 3; $revision_id++) { - $revision[$revision_id] = entity_create($entity_type, array('id' => 0, 'revision_id' => $revision_id)); // Note: we try to insert one extra value. - $values[$revision_id] = $this->_generateTestFieldValues($this->field['cardinality'] + 1); - $current_revision = $revision_id; - // If this is the first revision do an insert. - if (!$revision_id) { - $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]); - field_attach_insert($revision[$revision_id]); - } - else { - // Otherwise do an update. - $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]); - field_attach_update($revision[$revision_id]); - } + $current_values = $this->_generateTestFieldValues($this->field['cardinality'] + 1); + $entity->{$this->field_name}->setValue($current_values); + $entity->setNewRevision(); + $entity->save(); + $entity_id = $entity->id(); + $current_revision = $entity->getRevisionId(); + $values[$current_revision] = $current_values; } + $storage_controller = $this->container->get('plugin.manager.entity')->getStorageController($entity_type); + $storage_controller->resetCache(); + $entity = $storage_controller->load($entity_id); // Confirm current revision loads the correct data. - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0)); - field_attach_load($entity_type, array(0 => $entity)); // Number of values per field loaded equals the field cardinality. $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], 'Current revision: expected number of values'); for ($delta = 0; $delta < $this->field['cardinality']; $delta++) { @@ -92,9 +88,8 @@ function testFieldAttachSaveLoad() { } // Confirm each revision loads the correct data. - foreach (array_keys($revision) as $revision_id) { - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => $revision_id)); - field_attach_load_revision($entity_type, array(0 => $entity)); + foreach (array_keys($values) as $revision_id) { + $entity = $storage_controller->loadRevision($revision_id); // Number of values per field loaded equals the field cardinality. $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id))); for ($delta = 0; $delta < $this->field['cardinality']; $delta++) { @@ -130,7 +125,11 @@ function testFieldAttachLoadMultiple() { ); for ($i = 1; $i <= 3; $i++) { $field_names[$i] = 'field_' . $i; - $field = entity_create('field_entity', array('field_name' => $field_names[$i], 'type' => 'test_field')); + $field = entity_create('field_entity', array( + 'name' => $field_names[$i], + 'entity_type' => $entity_type, + 'type' => 'test_field', + )); $field->save(); $field_ids[$i] = $field['uuid']; foreach ($field_bundles_map[$i] as $bundle) { @@ -156,11 +155,14 @@ function testFieldAttachLoadMultiple() { $values[$index][$field_name] = mt_rand(1, 127); $entity->$field_name->setValue(array('value' => $values[$index][$field_name])); } - field_attach_insert($entity); + $entity->enforceIsnew(); + $entity->save(); } // Check that a single load correctly loads field values for both entities. - field_attach_load($entity_type, $entities); + $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType()); + $controller->resetCache(); + $entities = $controller->loadMultiple(); foreach ($entities as $index => $entity) { $instances = field_info_instances($entity_type, $bundles[$index]); foreach ($instances as $field_name => $instance) { @@ -170,165 +172,48 @@ function testFieldAttachLoadMultiple() { $this->assertEqual($entity->{$field_name}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => $index))); } } - - // Check that the single-field load option works. - $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $bundles[1])); - $instance = field_info_instance($entity->entityType(), $field_names[1], $entity->bundle()); - field_attach_load($entity_type, array(1 => $entity), FIELD_LOAD_CURRENT, array('instance' => $instance)); - $this->assertEqual($entity->{$field_names[1]}->value, $values[1][$field_names[1]], format_string('Entity %index: expected value was found.', array('%index' => 1))); - $this->assertEqual($entity->{$field_names[1]}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => 1))); - $this->assert(empty($entity->{$field_names[2]}->value), format_string('Entity %index: field %field_name is not loaded.', array('%index' => 2, '%field_name' => $field_names[2]))); - $this->assert(!isset($entity->{$field_names[3]}), format_string('Entity %index: field %field_name is not loaded.', array('%index' => 3, '%field_name' => $field_names[3]))); - } - - /** - * Test saving and loading fields using different storage backends. - */ - function testFieldAttachSaveLoadDifferentStorage() { - $entity_type = 'entity_test'; - - // Create two fields using different storage backends, and their instances. - $fields = array( - array( - 'field_name' => 'field_1', - 'type' => 'test_field', - 'cardinality' => 4, - 'storage' => array('type' => 'field_sql_storage') - ), - array( - 'field_name' => 'field_2', - 'type' => 'test_field', - 'cardinality' => 4, - 'storage' => array('type' => 'field_test_storage') - ), - ); - foreach ($fields as $field) { - entity_create('field_entity', $field)->save(); - $instance = array( - 'field_name' => $field['field_name'], - 'entity_type' => $entity_type, - 'bundle' => $entity_type, - ); - entity_create('field_instance', $instance)->save(); - } - - $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1)); - - // Create entity and insert random values. - $entity = clone($entity_init); - $values = array(); - foreach ($fields as $field) { - $values[$field['field_name']] = $this->_generateTestFieldValues($this->field['cardinality']); - $entity->{$field['field_name']} = $values[$field['field_name']]; - } - field_attach_insert($entity); - - // Check that values are loaded as expected. - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); - foreach ($fields as $field) { - $this->assertEqual($values[$field['field_name']], $entity->{$field['field_name']}->getValue(), format_string('%storage storage: expected values were found.', array('%storage' => $field['storage']['type']))); - } - } - - /** - * Test storage details alteration. - * - * @see field_test_storage_details_alter() - */ - function testFieldStorageDetailsAlter() { - $field_name = 'field_test_change_my_details'; - $field = entity_create('field_entity', array( - 'field_name' => $field_name, - 'type' => 'test_field', - 'cardinality' => 4, - 'storage' => array('type' => 'field_test_storage'), - )); - $field->save(); - $instance = entity_create('field_instance', array( - 'field_name' => $field_name, - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - )); - $instance->save(); - - // The storage details are indexed by a storage engine type. - $this->assertTrue(array_key_exists('drupal_variables', $field['storage_details']), 'The storage type is Drupal variables.'); - - $details = $field['storage_details']['drupal_variables']; - - // The field_test storage details are indexed by variable name. The details - // are altered, so moon and mars are correct for this test. - $this->assertTrue(array_key_exists('moon', $details[FIELD_LOAD_CURRENT]), 'Moon is available in the instance array.'); - $this->assertTrue(array_key_exists('mars', $details[FIELD_LOAD_REVISION]), 'Mars is available in the instance array.'); - - // Test current and revision storage details together because the columns - // are the same. - foreach ($field['columns'] as $column_name => $attributes) { - $this->assertEqual($details[FIELD_LOAD_CURRENT]['moon'][$column_name], $column_name, format_string('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'moon[FIELD_LOAD_CURRENT]'))); - $this->assertEqual($details[FIELD_LOAD_REVISION]['mars'][$column_name], $column_name, format_string('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'mars[FIELD_LOAD_REVISION]'))); - } } /** * Tests insert and update with empty or NULL fields. */ function testFieldAttachSaveEmptyData() { - $entity_type = 'entity_test_rev'; + $entity_type = 'entity_test'; $this->createFieldWithInstance('', $entity_type); - $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1)); + $entity_init = entity_create($entity_type, array('id' => 1)); // Insert: Field is NULL. - field_cache_clear(); - $entity = clone($entity_init); + $entity = clone $entity_init; $entity->{$this->field_name} = NULL; - field_attach_insert($entity); - - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $entity->enforceIsNew(); + $entity = $this->entitySaveReload($entity); $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved'); // Add some real data. - field_cache_clear(); $entity = clone($entity_init); $values = $this->_generateTestFieldValues(1); $entity->{$this->field_name} = $values; - field_attach_insert($entity); - - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $entity = $this->entitySaveReload($entity); $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved'); // Update: Field is NULL. Data should be wiped. - field_cache_clear(); $entity = clone($entity_init); $entity->{$this->field_name} = NULL; - field_attach_update($entity); - - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $entity = $this->entitySaveReload($entity); $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: NULL field removes existing values'); // Re-add some data. - field_cache_clear(); $entity = clone($entity_init); $values = $this->_generateTestFieldValues(1); $entity->{$this->field_name} = $values; - field_attach_update($entity); - - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $entity = $this->entitySaveReload($entity); $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved'); // Update: Field is empty array. Data should be wiped. - field_cache_clear(); $entity = clone($entity_init); $entity->{$this->field_name} = array(); - field_attach_update($entity); - - $entity = clone($entity_init); - field_attach_load($entity_type, array($entity->id() => $entity)); + $entity = $this->entitySaveReload($entity); $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: empty array removes existing values'); } @@ -351,11 +236,8 @@ function testFieldAttachSaveEmptyDataDefaultValue() { // Insert: Field is NULL. $entity = clone($entity_init); $entity->getBCEntity()->{$this->field_name} = NULL; - field_attach_insert($entity); - - $entity = clone($entity_init); - $entity->getBCEntity()->{$this->field_name} = array(); - field_attach_load($entity_type, array($entity->id() => $entity)); + $entity->enforceIsNew(); + $entity = $this->entitySaveReload($entity); $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved'); // Verify that prepopulated field values are not overwritten by defaults. @@ -370,53 +252,55 @@ function testFieldAttachSaveEmptyDataDefaultValue() { function testFieldAttachDelete() { $entity_type = 'entity_test_rev'; $this->createFieldWithInstance('', $entity_type); - $rev[0] = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle'])); + $entity = entity_create($entity_type, array('type' => $this->instance['bundle'])); + $vids = array(); // Create revision 0 $values = $this->_generateTestFieldValues($this->field['cardinality']); - $rev[0]->{$this->field_name} = $values; - field_attach_insert($rev[0]); + $entity->{$this->field_name} = $values; + $entity->save(); + $vids[] = $entity->getRevisionId(); // Create revision 1 - $rev[1] = entity_create($entity_type, array('id' => 0, 'revision_id' => 1, 'type' => $this->instance['bundle'])); - $rev[1]->{$this->field_name} = $values; - field_attach_update($rev[1]); + $entity->setNewRevision(); + $entity->save(); + $vids[] = $entity->getRevisionId(); // Create revision 2 - $rev[2] = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle'])); - $rev[2]->{$this->field_name} = $values; - field_attach_update($rev[2]); + $entity->setNewRevision(); + $entity->save(); + $vids[] = $entity->getRevisionId(); + $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType()); + $controller->resetCache(); // Confirm each revision loads - foreach (array_keys($rev) as $vid) { - $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle'])); - field_attach_load_revision($entity_type, array(0 => $read)); - $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values."); + foreach ($vids as $vid) { + $revision = $controller->loadRevision($vid); + $this->assertEqual(count($revision->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values."); } // Delete revision 1, confirm the other two still load. - field_attach_delete_revision($rev[1]); - foreach (array(0, 2) as $vid) { - $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle'])); - field_attach_load_revision($entity_type, array(0 => $read)); - $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values."); + $controller->deleteRevision($vids[1]); + $controller->resetCache(); + foreach (array(0, 2) as $key) { + $vid = $vids[$key]; + $revision = $controller->loadRevision($vid); + $this->assertEqual(count($revision->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values."); } // Confirm the current revision still loads - $read = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle'])); - field_attach_load($entity_type, array(0 => $read)); - $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values."); + $controller->resetCache(); + $current = $controller->load($entity->id()); + $this->assertEqual(count($current->{$this->field_name}), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values."); // Delete all field data, confirm nothing loads - field_attach_delete($rev[2]); + $entity->delete(); + $controller->resetCache(); foreach (array(0, 1, 2) as $vid) { - $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle'])); - field_attach_load_revision($entity_type, array(0 => $read)); - $this->assertIdentical($read->{$this->field_name}[0]->getValue(), array(), "The test entity revision $vid is deleted."); + $revision = $controller->loadRevision($vid); + $this->assertFalse($revision); } - $read = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle'])); - field_attach_load($entity_type, array(0 => $read)); - $this->assertIdentical($read->{$this->field_name}[0]->getValue(), array(), 'The test entity current revision is deleted.'); + $this->assertFalse($controller->load($entity->id())); } /** @@ -435,14 +319,12 @@ function testEntityCreateRenameBundle() { entity_create('field_instance', $this->instance_definition)->save(); // Save an entity with data in the field. - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle'])); + $entity = entity_create($entity_type, array('type' => $this->instance['bundle'])); $values = $this->_generateTestFieldValues($this->field['cardinality']); $entity->{$this->field_name} = $values; - field_attach_insert($entity); // Verify the field data is present on load. - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle'])); - field_attach_load($entity_type, array(0 => $entity)); + $entity = $this->entitySaveReload($entity); $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Data is retrieved for the new bundle"); // Rename the bundle. @@ -454,8 +336,9 @@ function testEntityCreateRenameBundle() { $this->assertIdentical($this->instance['bundle'], $new_bundle, "Bundle name has been updated in the instance."); // Verify the field data is present on load. - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle'])); - field_attach_load($entity_type, array(0 => $entity)); + $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType()); + $controller->resetCache(); + $entity = $controller->load($entity->id()); $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Bundle name has been updated in the field storage"); } @@ -476,7 +359,12 @@ function testEntityDeleteBundle() { // Create a second field for the test bundle $field_name = drupal_strtolower($this->randomName() . '_field_name'); - $field = array('field_name' => $field_name, 'type' => 'test_field', 'cardinality' => 1); + $field = array( + 'name' => $field_name, + 'entity_type' => $entity_type, + 'type' => 'test_field', + 'cardinality' => 1, + ); entity_create('field_entity', $field)->save(); $instance = array( 'field_name' => $field_name, @@ -489,15 +377,13 @@ function testEntityDeleteBundle() { entity_create('field_instance', $instance)->save(); // Save an entity with data for both fields - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle'])); + $entity = entity_create($entity_type, array('type' => $this->instance['bundle'])); $values = $this->_generateTestFieldValues($this->field['cardinality']); $entity->{$this->field_name} = $values; $entity->{$field_name} = $this->_generateTestFieldValues(1); - field_attach_insert($entity); + $entity = $this->entitySaveReload($entity); // Verify the fields are present on load - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle'])); - field_attach_load($entity_type, array(0 => $entity)); $this->assertEqual(count($entity->{$this->field_name}), 4, 'First field got loaded'); $this->assertEqual(count($entity->{$field_name}), 1, 'Second field got loaded'); @@ -505,8 +391,10 @@ function testEntityDeleteBundle() { entity_test_delete_bundle($this->instance['bundle'], $entity_type); // Verify no data gets loaded - $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle'])); - field_attach_load($entity_type, array(0 => $entity)); + $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType()); + $controller->resetCache(); + $entity= $controller->load($entity->id()); + $this->assertTrue(empty($entity->{$this->field_name}), 'No data for first field'); $this->assertTrue(empty($entity->{$field_name}), 'No data for second field'); diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php index b1a88fb..b6697e7 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php @@ -26,11 +26,13 @@ public static function getInfo() { * Tests creating fields and instances during default config import. */ function testImportCreateDefault() { - $field_id = 'field_test_import'; - $instance_id = "entity_test.entity_test.$field_id"; - $field_id_2 = 'field_test_import_2'; - $instance_id_2a = "entity_test.entity_test.$field_id_2"; - $instance_id_2b = "entity_test.entity_test.$field_id_2"; + $field_name = 'field_test_import'; + $field_id = "entity_test.$field_name"; + $instance_id = "entity_test.entity_test.$field_name"; + $field_name_2 = 'field_test_import_2'; + $field_id_2 = "entity_test.$field_name_2"; + $instance_id_2a = "entity_test.entity_test.$field_name_2"; + $instance_id_2b = "entity_test.test_bundle.$field_name_2"; // Check that the fields and instances do not exist yet. $this->assertFalse(entity_load('field_entity', $field_id)); @@ -72,15 +74,17 @@ function testImportCreateDefault() { */ function testImportCreate() { // One field with one field instance. - $field_id = 'field_test_import_staging'; - $instance_id = "entity_test.entity_test.$field_id"; + $field_name = 'field_test_import_staging'; + $field_id = "entity_test.$field_name"; + $instance_id = "entity_test.entity_test.$field_name"; $field_config_name = "field.field.$field_id"; $instance_config_name = "field.instance.$instance_id"; // One field with two field instances. - $field_id_2 = 'field_test_import_staging_2'; - $instance_id_2a = "entity_test.test_bundle.$field_id_2"; - $instance_id_2b = "entity_test.test_bundle_2.$field_id_2"; + $field_name_2 = 'field_test_import_staging_2'; + $field_id_2 = "entity_test.$field_name_2"; + $instance_id_2a = "entity_test.test_bundle.$field_name_2"; + $instance_id_2b = "entity_test.test_bundle_2.$field_name_2"; $field_config_name_2 = "field.field.$field_id_2"; $instance_config_name_2a = "field.instance.$instance_id_2a"; $instance_config_name_2b = "field.instance.$instance_id_2b"; diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php index 216d36a..23ae199 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php @@ -31,11 +31,13 @@ public static function getInfo() { * Tests deleting fields and instances as part of config import. */ public function testImportDelete() { - $field_id = 'field_test_import'; - $field_id_2 = 'field_test_import_2'; - $instance_id = "entity_test.test_bundle.$field_id"; - $instance_id_2a = "entity_test.test_bundle.$field_id_2"; - $instance_id_2b = "entity_test.test_bundle_2.$field_id_2"; + $field_name = 'field_test_import'; + $field_id = "entity_test.$field_name"; + $field_name_2 = 'field_test_import_2'; + $field_id_2 = "entity_test.$field_name_2"; + $instance_id = "entity_test.test_bundle.$field_name"; + $instance_id_2a = "entity_test.test_bundle.$field_name_2"; + $instance_id_2b = "entity_test.test_bundle_2.$field_name_2"; $field_config_name = "field.field.$field_id"; $field_config_name_2 = "field.field.$field_id_2"; $instance_config_name = "field.instance.$instance_id"; diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php index 70f99f1..ce98890 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php @@ -32,15 +32,6 @@ function testFieldInfo() { $this->assertEqual($info[$t_key]['provider'], 'field_test', 'Field type field_test module appears.'); } - $storage_info = field_test_field_storage_info(); - $info = field_info_storage_types(); - foreach ($storage_info as $s_key => $storage) { - foreach ($storage as $key => $val) { - $this->assertEqual($info[$s_key][$key], $val, format_string('Storage type %s_key key %key is %value', array('%s_key' => $s_key, '%key' => $key, '%value' => print_r($val, TRUE)))); - } - $this->assertEqual($info[$s_key]['module'], 'field_test', 'Storage type field_test module appears.'); - } - // Verify that no unexpected instances exist. $instances = field_info_instances('entity_test'); $expected = array(); @@ -51,7 +42,8 @@ function testFieldInfo() { // Create a field, verify it shows up. $core_fields = field_info_fields(); $field = entity_create('field_entity', array( - 'field_name' => drupal_strtolower($this->randomName()), + 'name' => drupal_strtolower($this->randomName()), + 'entity_type' => 'entity_test', 'type' => 'test_field', )); $field->save(); @@ -69,7 +61,7 @@ function testFieldInfo() { // Create an instance, verify that it shows up $instance_definition = array( - 'field_name' => $field['field_name'], + 'field_name' => $field['name'], 'entity_type' => 'entity_test', 'bundle' => 'entity_test', 'label' => $this->randomName(), @@ -121,7 +113,8 @@ function testFieldInfo() { */ function testFieldPrepare() { $field_definition = array( - 'field_name' => 'field', + 'name' => 'field', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); $field = entity_create('field_entity', $field_definition); @@ -136,7 +129,7 @@ function testFieldPrepare() { field_info_cache_clear(); // Read the field back. - $field = field_info_field($field_definition['field_name']); + $field = field_info_field('entity_test', $field_definition['name']); // Check that all expected settings are in place. $field_type = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinition($field_definition['type']); @@ -148,12 +141,13 @@ function testFieldPrepare() { */ function testInstancePrepare() { $field_definition = array( - 'field_name' => 'field', + 'name' => 'field', + 'entity_type' => 'entity_test', 'type' => 'test_field', ); entity_create('field_entity', $field_definition)->save(); $instance_definition = array( - 'field_name' => $field_definition['field_name'], + 'field_name' => $field_definition['name'], 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ); @@ -182,8 +176,10 @@ function testInstancePrepare() { function testInstanceDisabledEntityType() { // For this test the field type and the entity type must be exposed by // different modules. + $this->enableModules(array('node', 'comment')); $field_definition = array( - 'field_name' => 'field', + 'name' => 'field', + 'entity_type' => 'comment', 'type' => 'test_field', ); entity_create('field_entity', $field_definition)->save(); @@ -192,7 +188,7 @@ function testInstanceDisabledEntityType() { 'entity_type' => 'comment', 'bundle' => 'comment_node_article', ); - entity_create('field_instance', $instance_definition)->save(); + entity_create('field_instance', $instance_definition); // Disable coment module. This clears field_info cache. module_disable(array('comment')); @@ -212,11 +208,18 @@ function testFieldMap() { // Create a couple fields. $fields = array( array( - 'field_name' => 'field_1', + 'name' => 'field_1', + 'entity_type' => 'entity_test', 'type' => 'test_field', ), array( - 'field_name' => 'field_2', + 'name' => 'field_2', + 'entity_type' => 'entity_test', + 'type' => 'hidden_test_field', + ), + array( + 'name' => 'field_2', + 'entity_type' => 'entity_test_cache', 'type' => 'hidden_test_field', ), ); @@ -252,17 +255,20 @@ function testFieldMap() { } $expected = array( - 'field_1' => array( - 'type' => 'test_field', - 'bundles' => array( - 'entity_test' => array('entity_test', 'test_bundle_2'), + 'entity_test' => array( + 'field_1' => array( + 'type' => 'test_field', + 'bundles' => array('entity_test', 'test_bundle_2'), + ), + 'field_2' => array( + 'type' => 'hidden_test_field', + 'bundles' => array('entity_test'), ), ), - 'field_2' => array( - 'type' => 'hidden_test_field', - 'bundles' => array( - 'entity_test' => array('entity_test'), - 'entity_test_cache' => array('entity_test'), + 'entity_test_cache' => array( + 'field_2' => array( + 'type' => 'hidden_test_field', + 'bundles' => array('entity_test') ), ), ); @@ -293,7 +299,8 @@ function testFieldInfoCache() { // field_info_fields(). $field_name = drupal_strtolower($this->randomName()); $field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'test_field', )); $field->save(); diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php index cade864..3637788 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php @@ -44,13 +44,14 @@ function setUp() { parent::setUp(); $this->field_definition = array( - 'field_name' => drupal_strtolower($this->randomName()), + 'name' => drupal_strtolower($this->randomName()), + 'entity_type' => 'entity_test', 'type' => 'test_field', ); $this->field = entity_create('field_entity', $this->field_definition); $this->field->save(); $this->instance_definition = array( - 'field_name' => $this->field['field_name'], + 'field_name' => $this->field->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ); @@ -103,40 +104,6 @@ function testCreateFieldInstance() { $this->pass(t('Cannot create an instance of a non-existing field.')); } - // Create a field restricted to a specific entity type. - $field_restricted_definition = array( - 'field_name' => drupal_strtolower($this->randomName()), - 'type' => 'test_field', - 'entity_types' => array('entity_test_cache'), - ); - $field_restricted = entity_create('field_entity', $field_restricted_definition); - $field_restricted->save(); - - // Check that an instance can be added to an entity type allowed - // by the field. - try { - $instance = $this->instance_definition; - $instance['field_name'] = $field_restricted_definition['field_name']; - $instance['entity_type'] = 'entity_test_cache'; - entity_create('field_instance', $instance)->save(); - $this->pass(t('Can create an instance on an entity type allowed by the field.')); - } - catch (FieldException $e) { - $this->fail(t('Can create an instance on an entity type allowed by the field.')); - } - - // Check that an instance cannot be added to an entity type - // forbidden by the field. - try { - $instance = $this->instance_definition; - $instance['field_name'] = $field_restricted_definition['field_name']; - entity_create('field_instance', $instance)->save(); - $this->fail(t('Cannot create an instance on an entity type forbidden by the field.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create an instance on an entity type forbidden by the field.')); - } - // TODO: test other failures. } @@ -212,7 +179,7 @@ function testDeleteFieldInstance() { $another_instance->delete(); $deleted_fields = \Drupal::state()->get('field.field.deleted'); $this->assertTrue(isset($deleted_fields[$another_instance['field_id']]), 'A deleted field is marked for deletion.'); - $field = field_read_field($another_instance['field_name']); + $field = field_read_field($another_instance['entity_type'], $another_instance['field_name']); $this->assertFalse($field, 'The field marked to be deleted is not found anymore in the configuration.'); } diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php index 4580e7b..7ba1a18 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php @@ -20,7 +20,7 @@ * * @var array */ - public static $modules = array('user', 'entity', 'system', 'field', 'text', 'field_sql_storage', 'entity_test', 'field_test'); + public static $modules = array('user', 'entity', 'system', 'field', 'text', 'entity_test', 'field_test'); /** * A string for assert raw and text helper methods. @@ -65,7 +65,12 @@ function createFieldWithInstance($suffix = '', $entity_type = 'entity_test', $bu $instance_definition = 'instance_definition' . $suffix; $this->$field_name = drupal_strtolower($this->randomName() . '_field_name' . $suffix); - $this->$field = entity_create('field_entity', array('field_name' => $this->$field_name, 'type' => 'test_field', 'cardinality' => 4)); + $this->$field = entity_create('field_entity', array( + 'name' => $this->$field_name, + 'entity_type' => $entity_type, + 'type' => 'test_field', + 'cardinality' => 4, + )); $this->$field->save(); $this->$field_id = $this->{$field}['uuid']; $this->$instance_definition = array( @@ -92,6 +97,16 @@ function createFieldWithInstance($suffix = '', $entity_type = 'entity_test', $bu } /** + * Save and reload an entity. + */ + protected function entitySaveReload(EntityInterface $entity) { + $entity->save(); + $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType()); + $controller->resetCache(); + return $controller->load($entity->id()); + } + + /** * Generate random values for a field_test field. * * @param $cardinality diff --git a/core/modules/field/lib/Drupal/field/Tests/FormTest.php b/core/modules/field/lib/Drupal/field/Tests/FormTest.php index b7c600e..158c8de 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FormTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FormTest.php @@ -61,9 +61,23 @@ function setUp() { $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content')); $this->drupalLogin($web_user); - $this->field_single = array('field_name' => 'field_single', 'type' => 'test_field'); - $this->field_multiple = array('field_name' => 'field_multiple', 'type' => 'test_field', 'cardinality' => 4); - $this->field_unlimited = array('field_name' => 'field_unlimited', 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED); + $this->field_single = array( + 'name' => 'field_single', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + $this->field_multiple = array( + 'name' => 'field_multiple', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'cardinality' => 4, + ); + $this->field_unlimited = array( + 'name' => 'field_unlimited', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + ); $this->instance = array( 'entity_type' => 'entity_test', @@ -79,7 +93,7 @@ function setUp() { function testFieldFormSingle() { $field = $this->field_single; - $field_name = $field['field_name']; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; entity_create('field_entity', $field)->save(); entity_create('field_instance', $this->instance)->save(); @@ -162,7 +176,7 @@ function testFieldFormSingle() { */ function testFieldFormDefaultValue() { $field = $this->field_single; - $field_name = $field['field_name']; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; $default = rand(1, 127); $this->instance['default_value'] = array(array('value' => $default)); @@ -194,7 +208,7 @@ function testFieldFormDefaultValue() { function testFieldFormSingleRequired() { $field = $this->field_single; - $field_name = $field['field_name']; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; $this->instance['required'] = TRUE; entity_create('field_entity', $field)->save(); @@ -244,7 +258,7 @@ function testFieldFormSingleRequired() { function testFieldFormUnlimited() { $field = $this->field_unlimited; - $field_name = $field['field_name']; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; entity_create('field_entity', $field)->save(); entity_create('field_instance', $this->instance)->save(); @@ -331,7 +345,7 @@ function testFieldFormUnlimited() { function testFieldFormMultivalueWithRequiredRadio() { // Create a multivalue test field. $field = $this->field_unlimited; - $field_name = $field['field_name']; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; entity_create('field_entity', $field)->save(); entity_create('field_instance', $this->instance)->save(); @@ -342,7 +356,8 @@ function testFieldFormMultivalueWithRequiredRadio() { // Add a required radio field. entity_create('field_entity', array( - 'field_name' => 'required_radio_test', + 'name' => 'required_radio_test', + 'entity_type' => 'entity_test', 'type' => 'list_text', 'settings' => array( 'allowed_values' => array('yes' => 'yes', 'no' => 'no'), @@ -378,7 +393,7 @@ function testFieldFormMultivalueWithRequiredRadio() { function testFieldFormJSAddMore() { $field = $this->field_unlimited; - $field_name = $field['field_name']; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; entity_create('field_entity', $field)->save(); entity_create('field_instance', $this->instance)->save(); @@ -440,7 +455,7 @@ function testFieldFormMultipleWidget() { // Create a field with fixed cardinality and an instance using a multiple // widget. $field = $this->field_multiple; - $field_name = $field['field_name']; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; entity_create('field_entity', $field)->save(); entity_create('field_instance', $this->instance)->save(); @@ -485,10 +500,11 @@ function testFieldFormMultipleWidget() { * Tests fields with no 'edit' access. */ function testFieldFormAccess() { + $entity_type = 'entity_test_rev'; // Create a "regular" field. $field = $this->field_single; - $field_name = $field['field_name']; - $entity_type = 'entity_test_rev'; + $field['entity_type'] = $entity_type; + $field_name = $field['name']; $instance = $this->instance; $instance['field_name'] = $field_name; $instance['entity_type'] = $entity_type; @@ -501,10 +517,11 @@ function testFieldFormAccess() { // Create a field with no edit access - see field_test_field_access(). $field_no_access = array( - 'field_name' => 'field_no_edit_access', + 'name' => 'field_no_edit_access', + 'entity_type' => $entity_type, 'type' => 'test_field', ); - $field_name_no_access = $field_no_access['field_name']; + $field_name_no_access = $field_no_access['name']; $instance_no_access = array( 'field_name' => $field_name_no_access, 'entity_type' => $entity_type, @@ -577,7 +594,8 @@ function testFieldFormAccess() { function testFieldFormHiddenWidget() { $entity_type = 'entity_test_rev'; $field = $this->field_single; - $field_name = $field['field_name']; + $field['entity_type'] = $entity_type; + $field_name = $field['name']; $this->instance['field_name'] = $field_name; $this->instance['default_value'] = array(0 => array('value' => 99)); $this->instance['entity_type'] = $entity_type; diff --git a/core/modules/field/lib/Drupal/field/Tests/NestedFormTest.php b/core/modules/field/lib/Drupal/field/Tests/NestedFormTest.php index 3d180f6..e812ff5 100644 --- a/core/modules/field/lib/Drupal/field/Tests/NestedFormTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/NestedFormTest.php @@ -33,8 +33,17 @@ public function setUp() { $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content')); $this->drupalLogin($web_user); - $this->field_single = array('field_name' => 'field_single', 'type' => 'test_field'); - $this->field_unlimited = array('field_name' => 'field_unlimited', 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED); + $this->field_single = array( + 'name' => 'field_single', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + $this->field_unlimited = array( + 'name' => 'field_unlimited', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + ); $this->instance = array( 'entity_type' => 'entity_test', diff --git a/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php b/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php index 6f7f3a0..b54174f 100644 --- a/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php @@ -42,7 +42,8 @@ public function setUp() { // Create an field field and instance for validation. $field = array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test', 'type' => 'shape', ); entity_create('field_entity', $field)->save(); diff --git a/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php b/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php index e8b85d1..b4c4aa4 100644 --- a/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php @@ -42,7 +42,8 @@ public function setUp() { // Create an field field and instance for validation. $field = array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test', 'type' => 'test_field', ); entity_create('field_entity', $field)->save(); diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php index ebf9722..7b6ce22 100644 --- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php @@ -85,13 +85,14 @@ function setUp() { $this->entity_type = 'entity_test'; $this->field_definition = array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => $this->entity_type, 'type' => 'test_field', 'cardinality' => 4, 'translatable' => TRUE, ); entity_create('field_entity', $this->field_definition)->save(); - $this->field = field_read_field($this->field_name); + $this->field = field_read_field($this->entity_type, $this->field_name); $this->instance_definition = array( 'field_name' => $this->field_name, @@ -153,8 +154,7 @@ function testTranslatableFieldSaveLoad() { // Prepare the field translations. $entity_type = 'entity_test'; field_test_entity_info_translatable($entity_type, TRUE); - $id = $revision_id = 1; - $entity = entity_create($entity_type, array('id' => $id, 'revision_id' => $revision_id, 'type' => $this->instance['bundle'])); + $entity = entity_create($entity_type, array('type' => $this->instance['bundle'])); $field_translations = array(); $available_langcodes = field_available_languages($entity_type, $this->field); $this->assertTrue(count($available_langcodes) > 1, 'Field is translatable.'); @@ -165,10 +165,7 @@ function testTranslatableFieldSaveLoad() { } // Save and reload the field translations. - field_attach_insert($entity); - $entity = entity_create($entity_type, array('id' => $id, 'revision_id' => $revision_id, 'type' => $this->instance['bundle'])); - $entity->langcode->value = reset($available_langcodes); - field_attach_load($entity_type, array($id => $entity)); + $entity = $this->entitySaveReload($entity); // Check if the correct values were saved/loaded. foreach ($field_translations as $langcode => $items) { @@ -182,7 +179,7 @@ function testTranslatableFieldSaveLoad() { // Test default values. $field_name_default = drupal_strtolower($this->randomName() . '_field_name'); $field_definition = $this->field_definition; - $field_definition['field_name'] = $field_name_default; + $field_definition['name'] = $field_name_default; entity_create('field_entity', $field_definition)->save(); $instance_definition = $this->instance_definition; @@ -197,9 +194,7 @@ function testTranslatableFieldSaveLoad() { asort($translation_langcodes); $translation_langcodes = array_values($translation_langcodes); - $id++; - $revision_id++; - $values = array('id' => $id, 'revision_id' => $revision_id, 'type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]); + $values = array('type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]); $entity = entity_create($entity_type, $values); foreach ($translation_langcodes as $langcode) { $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']); @@ -217,9 +212,7 @@ function testTranslatableFieldSaveLoad() { // Check that explicit empty values are not overridden with default values. foreach (array(NULL, array()) as $empty_items) { - $id++; - $revision_id++; - $values = array('id' => $id, 'revision_id' => $revision_id, 'type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]); + $values = array('type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]); $entity = entity_create($entity_type, $values); foreach ($translation_langcodes as $langcode) { $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']); @@ -244,7 +237,8 @@ function testFieldDisplayLanguage() { // We need an additional field here to properly test display language // suggestions. $field = array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => $entity_type, 'type' => 'test_field', 'cardinality' => 2, 'translatable' => TRUE, @@ -252,7 +246,7 @@ function testFieldDisplayLanguage() { entity_create('field_entity', $field)->save(); $instance = array( - 'field_name' => $field['field_name'], + 'field_name' => $field['name'], 'entity_type' => $entity_type, 'bundle' => 'entity_test', ); @@ -272,7 +266,7 @@ function testFieldDisplayLanguage() { // enabled. foreach ($instances as $instance) { $field_name = $instance['field_name']; - $field = field_info_field($field_name); + $field = $instance->getField(); do { // Index 0 is reserved for the requested language, this way we ensure // that no field is actually populated with it. diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php index df93f12..a31153f 100644 --- a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php @@ -33,7 +33,7 @@ class TranslationWebTest extends FieldTestBase { * * @var string */ - protected $entity_type = 'test_entity'; + protected $entity_type = 'entity_test_rev'; /** * The field to use in this test. @@ -62,16 +62,15 @@ function setUp() { $this->field_name = drupal_strtolower($this->randomName() . '_field_name'); - $this->entity_type = 'entity_test_rev'; - $field = array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => $this->entity_type, 'type' => 'test_field', 'cardinality' => 4, 'translatable' => TRUE, ); entity_create('field_entity', $field)->save(); - $this->field = field_read_field($this->field_name); + $this->field = field_read_field($this->entity_type, $this->field_name); $instance = array( 'field_name' => $this->field_name, diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php index 4bf2625..d4d86ac 100644 --- a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php @@ -6,6 +6,7 @@ */ namespace Drupal\field\Tests\Views; +use Drupal\Core\Entity\DatabaseStorageController; /** * Test the produced views_data. @@ -28,9 +29,9 @@ public static function getInfo() { function setUp() { parent::setUp(); - $field_names = $this->setUpFields(); + $field_names = $this->setUpFields(1); - // The first one will be attached to nodes only. + // Attach the field to nodes only. $instance = array( 'field_name' => $field_names[0], 'entity_type' => 'node', @@ -38,33 +39,10 @@ function setUp() { ); entity_create('field_instance', $instance)->save(); - // The second one will be attached to users only. - $instance = array( - 'field_name' => $field_names[1], - 'entity_type' => 'user', - 'bundle' => 'user', - ); - entity_create('field_instance', $instance)->save(); - - // The third will be attached to both nodes and users. - $instance = array( - 'field_name' => $field_names[2], - 'entity_type' => 'node', - 'bundle' => 'page', - ); - entity_create('field_instance', $instance)->save(); - $instance = array( - 'field_name' => $field_names[2], - 'entity_type' => 'user', - 'bundle' => 'user', - ); - entity_create('field_instance', $instance)->save(); - // Now create some example nodes/users for the view result. for ($i = 0; $i < 5; $i++) { $edit = array( - 'field_name_0' => array((array('value' => $this->randomName()))), - 'field_name_2' => array((array('value' => $this->randomName()))), + $field_names[0] => array((array('value' => $this->randomName()))), ); $nodes[] = $this->drupalCreateNode($edit); } @@ -84,8 +62,8 @@ function testViewsData() { // Check the table and the joins of the first field. // Attached to node only. $field = $this->fields[0]; - $current_table = _field_sql_storage_tablename($field); - $revision_table = _field_sql_storage_revision_tablename($field); + $current_table = DatabaseStorageController::_fieldTableName($field); + $revision_table = DatabaseStorageController::_fieldRevisionTableName($field); $data[$current_table] = $views_data->get($current_table); $data[$revision_table] = $views_data->get($revision_table); @@ -113,49 +91,6 @@ function testViewsData() { ), ); $this->assertEqual($expected_join, $data[$revision_table]['table']['join']['node_field_revision']); - - // Check the table and the joins of the second field. - // Attached to both node and user. - $field_2 = $this->fields[2]; - $current_table_2 = _field_sql_storage_tablename($field_2); - $revision_table_2 = _field_sql_storage_revision_tablename($field_2); - $data[$current_table_2] = $views_data->get($current_table_2); - $data[$revision_table_2] = $views_data->get($revision_table_2); - - $this->assertTrue(isset($data[$current_table_2])); - $this->assertTrue(isset($data[$revision_table_2])); - // The second field should join against both node and users. - $this->assertTrue(isset($data[$current_table_2]['table']['join']['node'])); - $this->assertTrue(isset($data[$revision_table_2]['table']['join']['node_field_revision'])); - $this->assertTrue(isset($data[$current_table_2]['table']['join']['users'])); - - $expected_join = array( - 'left_field' => 'nid', - 'field' => 'entity_id', - 'extra' => array( - array('field' => 'entity_type', 'value' => 'node'), - array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE), - ) - ); - $this->assertEqual($expected_join, $data[$current_table_2]['table']['join']['node']); - $expected_join = array( - 'left_field' => 'vid', - 'field' => 'revision_id', - 'extra' => array( - array('field' => 'entity_type', 'value' => 'node'), - array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE), - ) - ); - $this->assertEqual($expected_join, $data[$revision_table_2]['table']['join']['node_field_revision']); - $expected_join = array( - 'left_field' => 'uid', - 'field' => 'entity_id', - 'extra' => array( - array('field' => 'entity_type', 'value' => 'user'), - array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE), - ) - ); - $this->assertEqual($expected_join, $data[$current_table_2]['table']['join']['users']); } } diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php b/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php index 3cba44c..2f8e5a6 100644 --- a/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php +++ b/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php @@ -59,7 +59,11 @@ function setUpFields($amount = 3) { $field_names = array(); for ($i = 0; $i < $amount; $i++) { $field_names[$i] = 'field_name_' . $i; - $field = array('field_name' => $field_names[$i], 'type' => 'text'); + $field = array( + 'name' => $field_names[$i], + 'entity_type' => 'node', + 'type' => 'text', + ); $this->fields[$i] = $field = entity_create('field_entity', $field); $field->save(); @@ -70,7 +74,7 @@ function setUpFields($amount = 3) { function setUpInstances($bundle = 'page') { foreach ($this->fields as $key => $field) { $instance = array( - 'field_name' => $field['field_name'], + 'field_name' => $field['name'], 'entity_type' => 'node', 'bundle' => 'page', ); diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php index 8658c52..2002c0f 100644 --- a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php @@ -47,10 +47,20 @@ protected function setUp() { $this->setUpFields(3); // Setup a field with cardinality > 1. - $this->fields[3] = $field = entity_create('field_entity', array('field_name' => 'field_name_3', 'type' => 'text', 'cardinality' => FIELD_CARDINALITY_UNLIMITED)); + $this->fields[3] = $field = entity_create('field_entity', array( + 'name' => 'field_name_3', + 'entity_type' => 'node', + 'type' => 'text', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + )); $field->save(); // Setup a field that will have no value. - $this->fields[4] = $field = entity_create('field_entity', array('field_name' => 'field_name_4', 'type' => 'text', 'cardinality' => FIELD_CARDINALITY_UNLIMITED)); + $this->fields[4] = $field = entity_create('field_entity', array( + 'name' => 'field_name_4', + 'entity_type' => 'node', + 'type' => 'text', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + )); $field->save(); $this->setUpInstances(); @@ -86,7 +96,7 @@ protected function prepareView(ViewExecutable $view) { $view->initDisplay(); foreach ($this->fields as $key => $field) { $view->display_handler->options['fields'][$field['field_name']]['id'] = $field['field_name']; - $view->display_handler->options['fields'][$field['field_name']]['table'] = 'field_data_' . $field['field_name']; + $view->display_handler->options['fields'][$field['field_name']]['table'] = 'node__' . $field['field_name']; $view->display_handler->options['fields'][$field['field_name']]['field'] = $field['field_name']; } } diff --git a/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php b/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php index 6d4ed4a..0b5400d 100644 --- a/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php @@ -21,7 +21,6 @@ class reEnableModuleFieldTest extends WebTestBase { */ public static $modules = array( 'field', - 'field_sql_storage', 'node', // We use telephone module instead of test_field because test_field is // hidden and does not display on the admin/modules page. @@ -51,7 +50,8 @@ function testReEnabledField() { // Add a telephone field to the article content type. $field = entity_create('field_entity', array( - 'field_name' => 'field_telephone', + 'name' => 'field_telephone', + 'entity_type' => 'node', 'type' => 'telephone', )); $field->save(); diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module index 800f4d4..3ab0c7e 100644 --- a/core/modules/field/tests/modules/field_test/field_test.module +++ b/core/modules/field/tests/modules/field_test/field_test.module @@ -18,7 +18,6 @@ require_once __DIR__ . '/field_test.entity.inc'; require_once __DIR__ . '/field_test.field.inc'; -require_once __DIR__ . '/field_test.storage.inc'; /** * Implements hook_permission(). diff --git a/core/modules/field/tests/modules/field_test/field_test.storage.inc b/core/modules/field/tests/modules/field_test/field_test.storage.inc index 66c9911..3bbbae2 100644 --- a/core/modules/field/tests/modules/field_test/field_test.storage.inc +++ b/core/modules/field/tests/modules/field_test/field_test.storage.inc @@ -195,7 +195,7 @@ function field_test_field_storage_delete(EntityInterface $entity, $fields) { // does, is highly inefficient in our case... foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) { if (isset($fields[$instance['field_id']])) { - $field = field_info_field_by_id($instance['field_id']); + $field = $instance->getField(); field_test_field_storage_purge($entity, $field, $instance); } } @@ -403,7 +403,7 @@ function field_test_field_storage_delete_field($field) { function field_test_field_storage_delete_instance($instance) { $data = _field_test_storage_data(); - $field = field_info_field($instance['field_name']); + $field = $instance->getField(); $field_data = &$data[$field['uuid']]; foreach (array('current', 'revisions') as $sub_table) { foreach ($field_data[$sub_table] as &$row) { @@ -424,8 +424,8 @@ function field_test_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) // We need to account for deleted or inactive fields and instances. $instances = field_read_instances(array('bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE)); - foreach ($instances as $field_name => $instance) { - $field = field_info_field_by_id($instance['field_id']); + foreach ($instances as $instance) { + $field = $instance->getField(); if ($field && $field['storage']['type'] == 'field_test_storage') { $field_data = &$data[$field['uuid']]; foreach (array('current', 'revisions') as $sub_table) { diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import.yml new file mode 100644 index 0000000..ae64a88 --- /dev/null +++ b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import.yml @@ -0,0 +1,15 @@ +id: entity_test.field_test_import +langcode: und +name: field_test_import +entity_type: entity_test +type: text +settings: + max_length: '255' +module: text +active: '1' +locked: '0' +cardinality: '1' +translatable: false +indexes: + format: + - format diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import_2.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import_2.yml new file mode 100644 index 0000000..38c855d --- /dev/null +++ b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import_2.yml @@ -0,0 +1,15 @@ +id: entity_test.field_test_import_2 +langcode: und +name: field_test_import_2 +entity_type: entity_test +type: text +settings: + max_length: '255' +module: text +active: '1' +locked: '0' +cardinality: '1' +translatable: false +indexes: + format: + - format diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import.yml deleted file mode 100644 index f472164..0000000 --- a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import.yml +++ /dev/null @@ -1,19 +0,0 @@ -id: field_test_import -langcode: und -type: text -settings: - max_length: '255' -module: text -active: '1' -entity_types: { } -storage: - type: field_sql_storage - settings: { } - module: field_sql_storage - active: '1' -locked: '0' -cardinality: '1' -translatable: false -indexes: - format: - - format diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import_2.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import_2.yml deleted file mode 100644 index 4d508a9..0000000 --- a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import_2.yml +++ /dev/null @@ -1,19 +0,0 @@ -id: field_test_import_2 -langcode: und -type: text -settings: - max_length: '255' -module: text -active: '1' -entity_types: { } -storage: - type: field_sql_storage - settings: { } - module: field_sql_storage - active: '1' -locked: '0' -cardinality: '1' -translatable: false -indexes: - format: - - format diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging.yml new file mode 100644 index 0000000..265e180 --- /dev/null +++ b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging.yml @@ -0,0 +1,16 @@ +id: entity_test.field_test_import_staging +uuid: 0bf654cc-f14a-4881-b94c-76959e47466b +langcode: und +name: field_test_import_staging +entity_type: entity_test +type: text +settings: + max_length: '255' +module: text +active: '1' +locked: '0' +cardinality: '1' +translatable: '0' +indexes: + format: + - format diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging_2.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging_2.yml new file mode 100644 index 0000000..ba36c64 --- /dev/null +++ b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging_2.yml @@ -0,0 +1,16 @@ +id: entity_test.field_test_import_staging_2 +uuid: 2165d9aa-9a0c-41a1-be02-2a49f3405c00 +langcode: und +name: field_test_import_staging_2 +entity_type: entity_test +type: text +settings: + max_length: '255' +module: text +active: '1' +locked: '0' +cardinality: '1' +translatable: '0' +indexes: + format: + - format diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging.yml deleted file mode 100644 index 4226f72..0000000 --- a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging.yml +++ /dev/null @@ -1,20 +0,0 @@ -id: field_test_import_staging -uuid: 0bf654cc-f14a-4881-b94c-76959e47466b -langcode: und -type: text -settings: - max_length: '255' -module: text -active: '1' -entity_types: { } -storage: - type: field_sql_storage - settings: { } - module: field_sql_storage - active: '1' -locked: '0' -cardinality: '1' -translatable: '0' -indexes: - format: - - format diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging_2.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging_2.yml deleted file mode 100644 index a0eb94e..0000000 --- a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging_2.yml +++ /dev/null @@ -1,20 +0,0 @@ -id: field_test_import_staging_2 -uuid: 2165d9aa-9a0c-41a1-be02-2a49f3405c00 -langcode: und -type: text -settings: - max_length: '255' -module: text -active: '1' -entity_types: { } -storage: - type: field_sql_storage - settings: { } - module: field_sql_storage - active: '1' -locked: '0' -cardinality: '1' -translatable: '0' -indexes: - format: - - format diff --git a/core/modules/field/tests/modules/field_test_views/test_views/views.view.test_view_fieldapi.yml b/core/modules/field/tests/modules/field_test_views/test_views/views.view.test_view_fieldapi.yml index 940848f..b370ab1 100644 --- a/core/modules/field/tests/modules/field_test_views/test_views/views.view.test_view_fieldapi.yml +++ b/core/modules/field/tests/modules/field_test_views/test_views/views.view.test_view_fieldapi.yml @@ -16,7 +16,7 @@ display: provider: node field_name_0: id: field_name_0 - table: field_data_field_name_0 + table: node__field_name_0 field: field_name_0 plugin_id: field provider: field diff --git a/core/modules/field_sql_storage/field_sql_storage.info.yml b/core/modules/field_sql_storage/field_sql_storage.info.yml deleted file mode 100644 index e5172b5..0000000 --- a/core/modules/field_sql_storage/field_sql_storage.info.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: 'Field SQL Storage' -type: module -description: 'Stores field data in an SQL database.' -package: Core -version: VERSION -core: 8.x -dependencies: - - field -required: true diff --git a/core/modules/field_sql_storage/field_sql_storage.install b/core/modules/field_sql_storage/field_sql_storage.install deleted file mode 100644 index 8d14ca8..0000000 --- a/core/modules/field_sql_storage/field_sql_storage.install +++ /dev/null @@ -1,153 +0,0 @@ -condition('entity_type', $entity_type) - ->condition('entity_id', $entity_id) - ->execute(); - db_delete($revision_name) - ->condition('entity_type', $entity_type) - ->condition('entity_id', $entity_id) - ->condition('revision_id', $revision_id) - ->execute(); - - $columns = array(); - foreach ($data as $langcode => $items) { - foreach ($items as $delta => $item) { - $record = array( - 'entity_type' => $entity_type, - 'entity_id' => $entity_id, - 'revision_id' => $revision_id, - 'bundle' => $bundle, - 'delta' => $delta, - 'langcode' => $langcode, - ); - foreach ($item as $column => $value) { - $record[_field_sql_storage_columnname($field_name, $column)] = $value; - } - - $records[] = $record; - // Record the columns used. - $columns += $record; - } - } - - if ($columns) { - $query = db_insert($table_name)->fields(array_keys($columns)); - $revision_query = db_insert($revision_name)->fields(array_keys($columns)); - foreach ($records as $record) { - $query->values($record); - if ($revision_id) { - $revision_query->values($record); - } - } - $query->execute(); - $revision_query->execute(); - } -} - -/** - * Implements hook_update_dependencies(). - */ -function field_sql_storage_update_dependencies() { - // Convert storage tables after field definitions have moved to - // ConfigEntities. - $dependencies['field_sql_storage'][8000] = array( - 'field' => 8003, - ); - return $dependencies; -} - -/** - * Renames the 'language' column to 'langcode' in field data tables. - */ -function field_sql_storage_update_8000(&$sandbox) { - // Get field definitions from config, and deleted fields from state system. - $config_names = config_get_storage_names_with_prefix('field.field'); - $deleted_fields = Drupal::state()->get('field.field.deleted') ?: array(); - // Ditch UUID keys, we will iterate through deleted fields using a numeric - // index. - $deleted_fields = array_values($deleted_fields); - - if (empty($config_names) && empty($deleted_fields)) { - return; - } - - if (!isset($sandbox['index'])) { - $sandbox['index'] = 0; - $sandbox['max'] = count($config_names) + count($deleted_fields); - } - - // Retrieve the next field definition. When the index exceeds the number of - // 'configuration' fields, use it to iterate on deleted fields. - if (isset($config_names[$sandbox['index']])) { - $field_config = config($config_names[$sandbox['index']])->get(); - } - else { - $field_config = $deleted_fields[$sandbox['index'] - count($config_names)]; - } - - if ($field_config['storage']['type'] == 'field_sql_storage') { - $field = new Field($field_config); - - // Prepare updated schema data structures. - $primary_key_data = array( - 'entity_type', - 'entity_id', - 'deleted', - 'delta', - 'langcode', - ); - $primary_key_revision = array( - 'entity_type', - 'entity_id', - 'revision_id', - 'deleted', - 'delta', - 'langcode', - ); - $langcode_index = array( - 'langcode', - ); - $field_langcode = array( - 'type' => 'varchar', - 'length' => 32, - 'not null' => TRUE, - 'default' => '', - ); - - $table_info = array( - _field_sql_storage_tablename($field) => $primary_key_data, - _field_sql_storage_revision_tablename($field) => $primary_key_revision, - ); - foreach ($table_info as $table => $primary_key) { - // Do not update tables which already have the langcode column, - // created during the upgrade before this update function. - if (db_field_exists($table, 'language')) { - db_drop_primary_key($table); - db_drop_index($table, 'language'); - db_change_field($table, 'language', 'langcode', $field_langcode); - db_add_primary_key($table, $primary_key); - db_add_index($table, 'langcode', $langcode_index); - } - } - } - - $sandbox['index']++; - $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['index'] / $sandbox['max']); -} diff --git a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php index fce0a52..ba87735 100644 --- a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php +++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php @@ -464,36 +464,6 @@ function testFieldUpdateIndexesWithData() { } /** - * Test the storage details. - */ - function testFieldStorageDetails() { - $current = _field_sql_storage_tablename($this->field); - $revision = _field_sql_storage_revision_tablename($this->field); - - // Retrieve the field and instance with field_info so the storage details are attached. - $field = field_info_field($this->field_name); - $instance = field_info_instance($this->instance->entity_type, $field->id(), $this->instance->bundle); - - // The storage details are indexed by a storage engine type. - $storage_details = $field->getStorageDetails(); - $this->assertTrue(array_key_exists('sql', $storage_details), 'The storage type is SQL.'); - - // The SQL details are indexed by table name. - $details = $storage_details['sql']; - $this->assertTrue(array_key_exists($current, $details[FIELD_LOAD_CURRENT]), 'Table name is available in the instance array.'); - $this->assertTrue(array_key_exists($revision, $details[FIELD_LOAD_REVISION]), 'Revision table name is available in the instance array.'); - - // Test current and revision storage details together because the columns - // are the same. - $schema = $this->field->getSchema(); - foreach ($schema['columns'] as $column_name => $attributes) { - $storage_column_name = _field_sql_storage_columnname($this->field_name, $column_name); - $this->assertEqual($details[FIELD_LOAD_CURRENT][$current][$column_name], $storage_column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => $current))); - $this->assertEqual($details[FIELD_LOAD_REVISION][$revision][$column_name], $storage_column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => $revision))); - } - } - - /** * Test foreign key support. */ function testFieldSqlStorageForeignKeys() { diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index 8a8674c..187bf46 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -216,7 +216,7 @@ function field_ui_instance_load($field_name, $entity_type, $bundle_name, $bundle $bundle_name = field_extract_bundle($entity_type, $bundle); } // Check whether the field exists at all. - if ($field = field_info_field($field_name)) { + if ($field = field_info_field($entity_type, $field_name)) { // Only return the field if a field instance exists for the given entity // type and bundle. if ($instance = field_info_instance($entity_type, $field_name, $bundle_name)) { diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php index 514e966..075ffe8 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php @@ -12,7 +12,6 @@ use Drupal\Core\Entity\EntityManager; use Drupal\Core\Entity\Field\FieldTypePluginManager; use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\field\FieldInfo; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -28,13 +27,6 @@ class FieldListController extends ConfigEntityListController { protected $fieldTypes; /** - * An array of field data. - * - * @var array - */ - protected $fieldInfo; - - /** * The entity manager. * * @var \Drupal\Core\Entity\EntityManager @@ -71,10 +63,9 @@ class FieldListController extends ConfigEntityListController { * @param \Drupal\Core\Entity\Field\FieldTypePluginManager $field_type_manager * The 'field type' plugin manager. */ - public function __construct($entity_type, array $entity_info, EntityManager $entity_manager, ModuleHandlerInterface $module_handler, FieldInfo $field_info, FieldTypePluginManager $field_type_manager) { + public function __construct($entity_type, array $entity_info, EntityManager $entity_manager, ModuleHandlerInterface $module_handler, FieldTypePluginManager $field_type_manager) { parent::__construct($entity_type, $entity_info, $entity_manager->getStorageController($entity_type), $module_handler); - $this->fieldInfo = $field_info->getFieldMap(); $this->entityManager = $entity_manager; $this->bundles = entity_get_bundles(); $this->fieldTypeManager = $field_type_manager; @@ -90,7 +81,6 @@ public static function createInstance(ContainerInterface $container, $entity_typ $entity_info, $container->get('plugin.manager.entity'), $container->get('module_handler'), - $container->get('field.info'), $container->get('plugin.manager.entity.field.field_type') ); } @@ -111,24 +101,22 @@ public function buildHeader() { /** * {@inheritdoc} */ - public function buildRow(EntityInterface $entity) { - if ($entity->locked) { + public function buildRow(EntityInterface $field) { + if ($field->locked) { $row['class'] = array('menu-disabled'); - $row['data']['id'] = t('@field_name (Locked)', array('@field_name' => $entity->id())); + $row['data']['id'] = t('@field_name (Locked)', array('@field_name' => $field->name)); } else { - $row['data']['id'] = $entity->id(); + $row['data']['id'] = $field->name; } - $field_type = $this->fieldTypes[$entity->getFieldType()]; + $field_type = $this->fieldTypes[$field->type]; $row['data']['type'] = t('@type (module: @module)', array('@type' => $field_type['label'], '@module' => $field_type['provider'])); $usage = array(); - foreach($this->fieldInfo[$entity->id()]['bundles'] as $entity_type => $field_bundles) { - foreach($field_bundles as $bundle) { - $admin_path = $this->entityManager->getAdminPath($entity_type, $bundle); - $usage[] = $admin_path ? l($this->bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $this->bundles[$entity_type][$bundle]['label']; - } + foreach ($field->getBundles() as $bundle) { + $admin_path = $this->entityManager->getAdminPath($field->entity_type, $bundle); + $usage[] = $admin_path ? l($this->bundles[$field->entity_type][$bundle]['label'], $admin_path . '/fields') : $this->bundles[$field->entity_type][$bundle]['label']; } $row['data']['usage'] = implode(', ', $usage); return $row; diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php index 621c08d..513efb3 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php @@ -118,7 +118,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, // Fields. foreach ($instances as $name => $instance) { - $field = field_info_field($instance['field_name']); + $field = $instance->getField(); $admin_field_path = $this->adminPath . '/fields/' . $instance->id(); $table[$name] = array( '#attributes' => array( @@ -202,7 +202,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL, '#description' => t('A unique machine-readable name containing letters, numbers, and underscores.'), // Calculate characters depending on the length of the field prefix // setting. Maximum length is 32. - '#maxlength' => Field::ID_MAX_LENGTH - strlen($field_prefix), + '#maxlength' => Field::NAME_MAX_LENGTH - strlen($field_prefix), '#prefix' => '
 
', '#machine_name' => array( 'source' => array('fields', $name, 'label'), @@ -382,12 +382,13 @@ public function submitForm(array &$form, array &$form_state) { $values = $form_values['_add_new_field']; $field = array( - 'field_name' => $values['field_name'], + 'name' => $values['field_name'], + 'entity_type' => $this->entity_type, 'type' => $values['type'], 'translatable' => $values['translatable'], ); $instance = array( - 'field_name' => $field['field_name'], + 'field_name' => $values['field_name'], 'entity_type' => $this->entity_type, 'bundle' => $this->bundle, 'label' => $values['label'], @@ -403,14 +404,14 @@ public function submitForm(array &$form, array &$form_state) { // default widget and settings). It stays hidden for other form modes // until it is explicitly configured. entity_get_form_display($this->entity_type, $this->bundle, 'default') - ->setComponent($field['field_name']) + ->setComponent($values['field_name']) ->save(); // Make sure the field is displayed in the 'default' view mode (using // default formatter and settings). It stays hidden for other view // modes until it is explicitly configured. entity_get_display($this->entity_type, $this->bundle, 'default') - ->setComponent($field['field_name']) + ->setComponent($values['field_name']) ->save(); // Always show the field settings step, as the cardinality needs to be @@ -419,7 +420,7 @@ public function submitForm(array &$form, array &$form_state) { $destinations[] = $this->adminPath . '/fields/' . $new_instance->id(); // Store new field information for any additional submit handlers. - $form_state['fields_added']['_add_new_field'] = $field['field_name']; + $form_state['fields_added']['_add_new_field'] = $values['field_name']; } catch (\Exception $e) { drupal_set_message(t('There was a problem creating field %label: !message', array('%label' => $instance['label'], '!message' => $e->getMessage())), 'error'); @@ -429,7 +430,7 @@ public function submitForm(array &$form, array &$form_state) { // Re-use existing field. if (!empty($form_values['_add_existing_field']['field_name'])) { $values = $form_values['_add_existing_field']; - $field = field_info_field($values['field_name']); + $field = field_info_field($this->entity_type, $values['field_name']); if (!empty($field['locked'])) { drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error'); } @@ -490,37 +491,42 @@ public function submitForm(array &$form, array &$form_state) { * An array of existing fields keyed by field name. */ protected function getExistingFieldOptions() { - $info = array(); - $field_types = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions(); - - foreach (field_info_instances() as $existing_entity_type => $bundles) { - foreach ($bundles as $existing_bundle => $instances) { - // No need to look in the current bundle. - if (!($existing_bundle == $this->bundle && $existing_entity_type == $this->entity_type)) { - foreach ($instances as $instance) { - $field = field_info_field($instance['field_name']); - // Don't show - // - locked fields, - // - fields already in the current bundle, - // - fields that cannot be added to the entity type, - // - fields that should not be added via user interface. - - if (empty($field['locked']) - && !field_info_instance($this->entity_type, $field['field_name'], $this->bundle) - && (empty($field['entity_types']) || in_array($this->entity_type, $field['entity_types'])) - && empty($field_types[$field['type']]['no_ui'])) { - $info[$instance['field_name']] = array( - 'type' => $field['type'], - 'type_label' => $field_types[$field['type']]['label'], - 'field' => $field['field_name'], - 'label' => $instance['label'], - ); - } - } + $options = array(); + + // Collect candidate field instances: all instances of fields for this + // entity type that are not already present in the current bundle. + $field_map = field_info_field_map(); + $instance_ids = array(); + if (!empty($field_map[$this->entity_type])) { + foreach ($field_map[$this->entity_type] as $field_name => $data) { + if (!in_array($this->bundle, $data['bundles'])) { + $bundle = reset($data['bundles']); + $instance_ids[] = $this->entity_type . '.' . $bundle . '.' . $field_name; + } + } + } + + // Load the instances and build the list of options. + if ($instance_ids) { + $field_types = $this->fieldTypeManager->getDefinitions(); + $instances = $this->entityManager->getStorageController('field_instance')->loadMultiple($instance_ids); + foreach ($instances as $instance) { + $field = $instance->getField(); + // Do not show: + // - locked fields, + // - fields that should not be added via user interface. + if (empty($field['locked']) && empty($field_types[$field['type']]['no_ui'])) { + $options[$field->name] = array( + 'type' => $field->type, + 'type_label' => $field_types[$field->type]['label'], + 'field' => $field->name, + 'label' => $instance->label, + ); } } } - return $info; + + return $options; } /** @@ -538,7 +544,7 @@ public function fieldNameExists($value) { // We need to check inactive fields as well, so we can't use // field_info_fields(). - return (bool) field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE)); + return (bool) field_read_fields(array('entity_type' => $this->entity_type, 'name' => $field_name), array('include_inactive' => TRUE)); } } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php index 305596f..65c5207 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php @@ -174,7 +174,7 @@ public function submitForm(array &$form, array &$form_state) { unset($field_values['container']); // Merge incoming form values into the existing field. - $field = Field::fieldInfo()->getField($field_values['field_name']); + $field = $this->instance->getField(); foreach ($field_values as $key => $value) { $field[$key] = $value; } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php index 046e012..743d779 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php @@ -198,7 +198,7 @@ public function validateForm(array &$form, array &$form_state) { // Extract the 'default value'. $items = $entity->getNGEntity()->{$field_name}; - $entity_form_display->getRenderer($this->instance->getField()->id)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + $entity_form_display->getRenderer($this->instance->getField()->name)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); $violations = $items->validate(); // Report errors. @@ -209,7 +209,7 @@ public function validateForm(array &$form, array &$form_state) { field_form_set_state($element['#parents'], $field_name, Language::LANGCODE_NOT_SPECIFIED, $form_state, $field_state); // Assign reported errors to the correct form element. - $entity_form_display->getRenderer($this->instance->getField()->id)->flagErrors($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + $entity_form_display->getRenderer($this->instance->getField()->name)->flagErrors($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); } } } @@ -228,7 +228,7 @@ public function submitForm(array &$form, array &$form_state) { // Extract field values. $items = $entity->getNGEntity()->{$field_name}; - $entity_form_display->getRenderer($this->instance->getField()->id)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + $entity_form_display->getRenderer($this->instance->getField()->name)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); $this->instance['default_value'] = $items->getValue() ?: NULL; } @@ -296,11 +296,11 @@ protected function getDefaultValueWidget($field, array &$form, &$form_state) { // Insert the widget. Since we do not use the "official" instance definition, // the whole flow cannot use field_invoke_method(). - $items = $entity->getNGEntity()->{$this->instance->getField()->id}; + $items = $entity->getNGEntity()->{$this->instance->getField()->name}; if (!empty($this->instance['default_value'])) { $items->setValue((array) $this->instance['default_value']); } - $element += $entity_form_display->getRenderer($this->instance->getField()->id)->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); + $element += $entity_form_display->getRenderer($this->instance->getField()->name)->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state); return $element; } diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php index 69be9ec..9d957c5 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php @@ -42,7 +42,8 @@ function setUp() { $vocabulary->save(); $field = array( - 'field_name' => 'field_' . $vocabulary->id(), + 'name' => 'field_' . $vocabulary->id(), + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', ); entity_create('field_entity', $field)->save(); @@ -116,13 +117,6 @@ function createField() { 'fields[_add_new_field][field_name]' => $this->field_name_input, ); $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->type, $edit); - - // Assert the field appears in the "re-use existing field" section for - // different entity types; e.g. if a field was added in a node entity, it - // should also appear in the 'taxonomy term' entity. - $vocabulary = entity_load('taxonomy_vocabulary', 'tags'); - $this->drupalGet('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/fields'); - $this->assertTrue($this->xpath('//select[@name="fields[_add_existing_field][field_name]"]//option[@value="' . $this->field_name . '"]'), 'Existing field was found in taxonomy term fields.'); } /** @@ -162,9 +156,8 @@ function addExistingField() { $this->drupalGet('admin/structure/types/manage/page/fields'); $this->assertRaw(t('Re-use existing field'), '"Re-use existing field" was found.'); - // Check that the list of options respects entity type restrictions on - // fields. The 'comment' field is restricted to the 'comment' entity type - // and should not appear in the list. + // Check that fields of other entity types (here, the 'comment_body' field) + // do not show up in the "Re-use existing field" list. $this->assertFalse($this->xpath('//select[@id="edit-add-existing-field-field-name"]//option[@value="comment"]'), 'The list of options respects entity type restrictions.'); // Add a new field based on an existing field. @@ -231,7 +224,7 @@ function assertFieldSettings($bundle, $field_name, $string = 'dummy test string' // Reset the fields info. field_info_cache_clear(); // Assert field settings. - $field = field_info_field($field_name); + $field = field_info_field($entity_type, $field_name); $this->assertTrue($field['settings']['test_field_setting'] == $string, 'Field settings were found.'); // Assert instance settings. @@ -276,7 +269,8 @@ function testDefaultValue() { // Create a test field and instance. $field_name = 'test'; entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'node', 'type' => 'test_field' ))->save(); $instance = entity_create('field_instance', array( @@ -366,7 +360,7 @@ function testDeleteField() { // Check that the field instance was deleted. $this->assertNull(field_info_instance('node', $this->field_name, $this->type), 'Field instance was deleted.'); // Check that the field was not deleted - $this->assertNotNull(field_info_field($this->field_name), 'Field was not deleted.'); + $this->assertNotNull(field_info_field('node', $this->field_name), 'Field was not deleted.'); // Delete the second instance. $this->fieldUIDeleteField($bundle_path2, "node.$type_name2.$this->field_name", $this->field_label, $type_name2); @@ -376,7 +370,7 @@ function testDeleteField() { // Check that the field instance was deleted. $this->assertNull(field_info_instance('node', $this->field_name, $type_name2), 'Field instance was deleted.'); // Check that the field was deleted too. - $this->assertNull(field_info_field($this->field_name), 'Field was deleted.'); + $this->assertNull(field_info_field('node', $this->field_name), 'Field was deleted.'); } /** @@ -386,7 +380,8 @@ function testLockedField() { // Create a locked field and attach it to a bundle. We need to do this // programatically as there's no way to create a locked field through UI. $field = entity_create('field_entity', array( - 'field_name' => strtolower($this->randomName(8)), + 'name' => strtolower($this->randomName(8)), + 'entity_type' => 'node', 'type' => 'test_field', 'cardinality' => 1, 'locked' => TRUE @@ -405,11 +400,11 @@ function testLockedField() { // Check that the links for edit and delete are not present. $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields'); - $locked = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->id())); + $locked = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->name)); $this->assertTrue(in_array('Locked', $locked), 'Field is marked as Locked in the UI'); - $edit_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->id())); + $edit_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->name)); $this->assertFalse(in_array('edit', $edit_link), 'Edit option for locked field is not present the UI'); - $delete_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->id())); + $delete_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->name)); $this->assertFalse(in_array('delete', $delete_link), 'Delete option for locked field is not present the UI'); } @@ -425,7 +420,11 @@ function testHiddenFields() { // Create a field and an instance programmatically. $field_name = 'hidden_test_field'; - entity_create('field_entity', array('field_name' => $field_name, 'type' => $field_name))->save(); + entity_create('field_entity', array( + 'name' => $field_name, + 'entity_type' => 'node', + 'type' => $field_name, + ))->save(); $instance = array( 'field_name' => $field_name, 'bundle' => $this->type, @@ -501,7 +500,7 @@ function testDeleteTaxonomyField() { // Check that the field instance was deleted. $this->assertNull(field_info_instance('taxonomy_term', $this->field_name, 'tags'), 'Field instance was deleted.'); // Check that the field was deleted too. - $this->assertNull(field_info_field($this->field_name), 'Field was deleted.'); + $this->assertNull(field_info_field('taxonomy_term', $this->field_name), 'Field was deleted.'); } /** @@ -510,7 +509,8 @@ function testDeleteTaxonomyField() { function testHelpDescriptions() { // Create an image field entity_create('field_entity', array( - 'field_name' => 'field_image', + 'name' => 'field_image', + 'entity_type' => 'node', 'type' => 'image', ))->save(); diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc index 6445527..1a8dcd5 100644 --- a/core/modules/file/file.field.inc +++ b/core/modules/file/file.field.inc @@ -355,7 +355,7 @@ function file_field_widget_multiple_count_validate($element, &$form_state, $form array_pop($parents); $current = count(element_children(NestedArray::getValue($form, $parents))) - 1; - $field = field_info_field($element['#field_name']); + $field = field_info_field($element['#entity_type'], $element['#field_name']); $uploaded = count($values['fids']); $count = $uploaded + $current; if ($count > $field['cardinality']) { diff --git a/core/modules/file/file.install b/core/modules/file/file.install index 614b07c..2e469ab 100644 --- a/core/modules/file/file.install +++ b/core/modules/file/file.install @@ -5,6 +5,7 @@ * Install, update and uninstall functions for File module. */ +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\field\Plugin\Core\Entity\Field; /** @@ -247,10 +248,10 @@ function file_update_dependencies() { 'file' => 8001, ); - // Convert the 'fid' column of file fields to 'target_id' after fields and - // instances have been moved to the config system. + // Convert the 'fid' column of file fields to 'target_id' after the field + // tables have been reorganized. $dependencies['file'][8003] = array( - 'field' => 8003, + 'field' => 8006, ); return $dependencies; } @@ -305,21 +306,21 @@ function file_update_8003() { foreach (config_get_storage_names_with_prefix('field.field.') as $config_name) { $field_config = config($config_name); // Only update file fields that use the default SQL storage. - if (in_array($field_config->get('type'), array('file', 'image')) && $field_config->get('storage.type') == 'field_sql_storage') { + if (in_array($field_config->get('type'), array('file', 'image'))) { $field = new Field($field_config->get()); $tables = array( - _field_sql_storage_tablename($field), - _field_sql_storage_revision_tablename($field), + DatabaseStorageController::_fieldTableName($field), + DatabaseStorageController::_fieldRevisionTableName($field), ); foreach ($tables as $table_name) { // Skip fields which were created during the upgrade process. - if (!db_field_exists($table_name, $field->id() . '_fid')) { + if (!db_field_exists($table_name, $field->name . '_fid')) { continue 2; } - db_change_field($table_name, $field->id() . '_fid', $field->id() . '_target_id', array( + db_change_field($table_name, $field->name . '_fid', $field->name . '_target_id', array( 'description' => 'The ID of the target entity.', 'type' => 'int', 'unsigned' => TRUE, @@ -327,8 +328,8 @@ function file_update_8003() { )); // Change the index. - db_drop_index($table_name, $field->id() . '_fid'); - db_add_index($table_name, $field->id() . '_target_id', array($field->id() . '_target_id')); + db_drop_index($table_name, $field->name . '_fid'); + db_add_index($table_name, $field->name . '_target_id', array($field->name . '_target_id')); } // Update the indexes in field config as well. diff --git a/core/modules/file/file.module b/core/modules/file/file.module index d37a1ba..eeb3205 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -648,7 +648,7 @@ function file_file_download($uri, $field_type = 'file') { foreach ($references as $field_name => $field_references) { foreach ($field_references as $entity_type => $entities) { foreach ($entities as $entity) { - $field = field_info_field($field_name); + $field = field_info_field($entity_type, $field_name); // Check if access to this field is not disallowed. if (!field_access('view', $field, $entity_type, $entity)) { $denied = TRUE; @@ -1867,7 +1867,7 @@ function file_get_file_references(File $file, $field = NULL, $age = FIELD_LOAD_R // This contains the possible field names. $instances = field_info_instances($entity_type, $bundle); foreach ($instances as $field_name => $instance) { - $current_field = field_info_field($field_name); + $current_field = $instance->getField(); // If this is the first time this field type is seen, check // whether it references files. if (!isset($field_columns[$current_field['type']])) { @@ -1905,9 +1905,11 @@ function file_get_file_references(File $file, $field = NULL, $age = FIELD_LOAD_R // cache is very small so this will be very fast. if ($field || $field_type) { foreach ($return as $field_name => $data) { - $current_field = field_info_field($field_name); - if (($field_type && $current_field['type'] != $field_type) || ($field && $field['id'] != $current_field['id'])) { - unset($return[$field_name]); + foreach (array_keys($data) as $entity_type) { + $current_field = field_info_field($entity_type, $field_name); + if (($field_type && $current_field['type'] != $field_type) || ($field && $field['id'] != $current_field['id'])) { + unset($return[$field_name][$entity_type]); + } } } } diff --git a/core/modules/file/file.views.inc b/core/modules/file/file.views.inc index db18c46..7632e49 100644 --- a/core/modules/file/file.views.inc +++ b/core/modules/file/file.views.inc @@ -7,6 +7,9 @@ * @ingroup views_module_handlers */ +use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\field\FieldInterface; + /** * Implements hook_views_data(). */ @@ -460,8 +463,8 @@ function file_views_data() { * * @see field_views_field_default_views_data() */ -function file_field_views_data($field) { - $data = field_views_field_default_views_data($field); +function file_field_views_data(FieldInterface $field, array $sql_entity_types) { + $data = field_views_field_default_views_data($field, $sql_entity_types); foreach ($data as $table_name => $table_data) { // Add the relationship only on the fid field. $data[$table_name][$field['field_name'] . '_target_id']['relationship'] = array( @@ -481,8 +484,8 @@ function file_field_views_data($field) { * * Views integration to provide reverse relationships on file fields. */ -function file_field_views_data_views_data_alter(&$data, $field) { - foreach ($field['bundles'] as $entity_type => $bundles) { +function file_field_views_data_views_data_alter(array &$data, FieldInterface $field, array $sql_entity_types) { + foreach ($sql_entity_types as $entity_type) { $entity_info = entity_get_info($entity_type); $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type; @@ -497,17 +500,14 @@ function file_field_views_data_views_data_alter(&$data, $field) { 'help' => t('Relate each @entity with a @field set to the file.', array('@entity' => $entity, '@field' => $label)), 'id' => 'entity_reverse', 'field_name' => $field['field_name'], - 'field table' => _field_sql_storage_tablename($field), + 'entity_type' => $field['entity_type'], + 'field table' => DatabaseStorageController::_fieldTableName($field), 'field field' => $field['field_name'] . '_target_id', 'base' => $entity_info['base_table'], 'base field' => $entity_info['entity_keys']['id'], 'label' => t('!field_name', array('!field_name' => $field['field_name'])), 'join_extra' => array( 0 => array( - 'field' => 'entity_type', - 'value' => $entity_type, - ), - 1 => array( 'field' => 'deleted', 'value' => 0, 'numeric' => TRUE, diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php index 4ef654d..0ed2f7f 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php @@ -36,7 +36,7 @@ function testNodeDisplay() { 'description_field' => '1', ); $widget_settings = array(); - $this->createFileField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings); + $this->createFileField($field_name, 'node', $type_name, $field_settings, $instance_settings, $widget_settings); // Create a new node *without* the file field set, and check that the field // is not shown for each node display. diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php index f2c45b6..3fa22c4 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php @@ -27,7 +27,7 @@ public static function getInfo() { function testUploadPath() { $field_name = strtolower($this->randomName()); $type_name = 'article'; - $this->createFileField($field_name, $type_name); + $this->createFileField($field_name, 'node', $type_name); $test_file = $this->getTestFile('text'); // Create a new node. diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php index d031ffe..e46f736 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php @@ -43,7 +43,7 @@ function testFileFieldRSSContent() { 'description_field' => '1', ); $widget_settings = array(); - $this->createFileField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings); + $this->createFileField($field_name, 'node', $type_name, $field_settings, $instance_settings, $widget_settings); // RSS display must be added manually. $this->drupalGet("admin/structure/types/manage/$type_name/display"); diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php index d9604cc..fa55141 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php @@ -35,10 +35,9 @@ public static function getInfo() { function testRevisions() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $this->createFileField($field_name, $type_name); - - // Attach the same fields to users. - $this->attachFileField($field_name, 'user', 'user'); + $this->createFileField($field_name, 'node', $type_name); + // Create the same fields for users. + $this->createFileField($field_name, 'user', 'user'); $test_file = $this->getTestFile('text'); diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php index 3582893..f91ce20 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php @@ -57,8 +57,10 @@ function getLastFileId() { * * @param $name * The name of the new field (all lowercase), exclude the "field_" prefix. - * @param $type_name - * The node type that this field will be added to. + * @param $entity_type + * The entity type. + * @param $bundle + * The bundle that this field will be added to. * @param $field_settings * A list of field settings that will be added to the defaults. * @param $instance_settings @@ -66,9 +68,10 @@ function getLastFileId() { * @param $widget_settings * A list of widget settings that will be added to the widget defaults. */ - function createFileField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) { + function createFileField($name, $entity_type, $bundle, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) { $field_definition = array( - 'field_name' => $name, + 'entity_type' => $entity_type, + 'name' => $name, 'type' => 'file', 'settings' => array(), 'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1, @@ -77,7 +80,7 @@ function createFileField($name, $type_name, $field_settings = array(), $instance $field = entity_create('field_entity', $field_definition); $field->save(); - $this->attachFileField($name, 'node', $type_name, $instance_settings, $widget_settings); + $this->attachFileField($name, $entity_type, $bundle, $instance_settings, $widget_settings); return $field; } @@ -159,7 +162,7 @@ function uploadNodeFile($file, $field_name, $nid_or_type, $new_revision = TRUE, } // Attach a file to the node. - $field = field_info_field($field_name); + $field = field_info_field('node', $field_name); $name = 'files[' . $field_name . '_' . $langcode . '_0]'; if ($field['cardinality'] != 1) { $name .= '[]'; diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php index a7cf1e5..670ce91 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php @@ -30,8 +30,8 @@ public static function getInfo() { function testRequired() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $field = $this->createFileField($field_name, $type_name, array(), array('required' => '1')); - $instance = field_info_instance('node', $field_name, $type_name); + $field = $this->createFileField($field_name, 'node', $type_name, array(), array('required' => '1')); + $instance = field_info_instance($field_name, 'node', $type_name); $test_file = $this->getTestFile('text'); @@ -53,7 +53,7 @@ function testRequired() { // Try again with a multiple value field. $field->delete(); - $this->createFileField($field_name, $type_name, array('cardinality' => FIELD_CARDINALITY_UNLIMITED), array('required' => '1')); + $this->createFileField($field_name, 'node', $type_name, array('cardinality' => FIELD_CARDINALITY_UNLIMITED), array('required' => '1')); // Try to post a new node without uploading a file in the multivalue field. $edit = array('title' => $this->randomName()); @@ -74,7 +74,7 @@ function testRequired() { function testFileMaxSize() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $this->createFileField($field_name, $type_name, array(), array('required' => '1')); + $this->createFileField($field_name, 'node', $type_name, array(), array('required' => '1')); $small_file = $this->getTestFile('text', 131072); // 128KB. $large_file = $this->getTestFile('text', 1310720); // 1.2MB @@ -120,7 +120,7 @@ function testFileMaxSize() { function testFileExtension() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $this->createFileField($field_name, $type_name); + $this->createFileField($field_name, 'node', $type_name); $test_file = $this->getTestFile('image'); list(, $test_file_extension) = explode('.', $test_file->getFilename()); diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php index e481384..1f8e9d6 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php @@ -35,7 +35,7 @@ public static function getInfo() { function testSingleValuedWidget() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $this->createFileField($field_name, $type_name); + $this->createFileField($field_name, 'node', $type_name); $test_file = $this->getTestFile('text'); @@ -96,8 +96,8 @@ function testMultiValuedWidget() { // names). $field_name = 'test_file_field_1'; $field_name2 = 'test_file_field_2'; - $this->createFileField($field_name, $type_name, array('cardinality' => 3)); - $this->createFileField($field_name2, $type_name, array('cardinality' => 3)); + $this->createFileField($field_name, 'node', $type_name, array('cardinality' => 3)); + $this->createFileField($field_name2, 'node', $type_name, array('cardinality' => 3)); $test_file = $this->getTestFile('text'); @@ -206,7 +206,7 @@ function testMultiValuedWidget() { function testPrivateFileSetting() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $this->createFileField($field_name, $type_name); + $this->createFileField($field_name, 'node', $type_name); $instance = field_info_instance('node', $field_name, $type_name); $test_file = $this->getTestFile('text'); @@ -316,7 +316,7 @@ function testPrivateFileComment() { function testWidgetValidation() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $this->createFileField($field_name, $type_name); + $this->createFileField($field_name, 'node', $type_name); $this->updateFileField($field_name, $type_name, array('file_extensions' => 'txt')); foreach (array('nojs', 'js') as $type) { @@ -326,7 +326,7 @@ function testWidgetValidation() { $this->drupalGet("node/$nid/edit"); $test_file_text = $this->getTestFile('text'); $test_file_image = $this->getTestFile('image'); - $field = field_info_field($field_name); + $field = field_info_field('ndde', $field_name); $name = 'files[' . $field_name . '_' . Language::LANGCODE_NOT_SPECIFIED . '_0]'; // Upload file with incorrect extension, check for validation error. diff --git a/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php b/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php index fd00c11..f44e48d 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php @@ -45,7 +45,8 @@ public function setUp() { $this->installSchema('file', 'file_usage'); entity_create('field_entity', array( - 'field_name' => 'file_test', + 'name' => 'file_test', + 'entity_type' => 'entity_test', 'type' => 'file', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, ))->save(); diff --git a/core/modules/file/lib/Drupal/file/Tests/FileListingTest.php b/core/modules/file/lib/Drupal/file/Tests/FileListingTest.php index 2b2bc55..ea08525 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileListingTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileListingTest.php @@ -34,7 +34,7 @@ function setUp() { $this->admin_user = $this->drupalCreateUser(array('access files overview', 'bypass node access')); $this->base_user = $this->drupalCreateUser(); - $this->createFileField('file', 'article', array(), array('file_extensions' => 'txt png')); + $this->createFileField('file', 'node', 'article', array(), array('file_extensions' => 'txt png')); } /** diff --git a/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php b/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php index 1b8a82f..bf338e0 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php @@ -41,11 +41,11 @@ public function setUp() { function testPrivateFile() { $type_name = 'article'; $field_name = strtolower($this->randomName()); - $this->createFileField($field_name, $type_name, array('uri_scheme' => 'private')); + $this->createFileField($field_name, 'node', $type_name, array('uri_scheme' => 'private')); // Create a field with no view access - see field_test_field_access(). $no_access_field_name = 'field_no_view_access'; - $this->createFileField($no_access_field_name, $type_name, array('uri_scheme' => 'private')); + $this->createFileField($no_access_field_name, 'node', $type_name, array('uri_scheme' => 'private')); $test_file = $this->getTestFile('text'); $nid = $this->uploadNodeFile($test_file, $field_name, $type_name, TRUE, array('private' => TRUE)); diff --git a/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php b/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php index 36d323d..b9ba145 100644 --- a/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php +++ b/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php @@ -35,7 +35,7 @@ function testFileTokenReplacement() { // Create file field. $type_name = 'article'; $field_name = 'field_' . strtolower($this->randomName()); - $this->createFileField($field_name, $type_name); + $this->createFileField($field_name, 'node', $type_name); $test_file = $this->getTestFile('text'); // Coping a file to test uploads with non-latin filenames. diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install index cd7ebdb..83c7b91 100644 --- a/core/modules/forum/forum.install +++ b/core/modules/forum/forum.install @@ -51,9 +51,10 @@ function forum_enable() { // Create the 'taxonomy_forums' field if it doesn't already exist. If forum // is being enabled at the same time as taxonomy after both modules have been // enabled, the field might exist but still be marked inactive. - if (!field_read_field('taxonomy_forums', array('include_inactive' => TRUE))) { + if (!field_read_field('node', 'taxonomy_forums', array('include_inactive' => TRUE))) { entity_create('field_entity', array( - 'field_name' => 'taxonomy_forums', + 'name' => 'taxonomy_forums', + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'settings' => array( 'allowed_values' => array( @@ -114,7 +115,7 @@ function forum_uninstall() { // Load the dependent Taxonomy module, in case it has been disabled. drupal_load('module', 'taxonomy'); - if ($field = field_info_field('taxonomy_forums')) { + if ($field = field_info_field('node', 'taxonomy_forums')) { $field->delete(); } diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index 4621ddd..9542d54 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -171,8 +171,8 @@ function forum_menu_local_tasks(&$data, $router_item, $root_path) { if ($forum_term) { $links = array(); // Loop through all bundles for forum taxonomy vocabulary field. - $field = field_info_field('taxonomy_forums'); - foreach ($field['bundles']['node'] as $type_name) { + $field = field_info_field('node', 'taxonomy_forums'); + foreach ($field['bundles'] as $type_name) { if (($type = entity_load('node_type', $type_name)) && node_access('create', $type_name)) { $links[$type_name] = array( '#theme' => 'menu_local_action', @@ -377,6 +377,33 @@ function forum_node_update(EntityInterface $node) { )) ->execute(); } + + // If the node is published, update the forum index. + if ($node->status) { + db_delete('forum_index')->condition('nid', $node->id())->execute(); + $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp')); + foreach ($node->taxonomy_forums as $language) { + foreach ($language as $item) { + $query->values(array( + 'nid' => $node->id(), + 'title' => $node->title, + 'tid' => $item['target_id'], + 'sticky' => $node->sticky, + 'created' => $node->created, + 'comment_count' => 0, + 'last_comment_timestamp' => $node->created, + )); + } + } + $query->execute(); + // The logic for determining last_comment_count is fairly complex, so + // call _forum_update_forum_index() too. + _forum_update_forum_index($node->id()); + } + // When a forum node is unpublished, remove it from the forum_index table. + else { + db_delete('forum_index')->condition('nid', $node->id())->execute(); + } } } @@ -394,6 +421,23 @@ function forum_node_insert(EntityInterface $node) { )) ->execute(); } + + if ($node->status) { + $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp')); + foreach ($node->getTranslationLanguages() as $langcode => $language) { + $translation = $node->getTranslation($langcode); + $query->values(array( + 'nid' => $node->id(), + 'title' => $translation->title->value, + 'tid' => $translation->taxonomy_forums->target_id, + 'sticky' => $node->sticky, + 'created' => $node->created, + 'comment_count' => 0, + 'last_comment_timestamp' => $node->created, + )); + } + $query->execute(); + } } } @@ -498,74 +542,6 @@ function forum_comment_delete($comment) { } /** - * Implements hook_field_storage_pre_insert(). - */ -function forum_field_storage_pre_insert(EntityInterface $entity, &$skip_fields) { - if ($entity->entityType() == 'node' && $entity->status && _forum_node_check_node_type($entity)) { - $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp')); - foreach ($entity->getTranslationLanguages() as $langcode => $language) { - $translation = $entity->getTranslation($langcode); - $query->values(array( - 'nid' => $entity->id(), - 'title' => $translation->title->value, - 'tid' => $translation->taxonomy_forums->target_id, - 'sticky' => $entity->sticky, - 'created' => $entity->created, - 'comment_count' => 0, - 'last_comment_timestamp' => $entity->created, - )); - } - $query->execute(); - } -} - -/** - * Implements hook_field_storage_pre_update(). - */ -function forum_field_storage_pre_update(EntityInterface $entity, &$skip_fields) { - $first_call = &drupal_static(__FUNCTION__, array()); - - if ($entity->entityType() == 'node' && _forum_node_check_node_type($entity)) { - - // If the node is published, update the forum index. - if ($entity->status) { - - // We don't maintain data for old revisions, so clear all previous values - // from the table. Since this hook runs once per field, per object, make - // sure we only wipe values once. - if (!isset($first_call[$entity->nid])) { - $first_call[$entity->nid] = FALSE; - db_delete('forum_index')->condition('nid', $entity->id())->execute(); - } - $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp')); - foreach ($entity->taxonomy_forums as $language) { - foreach ($language as $item) { - $query->values(array( - 'nid' => $entity->nid, - 'title' => $entity->title, - 'tid' => $item['target_id'], - 'sticky' => $entity->sticky, - 'created' => $entity->created, - 'comment_count' => 0, - 'last_comment_timestamp' => $entity->created, - )); - } - } - $query->execute(); - // The logic for determining last_comment_count is fairly complex, so - // call _forum_update_forum_index() too. - _forum_update_forum_index($entity->id()); - } - - // When a forum node is unpublished, remove it from the forum_index table. - else { - db_delete('forum_index')->condition('nid', $entity->id())->execute(); - } - - } -} - -/** * Implements hook_form_BASE_FORM_ID_alter(). */ function forum_form_taxonomy_vocabulary_form_alter(&$form, &$form_state, $form_id) { diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php index 0fe25e3..cce8db0 100644 --- a/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php +++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php @@ -34,7 +34,7 @@ public static function getInfo() { */ function testForumUninstallWithField() { // Ensure that the field exists before uninstallation. - $field = field_info_field('taxonomy_forums'); + $field = field_info_field('node', 'taxonomy_forums'); $this->assertNotNull($field, 'The taxonomy_forums field exists.'); // Uninstall the forum module which should trigger field deletion. @@ -42,7 +42,7 @@ function testForumUninstallWithField() { $this->container->get('module_handler')->uninstall(array('forum')); // Check that the field is now deleted. - $field = field_info_field('taxonomy_forums'); + $field = field_info_field('node', 'taxonomy_forums'); $this->assertNull($field, 'The taxonomy_forums field has been deleted.'); } @@ -52,12 +52,12 @@ function testForumUninstallWithField() { */ function testForumUninstallWithoutField() { // Manually delete the taxonomy_forums field before module uninstallation. - $field = field_info_field('taxonomy_forums'); + $field = field_info_field('node', 'taxonomy_forums'); $this->assertNotNull($field, 'The taxonomy_forums field exists.'); $field->delete(); // Check that the field is now deleted. - $field = field_info_field('taxonomy_forums'); + $field = field_info_field('node', 'taxonomy_forums'); $this->assertNull($field, 'The taxonomy_forums field has been deleted.'); // Ensure that uninstallation succeeds even if the field has already been diff --git a/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php b/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php index ea55fd9..a99b1aa 100644 --- a/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php +++ b/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php @@ -78,7 +78,8 @@ function setUp() { // Create the test text field. entity_create('field_entity', array( - 'field_name' => 'field_test_text', + 'name' => 'field_test_text', + 'entity_type' => 'entity_test', 'type' => 'text', 'translatable' => FALSE, ))->save(); @@ -90,7 +91,8 @@ function setUp() { // Create the test translatable field. entity_create('field_entity', array( - 'field_name' => 'field_test_translatable_text', + 'name' => 'field_test_translatable_text', + 'entity_type' => 'entity_test', 'type' => 'text', 'translatable' => TRUE, ))->save(); @@ -102,12 +104,13 @@ function setUp() { // Create the test entity reference field. entity_create('field_entity', array( + 'name' => 'field_test_entity_reference', + 'entity_type' => 'entity_test', + 'type' => 'entity_reference', 'translatable' => TRUE, 'settings' => array( 'target_type' => 'entity_test', ), - 'field_name' => 'field_test_entity_reference', - 'type' => 'entity_reference', ))->save(); entity_create('field_instance', array( 'entity_type' => 'entity_test', diff --git a/core/modules/image/image.views.inc b/core/modules/image/image.views.inc index 2e70c08..b97ca79 100644 --- a/core/modules/image/image.views.inc +++ b/core/modules/image/image.views.inc @@ -7,6 +7,9 @@ * @ingroup views_module_handlers */ +use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\field\FieldInterface; + /** * Implements hook_field_views_data(). * @@ -15,8 +18,8 @@ * * @see field_views_field_default_views_data() */ -function image_field_views_data($field) { - $data = field_views_field_default_views_data($field); +function image_field_views_data(FieldInterface $field, array $sql_entity_types) { + $data = field_views_field_default_views_data($field, $sql_entity_types); foreach ($data as $table_name => $table_data) { // Add the relationship only on the target_id field. $data[$table_name][$field['field_name'] . '_target_id']['relationship'] = array( @@ -35,8 +38,8 @@ function image_field_views_data($field) { * * Views integration to provide reverse relationships on image fields. */ -function image_field_views_data_views_data_alter(&$data, $field) { - foreach ($field['bundles'] as $entity_type => $bundles) { +function image_field_views_data_views_data_alter(array &$data, FieldInterface $field, array $sql_entity_types) { + foreach ($sql_entity_types as $entity_type) { $entity_info = entity_get_info($entity_type); $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type; @@ -51,17 +54,14 @@ function image_field_views_data_views_data_alter(&$data, $field) { 'help' => t('Relate each @entity with a @field set to the image.', array('@entity' => $entity, '@field' => $label)), 'id' => 'entity_reverse', 'field_name' => $field['field_name'], - 'field table' => _field_sql_storage_tablename($field), + 'entity_type' => $field['entity_type'], + 'field table' => DatabaseStorageController::_fieldTableName($field), 'field field' => $field['field_name'] . '_target_id', 'base' => $entity_info['base_table'], 'base field' => $entity_info['entity_keys']['id'], 'label' => t('!field_name', array('!field_name' => $field['field_name'])), 'join_extra' => array( 0 => array( - 'field' => 'entity_type', - 'value' => $entity_type, - ), - 1 => array( 'field' => 'deleted', 'value' => 0, 'numeric' => TRUE, diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php index 2c1ae39..afacde2 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php @@ -52,11 +52,11 @@ function testDefaultImages() { 'preview_image_style' => 'medium', ); $instance = $this->createImageField($field_name, 'article', $field_settings, $instance_settings, $widget_settings); - $field = field_info_field($field_name); + $field = field_info_field('node', $field_name); // Add another instance with another default image to the page content type. $instance2 = entity_create('field_instance', array( - 'field_name' => $field->id(), + 'field_name' => $field->name, 'entity_type' => 'node', 'bundle' => 'page', 'label' => $instance->label(), @@ -67,12 +67,12 @@ function testDefaultImages() { )); $instance2->save(); - $widget_settings = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($field['field_name']); + $widget_settings = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($field_name); entity_get_form_display('node', 'page', 'default') - ->setComponent($field->id(), $widget_settings) + ->setComponent($field_name, $widget_settings) ->save(); entity_get_display('node', 'page', 'default') - ->setComponent($field->id()) + ->setComponent($field_name) ->save(); // Confirm the defaults are present on the article field settings form. diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php index 8ec6727..38394a6 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php @@ -231,7 +231,7 @@ function testImageFieldDefaultImage() { $this->drupalPost("admin/structure/types/manage/article/fields/node.article.$field_name/field", $edit, t('Save field settings')); // Clear field info cache so the new default image is detected. field_info_cache_clear(); - $field = field_info_field($field_name); + $field = field_info_field('node', $field_name); $image = file_load($field['settings']['default_image']); $this->assertTrue($image->isPermanent(), 'The default image status is permanent.'); $default_output = theme('image', array('uri' => $image->getFileUri())); @@ -259,7 +259,7 @@ function testImageFieldDefaultImage() { $this->drupalPost("admin/structure/types/manage/article/fields/node.article.$field_name/field", $edit, t('Save field settings')); // Clear field info cache so the new default image is detected. field_info_cache_clear(); - $field = field_info_field($field_name); + $field = field_info_field('node', $field_name); $this->assertFalse($field['settings']['default_image'], 'Default image removed from field.'); // Create an image field that uses the private:// scheme and test that the // default image works as expected. @@ -273,7 +273,7 @@ function testImageFieldDefaultImage() { // Clear field info cache so the new default image is detected. field_info_cache_clear(); - $private_field = field_info_field($private_field_name); + $private_field = field_info_field('node', $private_field_name); $image = file_load($private_field['settings']['default_image']); $this->assertEqual('private', file_uri_scheme($image->getFileUri()), 'Default image uses private:// scheme.'); $this->assertTrue($image->isPermanent(), 'The default image status is permanent.'); diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php index 7d0f054..5dc38f3 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php @@ -66,7 +66,8 @@ function setUp() { */ function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) { $field = array( - 'field_name' => $name, + 'name' => $name, + 'entity_type' => 'node', 'type' => 'image', 'settings' => array(), 'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1, @@ -75,9 +76,9 @@ function createImageField($name, $type_name, $field_settings = array(), $instanc entity_create('field_entity', $field)->save(); $instance = array( - 'field_name' => $field['field_name'], - 'entity_type' => 'node', + 'field_name' => $field['name'], 'label' => $name, + 'entity_type' => 'node', 'bundle' => $type_name, 'required' => !empty($instance_settings['required']), 'description' => !empty($instance_settings['description']) ? $instance_settings['description'] : '', @@ -88,14 +89,14 @@ function createImageField($name, $type_name, $field_settings = array(), $instanc $field_instance->save(); entity_get_form_display('node', $type_name, 'default') - ->setComponent($field['field_name'], array( + ->setComponent($field['name'], array( 'type' => 'image_image', 'settings' => $widget_settings, )) ->save(); entity_get_display('node', $type_name, 'default') - ->setComponent($field['field_name']) + ->setComponent($field['name']) ->save(); return $field_instance; diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php index 5e7472f..d9c4099 100644 --- a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php +++ b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php @@ -44,7 +44,8 @@ public function setUp() { $this->installSchema('file', array('file_managed', 'file_usage')); entity_create('field_entity', array( - 'field_name' => 'image_test', + 'name' => 'image_test', + 'entity_type' => 'entity_test', 'type' => 'image', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, ))->save(); diff --git a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php index b4033ff..d48f587 100644 --- a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php +++ b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php @@ -68,7 +68,8 @@ function testURLValidation() { $field_name = drupal_strtolower($this->randomName()); // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'link', )); $this->field->save(); @@ -142,7 +143,8 @@ function testLinkTitle() { $field_name = drupal_strtolower($this->randomName()); // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'link', )); $this->field->save(); @@ -261,7 +263,8 @@ function testLinkFormatter() { $field_name = drupal_strtolower($this->randomName()); // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'link', 'cardinality' => 2, )); @@ -404,7 +407,8 @@ function testLinkSeparateFormatter() { $field_name = drupal_strtolower($this->randomName()); // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'link', 'cardinality' => 2, )); diff --git a/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php b/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php index 2cd88bc..a42d6a2 100644 --- a/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php +++ b/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php @@ -36,7 +36,8 @@ public function setUp() { // Create an link field and instance for validation. entity_create('field_entity', array( - 'field_name' => 'field_test', + 'name' => 'field_test', + 'entity_type' => 'entity_test', 'type' => 'link', ))->save(); entity_create('field_instance', array( diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php index 43d54ce..7242cbe 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php @@ -11,6 +11,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Database\Connection; +use Drupal\field\FieldInfo; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Cmf\Component\Routing\RouteProviderInterface; @@ -52,11 +53,13 @@ class MenuLinkStorageController extends DatabaseStorageController implements Men * An array of entity info for the entity type. * @param \Drupal\Core\Database\Connection $database * The database connection to be used. + * @param \Drupal\field\FieldInfo $field_info + * The field info service. * @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $route_provider * The route provider service. */ - public function __construct($entity_type, array $entity_info, Connection $database, RouteProviderInterface $route_provider) { - parent::__construct($entity_type, $entity_info, $database); + public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info, RouteProviderInterface $route_provider) { + parent::__construct($entity_type, $entity_info, $database, $field_info); $this->routeProvider = $route_provider; @@ -85,6 +88,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ $entity_type, $entity_info, $container->get('database'), + $container->get('field.info'), $container->get('router.route_provider') ); } diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index 1a874fe..3318acb 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\DatabaseStorageControllerNG; use Drupal\Core\Entity\EntityInterface; +use Symfony\Component\DependencyInjection\Container; /** * Controller class for nodes. @@ -46,10 +47,10 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { } if ($load_revision) { - field_attach_load_revision($this->entityType, $queried_entities); + $this->fieldLoad($queried_entities, FIELD_LOAD_REVISION); } else { - field_attach_load($this->entityType, $queried_entities); + $this->fieldLoad($queried_entities, FIELD_LOAD_CURRENT); } // Besides the list of nodes, pass one additional argument to @@ -80,14 +81,9 @@ protected function invokeHook($hook, EntityInterface $node) { // Inline parent::invokeHook() to pass on BC-entities to node-specific // hooks. - $function = 'field_attach_' . $hook; - // @todo: field_attach_delete_revision() is named the wrong way round, - // consider renaming it. - if ($function == 'field_attach_revision_delete') { - $function = 'field_attach_delete_revision'; - } - if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { - $function($node); + $method = Container::camelize('field_' . $hook); + if (!empty($this->entityInfo['fieldable']) && method_exists($this, $method)) { + $this->$method($node); } // Invoke the hook. diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php b/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php index acba6b6..2d55c6e 100644 --- a/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php +++ b/core/modules/node/lib/Drupal/node/Plugin/views/wizard/Node.php @@ -306,9 +306,10 @@ protected function buildFilters(&$form, &$form_state) { $form['displays']['show']['tagged_with'] = array( '#type' => 'textfield', '#title' => t('tagged with'), - '#autocomplete_path' => 'taxonomy/autocomplete/' . $tag_field_name, + '#autocomplete_path' => 'taxonomy/autocomplete/' . $this->entity_type . '/' . $tag_field_name, '#size' => 30, '#maxlength' => 1024, + '#entity_type' => $this->entity_type, '#field_name' => $tag_field_name, '#element_validate' => array('views_ui_taxonomy_autocomplete_validate'), ); diff --git a/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php b/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php index 65e3aec..4fc3f7b 100644 --- a/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php @@ -41,7 +41,8 @@ function testMultiStepNodeFormBasicOptions() { // Create an unlimited cardinality field. $this->field_name = drupal_strtolower($this->randomName()); entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => 'text', 'cardinality' => -1, ))->save(); diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php index 8b4bf7a..944aa4f 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php @@ -62,7 +62,8 @@ public function setUp() { // Add a custom field to the page content type. $this->field_name = drupal_strtolower($this->randomName() . '_field_name'); entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => 'text' ))->save(); entity_create('field_instance', array( diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php index 6df2698..6b451a0 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php @@ -59,7 +59,7 @@ function setUp() { $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), 'Basic page content type has been updated.'); // Make node body translatable. - $field = field_info_field('body'); + $field = field_info_field('node', 'body'); $field->translatable = TRUE; $field->save(); } diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php index dac3575..7c852d9 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php @@ -169,7 +169,7 @@ function testFieldTranslationForm() { $this->assertRaw('Not translated'); // Delete the only translatable field. - field_info_field('field_test_et_ui_test')->delete(); + field_info_field($this->entityType, 'field_test_et_ui_test')->delete(); // Visit translation page. $this->drupalGet('node/' . $article->id() . '/translations'); diff --git a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php index 0538e00..f9e3670 100644 --- a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php @@ -68,7 +68,8 @@ function setUp() { // Set up a field and instance. $this->field_name = drupal_strtolower($this->randomName()); entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'settings' => array( 'allowed_values' => array( diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 26f11a2..b10bf38 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -395,13 +395,13 @@ function node_type_load($name) { */ function node_add_body_field(NodeTypeInterface $type, $label = 'Body') { // Add or remove the body field, as needed. - $field = field_info_field('body'); + $field = field_info_field('node', 'body'); $instance = field_info_instance('node', 'body', $type->id()); if (empty($field)) { $field = entity_create('field_entity', array( - 'field_name' => 'body', + 'name' => 'body', + 'entity_type' => 'node', 'type' => 'text_with_summary', - 'entity_types' => array('node'), )); $field->save(); } @@ -417,20 +417,20 @@ function node_add_body_field(NodeTypeInterface $type, $label = 'Body') { // Assign widget settings for the 'default' form mode. entity_get_form_display('node', $type->type, 'default') - ->setComponent($field->id(), array( + ->setComponent('body', array( 'type' => 'text_textarea_with_summary', )) ->save(); // Assign display settings for the 'default' and 'teaser' view modes. entity_get_display('node', $type->type, 'default') - ->setComponent($field->id(), array( + ->setComponent('body', array( 'label' => 'hidden', 'type' => 'text_default', )) ->save(); entity_get_display('node', $type->type, 'teaser') - ->setComponent($field->id(), array( + ->setComponent('body', array( 'label' => 'hidden', 'type' => 'text_summary_or_trimmed', )) diff --git a/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module index 1baa48e..5b54e13 100644 --- a/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module +++ b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module @@ -50,7 +50,8 @@ function node_access_test_language_node_access_records(EntityInterface $node) { */ function node_access_test_language_enable() { $field_private = entity_create('field_entity', array( - 'field_name' => 'field_private', + 'name' => 'field_private', + 'entity_type' => 'node', 'type' => 'list_boolean', 'cardinality' => 1, 'translatable' => TRUE, @@ -61,7 +62,7 @@ function node_access_test_language_enable() { $field_private->save(); entity_create('field_instance', array( - 'field_name' => $field_private->id(), + 'field_name' => $field_private->name, 'entity_type' => 'node', 'bundle' => 'page', 'widget' => array( diff --git a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php index ad947e4..3839866 100644 --- a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php +++ b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php @@ -64,7 +64,8 @@ function setUp() { function testNumberDecimalField() { // Create a field with settings to validate. $this->field = entity_create('field_entity', array( - 'field_name' => drupal_strtolower($this->randomName()), + 'name' => drupal_strtolower($this->randomName()), + 'entity_type' => 'entity_test', 'type' => 'number_decimal', 'settings' => array( 'precision' => 8, 'scale' => 4, 'decimal_separator' => '.', @@ -72,13 +73,13 @@ function testNumberDecimalField() { )); $this->field->save(); entity_create('field_instance', array( - 'field_name' => $this->field->id(), + 'field_name' => $this->field->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ))->save(); entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->field->id(), array( + ->setComponent($this->field->name, array( 'type' => 'number', 'settings' => array( 'placeholder' => '0.00' @@ -86,7 +87,7 @@ function testNumberDecimalField() { )) ->save(); entity_get_display('entity_test', 'entity_test', 'default') - ->setComponent($this->field->id(), array( + ->setComponent($this->field->name, array( 'type' => 'number_decimal', )) ->save(); diff --git a/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php b/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php index a0cc904..636c55d 100644 --- a/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php +++ b/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php @@ -37,7 +37,8 @@ public function setUp() { // Create number fields and instances for validation. foreach (array('integer', 'float', 'decimal') as $type) { entity_create('field_entity', array( - 'field_name' => 'field_' . $type, + 'name' => 'field_' . $type, + 'entity_type' => 'entity_test', 'type' => 'number_' . $type, ))->save(); entity_create('field_instance', array( diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php index c270e4a..6607332 100644 --- a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php +++ b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php @@ -33,7 +33,8 @@ function setUp() { $this->field_name = 'test_options'; entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test_rev', 'type' => 'list_text', 'cardinality' => 1, 'settings' => array( diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php index 2b45acd..34f0a87 100644 --- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php +++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php @@ -231,7 +231,7 @@ function testOptionsAllowedValuesBoolean() { $this->drupalGet($this->admin_path); $this->assertFieldByName('on', $on, t("The 'On' value is stored correctly.")); $this->assertFieldByName('off', $off, t("The 'Off' value is stored correctly.")); - $field = field_info_field($this->field_name); + $field = field_info_field('node', $this->field_name); $this->assertEqual($field['settings']['allowed_values'], $allowed_values, 'The allowed value is correct'); $this->assertFalse(isset($field['settings']['on']), 'The on value is not saved into settings'); $this->assertFalse(isset($field['settings']['off']), 'The off value is not saved into settings'); @@ -259,7 +259,8 @@ function testOptionsTrimmedValuesText() { protected function createOptionsField($type) { // Create a test field and instance. entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => $type, ))->save(); entity_create('field_instance', array( @@ -294,7 +295,7 @@ function assertAllowedValuesInput($input_string, $result, $message) { } else { field_info_cache_clear(); - $field = field_info_field($this->field_name); + $field = field_info_field('node', $this->field_name); $this->assertIdentical($field['settings']['allowed_values'], $result, $message); } } diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php index 748ee6e..dc987d4 100644 --- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php +++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php @@ -58,7 +58,8 @@ public function setUp() { $this->installSchema('system', 'menu_router'); $this->fieldDefinition = array( - 'field_name' => $this->fieldName, + 'name' => $this->fieldName, + 'entity_type' => 'entity_test', 'type' => 'list_integer', 'cardinality' => 1, 'settings' => array( diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php index dbc1876..afa8a94 100644 --- a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php +++ b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php @@ -64,7 +64,8 @@ function setUp() { // Field with cardinality 1. $this->card_1 = entity_create('field_entity', array( - 'field_name' => 'card_1', + 'name' => 'card_1', + 'entity_type' => 'entity_test', 'type' => 'list_integer', 'cardinality' => 1, 'settings' => array( @@ -76,7 +77,8 @@ function setUp() { // Field with cardinality 2. $this->card_2 = entity_create('field_entity', array( - 'field_name' => 'card_2', + 'name' => 'card_2', + 'entity_type' => 'entity_test', 'type' => 'list_integer', 'cardinality' => 2, 'settings' => array( @@ -88,7 +90,8 @@ function setUp() { // Boolean field. $this->bool = entity_create('field_entity', array( - 'field_name' => 'bool', + 'name' => 'bool', + 'entity_type' => 'entity_test', 'type' => 'list_boolean', 'cardinality' => 1, 'settings' => array( @@ -108,13 +111,13 @@ function setUp() { function testRadioButtons() { // Create an instance of the 'single value' field. $instance = entity_create('field_instance', array( - 'field_name' => $this->card_1->id(), + 'field_name' => $this->card_1->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', )); $instance->save(); entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->card_1->id(), array( + ->setComponent($this->card_1->name, array( 'type' => 'options_buttons', )) ->save(); @@ -167,13 +170,13 @@ function testRadioButtons() { function testCheckBoxes() { // Create an instance of the 'multiple values' field. $instance = entity_create('field_instance', array( - 'field_name' => $this->card_2->id(), + 'field_name' => $this->card_2->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', )); $instance->save(); entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->card_2->id(), array( + ->setComponent($this->card_2->name, array( 'type' => 'options_buttons', )) ->save(); @@ -259,14 +262,14 @@ function testCheckBoxes() { function testSelectListSingle() { // Create an instance of the 'single value' field. $instance = entity_create('field_instance', array( - 'field_name' => $this->card_1->id(), + 'field_name' => $this->card_1->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', 'required' => TRUE, )); $instance->save(); entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->card_1->id(), array( + ->setComponent($this->card_1->name, array( 'type' => 'options_select', )) ->save(); @@ -361,13 +364,13 @@ function testSelectListSingle() { function testSelectListMultiple() { // Create an instance of the 'multiple values' field. $instance = entity_create('field_instance', array( - 'field_name' => $this->card_2->id(), + 'field_name' => $this->card_2->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', )); $instance->save(); entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->card_2->id(), array( + ->setComponent($this->card_2->name, array( 'type' => 'options_select', )) ->save(); @@ -483,12 +486,12 @@ function testSelectListMultiple() { function testOnOffCheckbox() { // Create an instance of the 'boolean' field. entity_create('field_instance', array( - 'field_name' => $this->bool->id(), + 'field_name' => $this->bool->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ))->save(); entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->bool->id(), array( + ->setComponent($this->bool->name, array( 'type' => 'options_onoff', )) ->save(); @@ -525,7 +528,12 @@ function testOnOffCheckbox() { // Display form: with 'off' value, option is unchecked. $this->drupalGet('entity_test/manage/' . $entity->id() . '/edit'); $this->assertNoFieldChecked("edit-bool-$langcode"); + } + /** + * Tests that the 'options_onoff' widget has a 'display_label' setting. + */ + function testOnOffCheckboxLabelSetting() { // Create Basic page node type. $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); @@ -534,11 +542,17 @@ function testOnOffCheckbox() { $this->drupalLogin($admin_user); // Create a test field instance. - $fieldUpdate = $this->bool; - $fieldUpdate['settings']['allowed_values'] = array(0 => 0, 1 => 'MyOnValue'); - $fieldUpdate->save(); + entity_create('field_entity', array( + 'name' => 'bool', + 'entity_type' => 'node', + 'type' => 'list_boolean', + 'cardinality' => 1, + 'settings' => array( + 'allowed_values' => array(0 => 'Zero', 1 => 'Some & unescaped markup'), + ), + ))->save(); entity_create('field_instance', array( - 'field_name' => $this->bool['field_name'], + 'field_name' => 'bool', 'entity_type' => 'node', 'bundle' => 'page', ))->save(); @@ -584,4 +598,5 @@ function testOnOffCheckbox() { t('Display label changes label of the checkbox') ); } + } diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php index 11176dc..46119d5 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php @@ -56,7 +56,7 @@ public function setUp() { $this->fieldName = strtolower($this->randomName()); $type_name = 'article'; - $this->createFileField($this->fieldName, $type_name); + $this->createFileField($this->fieldName, 'node', $type_name); // Set the teaser display to show this field. entity_get_display('node', 'article', 'teaser') diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php index 70bdda0..d082abe 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php @@ -154,7 +154,8 @@ function testNodeTeaser() { */ protected function createTaxonomyTermReferenceField($field_name, $vocabulary) { entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( diff --git a/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php b/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php index 0e3fd91..9e79bc3 100644 --- a/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php +++ b/core/modules/rest/lib/Drupal/rest/LinkManager/RelationLinkManager.php @@ -74,14 +74,14 @@ public function getRelations() { protected function writeCache() { $data = array(); - foreach (field_info_fields() as $field_info) { - foreach ($field_info['bundles'] as $entity_type => $bundles) { - foreach ($bundles as $bundle) { - $relation_uri = $this->getRelationUri($entity_type, $bundle, $field_info['field_name']); + foreach (field_info_fields() as $entity_type => $fields) { + foreach ($fields as $field_name => $field_info) { + foreach ($field_info['bundles'] as $bundle) { + $relation_uri = $this->getRelationUri($entity_type, $bundle, $field_name); $data[$relation_uri] = array( 'entity_type' => $entity_type, 'bundle' => $bundle, - 'field_name' => $field_info['field_name'], + 'field_name' => $field_name, ); } } diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php index d9ab415..60f49aa 100644 --- a/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php +++ b/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php @@ -48,7 +48,7 @@ function setUp() { // Make the body field translatable. // The parent class has already created the article and page content types. - $field = field_info_field('body'); + $field = field_info_field('node', 'body'); $field->translatable = TRUE; $field->save(); diff --git a/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php b/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php index 48d0293..5d9dac4 100644 --- a/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php +++ b/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php @@ -38,7 +38,8 @@ protected function setUp() { 'settings' => array( 'target_type' => 'entity_test_mulrev', ), - 'field_name' => 'field_test_entity_reference', + 'name' => 'field_test_entity_reference', + 'entity_type' => 'entity_test_mulrev', 'type' => 'entity_reference', ))->save(); diff --git a/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php b/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php index 74fa8d9..8bb36f2 100644 --- a/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php +++ b/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php @@ -16,7 +16,7 @@ * * @var array */ - public static $modules = array('serialization', 'system', 'entity', 'field', 'entity_test', 'text', 'field_sql_storage'); + public static $modules = array('serialization', 'system', 'entity', 'field', 'entity_test', 'text'); protected function setUp() { parent::setUp(); @@ -27,7 +27,8 @@ protected function setUp() { // Auto-create a field for testing. entity_create('field_entity', array( - 'field_name' => 'field_test_text', + 'name' => 'field_test_text', + 'entity_type' => 'entity_test_mulrev', 'type' => 'text', 'cardinality' => 1, 'translatable' => FALSE, diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php index 1171d1e..efcc99c 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php @@ -232,12 +232,13 @@ function testEnableModulesFixedList() { 'mode' => 'default', )); $field = entity_create('field_entity', array( - 'field_name' => 'test_field', + 'name' => 'test_field', + 'entity_type' => 'entity_test', 'type' => 'test_field' )); $field->save(); entity_create('field_instance', array( - 'field_name' => $field->id(), + 'field_name' => $field->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ))->save(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php index f15f382..5051384 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php @@ -35,7 +35,8 @@ function setUp() { // Create a multi-valued field for 'page' nodes to use for Ajax testing. $field_name = 'field_ajax_test'; entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'node', 'type' => 'text', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, ))->save(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Database/SchemaTest.php b/core/modules/system/lib/Drupal/system/Tests/Database/SchemaTest.php index 4845751..4c0085b 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Database/SchemaTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Database/SchemaTest.php @@ -87,6 +87,19 @@ function testSchema() { $index_exists = Database::getConnection()->schema()->indexExists('test_table2', 'test_field'); $this->assertTrue($index_exists, 'Index was renamed.'); + // Copy the schema of the table. + db_copy_table('test_table2', 'test_table3'); + + // Index should be copied. + $index_exists = Database::getConnection()->schema()->indexExists('test_table3', 'test_field'); + $this->assertTrue($index_exists, 'Index was copied.'); + + // Data should still exist on the old table but not on the new one. + $count = db_select('test_table2')->countQuery()->execute()->fetchField(); + $this->assertEqual($count, 1, 'The old table still has its content.'); + $count = db_select('test_table3')->countQuery()->execute()->fetchField(); + $this->assertEqual($count, 0, 'The new table has no content.'); + // We need the default so that we can insert after the rename. db_field_set_default('test_table2', 'test_field', 0); $this->assertFalse($this->tryInsert(), 'Insert into the old table failed.'); @@ -154,9 +167,9 @@ function testSchema() { */ function tryInsert($table = 'test_table') { try { - db_insert($table) - ->fields(array('id' => mt_rand(10, 20))) - ->execute(); + db_insert($table) + ->fields(array('id' => mt_rand(10, 20))) + ->execute(); return TRUE; } catch (\Exception $e) { @@ -227,8 +240,8 @@ function testUnsignedColumns() { function tryUnsignedInsert($table_name, $column_name) { try { db_insert($table_name) - ->fields(array($column_name => -1)) - ->execute(); + ->fields(array($column_name => -1)) + ->execute(); return TRUE; } catch (\Exception $e) { diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php index faa7090..7939fb0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php @@ -62,7 +62,8 @@ public function setUp() { for ($i = 1; $i <= 2; $i++) { $field_name = 'field_test_' . $i; entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test', 'type' => 'number_integer', 'cardinality' => 2, ))->save(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php index ae99e9d..ee498c4 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php @@ -81,7 +81,8 @@ public function setUp() { // Second, create the field. $this->fieldName = strtolower($this->randomName()); $field = array( - 'field_name' => $this->fieldName, + 'name' => $this->fieldName, + 'entity_type' => 'entity_test', 'type' => 'taxonomy_term_reference', ); $field['settings']['allowed_values']['vocabulary'] = $vocabulary->id(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php index 284526f..e1b0ea7 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php @@ -63,7 +63,8 @@ function setUp() { $greetings = drupal_strtolower($this->randomName()); foreach (array($figures => 'shape', $greetings => 'text') as $field_name => $field_type) { $field = entity_create('field_entity', array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'entity_test_mulrev', 'type' => $field_type, 'cardinality' => 2, 'translatable' => TRUE, @@ -81,7 +82,7 @@ function setUp() { entity_test_create_bundle($bundle); foreach ($fields as $field) { entity_create('field_instance', array( - 'field_name' => $field->id(), + 'field_name' => $field->name, 'entity_type' => 'entity_test_mulrev', 'bundle' => $bundle, ))->save(); @@ -404,12 +405,19 @@ protected function testTableSort() { } /** - * Test entity count query. + * Test that count queries are separated across entity types. */ protected function testCount() { - // Attach the existing 'figures' field to a second entity type so that we - // can test whether cross entity type fields produce the correct query. + // Create a field with the same name in a different entity type. $field_name = $this->figures; + $field = entity_create('field_entity', array( + 'name' => $field_name, + 'entity_type' => 'entity_test', + 'type' => 'shape', + 'cardinality' => 2, + 'translatable' => TRUE, + )); + $field->save(); $bundle = $this->randomName(); entity_create('field_instance', array( 'field_name' => $field_name, @@ -424,6 +432,7 @@ protected function testCount() { $entity->enforceIsNew(); $entity->setNewRevision(); $entity->save(); + // As the single entity of this type we just saved does not have a value // in the color field, the result should be 0. $count = $this->factory->get('entity_test') diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php index 80e8a6b..e152a68 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php @@ -104,10 +104,10 @@ function testEntityFormLanguage() { $this->assertTrue($node, 'Node found in database.'); // Make body translatable. - $field = field_info_field('body'); + $field = field_info_field('node', 'body'); $field->translatable = TRUE; $field->save(); - $field = field_info_field('body'); + $field = field_info_field('node', 'body'); $this->assertTrue($field['translatable'], 'Field body is translatable.'); // Create a body translation and check the form language. diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php index 40a7e44..7adfda3 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php @@ -51,16 +51,16 @@ function setUp() { // Create a translatable test field. $this->field_name = drupal_strtolower($this->randomName() . '_field_name'); - entity_create('field_entity', array( - 'field_name' => $this->field_name, - 'type' => 'text', - 'cardinality' => 4, - 'translatable' => TRUE, - ))->save(); - $this->field = field_read_field($this->field_name); // Create instance in all entity variations. foreach (entity_test_entity_types() as $entity_type) { + entity_create('field_entity', array( + 'name' => $this->field_name, + 'entity_type' => $entity_type, + 'type' => 'text', + 'cardinality' => 4, + 'translatable' => TRUE, + ))->save(); entity_create('field_instance', array( 'field_name' => $this->field_name, 'entity_type' => $entity_type, diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php index 34fb4cc..d848bcf 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php @@ -20,7 +20,7 @@ * * @var array */ - public static $modules = array('entity', 'user', 'system', 'field', 'text', 'field_sql_storage', 'entity_test'); + public static $modules = array('entity', 'user', 'system', 'field', 'text', 'entity_test'); /** * The entity manager service. diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php index cc6546a..193c2d2 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php @@ -34,7 +34,8 @@ function setUp() { // Auto-create a field for testing. entity_create('field_entity', array( - 'field_name' => 'test_multiple', + 'name' => 'test_multiple', + 'entity_type' => 'user', 'type' => 'text', 'cardinality' => -1, 'translatable' => FALSE, diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php index c580e88..460e0ca 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php @@ -72,7 +72,8 @@ function testPreserveFormActionAfterAJAX() { // Create a multi-valued field for 'page' nodes to use for Ajax testing. $field_name = 'field_ajax_test'; $field = array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'node', 'type' => 'text', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, ); diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php index 01794f0..982a70d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php @@ -14,7 +14,7 @@ */ class TreeOutputTest extends DrupalUnitTestBase { - public static $modules = array('system', 'menu_link'); + public static $modules = array('system', 'menu_link', 'field'); /** * Dummy link structure acceptable for menu_tree_output(). diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php index b04e2d8..262537b 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php @@ -17,7 +17,7 @@ */ class ContextPluginTest extends DrupalUnitTestBase { - public static $modules = array('system', 'user', 'node'); + public static $modules = array('system', 'user', 'node', 'field'); public static function getInfo() { return array( diff --git a/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php b/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php index 7b61c15..53ff2fc 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php @@ -20,7 +20,7 @@ class PasswordHashingTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('user'); + public static $modules = array('field', 'user'); public static function getInfo() { return array( diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php index dd13cf9..307023b 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php @@ -6,7 +6,10 @@ */ namespace Drupal\system\Tests\Upgrade; + +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Language\Language; +use Drupal\field\Plugin\Core\Entity\Field; /** * Tests upgrade of system variables. @@ -121,27 +124,24 @@ function testFieldUpgradeToConfig() { $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Check that the configuration for the 'body' field is correct. - $config = \Drupal::config('field.field.body')->get(); + $config = \Drupal::config('field.field.node.body')->get(); + // This will be necessary to retrieve the table name. + $field_entity = new Field($config); // We cannot predict the value of the UUID, we just check it's present. $this->assertFalse(empty($config['uuid'])); $field_uuid = $config['uuid']; unset($config['uuid']); $this->assertEqual($config, array( - 'id' => 'body', + 'id' => 'node.body', + 'name' => 'body', 'type' => 'text_with_summary', 'module' => 'text', 'active' => '1', + 'entity_type' => 'node', 'settings' => array(), - 'storage' => array( - 'type' => 'field_sql_storage', - 'module' => 'field_sql_storage', - 'active' => '1', - 'settings' => array(), - ), 'locked' => 0, 'cardinality' => 1, 'translatable' => 0, - 'entity_types' => array('node'), 'indexes' => array( 'format' => array('format') ), @@ -195,7 +195,7 @@ function testFieldUpgradeToConfig() { $uuid_key = key($deleted_fields); $deleted_field = $deleted_fields[$uuid_key]; $this->assertEqual($deleted_field['uuid'], $uuid_key); - $this->assertEqual($deleted_field['id'], 'test_deleted_field'); + $this->assertEqual($deleted_field['id'], 'node.test_deleted_field'); // Check that the definition of a deleted instance is stored in state rather // than config. @@ -209,16 +209,11 @@ function testFieldUpgradeToConfig() { // The deleted field uuid and deleted instance field_uuid must match. $this->assertEqual($deleted_field['uuid'], $deleted_instance['field_uuid']); - // Check that pre-existing deleted field values are read correctly. - $entity = _field_create_entity_from_ids((object) array( - 'entity_type' => 'node', - 'bundle' => 'article', - 'entity_id' => 2, - 'revision_id' => 2, - )); - field_attach_load('node', array(2 => $entity), FIELD_LOAD_CURRENT, array('instance' => entity_create('field_instance', $deleted_instance))); - $deleted_value = $entity->get('test_deleted_field'); - $this->assertEqual($deleted_value[Language::LANGCODE_NOT_SPECIFIED][0]['value'], 'Some deleted value'); + // Check that pre-existing deleted field table is renamed correctly. + $field_entity = new Field($deleted_field); + $table_name = DatabaseStorageController::_fieldTableName($field_entity); + $this->assertEqual("field_deleted_data_" . substr(hash('sha256', $deleted_field['uuid']), 0, 10), $table_name); + $this->assertTrue(db_table_exists($table_name)); // Check that creation of a new node works as expected. $value = $this->randomName(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php index 2503aa5..c8825af 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php @@ -52,7 +52,7 @@ public function testUserPictureUpgrade() { // Check file usage for the default image. $usage = file_usage()->listUsage($file); - $field = field_info_field('user_picture'); + $field = field_info_field('user', 'user_picture'); $this->assertTrue(isset($usage['image']['default_image'][$field['uuid']])); $this->assertEqual($instance['settings']['max_resolution'], '800x800', 'User picture maximum resolution has been migrated.'); diff --git a/core/modules/system/tests/modules/entity_test/entity_test.install b/core/modules/system/tests/modules/entity_test/entity_test.install index d6f1b34..346eccb 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.install +++ b/core/modules/system/tests/modules/entity_test/entity_test.install @@ -9,14 +9,6 @@ * Implements hook_install(). */ function entity_test_install() { - // Auto-create a field for testing. - entity_create('field_entity', array( - 'field_name' => 'field_test_text', - 'type' => 'text', - 'cardinality' => 1, - 'translatable' => FALSE, - ))->save(); - $entity_types = array( 'entity_test', 'entity_test_rev', @@ -24,6 +16,14 @@ function entity_test_install() { 'entity_test_mulrev', ); foreach ($entity_types as $entity_type) { + // Auto-create fields for testing. + entity_create('field_entity', array( + 'name' => 'field_test_text', + 'entity_type' => $entity_type, + 'type' => 'text', + 'cardinality' => 1, + 'translatable' => FALSE, + ))->save(); entity_create('field_instance', array( 'entity_type' => $entity_type, 'field_name' => 'field_test_text', diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php index d2ad106..0ce4fdd 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/field/widget/TaxonomyAutocompleteWidget.php @@ -73,7 +73,7 @@ public function formElement(FieldInterface $items, $delta, array $element, $lang $element += array( '#type' => 'textfield', '#default_value' => taxonomy_implode_tags($tags), - '#autocomplete_path' => $this->getSetting('autocomplete_path') . '/' . $this->fieldDefinition->getFieldName(), + '#autocomplete_path' => $this->getSetting('autocomplete_path') . '/' . $items->getParent()->entityType() . '/' . $this->fieldDefinition->getFieldName(), '#size' => $this->getSetting('size'), '#placeholder' => $this->getSetting('placeholder'), '#maxlength' => 1024, diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php index 0257435..b95a633 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php @@ -135,10 +135,10 @@ public function getArgument() { // Just check, if a node could be detected. if ($node) { $taxonomy = array(); - $fields = field_info_instances('node', $node->type); - foreach ($fields as $name => $info) { - $field_info = field_info_field($name); - if ($field_info['type'] == 'taxonomy_term_reference') { + $instances = field_info_instances('node', $node->type); + foreach ($instances as $instance) { + $field = $instance->getField(); + if ($field['type'] == 'taxonomy_term_reference') { foreach ($node->get($name) as $item) { $taxonomy[$item->target_id] = $field_info['settings']['allowed_values'][0]['vocabulary']; } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php index c9b8078..905cc14 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php @@ -38,7 +38,8 @@ function setUp() { $this->field_name = 'taxonomy_' . $this->vocabulary->id(); $this->field = entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php index 2308f63..c5e96f7 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php @@ -45,7 +45,8 @@ public function setUp() { $vocabulary->save(); entity_create('field_entity', array( - 'field_name' => 'field_test_taxonomy', + 'name' => 'field_test_taxonomy', + 'entity_type' => 'entity_test', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php index c19ce9d..4cfb173 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php @@ -43,7 +43,8 @@ function setUp() { // Set up a field and instance. $this->field_name = drupal_strtolower($this->randomName()); entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( @@ -125,7 +126,7 @@ function testTaxonomyTermFieldMultipleVocabularies() { $this->assertNoText($term2->label(), 'Term 2 name is not displayed.'); // Verify that field and instance settings are correct. - $field_info = field_info_field($this->field_name); + $field_info = field_info_field('entity_test', $this->field_name); $this->assertEqual(count($field_info['settings']['allowed_values']), 1, 'Only one vocabulary is allowed for the field.'); // The widget should still be displayed. diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php index e893001..1fee5c3 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php @@ -46,7 +46,8 @@ function setUp() { // Setup a field and instance. $this->field_name = drupal_strtolower($this->randomName()); $this->field = entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test', 'type' => 'taxonomy_term_reference', 'settings' => array( 'allowed_values' => array( @@ -159,7 +160,7 @@ function testTaxonomyTermFieldChangeMachineName() { $this->vocabulary->save(); // Check that the field instance is still attached to the vocabulary. - $field = field_info_field($this->field_name); + $field = field_info_field('entity_test', $this->field_name); $allowed_values = $field['settings']['allowed_values']; $this->assertEqual($allowed_values[0]['vocabulary'], $new_name, 'Index 0: Machine name was updated correctly.'); $this->assertEqual($allowed_values[1]['vocabulary'], $new_name, 'Index 1: Machine name was updated correctly.'); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php index 991f274..0697de2 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php @@ -34,7 +34,8 @@ function setUp() { $this->field_name_1 = drupal_strtolower($this->randomName()); entity_create('field_entity', array( - 'field_name' => $this->field_name_1, + 'name' => $this->field_name_1, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( @@ -64,7 +65,8 @@ function setUp() { $this->field_name_2 = drupal_strtolower($this->randomName()); entity_create('field_entity', array( - 'field_name' => $this->field_name_2, + 'name' => $this->field_name_2, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php index 99ab62e..5896c09 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php @@ -29,7 +29,8 @@ function setUp() { $this->vocabulary = $this->createVocabulary(); $field = array( - 'field_name' => 'taxonomy_' . $this->vocabulary->id(), + 'name' => 'taxonomy_' . $this->vocabulary->id(), + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( @@ -219,21 +220,21 @@ function testNodeTermCreationAndDeletion() { // Test autocomplete on term 3, which contains a comma. // The term will be quoted, and the " will be encoded in unicode (\u0022). $input = substr($term_objects['term3']->label(), 0, 3); - $json = $this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->id(), array('query' => array('q' => $input))); + $json = $this->drupalGet('taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(), array('query' => array('q' => $input))); $this->assertEqual($json, '{"\u0022' . $term_objects['term3']->label() . '\u0022":"' . $term_objects['term3']->label() . '"}', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term3']->label()))); // Test autocomplete on term 4 - it is alphanumeric only, so no extra // quoting. $input = substr($term_objects['term4']->label(), 0, 3); - $this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->id(), array('query' => array('q' => $input))); + $this->drupalGet('taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(), array('query' => array('q' => $input))); $this->assertRaw('{"' . $term_objects['term4']->label() . '":"' . $term_objects['term4']->label() . '"}', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term4']->label()))); // Test taxonomy autocomplete with a nonexistent field. $field_name = $this->randomName(); $tag = $this->randomName(); $message = t("Taxonomy field @field_name not found.", array('@field_name' => $field_name)); - $this->assertFalse(field_info_field($field_name), format_string('Field %field_name does not exist.', array('%field_name' => $field_name))); - $this->drupalGet('taxonomy/autocomplete/' . $field_name, array('query' => array('q' => $tag))); + $this->assertFalse(field_info_field('node', $field_name), format_string('Field %field_name does not exist.', array('%field_name' => $field_name))); + $this->drupalGet('taxonomy/autocomplete/node/' . $field_name, array('query' => array('q' => $tag))); $this->assertRaw($message, 'Autocomplete returns correct error message when the taxonomy field does not exist.'); } @@ -257,7 +258,7 @@ function testTermAutocompletion() { // Try to autocomplete a term name that matches both terms. // We should get both term in a json encoded string. $input = '10/'; - $path = 'taxonomy/autocomplete/taxonomy_' . $this->vocabulary->id(); + $path = 'taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(); // The result order is not guaranteed, so check each term separately. $result = $this->drupalGet($path, array('query' => array('q' => $input))); $data = drupal_json_decode($result); @@ -267,14 +268,14 @@ function testTermAutocompletion() { // Try to autocomplete a term name that matches first term. // We should only get the first term in a json encoded string. $input = '10/16'; - $path = 'taxonomy/autocomplete/taxonomy_' . $this->vocabulary->id(); + $path = 'taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(); $this->drupalGet($path, array('query' => array('q' => $input))); $target = array($first_term->label() => check_plain($first_term->label())); $this->assertRaw(drupal_json_encode($target), 'Autocomplete returns only the expected matching term.'); // Try to autocomplete a term name with both a comma and a slash. $input = '"term with, comma and / a'; - $path = 'taxonomy/autocomplete/taxonomy_' . $this->vocabulary->id(); + $path = 'taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(); $this->drupalGet($path, array('query' => array('q' => $input))); $n = $third_term->label(); // Term names containing commas or quotes must be wrapped in quotes. diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php index 35f4555..d785f2f 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php @@ -30,7 +30,8 @@ function setUp() { $this->langcode = Language::LANGCODE_NOT_SPECIFIED; $this->field_name = 'taxonomy_' . $this->vocabulary->id(); entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php index e7c7031..6e5e7ff 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php @@ -78,7 +78,8 @@ protected function mockStandardInstall() { $this->vocabulary->save(); $this->field_name = 'field_' . $this->vocabulary->id(); entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', // Set cardinality to unlimited for tagging. 'cardinality' => FIELD_CARDINALITY_UNLIMITED, diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php index 8901db1..13d4762 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php @@ -155,7 +155,8 @@ function testTaxonomyVocabularyLoadMultiple() { function testTaxonomyVocabularyChangeMachineName() { // Add a field instance to the vocabulary. entity_create('field_entity', array( - 'field_name' => 'field_test', + 'name' => 'field_test', + 'entity_type' => 'taxonomy_term', 'type' => 'test_field', ))->save(); entity_create('field_instance', array( @@ -187,7 +188,8 @@ function testUninstallReinstall() { // removed when the module is uninstalled. $this->field_name = drupal_strtolower($this->randomName() . '_field_name'); $this->field_definition = array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'taxonomy_term', 'type' => 'text', 'cardinality' => 4 ); diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install index 860cde3..d1e7c26 100644 --- a/core/modules/taxonomy/taxonomy.install +++ b/core/modules/taxonomy/taxonomy.install @@ -6,12 +6,17 @@ */ use Drupal\Component\Uuid\Uuid; +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\field\Plugin\Core\Entity\Field; /** * Implements hook_uninstall(). */ function taxonomy_uninstall() { + Drupal::entityManager()->addNamespaces(new ArrayIterator(array( + 'Drupal\taxonomy' => DRUPAL_ROOT . '/core/modules/taxonomy/lib', + ))); + drupal_classloader_register('taxonomy', 'core/modules/taxonomy'); // Remove taxonomy_term bundles. $config_names = config_get_storage_names_with_prefix('taxonomy.vocabulary.'); foreach ($config_names as $config_name) { @@ -199,9 +204,9 @@ function taxonomy_field_schema($field) { */ function taxonomy_update_dependencies() { // Convert the 'tid' column of the taxonomy reference field to 'target_id' - // after fields and instances have been moved to the config system. + // after the field tables have been reorganized. $dependencies['taxonomy'][8007] = array( - 'field' => 8003, + 'field' => 8006, ); return $dependencies; } @@ -356,16 +361,16 @@ function taxonomy_update_8007() { foreach (config_get_storage_names_with_prefix('field.field.') as $config_name) { $field_config = config($config_name); // Only update taxonomy reference fields that use the default SQL storage. - if ($field_config->get('type') == 'taxonomy_term_reference' && $field_config->get('storage.type') == 'field_sql_storage') { + if ($field_config->get('type') == 'taxonomy_term_reference') { $field = new Field($field_config->get()); $tables = array( - _field_sql_storage_tablename($field), - _field_sql_storage_revision_tablename($field), + DatabaseStorageController::_fieldTableName($field), + DatabaseStorageController::_fieldRevisionTableName($field), ); foreach ($tables as $table_name) { - db_change_field($table_name, $field->id() . '_tid', $field->id() . '_target_id', array( + db_change_field($table_name, $field->name . '_tid', $field->name . '_target_id', array( 'description' => 'The ID of the target entity.', 'type' => 'int', 'unsigned' => TRUE, @@ -373,8 +378,8 @@ function taxonomy_update_8007() { )); // Change the index. - db_drop_index($table_name, $field->id() . '_tid'); - db_add_index($table_name, $field->id() . '_target_id', array($field->id() . '_target_id')); + db_drop_index($table_name, $field->name . '_tid'); + db_add_index($table_name, $field->name . '_target_id', array($field->name . '_target_id')); } // Update the indexes in field config as well. diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 2167270..86e7805 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -9,6 +9,7 @@ use Drupal\node\Plugin\Core\Entity\Node; use Drupal\taxonomy\Plugin\Core\Entity\Term; use Drupal\taxonomy\Plugin\Core\Entity\Vocabulary; +use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Field\FieldDefinitionInterface; @@ -292,10 +293,10 @@ function taxonomy_menu() { 'type' => MENU_CALLBACK, 'file' => 'taxonomy.pages.inc', ); - $items['taxonomy/autocomplete/%'] = array( + $items['taxonomy/autocomplete/%/%'] = array( 'title' => 'Autocomplete taxonomy', 'page callback' => 'taxonomy_autocomplete', - 'page arguments' => array(2), + 'page arguments' => array(2, 3), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, 'file' => 'taxonomy.pages.inc', @@ -1128,18 +1129,18 @@ function taxonomy_node_insert(EntityInterface $node) { function taxonomy_build_node_index($node) { // We maintain a denormalized table of term/node relationships, containing // only data for current, published nodes. - $status = NULL; - if (config('taxonomy.settings')->get('maintain_index_table')) { - // If a node property is not set in the node object when $node->save() is - // called, the old value from $node->original is used. - if (!empty($node->original)) { - $status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status))); - $sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky))); - } - else { - $status = (int)(!empty($node->status)); - $sticky = (int)(!empty($node->sticky)); - } + if (!config('taxonomy.settings')->get('maintain_index_table') || !(Drupal::entityManager()->getStorageController('node') instanceof DatabaseStorageController)) { + return; + } + // If a node property is not set in the node object when $node->save() is + // called, the old value from $node->original is used. + if (!empty($node->original)) { + $status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status))); + $sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky))); + } + else { + $status = (int)(!empty($node->status)); + $sticky = (int)(!empty($node->sticky)); } // We only maintain the taxonomy index for published nodes. if ($status && $node->isDefaultRevision()) { @@ -1147,8 +1148,8 @@ function taxonomy_build_node_index($node) { $tid_all = array(); foreach (field_info_instances('node', $node->type) as $instance) { $field_name = $instance['field_name']; - $field = field_info_field($field_name); - if ($field['module'] == 'taxonomy' && $field['storage']['type'] == 'field_sql_storage') { + $field = $instance->getField(); + if ($field['module'] == 'taxonomy') { // If a field value is not set in the node object when $node->save() is // called, the old value from $node->original is used. if (isset($node->{$field_name})) { diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc index d70b8fd..a8b5771 100644 --- a/core/modules/taxonomy/taxonomy.pages.inc +++ b/core/modules/taxonomy/taxonomy.pages.inc @@ -98,19 +98,21 @@ function taxonomy_term_feed(Term $term) { * }; * @endcode * - * @param $field_name + * @param string $entity_type + * The entity_type. + * @param string $field_name * The name of the term reference field. * * @see taxonomy_menu() * @see taxonomy_field_widget_info() */ -function taxonomy_autocomplete($field_name) { +function taxonomy_autocomplete($entity_type, $field_name) { // A comma-separated list of term names entered in the autocomplete form // element. Only the last term is used for autocompletion. $tags_typed = Drupal::request()->query->get('q'); // Make sure the field exists and is a taxonomy field. - if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') { + if (!($field = field_info_field($entity_type, $field_name)) || $field['type'] !== 'taxonomy_term_reference') { // Error string. The JavaScript handler will realize this is not JSON and // will display it as debugging information. print t('Taxonomy field @field_name not found.', array('@field_name' => $field_name)); diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc index 5646268..25c0c40 100644 --- a/core/modules/taxonomy/taxonomy.views.inc +++ b/core/modules/taxonomy/taxonomy.views.inc @@ -7,6 +7,9 @@ * @ingroup views_module_handlers */ +use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\field\FieldInterface; + /** * Implements hook_views_data(). */ @@ -335,8 +338,8 @@ function taxonomy_views_data_alter(&$data) { * * @see field_views_field_default_views_data() */ -function taxonomy_field_views_data($field) { - $data = field_views_field_default_views_data($field); +function taxonomy_field_views_data(FieldInterface $field, array $sql_entity_types) { + $data = field_views_field_default_views_data($field, $sql_entity_types); foreach ($data as $table_name => $table_data) { foreach ($table_data as $field_name => $field_data) { if (isset($field_data['filter']) && $field_name != 'delta') { @@ -363,8 +366,8 @@ function taxonomy_field_views_data($field) { * * Views integration to provide reverse relationships on term references. */ -function taxonomy_field_views_data_views_data_alter(&$data, $field) { - foreach ($field['bundles'] as $entity_type => $bundles) { +function taxonomy_field_views_data_views_data_alter(array &$data, FieldInterface $field, array $sql_entity_types) { + foreach ($sql_entity_types as $entity_type) { $entity_info = entity_get_info($entity_type); $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type; @@ -379,17 +382,14 @@ function taxonomy_field_views_data_views_data_alter(&$data, $field) { 'help' => t('Relate each @entity with a @field set to the term.', array('@entity' => $entity, '@field' => $label)), 'id' => 'entity_reverse', 'field_name' => $field['field_name'], - 'field table' => _field_sql_storage_tablename($field), + 'entity_type' => $field['entity_type'], + 'field table' => DatabaseStorageController::_fieldTableName($field), 'field field' => $field['field_name'] . '_target_id', 'base' => $entity_info['base_table'], 'base field' => $entity_info['entity_keys']['id'], 'label' => t('!field_name', array('!field_name' => $field['field_name'])), 'join_extra' => array( 0 => array( - 'field' => 'entity_type', - 'value' => $entity_type, - ), - 1 => array( 'field' => 'deleted', 'value' => 0, 'numeric' => TRUE, diff --git a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php index 6158f07..8e290ba 100644 --- a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php +++ b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php @@ -21,7 +21,6 @@ class TelephoneFieldTest extends WebTestBase { */ public static $modules = array( 'field', - 'field_sql_storage', 'node', 'telephone' ); @@ -54,7 +53,8 @@ function testTelephoneField() { // Add the telepone field to the article content type. entity_create('field_entity', array( - 'field_name' => 'field_telephone', + 'name' => 'field_telephone', + 'entity_type' => 'node', 'type' => 'telephone', ))->save(); entity_create('field_instance', array( diff --git a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php index bd3633b..6049260 100644 --- a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php +++ b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php @@ -36,7 +36,8 @@ public function setUp() { // Create a telephone field and instance for validation. entity_create('field_entity', array( - 'field_name' => 'field_test', + 'name' => 'field_test', + 'entity_type' => 'entity_test', 'type' => 'telephone', ))->save(); entity_create('field_instance', array( diff --git a/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php b/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php index 0a2b900..f568103 100644 --- a/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php +++ b/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php @@ -26,7 +26,7 @@ class TextPlainUnitTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('entity', 'field', 'field_sql_storage', 'text', 'entity_test', 'system'); + public static $modules = array('entity', 'field', 'text', 'entity_test', 'system'); /** * Contains rendered content. @@ -68,7 +68,8 @@ function setUp() { $this->formatter_settings = array(); $this->field = entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => $this->entity_type, 'type' => $this->field_type, 'settings' => $this->field_settings, )); diff --git a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php index 4627fb5..fb9e901 100644 --- a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php +++ b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php @@ -50,7 +50,8 @@ function testTextFieldValidation() { // Create a field with settings to validate. $max_length = 3; $this->field = entity_create('field_entity', array( - 'field_name' => drupal_strtolower($this->randomName()), + 'name' => drupal_strtolower($this->randomName()), + 'entity_type' => 'entity_test', 'type' => 'text', 'settings' => array( 'max_length' => $max_length, @@ -58,7 +59,7 @@ function testTextFieldValidation() { )); $this->field->save(); entity_create('field_instance', array( - 'field_name' => $this->field->id(), + 'field_name' => $this->field->name, 'entity_type' => 'entity_test', 'bundle' => 'entity_test', ))->save(); @@ -66,8 +67,8 @@ function testTextFieldValidation() { // Test validation with valid and invalid values. $entity = entity_create('entity_test', array()); for ($i = 0; $i <= $max_length + 2; $i++) { - $entity->{$this->field->id()}->value = str_repeat('x', $i); - $violations = $entity->{$this->field->id()}->validate(); + $entity->{$this->field->name}->value = str_repeat('x', $i); + $violations = $entity->{$this->field->name}->validate(); if ($i <= $max_length) { $this->assertEqual(count($violations), 0, "Length $i does not cause validation error when max_length is $max_length"); } @@ -90,10 +91,10 @@ function testTextfieldWidgets() { */ function _testTextfieldWidgets($field_type, $widget_type) { // Setup a field and instance - $entity_type = 'entity_test'; $this->field_name = drupal_strtolower($this->randomName()); $this->field = entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test', 'type' => $field_type )); $this->field->save(); @@ -161,7 +162,8 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) { // Setup a field and instance $this->field_name = drupal_strtolower($this->randomName()); $this->field = entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'entity_test', 'type' => $field_type )); $this->field->save(); diff --git a/core/modules/user/lib/Drupal/user/Tests/UserCreateTest.php b/core/modules/user/lib/Drupal/user/Tests/UserCreateTest.php index 1e1c891..6d2c846 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserCreateTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserCreateTest.php @@ -40,7 +40,8 @@ protected function testUserAdd() { // Create a field and an instance. $field_name = 'test_field'; $field = array( - 'field_name' => $field_name, + 'name' => $field_name, + 'entity_type' => 'user', 'module' => 'image', 'type' => 'image', 'cardinality' => 1, diff --git a/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php b/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php index 14d885c..c073b95 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php @@ -23,7 +23,7 @@ class UserEntityTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('system', 'user'); + public static $modules = array('system', 'user', 'field'); public static function getInfo() { return array( diff --git a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php index deb1175..e169b90 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php @@ -196,8 +196,9 @@ function testRegistrationDefaultValues() { function testRegistrationWithUserFields() { // Create a field, and an instance on 'user' entity type. $field = entity_create('field_entity', array( + 'name' => 'test_user_field', + 'entity_type' => 'user', 'type' => 'test_field', - 'field_name' => 'test_user_field', 'cardinality' => 1, )); $field->save(); diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php index a441023..59f0086 100644 --- a/core/modules/user/lib/Drupal/user/UserStorageController.php +++ b/core/modules/user/lib/Drupal/user/UserStorageController.php @@ -11,7 +11,9 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Password\PasswordInterface; use Drupal\Core\Database\Connection; +use Drupal\field\FieldInfo; use Drupal\user\UserDataInterface; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Entity\DatabaseStorageControllerNG; @@ -46,13 +48,15 @@ class UserStorageController extends DatabaseStorageControllerNG implements UserS * An array of entity info for the entity type. * @param \Drupal\Core\Database\Connection $database * The database connection to be used. + * @param \Drupal\field\FieldInfo $field_info + * The field info service. * @param \Drupal\Core\Password\PasswordInterface $password * The password hashing service. * @param \Drupal\user\UserDataInterface $user_data * The user data service. */ - public function __construct($entity_type, $entity_info, Connection $database, PasswordInterface $password, UserDataInterface $user_data) { - parent::__construct($entity_type, $entity_info, $database); + public function __construct($entity_type, $entity_info, Connection $database, FieldInfo $field_info, PasswordInterface $password, UserDataInterface $user_data) { + parent::__construct($entity_type, $entity_info, $database, $field_info); $this->password = $password; $this->userData = $user_data; @@ -66,6 +70,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ $entity_type, $entity_info, $container->get('database'), + $container->get('field.info'), $container->get('password'), $container->get('user.data') ); @@ -143,14 +148,9 @@ public function deleteUserRoles(array $uids) { * {@inheritdoc} */ protected function invokeHook($hook, EntityInterface $entity) { - $function = 'field_attach_' . $hook; - // @todo: field_attach_delete_revision() is named the wrong way round, - // consider renaming it. - if ($function == 'field_attach_revision_delete') { - $function = 'field_attach_delete_revision'; - } - if (!empty($this->entityInfo['fieldable']) && function_exists($function)) { - $function($entity); + $method = Container::camelize('field_' . $hook); + if (!empty($this->entityInfo['fieldable']) && method_exists($this, $method)) { + $this->$method($entity); } // Invoke the hook. diff --git a/core/modules/user/user.install b/core/modules/user/user.install index 62eb4a9..6371077 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -268,7 +268,8 @@ function user_install() { */ function user_install_picture_field() { $field = array( - 'field_name' => 'user_picture', + 'name' => 'user_picture', + 'entity_type' => 'user', 'module' => 'image', 'type' => 'image', 'cardinality' => 1, @@ -343,9 +344,9 @@ function user_install_picture_field() { */ function user_update_dependencies() { // Convert user picture to field after the fields and instances are converted - // to ConfigEntities. + // to ConfigEntities and the tables are split. $dependencies['user'][8011] = array( - 'field' => 8003, + 'field' => 8006, ); return $dependencies; } @@ -655,7 +656,8 @@ function user_update_8011() { // Create the field and instance. $field = array( - 'id' => 'user_picture', + 'name' => 'user_picture', + 'entity_type' => 'user', 'module' => 'image', 'type' => 'image', 'cardinality' => 1, @@ -710,10 +712,9 @@ function user_update_8011() { _update_8003_field_create_field($field); $instance = array( - 'id' => 'user.user.user_picture', 'entity_type' => 'user', - 'label' => 'Picture', 'bundle' => 'user', + 'label' => 'Picture', 'description' => update_variable_get('user_picture_guidelines', ''), 'required' => FALSE, 'settings' => array( @@ -816,9 +817,8 @@ function user_update_8012(&$sandbox) { $rows = db_query_range('SELECT uid, picture FROM {users} WHERE picture > 0', 0, 20)->fetchAllKeyed(); foreach ($rows as $uid => $fid) { // Add a row to the field data and revision tables. - db_insert('field_data_user_picture') + db_insert('user__user_picture') ->fields(array( - 'entity_type' => 'user', 'bundle' => 'user', 'entity_id' => $uid, 'revision_id' => $uid, @@ -827,9 +827,8 @@ function user_update_8012(&$sandbox) { 'user_picture_target_id' => $fid, )) ->execute(); - db_insert('field_revision_user_picture') + db_insert('user_revision__user_picture') ->fields(array( - 'entity_type' => 'user', 'bundle' => 'user', 'entity_id' => $uid, 'revision_id' => $uid, diff --git a/core/modules/views/config/views.view.comments_recent.yml b/core/modules/views/config/views.view.comments_recent.yml index 378170d..9b9db7d 100644 --- a/core/modules/views/config/views.view.comments_recent.yml +++ b/core/modules/views/config/views.view.comments_recent.yml @@ -378,7 +378,7 @@ display: provider: comment comment: id: comment - table: field_data_comment_body + table: comment__comment_body field: comment_body label: '' plugin_id: field diff --git a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php index 066f518..f3321f8 100644 --- a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php @@ -62,7 +62,8 @@ protected function setUp() { // Setup a field and instance. $this->field_name = drupal_strtolower($this->randomName()); entity_create('field_entity', array( - 'field_name' => $this->field_name, + 'name' => $this->field_name, + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'settings' => array( 'allowed_values' => array( diff --git a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php index 2f870d8..c7ec4e0 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php @@ -56,7 +56,8 @@ function setUp() { // Create the tag field itself. $this->tag_field = entity_create('field_entity', array( - 'field_name' => 'field_views_testing_tags', + 'name' => 'field_views_testing_tags', + 'entity_type' => 'node', 'type' => 'taxonomy_term_reference', 'cardinality' => FIELD_CARDINALITY_UNLIMITED, 'settings' => array( @@ -108,7 +109,7 @@ function testTaggedWith() { $node_add_path = 'node/add/' . $this->node_type_with_tags->type; // Create three nodes, with different tags. - $tag_field = $this->tag_field->id() . '[' . Language::LANGCODE_NOT_SPECIFIED . ']'; + $tag_field = $this->tag_field->name . '[' . Language::LANGCODE_NOT_SPECIFIED . ']'; $edit = array(); $edit['title'] = $node_tag1_title = $this->randomName(); $edit[$tag_field] = 'tag1'; diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_admin_ui.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_admin_ui.yml index 910d770..1c993fb 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_admin_ui.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_admin_ui.yml @@ -26,7 +26,7 @@ display: provider: views body_value: id: body_value - table: field_data_body + table: node__body field: body_value relationship: none group_type: group diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc index d05888f..aeea6b2 100644 --- a/core/modules/views_ui/admin.inc +++ b/core/modules/views_ui/admin.inc @@ -224,7 +224,7 @@ function views_ui_taxonomy_autocomplete_validate($element, &$form_state) { if ($tags = $element['#value']) { // Get the machine names of the vocabularies we will search, keyed by the // vocabulary IDs. - $field = field_info_field($element['#field_name']); + $field = field_info_field($element['#entity_type'], $element['#field_name']); $vocabularies = array(); if (!empty($field['settings']['allowed_values'])) { foreach ($field['settings']['allowed_values'] as $tree) { diff --git a/core/profiles/standard/config/field.field.field_image.yml b/core/profiles/standard/config/field.field.field_image.yml deleted file mode 100644 index 0fc032a..0000000 --- a/core/profiles/standard/config/field.field.field_image.yml +++ /dev/null @@ -1,34 +0,0 @@ -id: field_image -type: image -module: image -active: '1' -settings: - uri_scheme: public - default_image: false - column_groups: - file: - label: File - columns: - - target_id - - width - - height - alt: - label: Alt - translatable: true - title: - label: Title - translatable: true -storage: - type: field_sql_storage - module: field_sql_storage - active: '1' - settings: { } -locked: '0' -cardinality: '1' -translatable: '0' -entity_types: { } -indexes: - target_id: - - target_id -status: 1 -langcode: und diff --git a/core/profiles/standard/config/field.field.field_tags.yml b/core/profiles/standard/config/field.field.field_tags.yml deleted file mode 100644 index e0f6952..0000000 --- a/core/profiles/standard/config/field.field.field_tags.yml +++ /dev/null @@ -1,23 +0,0 @@ -id: field_tags -type: taxonomy_term_reference -module: taxonomy -active: '1' -settings: - allowed_values: - - - vocabulary: tags - parent: 0 -storage: - type: field_sql_storage - module: field_sql_storage - active: '1' - settings: { } -locked: '0' -cardinality: '-1' -translatable: '0' -entity_types: { } -indexes: - target_id: - - target_id -status: 1 -langcode: und diff --git a/core/profiles/standard/config/field.field.node.field_image.yml b/core/profiles/standard/config/field.field.node.field_image.yml new file mode 100644 index 0000000..9611082 --- /dev/null +++ b/core/profiles/standard/config/field.field.node.field_image.yml @@ -0,0 +1,30 @@ +id: node.field_image +name: field_image +entity_type: node +type: image +module: image +active: '1' +settings: + uri_scheme: public + default_image: false + column_groups: + file: + label: File + columns: + - target_id + - width + - height + alt: + label: Alt + translatable: true + title: + label: Title + translatable: true +locked: '0' +cardinality: '1' +translatable: '0' +indexes: + target_id: + - target_id +status: 1 +langcode: und diff --git a/core/profiles/standard/config/field.field.node.field_tags.yml b/core/profiles/standard/config/field.field.node.field_tags.yml new file mode 100644 index 0000000..5cab894 --- /dev/null +++ b/core/profiles/standard/config/field.field.node.field_tags.yml @@ -0,0 +1,19 @@ +id: node.field_tags +name: field_tags +entity_type: node +type: taxonomy_term_reference +module: taxonomy +active: '1' +settings: + allowed_values: + - + vocabulary: tags + parent: 0 +locked: '0' +cardinality: '-1' +translatable: '0' +indexes: + target_id: + - target_id +status: 1 +langcode: und