diff --git a/core/core.api.php b/core/core.api.php index c4d78c5..27bc96d 100644 --- a/core/core.api.php +++ b/core/core.api.php @@ -283,16 +283,16 @@ * * The first task in using the simple configuration API is to define the * configuration file structure, file name, and schema of your settings (see - * @ref sec_yaml above). Once you have done that, you can retrieve the active - * configuration object that corresponds to configuration file mymodule.foo.yml - * with a call to: + * @ref sec_yaml above). Once you have done that, you can retrieve the + * active configuration object that corresponds to configuration file + * mymodule.foo.yml with a call to: * @code * $config = \Drupal::config('mymodule.foo'); * @endcode * * This will be an object of class \Drupal\Core\Config\Config, which has methods - * for getting configuration information. For instance, if your YAML file - * structure looks like this: + * for getting and setting configuration information. For instance, if your + * YAML file structure looks like this: * @code * enabled: '0' * bar: @@ -307,34 +307,12 @@ * $bar = $config->get('bar'); * // Get one element of the array. * $bar_baz = $config->get('bar.baz'); - * @endcode - * - * The Config object that was obtained and used in the previous examples does - * not allow you to change configuration. If you want to change configuration, - * you will instead need to get the Config object by making a call to - * getEditable() on the config factory: - * @code - * $config =\Drupal::service('config.factory')->getEditable('mymodule.foo'); - * @endcode - * - * Individual configuration values can be changed or added using the set() - * method and saved using the save() method: - * @code - * // Set a scalar value. - * $config->set('enabled', 1); - * // Save the configuration. + * // Update a value. Nesting works the same as get(). + * $config->set('bar.baz', 'string2'); + * // Nothing actually happens with set() until you call save(). * $config->save(); * @endcode * - * Configuration values can also be unset using the clear() method, which is - * also chainable: - * @code - * $config->clear('bar.boo')->save(); - * $config_data = $config->get('bar'); - * @endcode - * In this example $config_data would return an array with one key - 'baz' - - * because 'boo' was unset. - * * @section sec_entity Configuration entities * In contrast to the simple configuration settings described in the previous * section, if your module allows users to create zero or more items (where @@ -731,8 +709,7 @@ * top-level core directory). Some Drupal Core modules and contributed modules * also define services in modulename.services.yml files. API reference sites * (such as https://api.drupal.org) generate lists of all existing services from - * these files. Look for the Services link in the API Navigation block. - * Alternatively you can look through the individual files manually. + * these files, or you can look through the individual files manually. * * A typical service definition in a *.services.yml file looks like this: * @code diff --git a/core/core.services.yml b/core/core.services.yml index 62a0f3e..551de6c 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1584,3 +1584,6 @@ services: arguments: ['@current_user', '@path.current', '@path.matcher', '@language_manager'] tags: - { name: event_subscriber } + plugin.manager.entity.display_component_handler: + class: Drupal\Core\Entity\DisplayComponentHandlerPluginManager + parent: default_plugin_manager diff --git a/core/includes/common.inc b/core/includes/common.inc index 5cd3ce8..5d62aad 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -133,7 +133,7 @@ const LOCALE_PLURAL_DELIMITER = PluralTranslatableMarkup::DELIMITER; /** - * Prepares a 'destination' URL query parameter. + * Prepares a 'destination' URL query parameter for use with url(). * * Used to direct the user back to the referring page after completing a form. * By default the current URL is returned. If a destination exists in the diff --git a/core/includes/form.inc b/core/includes/form.inc index daf75cd..c1c82c1 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -687,8 +687,8 @@ function template_preprocess_form_element_label(&$variables) { * .module file. The path should be relative to base_path(), and thus should * be built using drupal_get_path(). * - css: Array of paths to CSS files to be used on the progress page. - * - url_options: options passed to the \Drupal\Core\Url object when - * constructing redirect URLs for the batch. + * - url_options: options passed to url() when constructing redirect URLs for + * the batch. * - progressive: A Boolean that indicates whether or not the batch needs to * run progressively. TRUE indicates that the batch will run in more than * one run. FALSE (default) indicates that the batch will finish in a single diff --git a/core/lib/Drupal/Core/Entity/Annotation/DisplayComponent.php b/core/lib/Drupal/Core/Entity/Annotation/DisplayComponent.php new file mode 100644 index 0000000..e2178c2 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Annotation/DisplayComponent.php @@ -0,0 +1,26 @@ +context = $context; + } + + /** + * {@inheritdoc} + */ + public function prepareDisplayComponents(array &$components, array &$hidden_components) { + } + + /** + * {@inheritdoc} + */ + public function hasElement($name) { + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function massageIn($name, array $options) { + return $options; + } + + /** + * {@inheritdoc} + */ + public function massageOut($properties) { + return $properties; + } + + /** + * {@inheritdoc} + */ + public function getRenderer($name, array $options) { + } + +} diff --git a/core/lib/Drupal/Core/Entity/DisplayComponentHandlerInterface.php b/core/lib/Drupal/Core/Entity/DisplayComponentHandlerInterface.php new file mode 100644 index 0000000..fcb886d --- /dev/null +++ b/core/lib/Drupal/Core/Entity/DisplayComponentHandlerInterface.php @@ -0,0 +1,88 @@ +alterInfo('display_component_handler_info'); + $this->setCacheBackend($cache_backend, 'display_component_handlers'); + } + + /** + * {@inheritdoc} + */ + public function getInstance(array $options) { + $plugin_id = $options['type']; + + if (!isset($this->plugins[$plugin_id]) && !array_key_exists($plugin_id, $this->plugins)) { + $this->plugins[$plugin_id] = $this->discovery->getDefinition($plugin_id) ? $this->createInstance($plugin_id) : NULL; + } + + return $this->plugins[$plugin_id]; + } + +} diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php index bee0144..50d63cf 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php @@ -134,33 +134,6 @@ public function __construct(array $values, $entity_type) { /** * {@inheritdoc} */ - public function getRenderer($field_name) { - if (isset($this->plugins[$field_name])) { - return $this->plugins[$field_name]; - } - - // Instantiate the widget object from the stored display properties. - if (($configuration = $this->getComponent($field_name)) && isset($configuration['type']) && ($definition = $this->getFieldDefinition($field_name))) { - $widget = $this->pluginManager->getInstance(array( - 'field_definition' => $definition, - 'form_mode' => $this->originalMode, - // No need to prepare, defaults have been merged in setComponent(). - 'prepare' => FALSE, - 'configuration' => $configuration - )); - } - else { - $widget = NULL; - } - - // Persist the widget object. - $this->plugins[$field_name] = $widget; - return $widget; - } - - /** - * {@inheritdoc} - */ public function buildForm(FieldableEntityInterface $entity, array &$form, FormStateInterface $form_state) { // Set #parents to 'top-level' by default. $form += array('#parents' => array()); diff --git a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php index b835327..7ff35ee 100644 --- a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php +++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php @@ -84,6 +84,11 @@ protected $hidden = array(); /** + * The renderer objects used for this display, keyed by component name. + */ + protected $renderers = array(); + + /** * The original view or form mode that was requested (case of view/form modes * being configured to fall back to the 'default' display). * @@ -120,6 +125,18 @@ protected $renderer; /** + * A mapping of display elements and its corresponding handler. + */ + protected $handlers; + + /** + * The display component handler plugin manager. + * + * @var \Drupal\Core\Entity\DisplayComponentHandlerPluginManager + */ + protected $handlerManager; + + /** * {@inheritdoc} */ public function __construct(array $values, $entity_type) { @@ -143,6 +160,8 @@ public function __construct(array $values, $entity_type) { parent::__construct($values, $entity_type); + $this->handlerManager = \Drupal::service('plugin.manager.entity.display_component_handler'); + $this->originalMode = $this->mode; $this->init(); @@ -286,13 +305,14 @@ public function calculateDependencies() { */ public function toArray() { $properties = parent::toArray(); - // Do not store options for fields whose display is not set to be - // configurable. - foreach ($this->getFieldDefinitions() as $field_name => $definition) { - if (!$definition->isDisplayConfigurable($this->displayContext)) { - unset($properties['content'][$field_name]); - unset($properties['hidden'][$field_name]); - } + + // Let the component handlers add missing components. + if (!$this->handlerManager) { + $this->handlerManager = \Drupal::service('plugin.manager.entity.display_component_handler'); + } + $handlers = $this->handlerManager->getDefinitions(); + foreach (array_keys($handlers) as $type) { + $properties = $this->getComponentHandler($type)->massageOut($properties); } return $properties; @@ -331,9 +351,10 @@ public function setComponent($name, array $options = array()) { $options['weight'] = isset($max) ? $max + 1 : 0; } - // For a field, fill in default options. - if ($field_definition = $this->getFieldDefinition($name)) { - $options = $this->pluginManager->prepareConfiguration($field_definition->getType(), $options); + // Massage in some values. + $handler = $this->getComponentHandlerByElementName($name); + if ($handler) { + $options = $handler->massageIn($name, $options); } // Ensure we always have an empty settings and array. @@ -341,7 +362,7 @@ public function setComponent($name, array $options = array()) { $this->content[$name] = $options; unset($this->hidden[$name]); - unset($this->plugins[$name]); + unset($this->renderers[$name]); return $this; } @@ -550,4 +571,69 @@ protected function getLogger() { return \Drupal::logger('system'); } + /** + * Finds component handler by element name. + * + * @param string $name + * The element name. + * + * @return \Drupal\Core\Entity\DisplayComponentHandlerInterface + */ + public function getComponentHandlerByElementName($name) { + if (!isset($this->handlers[$name])) { + $handlers = $this->handlerManager->getDefinitions(); + foreach (array_keys($handlers) as $type) { + $handler = $this->getComponentHandler($type); + if ($handler && $handler->hasElement($name)) { + break; + } + $handler = NULL; + } + $this->handlers[$name] = $handler; + } + + return $this->handlers[$name]; + } + + /** + * Instantiates component handler. + * + * @param string $type + * The type of component handler (field, extra_field). + * + * @return \Drupal\Core\Entity\DisplayComponentHandlerInterface + */ + public function getComponentHandler($type) { + $handler = $this->handlerManager->getInstance(array('type' => $type)); + if ($handler) { + $handler->setContext(array( + 'entity_type' => $this->targetEntityType, + 'bundle' => $this->bundle, + 'mode' => $this->originalMode, + 'display_context' => $this->displayContext, + )); + } + return $handler; + } + + /**+ + * {@inheritdoc} + */ + public function getRenderer($name) { + if (!isset($this->content[$name])) { + return NULL; + } + + if (!array_key_exists($name, $this->renderers)) { + if ($handler = $this->getComponentHandlerByElementName($name)) { + $options = $this->getComponent($name); + $this->renderers[$name] = $handler->getRenderer($name, $options); + } + else { + $this->renderers[$name] = NULL; + } + } + return $this->renderers[$name]; + } + } diff --git a/core/lib/Drupal/Core/Entity/Plugin/DisplayComponent/ExtraFieldDisplayComponentHandler.php b/core/lib/Drupal/Core/Entity/Plugin/DisplayComponent/ExtraFieldDisplayComponentHandler.php new file mode 100644 index 0000000..6db98e4 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Plugin/DisplayComponent/ExtraFieldDisplayComponentHandler.php @@ -0,0 +1,59 @@ +fetchExtraFields(); + foreach ($extra_fields as $name => $definition) { + if (!isset($components[$name]) && !isset($hidden_components[$name])) { + // Extra fields are visible by default unless they explicitly say so. + if (!isset($definition['visible']) || $definition['visible'] == TRUE) { + $components[$name] = array( + 'weight' => $definition['weight'] + ); + } + else { + $hidden_components[$name] = TRUE; + } + } + } + } + + /** + * {@inheritdoc} + */ + public function hasElement($name) { + $extra_fields = $this->fetchExtraFields(); + return isset($extra_fields[$name]); + } + + /** + * Fetches all the extra fields. + */ + protected function fetchExtraFields() { + $context = $this->context['display_context'] == 'view' ? 'display' : $this->context['display_context']; + $extra_fields = \Drupal::entityManager()->getExtraFields($this->context['entity_type'], $this->context['bundle']); + return isset($extra_fields[$context]) ? $extra_fields[$context] : array(); + } + +} diff --git a/core/lib/Drupal/Core/Entity/Plugin/DisplayComponent/FieldDisplayComponentHandler.php b/core/lib/Drupal/Core/Entity/Plugin/DisplayComponent/FieldDisplayComponentHandler.php new file mode 100644 index 0000000..0b51039 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Plugin/DisplayComponent/FieldDisplayComponentHandler.php @@ -0,0 +1,203 @@ +formatterPluginManager = $formatter_plugin_manager; + $this->widgetPluginManager = $widget_plugin_manager; + $this->entityManager = $entity_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static($configuration, $plugin_id, $plugin_definition, + $container->get('plugin.manager.field.formatter'), + $container->get('plugin.manager.field.widget'), + $container->get('entity.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function massageIn($name, array $options) { + $field_definition = $this->getFieldDefinition($name); + if (!isset($field_definition)) { + // The field in process of removal from display. + return $options; + } + if ($this->context['display_context'] == 'view') { + return $this->formatterPluginManager->prepareConfiguration($field_definition->getType(), $options); + } + else { + return $this->widgetPluginManager->prepareConfiguration($field_definition->getType(), $options); + } + } + + /** + * {@inheritdoc} + */ + public function massageOut($properties) { + // Do not store options for fields whose display is not set to be + // configurable. + foreach ($this->getFieldDefinitions() as $field_name => $definition) { + if (!$definition->isDisplayConfigurable($this->context['display_context'])) { + unset($properties['content'][$field_name]); + unset($properties['hidden'][$field_name]); + } + } + + return $properties; + } + + /** + * {@inheritdoc} + */ + public function prepareDisplayComponents(array &$components, array &$hidden_components) { + if ($this->context['display_context'] == 'view') { + $plugin_manager = $this->formatterPluginManager; + } + else { + $plugin_manager = $this->widgetPluginManager; + } + + // Fill in defaults for fields. + $fields = $this->getFieldDefinitions(); + foreach ($fields as $name => $definition) { + if (!$definition->isDisplayConfigurable($this->context['display_context']) || (!isset($components[$name]) && !isset($hidden_components[$name]))) { + $options = $definition->getDisplayOptions($this->context['display_context']); + + if (!empty($options['type']) && $options['type'] == 'hidden') { + $hidden_components[$name] = TRUE; + } + elseif ($options) { + $components[$name] = $plugin_manager->prepareConfiguration($definition->getType(), $options); + } + // Note: (base) fields that do not specify display options are not + // tracked in the display at all, in order to avoid cluttering the + // configuration that gets saved back. + } + } + } + + /** + * {@inheritdoc} + */ + public function getRenderer($name, array $options) { + if (isset($options['type']) && ($definition = $this->getFieldDefinition($name))) { + if ($this->context['display_context'] == 'view') { + $plugin_manager = $this->formatterPluginManager; + $mode_key = 'view_mode'; + } + else { + $plugin_manager = $this->widgetPluginManager; + $mode_key = 'form_mode'; + } + + return $plugin_manager->getInstance(array( + 'field_definition' => $definition, + $mode_key => $this->context['mode'], + // No need to prepare, defaults have been merged when the options were + // written in the display. + 'prepare' => FALSE, + 'configuration' => $options, + )); + } + return NULL; + } + + /** + * {@inheritdoc} + */ + public function hasElement($name) { + $field_definition = $this->getFieldDefinition($name); + return isset($field_definition); + } + + /** + * Returns the field definition of a field. + */ + protected function getFieldDefinition($field_name) { + $definitions = $this->getFieldDefinitions(); + return isset($definitions[$field_name]) ? $definitions[$field_name] : NULL; + } + + /** + * Returns the definitions of the fields that are candidate for display. + */ + protected function getFieldDefinitions() { + $entity_type = $this->context['entity_type']; + $bundle = $this->context['bundle']; + $display_context = $this->context['display_context']; + $definitions = $this->entityManager->getFieldDefinitions($entity_type, $bundle); + + // The display only cares about fields that specify display options. + // Discard base fields that are not rendered through formatters / widgets. + return array_filter($definitions, function (FieldDefinitionInterface $definition) use ($display_context) { + return $definition->getDisplayOptions($display_context); + }); + } + +} diff --git a/core/lib/Drupal/Core/Entity/entity.api.php b/core/lib/Drupal/Core/Entity/entity.api.php index 064ef01..5a5a25e 100644 --- a/core/lib/Drupal/Core/Entity/entity.api.php +++ b/core/lib/Drupal/Core/Entity/entity.api.php @@ -2016,6 +2016,21 @@ function hook_entity_extra_field_info_alter(&$info) { } } +/* + * Modify the list of available component handler plugins. + * + * This hook may be used to modify plugin properties after they have been + * specified by other modules. + * + * @param $plugins + * An array of all the existing plugin definitions, passed by reference. + * + * @see DisplayComponentHandlerPluginManager + */ +function hook_display_component_handler_info_alter(array &$plugins) { + $plugins['someplugin']['label'] = t('Better name'); +} + /** * @} End of "addtogroup hooks". */ diff --git a/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php b/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php index 172a77b..1cbac3c 100644 --- a/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php +++ b/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php @@ -30,6 +30,11 @@ /** * Retrieves a configuration object. * + * Objects that use the trait need to implement the + * \Drupal\Core\Form\ConfigFormBaseTrait::getEditableConfigNames() to declare + * which configuration objects this method returns override free and mutable. + * This ensures that overrides do not pollute saved configuration. + * * @param string $name * The name of the configuration object to retrieve. The name corresponds to * a configuration file. For @code \Drupal::config('book.admin') @endcode, @@ -37,9 +42,7 @@ * configuration file. * * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig - * An editable configuration object if the given name is listed in the - * getEditableConfigNames() method or an immutable configuration object if - * not. + * A configuration object. */ protected function config($name) { /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */ diff --git a/core/lib/Drupal/Core/Render/theme.api.php b/core/lib/Drupal/Core/Render/theme.api.php index 19a7038..d9c0fc9 100644 --- a/core/lib/Drupal/Core/Render/theme.api.php +++ b/core/lib/Drupal/Core/Render/theme.api.php @@ -324,11 +324,8 @@ * namespace Element, and generally extend the * \Drupal\Core\Render\Element\FormElement base class. * See the @link plugin_api Plugin API topic @endlink for general information - * on plugins. You can search for classes with the RenderElement or FormElement - * annotation to discover what render elements are available. API reference - * sites (such as https://api.drupal.org) generate lists of all existing - * elements from these classes. Look for the Elements link in the API Navigation - * block. + * on plugins, and look for classes with the RenderElement or FormElement + * annotation to discover what render elements are available. * * Modules can define render elements by defining an element plugin. * diff --git a/core/lib/Drupal/Core/Theme/ThemeNegotiatorInterface.php b/core/lib/Drupal/Core/Theme/ThemeNegotiatorInterface.php index 94bd779..673893e 100644 --- a/core/lib/Drupal/Core/Theme/ThemeNegotiatorInterface.php +++ b/core/lib/Drupal/Core/Theme/ThemeNegotiatorInterface.php @@ -13,8 +13,9 @@ * Defines an interface for classes which determine the active theme. * * To set the active theme, create a new service tagged with 'theme_negotiator' - * (see the theme.negotiator.admin_theme service in user.services.yml for an - * example). Your service class needs to implement this interface. + * (see user.services.yml for an example). The only method this service needs + * to implement is determineActiveTheme. Return the name of the theme, or NULL + * if other negotiators like the configured default one should kick in instead. * * If you are setting a theme which is closely tied to the functionality of a * particular page or set of pages (such that the page might not function @@ -45,8 +46,7 @@ public function applies(RouteMatchInterface $route_match); * The current route match object. * * @return string|null - * The name of the theme, or NULL if other negotiators, like the configured - * default one, should be used instead. + * Returns the active theme name, else return NULL. */ public function determineActiveTheme(RouteMatchInterface $route_match); diff --git a/core/modules/comment/src/Tests/CommentItemTest.php b/core/modules/comment/src/Tests/CommentItemTest.php new file mode 100644 index 0000000..9b28a58 --- /dev/null +++ b/core/modules/comment/src/Tests/CommentItemTest.php @@ -0,0 +1,69 @@ +installSchema('comment', ['comment_entity_statistics']); + $this->installConfig(['comment']); + } + + /** + * Tests using entity fields of the comment field type. + */ + public function testCommentItem() { + $this->addDefaultCommentField('entity_test', 'entity_test', 'comment'); + + // Verify entity creation. + $entity = EntityTest::create(); + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id, TRUE); + $this->assertTrue($entity->comment instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->comment[0] instanceof CommentItemInterface, 'Field item implements interface.'); + + // Test sample item generation. + /** @var \Drupal\entity_test\Entity\EntityTest $entity */ + $entity = EntityTest::create(); + $entity->comment->generateSampleItems(); + $this->entityValidateAndSave($entity); + $this->assertTrue(in_array($entity->get('comment')->status, [ + CommentItemInterface::HIDDEN, + CommentItemInterface::CLOSED, + CommentItemInterface::OPEN, + ]), 'Comment status value in defined range'); + + $mainProperty = $entity->comment[0]->mainPropertyName(); + $this->assertEqual('status', $mainProperty); + } + +} diff --git a/core/modules/comment/tests/src/Kernel/CommentItemTest.php b/core/modules/comment/tests/src/Kernel/CommentItemTest.php deleted file mode 100644 index 4c8ed65..0000000 --- a/core/modules/comment/tests/src/Kernel/CommentItemTest.php +++ /dev/null @@ -1,70 +0,0 @@ -installSchema('comment', ['comment_entity_statistics']); - $this->installConfig(['comment']); - } - - /** - * Tests using entity fields of the comment field type. - */ - public function testCommentItem() { - $this->addDefaultCommentField('entity_test', 'entity_test', 'comment'); - - // Verify entity creation. - $entity = EntityTest::create(); - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id, TRUE); - $this->assertTrue($entity->comment instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->comment[0] instanceof CommentItemInterface, 'Field item implements interface.'); - - // Test sample item generation. - /** @var \Drupal\entity_test\Entity\EntityTest $entity */ - $entity = EntityTest::create(); - $entity->comment->generateSampleItems(); - $this->entityValidateAndSave($entity); - $this->assertTrue(in_array($entity->get('comment')->status, [ - CommentItemInterface::HIDDEN, - CommentItemInterface::CLOSED, - CommentItemInterface::OPEN, - ]), 'Comment status value in defined range'); - - $mainProperty = $entity->comment[0]->mainPropertyName(); - $this->assertEqual('status', $mainProperty); - } - -} diff --git a/core/modules/datetime/src/Tests/DateTimeItemTest.php b/core/modules/datetime/src/Tests/DateTimeItemTest.php new file mode 100644 index 0000000..03d72e9 --- /dev/null +++ b/core/modules/datetime/src/Tests/DateTimeItemTest.php @@ -0,0 +1,128 @@ + 'field_datetime', + 'type' => 'datetime', + 'entity_type' => 'entity_test', + 'settings' => array('datetime_type' => 'date'), + )); + $field_storage->save(); + $field = FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => 'entity_test', + 'settings' => array( + 'default_value' => 'blank', + ), + ]); + $field->save(); + } + + /** + * Tests using entity fields of the date field type. + */ + public function testDateTimeItem() { + // Verify entity creation. + $entity = EntityTest::create(); + $value = '2014-01-01T20:00:00Z'; + $entity->field_datetime = $value; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->field_datetime instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_datetime[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_datetime->value, $value); + $this->assertEqual($entity->field_datetime[0]->value, $value); + + // Verify changing the date value. + $new_value = $this->randomMachineName(); + $entity->field_datetime->value = $new_value; + $this->assertEqual($entity->field_datetime->value, $new_value); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_datetime->value, $new_value); + + // Test the generateSampleValue() method. + $entity = EntityTest::create(); + $entity->field_datetime->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + + /** + * Tests DateTimeItem::setValue(). + */ + public function testSetValue() { + // Test DateTimeItem::setValue() using string. + $entity = EntityTest::create(); + $value = '2014-01-01T20:00:00Z'; + $entity->get('field_datetime')->set(0, $value); + $entity->save(); + // Load the entity and ensure the field was saved correctly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_datetime[0]->value, $value, 'DateTimeItem::setValue() works with string value.'); + + // Test DateTimeItem::setValue() using property array. + $entity = EntityTest::create(); + $value = '2014-01-01T20:00:00Z'; + $entity->set('field_datetime', $value); + $entity->save(); + // Load the entity and ensure the field was saved correctly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_datetime[0]->value, $value, 'DateTimeItem::setValue() works with array value.'); + } + + /** + * Tests setting the value of the DateTimeItem directly. + */ + public function testSetValueProperty() { + // Test Date::setValue(). + $entity = EntityTest::create(); + $value = '2014-01-01T20:00:00Z'; + + $entity->set('field_datetime', $value); + $entity->save(); + // Load the entity and ensure the field was saved correctly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_datetime[0]->value, $value, '"Value" property can be set directly.'); + } + +} diff --git a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php deleted file mode 100644 index 0bf8d68..0000000 --- a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php +++ /dev/null @@ -1,128 +0,0 @@ - 'field_datetime', - 'type' => 'datetime', - 'entity_type' => 'entity_test', - 'settings' => array('datetime_type' => 'date'), - )); - $field_storage->save(); - $field = FieldConfig::create([ - 'field_storage' => $field_storage, - 'bundle' => 'entity_test', - 'settings' => array( - 'default_value' => 'blank', - ), - ]); - $field->save(); - } - - /** - * Tests using entity fields of the date field type. - */ - public function testDateTimeItem() { - // Verify entity creation. - $entity = EntityTest::create(); - $value = '2014-01-01T20:00:00Z'; - $entity->field_datetime = $value; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->field_datetime instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_datetime[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_datetime->value, $value); - $this->assertEqual($entity->field_datetime[0]->value, $value); - - // Verify changing the date value. - $new_value = $this->randomMachineName(); - $entity->field_datetime->value = $new_value; - $this->assertEqual($entity->field_datetime->value, $new_value); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_datetime->value, $new_value); - - // Test the generateSampleValue() method. - $entity = EntityTest::create(); - $entity->field_datetime->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - - /** - * Tests DateTimeItem::setValue(). - */ - public function testSetValue() { - // Test DateTimeItem::setValue() using string. - $entity = EntityTest::create(); - $value = '2014-01-01T20:00:00Z'; - $entity->get('field_datetime')->set(0, $value); - $entity->save(); - // Load the entity and ensure the field was saved correctly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_datetime[0]->value, $value, 'DateTimeItem::setValue() works with string value.'); - - // Test DateTimeItem::setValue() using property array. - $entity = EntityTest::create(); - $value = '2014-01-01T20:00:00Z'; - $entity->set('field_datetime', $value); - $entity->save(); - // Load the entity and ensure the field was saved correctly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_datetime[0]->value, $value, 'DateTimeItem::setValue() works with array value.'); - } - - /** - * Tests setting the value of the DateTimeItem directly. - */ - public function testSetValueProperty() { - // Test Date::setValue(). - $entity = EntityTest::create(); - $value = '2014-01-01T20:00:00Z'; - - $entity->set('field_datetime', $value); - $entity->save(); - // Load the entity and ensure the field was saved correctly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_datetime[0]->value, $value, '"Value" property can be set directly.'); - } - -} diff --git a/core/modules/field/src/Tests/Boolean/BooleanFormatterTest.php b/core/modules/field/src/Tests/Boolean/BooleanFormatterTest.php new file mode 100644 index 0000000..214590d --- /dev/null +++ b/core/modules/field/src/Tests/Boolean/BooleanFormatterTest.php @@ -0,0 +1,144 @@ +installConfig(['field']); + $this->installEntitySchema('entity_test'); + + $this->entityType = 'entity_test'; + $this->bundle = $this->entityType; + $this->fieldName = Unicode::strtolower($this->randomMachineName()); + + $field_storage = FieldStorageConfig::create([ + 'field_name' => $this->fieldName, + 'entity_type' => $this->entityType, + 'type' => 'boolean', + ]); + $field_storage->save(); + + $instance = FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => $this->bundle, + 'label' => $this->randomMachineName(), + ]); + $instance->save(); + + $this->display = entity_get_display($this->entityType, $this->bundle, 'default') + ->setComponent($this->fieldName, [ + 'type' => 'boolean', + 'settings' => [], + ]); + $this->display->save(); + } + + /** + * Renders fields of a given entity with a given display. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity object with attached fields to render. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The display to render the fields in. + * + * @return string + * The rendered entity fields. + */ + protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { + $content = $display->build($entity); + $content = $this->render($content); + return $content; + } + + /** + * Tests boolean formatter output. + */ + public function testBooleanFormatter() { + $data = []; + $data[] = [0, [], 'Off']; + $data[] = [1, [], 'On']; + + $format = ['format' => 'enabled-disabled']; + $data[] = [0, $format, 'Disabled']; + $data[] = [1, $format, 'Enabled']; + + $format = ['format' => 'unicode-yes-no']; + $data[] = [1, $format, '✔']; + $data[] = [0, $format, '✖']; + + $format = [ + 'format' => 'custom', + 'format_custom_false' => 'FALSE', + 'format_custom_true' => 'TRUE' + ]; + $data[] = [0, $format, 'FALSE']; + $data[] = [1, $format, 'TRUE']; + + foreach ($data as $test_data) { + list($value, $settings, $expected) = $test_data; + + $component = $this->display->getComponent($this->fieldName); + $component['settings'] = $settings; + $this->display->setComponent($this->fieldName, $component); + + $entity = EntityTest::create([]); + $entity->{$this->fieldName}->value = $value; + + // Verify that all HTML is escaped and newlines are retained. + $this->renderEntityFields($entity, $this->display); + $this->assertRaw($expected); + } + } + +} diff --git a/core/modules/field/src/Tests/Boolean/BooleanItemTest.php b/core/modules/field/src/Tests/Boolean/BooleanItemTest.php new file mode 100644 index 0000000..8ae2259 --- /dev/null +++ b/core/modules/field/src/Tests/Boolean/BooleanItemTest.php @@ -0,0 +1,85 @@ + 'field_boolean', + 'entity_type' => 'entity_test', + 'type' => 'boolean', + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'field_boolean', + 'bundle' => 'entity_test', + ])->save(); + + // Create a form display for the default form mode. + entity_get_form_display('entity_test', 'entity_test', 'default') + ->setComponent('field_boolean', array( + 'type' => 'boolean_checkbox', + )) + ->save(); + } + + /** + * Tests using entity fields of the boolean field type. + */ + public function testBooleanItem() { + // Verify entity creation. + $entity = EntityTest::create(); + $value = '1'; + $entity->field_boolean = $value; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->field_boolean instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_boolean[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_boolean->value, $value); + $this->assertEqual($entity->field_boolean[0]->value, $value); + + // Verify changing the boolean value. + $new_value = 0; + $entity->field_boolean->value = $new_value; + $this->assertEqual($entity->field_boolean->value, $new_value); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_boolean->value, $new_value); + + // Test sample item generation. + $entity = EntityTest::create(); + $entity->field_boolean->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + +} diff --git a/core/modules/field/src/Tests/BulkDeleteTest.php b/core/modules/field/src/Tests/BulkDeleteTest.php new file mode 100644 index 0000000..2949867 --- /dev/null +++ b/core/modules/field/src/Tests/BulkDeleteTest.php @@ -0,0 +1,364 @@ + $invocations) { + $actual_invocations = $actual_hooks[$hook]; + + // Check that the number of invocations is correct. + $this->assertEqual(count($actual_invocations), count($invocations), "$hook() was called the expected number of times."); + + // Check that the hook was called for each expected argument. + foreach ($invocations as $argument) { + $found = FALSE; + foreach ($actual_invocations as $actual_arguments) { + // The argument we are looking for is either an array of entities as + // the second argument or a single entity object as the first. + if ($argument instanceof EntityInterface && $actual_arguments[0]->id() == $argument->id()) { + $found = TRUE; + break; + } + // In case of an array, compare the array size and make sure it + // contains the same elements. + elseif (is_array($argument) && count($actual_arguments[1]) == count($argument) && count(array_diff_key($actual_arguments[1], $argument)) == 0) { + $found = TRUE; + break; + } + } + $this->assertTrue($found, "$hook() was called on expected argument"); + } + } + } + + protected function setUp() { + parent::setUp(); + + $this->fieldStorages = array(); + $this->entities = array(); + $this->entitiesByBundles = array(); + + // Create two bundles. + $this->bundles = array('bb_1' => 'bb_1', 'bb_2' => 'bb_2'); + foreach ($this->bundles as $name => $desc) { + entity_test_create_bundle($name, $desc); + } + + // Create two field storages. + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'bf_1', + 'entity_type' => $this->entityTypeId, + 'type' => 'test_field', + 'cardinality' => 1 + )); + $field_storage->save(); + $this->fieldStorages[] = $field_storage; + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'bf_2', + 'entity_type' => $this->entityTypeId, + 'type' => 'test_field', + 'cardinality' => 4 + )); + $field_storage->save(); + $this->fieldStorages[] = $field_storage; + + // For each bundle, create each field, and 10 entities with values for the + // fields. + foreach ($this->bundles as $bundle) { + foreach ($this->fieldStorages as $field_storage) { + FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => $bundle, + ])->save(); + } + for ($i = 0; $i < 10; $i++) { + $entity = $this->container->get('entity_type.manager') + ->getStorage($this->entityTypeId) + ->create(array('type' => $bundle)); + foreach ($this->fieldStorages as $field_storage) { + $entity->{$field_storage->getName()}->setValue($this->_generateTestFieldValues($field_storage->getCardinality())); + } + $entity->save(); + } + } + $this->entities = entity_load_multiple($this->entityTypeId); + foreach ($this->entities as $entity) { + // This test relies on the entities having stale field definitions + // so that the deleted field can be accessed on them. Access the field + // now, so that they are always loaded. + $entity->bf_1->value; + + // Also keep track of the entities per bundle. + $this->entitiesByBundles[$entity->bundle()][$entity->id()] = $entity; + } + } + + /** + * Verify that deleting a field leaves the field data items in the database + * and that the appropriate Field API functions can operate on the deleted + * data and field definition. + * + * This tests how EntityFieldQuery interacts with field deletion and could be + * moved to FieldCrudTestCase, but depends on this class's setUp(). + */ + function testDeleteField() { + $bundle = reset($this->bundles); + $field_storage = reset($this->fieldStorages); + $field_name = $field_storage->getName(); + $factory = \Drupal::service('entity.query'); + + // There are 10 entities of this bundle. + $found = $factory->get('entity_test') + ->condition('type', $bundle) + ->execute(); + $this->assertEqual(count($found), 10, 'Correct number of entities found before deleting'); + + // Delete the field. + $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); + $field->delete(); + + // The field still exists, deleted. + $fields = entity_load_multiple_by_properties('field_config', array('field_storage_uuid' => $field_storage->uuid(), 'deleted' => TRUE, 'include_deleted' => TRUE)); + $this->assertEqual(count($fields), 1, 'There is one deleted field'); + $field = $fields[$field->uuid()]; + $this->assertEqual($field->getTargetBundle(), $bundle, 'The deleted field is for the correct bundle'); + + // Check that the actual stored content did not change during delete. + $storage = \Drupal::entityManager()->getStorage($this->entityTypeId); + /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ + $table_mapping = $storage->getTableMapping(); + $table = $table_mapping->getDedicatedDataTableName($field_storage); + $column = $table_mapping->getFieldColumnName($field_storage, 'value'); + $result = db_select($table, 't') + ->fields('t') + ->execute(); + foreach ($result as $row) { + $this->assertEqual($this->entities[$row->entity_id]->{$field_name}->value, $row->$column); + } + + // There are 0 entities of this bundle with non-deleted data. + $found = $factory->get('entity_test') + ->condition('type', $bundle) + ->condition("$field_name.deleted", 0) + ->execute(); + $this->assertFalse($found, 'No entities found after deleting'); + + // There are 10 entities of this bundle when deleted fields are allowed, and + // their values are correct. + $found = $factory->get('entity_test') + ->condition('type', $bundle) + ->condition("$field_name.deleted", 1) + ->sort('id') + ->execute(); + $this->assertEqual(count($found), 10, 'Correct number of entities found after deleting'); + $this->assertFalse(array_diff($found, array_keys($this->entities))); + } + + /** + * Verify that field data items and fields are purged when a field storage is + * deleted. + */ + function testPurgeField() { + // Start recording hook invocations. + field_test_memorize(); + + $bundle = reset($this->bundles); + $field_storage = reset($this->fieldStorages); + $field_name = $field_storage->getName(); + + // Delete the field. + $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); + $field->delete(); + + // No field hooks were called. + $mem = field_test_memorize(); + $this->assertEqual(count($mem), 0, 'No field hooks were called'); + + $batch_size = 2; + for ($count = 8; $count >= 0; $count -= $batch_size) { + // Purge two entities. + field_purge_batch($batch_size); + + // There are $count deleted entities left. + $found = \Drupal::entityQuery('entity_test') + ->condition('type', $bundle) + ->condition($field_name . '.deleted', 1) + ->execute(); + $this->assertEqual(count($found), $count, 'Correct number of entities found after purging 2'); + } + + // Check hooks invocations. + // FieldItemInterface::delete() should have been called once for each entity in the + // bundle. + $actual_hooks = field_test_memorize(); + $hooks = array(); + $entities = $this->entitiesByBundles[$bundle]; + foreach ($entities as $id => $entity) { + $hooks['field_test_field_delete'][] = $entity; + } + $this->checkHooksInvocations($hooks, $actual_hooks); + + // The field still exists, deleted. + $fields = entity_load_multiple_by_properties('field_config', array('field_storage_uuid' => $field_storage->uuid(), 'deleted' => TRUE, 'include_deleted' => TRUE)); + $this->assertEqual(count($fields), 1, 'There is one deleted field'); + + // Purge the field. + field_purge_batch($batch_size); + + // The field is gone. + $fields = entity_load_multiple_by_properties('field_config', array('field_storage_uuid' => $field_storage->uuid(), 'deleted' => TRUE, 'include_deleted' => TRUE)); + $this->assertEqual(count($fields), 0, 'The field is gone'); + + // The field storage still exists, not deleted, because it has a second + // field. + $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); + $this->assertTrue(isset($storages[$field_storage->uuid()]), 'The field storage exists and is not deleted'); + } + + /** + * Verify that field storages are preserved and purged correctly as multiple + * fields are deleted and purged. + */ + function testPurgeFieldStorage() { + // Start recording hook invocations. + field_test_memorize(); + + $field_storage = reset($this->fieldStorages); + $field_name = $field_storage->getName(); + + // Delete the first field. + $bundle = reset($this->bundles); + $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); + $field->delete(); + + // Assert that FieldItemInterface::delete() was not called yet. + $mem = field_test_memorize(); + $this->assertEqual(count($mem), 0, 'No field hooks were called.'); + + // Purge the data. + field_purge_batch(10); + + // Check hooks invocations. + // FieldItemInterface::delete() should have been called once for each entity in the + // bundle. + $actual_hooks = field_test_memorize(); + $hooks = array(); + $entities = $this->entitiesByBundles[$bundle]; + foreach ($entities as $id => $entity) { + $hooks['field_test_field_delete'][] = $entity; + } + $this->checkHooksInvocations($hooks, $actual_hooks); + + // The field still exists, deleted. + $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); + $this->assertTrue(isset($fields[$field->uuid()]) && $fields[$field->uuid()]->isDeleted(), 'The field exists and is deleted'); + + // Purge again to purge the field. + field_purge_batch(0); + + // The field is gone. + $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); + $this->assertEqual(count($fields), 0, 'The field is purged.'); + // The field storage still exists, not deleted. + $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); + $this->assertTrue(isset($storages[$field_storage->uuid()]) && !$storages[$field_storage->uuid()]->isDeleted(), 'The field storage exists and is not deleted'); + + // Delete the second field. + $bundle = next($this->bundles); + $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); + $field->delete(); + + // Assert that FieldItemInterface::delete() was not called yet. + $mem = field_test_memorize(); + $this->assertEqual(count($mem), 0, 'No field hooks were called.'); + + // Purge the data. + field_purge_batch(10); + + // Check hooks invocations (same as above, for the 2nd bundle). + $actual_hooks = field_test_memorize(); + $hooks = array(); + $entities = $this->entitiesByBundles[$bundle]; + foreach ($entities as $id => $entity) { + $hooks['field_test_field_delete'][] = $entity; + } + $this->checkHooksInvocations($hooks, $actual_hooks); + + // The field and the storage still exist, deleted. + $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); + $this->assertTrue(isset($fields[$field->uuid()]) && $fields[$field->uuid()]->isDeleted(), 'The field exists and is deleted'); + $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); + $this->assertTrue(isset($storages[$field_storage->uuid()]) && $storages[$field_storage->uuid()]->isDeleted(), 'The field storage exists and is deleted'); + + // Purge again to purge the field and the storage. + field_purge_batch(0); + + // The field and the storage are gone. + $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); + $this->assertEqual(count($fields), 0, 'The field is purged.'); + $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); + $this->assertEqual(count($storages), 0, 'The field storage is purged.'); + } + +} diff --git a/core/modules/field/src/Tests/ConfigFieldDefinitionTest.php b/core/modules/field/src/Tests/ConfigFieldDefinitionTest.php new file mode 100644 index 0000000..44e8c89 --- /dev/null +++ b/core/modules/field/src/Tests/ConfigFieldDefinitionTest.php @@ -0,0 +1,76 @@ +entityType = 'entity_test'; + $this->bundle = 'entity_test'; + $this->createFieldWithStorage('', $this->entityType, $this->bundle); + $this->entityManager = $this->container->get('entity.manager'); + + // Create a second field on 'entity_test_rev'. + $this->createFieldWithStorage('_rev', 'entity_test_rev', 'entity_test_rev'); + } + + /** + * Makes sure a field definition is exposed for a configurable field. + */ + public function testBundleFieldDefinition() { + $definitions = $this->entityManager->getFieldDefinitions($this->entityType, $this->bundle); + $this->assertTrue(isset($definitions[$this->fieldTestData->field->getName()])); + $this->assertTrue($definitions[$this->fieldTestData->field->getName()] instanceof FieldDefinitionInterface); + // Make sure fields on other entity types are not exposed. + $this->assertFalse(isset($definitions[$this->fieldTestData->field_rev->getName()])); + } + + /** + * Makes sure a field storage definition is exposed for a configurable field. + */ + public function testFieldStorageDefinition() { + $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->entityType); + $this->assertTrue(isset($field_storage_definitions[$this->fieldTestData->field->getName()])); + $this->assertTrue($field_storage_definitions[$this->fieldTestData->field->getName()] instanceof FieldStorageDefinitionInterface); + // Make sure storages on other entity types are not exposed. + $this->assertFalse(isset($field_storage_definitions[$this->fieldTestData->field_rev->getName()])); + } + +} diff --git a/core/modules/field/src/Tests/DisplayApiTest.php b/core/modules/field/src/Tests/DisplayApiTest.php new file mode 100644 index 0000000..362699b --- /dev/null +++ b/core/modules/field/src/Tests/DisplayApiTest.php @@ -0,0 +1,311 @@ +fieldName = 'test_field'; + $this->label = $this->randomMachineName(); + $this->cardinality = 4; + + $field_storage = array( + 'field_name' => $this->fieldName, + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'cardinality' => $this->cardinality, + ); + $field = array( + 'field_name' => $this->fieldName, + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + 'label' => $this->label, + ); + + $this->displayOptions = array( + 'default' => array( + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $this->randomMachineName(), + ), + ), + 'teaser' => array( + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $this->randomMachineName(), + ), + ), + ); + + FieldStorageConfig::create($field_storage)->save(); + FieldConfig::create($field)->save(); + // Create a display for the default view mode. + entity_get_display($field['entity_type'], $field['bundle'], 'default') + ->setComponent($this->fieldName, $this->displayOptions['default']) + ->save(); + // Create a display for the teaser view mode. + EntityViewMode::create(array('id' => 'entity_test.teaser', 'targetEntityType' => 'entity_test'))->save(); + entity_get_display($field['entity_type'], $field['bundle'], 'teaser') + ->setComponent($this->fieldName, $this->displayOptions['teaser']) + ->save(); + + // Create an entity with values. + $this->values = $this->_generateTestFieldValues($this->cardinality); + $this->entity = EntityTest::create(); + $this->entity->{$this->fieldName}->setValue($this->values); + $this->entity->save(); + } + + /** + * Tests the FieldItemListInterface::view() method. + */ + function testFieldItemListView() { + $items = $this->entity->get($this->fieldName); + + \Drupal::service('theme_handler')->install(['classy']); + \Drupal::service('theme_handler')->setDefault('classy'); + + // No display settings: check that default display settings are used. + $build = $items->view(); + $this->render($build); + $settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings('field_test_default'); + $setting = $settings['test_formatter_setting']; + $this->assertText($this->label, 'Label was displayed.'); + foreach ($this->values as $delta => $value) { + $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + + // Display settings: Check hidden field. + $display = array( + 'label' => 'hidden', + 'type' => 'field_test_multiple', + 'settings' => array( + 'test_formatter_setting_multiple' => $this->randomMachineName(), + 'alter' => TRUE, + ), + ); + $build = $items->view($display); + $this->render($build); + $setting = $display['settings']['test_formatter_setting_multiple']; + $this->assertNoText($this->label, 'Label was not displayed.'); + $this->assertText('field_test_entity_display_build_alter', 'Alter fired, display passed.'); + $this->assertText('entity language is en', 'Language is placed onto the context.'); + $array = array(); + foreach ($this->values as $delta => $value) { + $array[] = $delta . ':' . $value['value']; + } + $this->assertText($setting . '|' . implode('|', $array), 'Values were displayed with expected setting.'); + + // Display settings: Check visually_hidden field. + $display = array( + 'label' => 'visually_hidden', + 'type' => 'field_test_multiple', + 'settings' => array( + 'test_formatter_setting_multiple' => $this->randomMachineName(), + 'alter' => TRUE, + ), + ); + $build = $items->view($display); + $this->render($build); + $setting = $display['settings']['test_formatter_setting_multiple']; + $this->assertRaw('visually-hidden', 'Label was visually hidden.'); + $this->assertText('field_test_entity_display_build_alter', 'Alter fired, display passed.'); + $this->assertText('entity language is en', 'Language is placed onto the context.'); + $array = array(); + foreach ($this->values as $delta => $value) { + $array[] = $delta . ':' . $value['value']; + } + $this->assertText($setting . '|' . implode('|', $array), 'Values were displayed with expected setting.'); + + // Check the prepare_view steps are invoked. + $display = array( + 'label' => 'hidden', + 'type' => 'field_test_with_prepare_view', + 'settings' => array( + 'test_formatter_setting_additional' => $this->randomMachineName(), + ), + ); + $build = $items->view($display); + $this->render($build); + $setting = $display['settings']['test_formatter_setting_additional']; + $this->assertNoText($this->label, 'Label was not displayed.'); + $this->assertNoText('field_test_entity_display_build_alter', 'Alter not fired.'); + foreach ($this->values as $delta => $value) { + $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + + // View mode: check that display settings specified in the display object + // are used. + $build = $items->view('teaser'); + $this->render($build); + $setting = $this->displayOptions['teaser']['settings']['test_formatter_setting']; + $this->assertText($this->label, 'Label was displayed.'); + foreach ($this->values as $delta => $value) { + $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + + // Unknown view mode: check that display settings for 'default' view mode + // are used. + $build = $items->view('unknown_view_mode'); + $this->render($build); + $setting = $this->displayOptions['default']['settings']['test_formatter_setting']; + $this->assertText($this->label, 'Label was displayed.'); + foreach ($this->values as $delta => $value) { + $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + } + + /** + * Tests the FieldItemInterface::view() method. + */ + function testFieldItemView() { + // No display settings: check that default display settings are used. + $settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings('field_test_default'); + $setting = $settings['test_formatter_setting']; + foreach ($this->values as $delta => $value) { + $item = $this->entity->{$this->fieldName}[$delta]; + $build = $item->view(); + $this->render($build); + $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + + // Check that explicit display settings are used. + $display = array( + 'type' => 'field_test_multiple', + 'settings' => array( + 'test_formatter_setting_multiple' => $this->randomMachineName(), + ), + ); + $setting = $display['settings']['test_formatter_setting_multiple']; + foreach ($this->values as $delta => $value) { + $item = $this->entity->{$this->fieldName}[$delta]; + $build = $item->view($display); + $this->render($build); + $this->assertText($setting . '|0:' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + + // Check that prepare_view steps are invoked. + $display = array( + 'type' => 'field_test_with_prepare_view', + 'settings' => array( + 'test_formatter_setting_additional' => $this->randomMachineName(), + ), + ); + $setting = $display['settings']['test_formatter_setting_additional']; + foreach ($this->values as $delta => $value) { + $item = $this->entity->{$this->fieldName}[$delta]; + $build = $item->view($display); + $this->render($build); + $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + + // View mode: check that display settings specified in the field are used. + $setting = $this->displayOptions['teaser']['settings']['test_formatter_setting']; + foreach ($this->values as $delta => $value) { + $item = $this->entity->{$this->fieldName}[$delta]; + $build = $item->view('teaser'); + $this->render($build); + $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + + // Unknown view mode: check that display settings for 'default' view mode + // are used. + $setting = $this->displayOptions['default']['settings']['test_formatter_setting']; + foreach ($this->values as $delta => $value) { + $item = $this->entity->{$this->fieldName}[$delta]; + $build = $item->view('unknown_view_mode'); + $this->render($build); + $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); + } + } + + /** + * Tests that the prepareView() formatter method still fires for empty values. + */ + function testFieldEmpty() { + // Uses \Drupal\field_test\Plugin\Field\FieldFormatter\TestFieldEmptyFormatter. + $display = array( + 'label' => 'hidden', + 'type' => 'field_empty_test', + 'settings' => array( + 'test_empty_string' => '**EMPTY FIELD**' . $this->randomMachineName(), + ), + ); + // $this->entity is set by the setUp() method and by default contains 4 + // numeric values. We only want to test the display of this one field. + $build = $this->entity->get($this->fieldName)->view($display); + $this->render($build); + // The test field by default contains values, so should not display the + // default "empty" text. + $this->assertNoText($display['settings']['test_empty_string']); + + // Now remove the values from the test field and retest. + $this->entity->{$this->fieldName} = array(); + $this->entity->save(); + $build = $this->entity->get($this->fieldName)->view($display); + $this->render($build); + // This time, as the field values have been removed, we *should* show the + // default "empty" text. + $this->assertText($display['settings']['test_empty_string']); + } +} diff --git a/core/modules/field/src/Tests/Email/EmailItemTest.php b/core/modules/field/src/Tests/Email/EmailItemTest.php new file mode 100644 index 0000000..4427e3f --- /dev/null +++ b/core/modules/field/src/Tests/Email/EmailItemTest.php @@ -0,0 +1,82 @@ + 'field_email', + 'entity_type' => 'entity_test', + 'type' => 'email', + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'field_email', + 'bundle' => 'entity_test', + ])->save(); + + // Create a form display for the default form mode. + entity_get_form_display('entity_test', 'entity_test', 'default') + ->setComponent('field_email', array( + 'type' => 'email_default', + )) + ->save(); + } + + /** + * Tests using entity fields of the email field type. + */ + public function testEmailItem() { + // Verify entity creation. + $entity = EntityTest::create(); + $value = 'test@example.com'; + $entity->field_email = $value; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->field_email instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_email[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_email->value, $value); + $this->assertEqual($entity->field_email[0]->value, $value); + + // Verify changing the email value. + $new_value = $this->randomMachineName(); + $entity->field_email->value = $new_value; + $this->assertEqual($entity->field_email->value, $new_value); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_email->value, $new_value); + + // Test sample item generation. + $entity = EntityTest::create(); + $entity->field_email->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + +} diff --git a/core/modules/field/src/Tests/EntityReference/EntityReferenceItemTest.php b/core/modules/field/src/Tests/EntityReference/EntityReferenceItemTest.php new file mode 100644 index 0000000..49dfa86 --- /dev/null +++ b/core/modules/field/src/Tests/EntityReference/EntityReferenceItemTest.php @@ -0,0 +1,540 @@ +installEntitySchema('entity_test_string_id'); + $this->installEntitySchema('taxonomy_term'); + $this->installEntitySchema('node'); + $this->installEntitySchema('comment'); + $this->installEntitySchema('file'); + + $this->installSchema('comment', ['comment_entity_statistics']); + $this->installSchema('node', ['node_access']); + + $this->vocabulary = Vocabulary::create([ + 'name' => $this->randomMachineName(), + 'vid' => Unicode::strtolower($this->randomMachineName()), + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]); + $this->vocabulary->save(); + + $this->term = Term::create([ + 'name' => $this->randomMachineName(), + 'vid' => $this->vocabulary->id(), + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]); + $this->term->save(); + + $this->entityStringId = EntityTestStringId::create([ + 'id' => $this->randomMachineName(), + ]); + $this->entityStringId->save(); + + // Use the util to create an instance. + $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_taxonomy_term', 'Test content entity reference', 'taxonomy_term'); + $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_entity_test_string_id', 'Test content entity reference with string ID', 'entity_test_string_id'); + $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_taxonomy_vocabulary', 'Test config entity reference', 'taxonomy_vocabulary'); + $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_node', 'Test node entity reference', 'node', 'default', [], FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); + $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_user', 'Test user entity reference', 'user'); + $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_comment', 'Test comment entity reference', 'comment'); + $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_file', 'Test file entity reference', 'file'); + } + + /** + * Tests the entity reference field type for referencing content entities. + */ + public function testContentEntityReferenceItem() { + $tid = $this->term->id(); + + // Just being able to create the entity like this verifies a lot of code. + $entity = EntityTest::create(); + $entity->field_test_taxonomy_term->target_id = $tid; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + $entity = entity_load('entity_test', $entity->id()); + $this->assertTrue($entity->field_test_taxonomy_term instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_test_taxonomy_term[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_test_taxonomy_term->target_id, $tid); + $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $this->term->getName()); + $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $tid); + $this->assertEqual($entity->field_test_taxonomy_term->entity->uuid(), $this->term->uuid()); + // Verify that the label for the target ID property definition is correct. + $label = $entity->field_test_taxonomy_term->getFieldDefinition()->getFieldStorageDefinition()->getPropertyDefinition('target_id')->getLabel(); + $this->assertTrue($label instanceof TranslatableMarkup); + $this->assertEqual($label->render(), 'Taxonomy term ID'); + + // Change the name of the term via the reference. + $new_name = $this->randomMachineName(); + $entity->field_test_taxonomy_term->entity->setName($new_name); + $entity->field_test_taxonomy_term->entity->save(); + // Verify it is the correct name. + $term = Term::load($tid); + $this->assertEqual($term->getName(), $new_name); + + // Make sure the computed term reflects updates to the term id. + $term2 = Term::create([ + 'name' => $this->randomMachineName(), + 'vid' => $this->term->bundle(), + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]); + $term2->save(); + + // Test all the possible ways of assigning a value. + $entity->field_test_taxonomy_term->target_id = $term->id(); + $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term->id()); + $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term->getName()); + + $entity->field_test_taxonomy_term = [['target_id' => $term2->id()]]; + $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term2->id()); + $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term2->getName()); + + // Test value assignment via the computed 'entity' property. + $entity->field_test_taxonomy_term->entity = $term; + $this->assertEqual($entity->field_test_taxonomy_term->target_id, $term->id()); + $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term->getName()); + + $entity->field_test_taxonomy_term = [['entity' => $term2]]; + $this->assertEqual($entity->field_test_taxonomy_term->target_id, $term2->id()); + $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term2->getName()); + + // Test assigning an invalid item throws an exception. + try { + $entity->field_test_taxonomy_term = ['target_id' => 'invalid', 'entity' => $term2]; + $this->fail('Assigning an invalid item throws an exception.'); + } + catch (\InvalidArgumentException $e) { + $this->pass('Assigning an invalid item throws an exception.'); + } + + // Delete terms so we have nothing to reference and try again + $term->delete(); + $term2->delete(); + $entity = EntityTest::create(array('name' => $this->randomMachineName())); + $entity->save(); + + // Test the generateSampleValue() method. + $entity = EntityTest::create(); + $entity->field_test_taxonomy_term->generateSampleItems(); + $entity->field_test_taxonomy_vocabulary->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + + /** + * Tests referencing content entities with string IDs. + */ + public function testContentEntityReferenceItemWithStringId() { + $entity = EntityTest::create(); + $entity->field_test_entity_test_string_id->target_id = $this->entityStringId->id(); + $entity->save(); + $storage = \Drupal::entityManager()->getStorage('entity_test'); + $storage->resetCache(); + $this->assertEqual($this->entityStringId->id(), $storage->load($entity->id())->field_test_entity_test_string_id->target_id); + // Verify that the label for the target ID property definition is correct. + $label = $entity->field_test_taxonomy_term->getFieldDefinition()->getFieldStorageDefinition()->getPropertyDefinition('target_id')->getLabel(); + $this->assertTrue($label instanceof TranslatableMarkup); + $this->assertEqual($label->render(), 'Taxonomy term ID'); + } + + /** + * Tests the entity reference field type for referencing config entities. + */ + public function testConfigEntityReferenceItem() { + $referenced_entity_id = $this->vocabulary->id(); + + // Just being able to create the entity like this verifies a lot of code. + $entity = EntityTest::create(); + $entity->field_test_taxonomy_vocabulary->target_id = $referenced_entity_id; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + $entity = entity_load('entity_test', $entity->id()); + $this->assertTrue($entity->field_test_taxonomy_vocabulary instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_test_taxonomy_vocabulary[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_test_taxonomy_vocabulary->target_id, $referenced_entity_id); + $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->label(), $this->vocabulary->label()); + $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->id(), $referenced_entity_id); + $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->uuid(), $this->vocabulary->uuid()); + + // Change the name of the term via the reference. + $new_name = $this->randomMachineName(); + $entity->field_test_taxonomy_vocabulary->entity->set('name', $new_name); + $entity->field_test_taxonomy_vocabulary->entity->save(); + // Verify it is the correct name. + $vocabulary = Vocabulary::load($referenced_entity_id); + $this->assertEqual($vocabulary->label(), $new_name); + + // Make sure the computed term reflects updates to the term id. + $vocabulary2 = $vocabulary = Vocabulary::create([ + 'name' => $this->randomMachineName(), + 'vid' => Unicode::strtolower($this->randomMachineName()), + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]); + $vocabulary2->save(); + + $entity->field_test_taxonomy_vocabulary->target_id = $vocabulary2->id(); + $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->id(), $vocabulary2->id()); + $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->label(), $vocabulary2->label()); + + // Delete terms so we have nothing to reference and try again + $this->vocabulary->delete(); + $vocabulary2->delete(); + $entity = EntityTest::create(array('name' => $this->randomMachineName())); + $entity->save(); + } + + /** + * Tests entity auto create. + */ + public function testEntityAutoCreate() { + // The term entity is unsaved here. + $term = Term::create(array( + 'name' => $this->randomMachineName(), + 'vid' => $this->term->bundle(), + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + )); + $entity = EntityTest::create(); + // Now assign the unsaved term to the field. + $entity->field_test_taxonomy_term->entity = $term; + $entity->name->value = $this->randomMachineName(); + // This is equal to storing an entity to tempstore or cache and retrieving + // it back. An example for this is node preview. + $entity = serialize($entity); + $entity = unserialize($entity); + // And then the entity. + $entity->save(); + $term = \Drupal::entityManager()->loadEntityByUuid($term->getEntityTypeId(), $term->uuid()); + $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term->id()); + } + + /** + * Test saving order sequence doesn't matter. + */ + public function testEntitySaveOrder() { + // The term entity is unsaved here. + $term = Term::create([ + 'name' => $this->randomMachineName(), + 'vid' => $this->term->bundle(), + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]); + $entity = EntityTest::create(); + // Now assign the unsaved term to the field. + $entity->field_test_taxonomy_term->entity = $term; + $entity->name->value = $this->randomMachineName(); + // Now get the field value. + $value = $entity->get('field_test_taxonomy_term'); + $this->assertTrue(empty($value['target_id'])); + $this->assertNull($entity->field_test_taxonomy_term->target_id); + // And then set it. + $entity->field_test_taxonomy_term = $value; + // Now save the term. + $term->save(); + // And then the entity. + $entity->save(); + $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term->id()); + } + + /** + * Tests that the 'handler' field setting stores the proper plugin ID. + */ + public function testSelectionHandlerSettings() { + $field_name = Unicode::strtolower($this->randomMachineName()); + $field_storage = FieldStorageConfig::create(array( + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'type' => 'entity_reference', + 'settings' => array( + 'target_type' => 'entity_test' + ), + )); + $field_storage->save(); + + // Do not specify any value for the 'handler' setting in order to verify + // that the default handler with the correct derivative is used. + $field = FieldConfig::create(array( + 'field_storage' => $field_storage, + 'bundle' => 'entity_test', + )); + $field->save(); + $field = FieldConfig::load($field->id()); + $this->assertEqual($field->getSetting('handler'), 'default:entity_test'); + + // Change the target_type in the field storage, and check that the handler + // was correctly reassigned in the field. + $field_storage->setSetting('target_type', 'entity_test_rev'); + $field_storage->save(); + $field = FieldConfig::load($field->id()); + $this->assertEqual($field->getSetting('handler'), 'default:entity_test_rev'); + + // Change the handler to another, non-derivative plugin. + $field->setSetting('handler', 'views'); + $field->save(); + $field = FieldConfig::load($field->id()); + $this->assertEqual($field->getSetting('handler'), 'views'); + + // Change the target_type in the field storage again, and check that the + // non-derivative handler was unchanged. + $field_storage->setSetting('target_type', 'entity_test_rev'); + $field_storage->save(); + $field = FieldConfig::load($field->id()); + $this->assertEqual($field->getSetting('handler'), 'views'); + } + + /** + * Tests ValidReferenceConstraint with newly created and unsaved entities. + */ + public function testAutocreateValidation() { + // The term entity is unsaved here. + $term = Term::create(array( + 'name' => $this->randomMachineName(), + 'vid' => $this->term->bundle(), + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + )); + $entity = EntityTest::create([ + 'field_test_taxonomy_term' => [ + 'entity' => $term, + 'target_id' => NULL, + ], + ]); + $errors = $entity->validate(); + // Using target_id of NULL is valid with an unsaved entity. + $this->assertEqual(0, count($errors)); + // Using target_id of NULL is not valid with a saved entity. + $term->save(); + $entity = EntityTest::create([ + 'field_test_taxonomy_term' => [ + 'entity' => $term, + 'target_id' => NULL, + ], + ]); + $errors = $entity->validate(); + $this->assertEqual(1, count($errors)); + $this->assertEqual($errors[0]->getMessage(), 'This value should not be null.'); + $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_taxonomy_term.0'); + // This should rectify the issue, favoring the entity over the target_id. + $entity->save(); + $errors = $entity->validate(); + $this->assertEqual(0, count($errors)); + + // Test with an unpublished and unsaved node. + $title = $this->randomString(); + $node = Node::create([ + 'title' => $title, + 'type' => 'node', + 'status' => NODE_NOT_PUBLISHED, + ]); + + $entity = EntityTest::create([ + 'field_test_node' => [ + 'entity' => $node, + ], + ]); + + $errors = $entity->validate(); + $this->assertEqual(1, count($errors)); + $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $title])); + $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_node.0.entity'); + + // Publish the node and try again. + $node->setPublished(TRUE); + $errors = $entity->validate(); + $this->assertEqual(0, count($errors)); + + // Test with a mix of valid and invalid nodes. + $unsaved_unpublished_node_title = $this->randomString(); + $unsaved_unpublished_node = Node::create([ + 'title' => $unsaved_unpublished_node_title, + 'type' => 'node', + 'status' => NODE_NOT_PUBLISHED, + ]); + + $saved_unpublished_node_title = $this->randomString(); + $saved_unpublished_node = Node::create([ + 'title' => $saved_unpublished_node_title, + 'type' => 'node', + 'status' => NODE_NOT_PUBLISHED, + ]); + $saved_unpublished_node->save(); + + $saved_published_node_title = $this->randomString(); + $saved_published_node = Node::create([ + 'title' => $saved_published_node_title, + 'type' => 'node', + 'status' => NODE_PUBLISHED, + ]); + $saved_published_node->save(); + + $entity = EntityTest::create([ + 'field_test_node' => [ + [ + 'entity' => $unsaved_unpublished_node, + ], + [ + 'target_id' => $saved_unpublished_node->id(), + ], + [ + 'target_id' => $saved_published_node->id(), + ], + ], + ]); + + $errors = $entity->validate(); + $this->assertEqual(2, count($errors)); + $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $unsaved_unpublished_node_title])); + $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_node.0.entity'); + $this->assertEqual($errors[1]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $saved_unpublished_node->id()])); + $this->assertEqual($errors[1]->getPropertyPath(), 'field_test_node.1.target_id'); + + // Publish one of the nodes and try again. + $saved_unpublished_node->setPublished(TRUE); + $saved_unpublished_node->save(); + $errors = $entity->validate(); + $this->assertEqual(1, count($errors)); + $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $unsaved_unpublished_node_title])); + $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_node.0.entity'); + + // Publish the last invalid node and try again. + $unsaved_unpublished_node->setPublished(TRUE); + $errors = $entity->validate(); + $this->assertEqual(0, count($errors)); + + // Test with an unpublished and unsaved comment. + $title = $this->randomString(); + $comment = Comment::create([ + 'subject' => $title, + 'comment_type' => 'comment', + 'status' => 0, + ]); + + $entity = EntityTest::create([ + 'field_test_comment' => [ + 'entity' => $comment, + ], + ]); + + $errors = $entity->validate(); + $this->assertEqual(1, count($errors)); + $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'comment', '%label' => $title])); + $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_comment.0.entity'); + + // Publish the comment and try again. + $comment->setPublished(TRUE); + $errors = $entity->validate(); + $this->assertEqual(0, count($errors)); + + // Test with an inactive and unsaved user. + $name = $this->randomString(); + $user = User::create([ + 'name' => $name, + 'status' => 0, + ]); + + $entity = EntityTest::create([ + 'field_test_user' => [ + 'entity' => $user, + ], + ]); + + $errors = $entity->validate(); + $this->assertEqual(1, count($errors)); + $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'user', '%label' => $name])); + $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_user.0.entity'); + + // Activate the user and try again. + $user->activate(); + $errors = $entity->validate(); + $this->assertEqual(0, count($errors)); + + // Test with a temporary and unsaved file. + $filename = $this->randomMachineName() . '.txt'; + $file = File::create([ + 'filename' => $filename, + 'status' => 0, + ]); + + $entity = EntityTest::create([ + 'field_test_file' => [ + 'entity' => $file, + ], + ]); + + $errors = $entity->validate(); + $this->assertEqual(1, count($errors)); + $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'file', '%label' => $filename])); + $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_file.0.entity'); + + // Set the file as permanent and try again. + $file->setPermanent(); + $errors = $entity->validate(); + $this->assertEqual(0, count($errors)); + } + +} diff --git a/core/modules/field/src/Tests/FieldAttachOtherTest.php b/core/modules/field/src/Tests/FieldAttachOtherTest.php new file mode 100644 index 0000000..6c67793 --- /dev/null +++ b/core/modules/field/src/Tests/FieldAttachOtherTest.php @@ -0,0 +1,386 @@ +container->get('router.builder')->rebuild(); + $this->installEntitySchema('entity_test_rev'); + $this->createFieldWithStorage(); + } + + /** + * Test rendering fields with EntityDisplay build(). + */ + function testEntityDisplayBuild() { + $this->createFieldWithStorage('_2'); + + $entity_type = 'entity_test'; + $entity_init = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(); + + // Populate values to be displayed. + $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage->getCardinality()); + $entity_init->{$this->fieldTestData->field_name}->setValue($values); + $values_2 = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); + $entity_init->{$this->fieldTestData->field_name_2}->setValue($values_2); + + // Simple formatter, label displayed. + $entity = clone($entity_init); + $display = entity_get_display($entity_type, $entity->bundle(), 'full'); + + $formatter_setting = $this->randomMachineName(); + $display_options = array( + 'label' => 'above', + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $formatter_setting, + ), + ); + $display->setComponent($this->fieldTestData->field_name, $display_options); + + $formatter_setting_2 = $this->randomMachineName(); + $display_options_2 = array( + 'label' => 'above', + 'type' => 'field_test_default', + 'settings' => array( + 'test_formatter_setting' => $formatter_setting_2, + ), + ); + $display->setComponent($this->fieldTestData->field_name_2, $display_options_2); + + // View all fields. + $content = $display->build($entity); + $this->render($content); + $this->assertRaw($this->fieldTestData->field->getLabel(), "First field's label is displayed."); + foreach ($values as $delta => $value) { + $this->assertRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); + } + $this->assertRaw($this->fieldTestData->field_2->getLabel(), "Second field's label is displayed."); + foreach ($values_2 as $delta => $value) { + $this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); + } + + // Label hidden. + $entity = clone($entity_init); + $display_options['label'] = 'hidden'; + $display->setComponent($this->fieldTestData->field_name, $display_options); + $content = $display->build($entity); + $this->render($content); + $this->assertNoRaw($this->fieldTestData->field->getLabel(), "Hidden label: label is not displayed."); + + // Field hidden. + $entity = clone($entity_init); + $display->removeComponent($this->fieldTestData->field_name); + $content = $display->build($entity); + $this->render($content); + $this->assertNoRaw($this->fieldTestData->field->getLabel(), "Hidden field: label is not displayed."); + foreach ($values as $delta => $value) { + $this->assertNoRaw("$formatter_setting|{$value['value']}", "Hidden field: value $delta is not displayed."); + } + + // Multiple formatter. + $entity = clone($entity_init); + $formatter_setting = $this->randomMachineName(); + $display->setComponent($this->fieldTestData->field_name, array( + 'label' => 'above', + 'type' => 'field_test_multiple', + 'settings' => array( + 'test_formatter_setting_multiple' => $formatter_setting, + ), + )); + $content = $display->build($entity); + $this->render($content); + $expected_output = $formatter_setting; + foreach ($values as $delta => $value) { + $expected_output .= "|$delta:{$value['value']}"; + } + $this->assertRaw($expected_output, "Multiple formatter: all values are displayed, formatter settings are applied."); + + // Test a formatter that uses hook_field_formatter_prepare_view(). + $entity = clone($entity_init); + $formatter_setting = $this->randomMachineName(); + $display->setComponent($this->fieldTestData->field_name, array( + 'label' => 'above', + 'type' => 'field_test_with_prepare_view', + 'settings' => array( + 'test_formatter_setting_additional' => $formatter_setting, + ), + )); + $content = $display->build($entity); + $this->render($content); + foreach ($values as $delta => $value) { + $expected = $formatter_setting . '|' . $value['value'] . '|' . ($value['value'] + 1); + $this->assertRaw($expected, "Value $delta is displayed, formatter settings are applied."); + } + + // TODO: + // - check display order with several fields + } + + /** + * Tests rendering fields with EntityDisplay::buildMultiple(). + */ + function testEntityDisplayViewMultiple() { + // Use a formatter that has a prepareView() step. + $display = entity_get_display('entity_test', 'entity_test', 'full') + ->setComponent($this->fieldTestData->field_name, array( + 'type' => 'field_test_with_prepare_view', + )); + + // Create two entities. + $entity1 = EntityTest::create(array('id' => 1, 'type' => 'entity_test')); + $entity1->{$this->fieldTestData->field_name}->setValue($this->_generateTestFieldValues(1)); + $entity2 = EntityTest::create(array('id' => 2, 'type' => 'entity_test')); + $entity2->{$this->fieldTestData->field_name}->setValue($this->_generateTestFieldValues(1)); + + // Run buildMultiple(), and check that the entities come out as expected. + $display->buildMultiple(array($entity1, $entity2)); + $item1 = $entity1->{$this->fieldTestData->field_name}[0]; + $this->assertEqual($item1->additional_formatter_value, $item1->value + 1, 'Entity 1 ran through the prepareView() formatter method.'); + $item2 = $entity2->{$this->fieldTestData->field_name}[0]; + $this->assertEqual($item2->additional_formatter_value, $item2->value + 1, 'Entity 2 ran through the prepareView() formatter method.'); + } + + /** + * Test entity cache. + * + * Complements unit test coverage in + * \Drupal\Tests\Core\Entity\Sql\SqlContentEntityStorageTest. + */ + function testEntityCache() { + // Initialize random values and a test entity. + $entity_init = EntityTest::create(array('type' => $this->fieldTestData->field->getTargetBundle())); + $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage->getCardinality()); + + // Non-cacheable entity type. + $entity_type = 'entity_test'; + $cid = "values:$entity_type:" . $entity_init->id(); + + // Check that no initial cache entry is present. + $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Non-cached: no initial cache entry'); + + // Save, and check that no cache entry is present. + $entity = clone($entity_init); + $entity->{$this->fieldTestData->field_name}->setValue($values); + $entity = $this->entitySaveReload($entity); + $cid = "values:$entity_type:" . $entity->id(); + $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Non-cached: no cache entry on insert and load'); + + // Cacheable entity type. + $entity_type = 'entity_test_rev'; + $this->createFieldWithStorage('_2', $entity_type); + + $entity_init = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array( + 'type' => $entity_type, + )); + + // Check that no initial cache entry is present. + $cid = "values:$entity_type:" . $entity->id(); + $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no initial cache entry'); + + // Save, and check that no cache entry is present. + $entity = clone($entity_init); + $entity->{$this->fieldTestData->field_name_2} = $values; + $entity->save(); + $cid = "values:$entity_type:" . $entity->id(); + + $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry on insert'); + // Load, and check that a cache entry is present with the expected values. + $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); + $controller->resetCache(); + $cached_entity = $controller->load($entity->id()); + $cache = \Drupal::cache('entity')->get($cid); + $this->assertEqual($cache->data, $cached_entity, 'Cached: correct cache entry on load'); + + // Update with different values, and check that the cache entry is wiped. + $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); + $entity->{$this->fieldTestData->field_name_2} = $values; + $entity->save(); + $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry on update'); + + // Load, and check that a cache entry is present with the expected values. + $controller->resetCache(); + $cached_entity = $controller->load($entity->id()); + $cache = \Drupal::cache('entity')->get($cid); + $this->assertEqual($cache->data, $cached_entity, 'Cached: correct cache entry on load'); + + // Create a new revision, and check that the cache entry is wiped. + $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); + $entity->{$this->fieldTestData->field_name_2} = $values; + $entity->setNewRevision(); + $entity->save(); + $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry on new revision creation'); + + // Load, and check that a cache entry is present with the expected values. + $controller->resetCache(); + $cached_entity = $controller->load($entity->id()); + $cache = \Drupal::cache('entity')->get($cid); + $this->assertEqual($cache->data, $cached_entity, 'Cached: correct cache entry on load'); + + // Delete, and check that the cache entry is wiped. + $entity->delete(); + $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry after delete'); + } + + /** + * Tests \Drupal\Core\Entity\Display\EntityFormDisplayInterface::buildForm(). + * + * This could be much more thorough, but it does verify that the correct + * widgets show up. + */ + function testEntityFormDisplayBuildForm() { + $this->createFieldWithStorage('_2'); + + $entity_type = 'entity_test'; + $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $this->fieldTestData->field->getTargetBundle())); + + // Test generating widgets for all fields. + $display = entity_get_form_display($entity_type, $this->fieldTestData->field->getTargetBundle(), 'default'); + $form = array(); + $form_state = new FormState(); + $display->buildForm($entity, $form, $form_state); + + $this->assertEqual($form[$this->fieldTestData->field_name]['widget']['#title'], $this->fieldTestData->field->getLabel(), "First field's form title is {$this->fieldTestData->field->getLabel()}"); + $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget']['#title'], $this->fieldTestData->field_2->getLabel(), "Second field's form title is {$this->fieldTestData->field_2->getLabel()}"); + for ($delta = 0; $delta < $this->fieldTestData->field_storage->getCardinality(); $delta++) { + // field_test_widget uses 'textfield' + $this->assertEqual($form[$this->fieldTestData->field_name]['widget'][$delta]['value']['#type'], 'textfield', "First field's form delta $delta widget is textfield"); + } + for ($delta = 0; $delta < $this->fieldTestData->field_storage_2->getCardinality(); $delta++) { + // field_test_widget uses 'textfield' + $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget'][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield"); + } + + // Test generating widgets for all fields. + $display = entity_get_form_display($entity_type, $this->fieldTestData->field->getTargetBundle(), 'default'); + foreach ($display->getComponents() as $name => $options) { + if ($name != $this->fieldTestData->field_name_2) { + $display->removeComponent($name); + } + } + $form = array(); + $form_state = new FormState(); + $display->buildForm($entity, $form, $form_state); + + $this->assertFalse(isset($form[$this->fieldTestData->field_name]), 'The first field does not exist in the form'); + $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget']['#title'], $this->fieldTestData->field_2->getLabel(), "Second field's form title is {$this->fieldTestData->field_2->getLabel()}"); + for ($delta = 0; $delta < $this->fieldTestData->field_storage_2->getCardinality(); $delta++) { + // field_test_widget uses 'textfield' + $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget'][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield"); + } + } + + /** + * Tests \Drupal\Core\Entity\Display\EntityFormDisplayInterface::extractFormValues(). + */ + function testEntityFormDisplayExtractFormValues() { + $this->createFieldWithStorage('_2'); + + $entity_type = 'entity_test'; + $entity_init = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('id' => 1, 'revision_id' => 1, 'type' => $this->fieldTestData->field->getTargetBundle())); + + // Build the form for all fields. + $display = entity_get_form_display($entity_type, $this->fieldTestData->field->getTargetBundle(), 'default'); + $form = array(); + $form_state = new FormState(); + $display->buildForm($entity_init, $form, $form_state); + + // Simulate incoming values. + // First field. + $values = array(); + $weights = array(); + for ($delta = 0; $delta < $this->fieldTestData->field_storage->getCardinality(); $delta++) { + $values[$delta]['value'] = mt_rand(1, 127); + // Assign random weight. + do { + $weight = mt_rand(0, $this->fieldTestData->field_storage->getCardinality()); + } while (in_array($weight, $weights)); + $weights[$delta] = $weight; + $values[$delta]['_weight'] = $weight; + } + // Leave an empty value. 'field_test' fields are empty if empty(). + $values[1]['value'] = 0; + // Second field. + $values_2 = array(); + $weights_2 = array(); + for ($delta = 0; $delta < $this->fieldTestData->field_storage_2->getCardinality(); $delta++) { + $values_2[$delta]['value'] = mt_rand(1, 127); + // Assign random weight. + do { + $weight = mt_rand(0, $this->fieldTestData->field_storage_2->getCardinality()); + } while (in_array($weight, $weights_2)); + $weights_2[$delta] = $weight; + $values_2[$delta]['_weight'] = $weight; + } + // Leave an empty value. 'field_test' fields are empty if empty(). + $values_2[1]['value'] = 0; + + // Pretend the form has been built. + $form_state->setFormObject(\Drupal::entityManager()->getFormObject($entity_type, 'default')); + \Drupal::formBuilder()->prepareForm('field_test_entity_form', $form, $form_state); + \Drupal::formBuilder()->processForm('field_test_entity_form', $form, $form_state); + $form_state->setValue($this->fieldTestData->field_name, $values); + $form_state->setValue($this->fieldTestData->field_name_2, $values_2); + + // Extract values for all fields. + $entity = clone($entity_init); + $display->extractFormValues($entity, $form, $form_state); + + asort($weights); + asort($weights_2); + $expected_values = array(); + $expected_values_2 = array(); + foreach ($weights as $key => $value) { + if ($key != 1) { + $expected_values[] = array('value' => $values[$key]['value']); + } + } + $this->assertIdentical($entity->{$this->fieldTestData->field_name}->getValue(), $expected_values, 'Submit filters empty values'); + foreach ($weights_2 as $key => $value) { + if ($key != 1) { + $expected_values_2[] = array('value' => $values_2[$key]['value']); + } + } + $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values'); + + // Call EntityFormDisplayInterface::extractFormValues() for a single field (the second field). + foreach ($display->getComponents() as $name => $options) { + if ($name != $this->fieldTestData->field_name_2) { + $display->removeComponent($name); + } + } + $entity = clone($entity_init); + $display->extractFormValues($entity, $form, $form_state); + $expected_values_2 = array(); + foreach ($weights_2 as $key => $value) { + if ($key != 1) { + $expected_values_2[] = array('value' => $values_2[$key]['value']); + } + } + $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'The first field is empty in the entity object'); + $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values'); + } + +} diff --git a/core/modules/field/src/Tests/FieldAttachStorageTest.php b/core/modules/field/src/Tests/FieldAttachStorageTest.php new file mode 100644 index 0000000..596eb13 --- /dev/null +++ b/core/modules/field/src/Tests/FieldAttachStorageTest.php @@ -0,0 +1,381 @@ +installEntitySchema('entity_test_rev'); + } + + /** + * Check field values insert, update and load. + * + * Works independently of the underlying field storage backend. Inserts or + * updates random field data and then loads and verifies the data. + */ + function testFieldAttachSaveLoad() { + $entity_type = 'entity_test_rev'; + $this->createFieldWithStorage('', $entity_type); + $cardinality = $this->fieldTestData->field_storage->getCardinality(); + + // TODO : test empty values filtering and "compression" (store consecutive deltas). + // Preparation: create three revisions and store them in $revision array. + $values = array(); + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(); + for ($revision_id = 0; $revision_id < 3; $revision_id++) { + // Note: we try to insert one extra value. + $current_values = $this->_generateTestFieldValues($cardinality + 1); + $entity->{$this->fieldTestData->field_name}->setValue($current_values); + $entity->setNewRevision(); + $entity->save(); + $entity_id = $entity->id(); + $current_revision = $entity->getRevisionId(); + $values[$current_revision] = $current_values; + } + + $storage = $this->container->get('entity.manager')->getStorage($entity_type); + $storage->resetCache(); + $entity = $storage->load($entity_id); + // Confirm current revision loads the correct data. + // Number of values per field loaded equals the field cardinality. + $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, 'Current revision: expected number of values'); + for ($delta = 0; $delta < $cardinality; $delta++) { + // The field value loaded matches the one inserted or updated. + $this->assertEqual($entity->{$this->fieldTestData->field_name}[$delta]->value , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta))); + } + + // Confirm each revision loads the correct data. + foreach (array_keys($values) as $revision_id) { + $entity = $storage->loadRevision($revision_id); + // Number of values per field loaded equals the field cardinality. + $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id))); + for ($delta = 0; $delta < $cardinality; $delta++) { + // The field value loaded matches the one inserted or updated. + $this->assertEqual($entity->{$this->fieldTestData->field_name}[$delta]->value, $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta))); + } + } + } + + /** + * Test the 'multiple' load feature. + */ + function testFieldAttachLoadMultiple() { + $entity_type = 'entity_test_rev'; + + // Define 2 bundles. + $bundles = array( + 1 => 'test_bundle_1', + 2 => 'test_bundle_2', + ); + entity_test_create_bundle($bundles[1]); + entity_test_create_bundle($bundles[2]); + // Define 3 fields: + // - field_1 is in bundle_1 and bundle_2, + // - field_2 is in bundle_1, + // - field_3 is in bundle_2. + $field_bundles_map = array( + 1 => array(1, 2), + 2 => array(1), + 3 => array(2), + ); + for ($i = 1; $i <= 3; $i++) { + $field_names[$i] = 'field_' . $i; + $field_storage = FieldStorageConfig::create(array( + 'field_name' => $field_names[$i], + 'entity_type' => $entity_type, + 'type' => 'test_field', + )); + $field_storage->save(); + $field_ids[$i] = $field_storage->uuid(); + foreach ($field_bundles_map[$i] as $bundle) { + FieldConfig::create([ + 'field_name' => $field_names[$i], + 'entity_type' => $entity_type, + 'bundle' => $bundles[$bundle], + ])->save(); + } + } + + // Create one test entity per bundle, with random values. + foreach ($bundles as $index => $bundle) { + $entities[$index] = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('id' => $index, 'revision_id' => $index, 'type' => $bundle)); + $entity = clone($entities[$index]); + foreach ($field_names as $field_name) { + if (!$entity->hasField($field_name)) { + continue; + } + $values[$index][$field_name] = mt_rand(1, 127); + $entity->$field_name->setValue(array('value' => $values[$index][$field_name])); + } + $entity->enforceIsnew(); + $entity->save(); + } + + // Check that a single load correctly loads field values for both entities. + $controller = \Drupal::entityManager()->getStorage($entity->getEntityTypeId()); + $controller->resetCache(); + $entities = $controller->loadMultiple(); + foreach ($entities as $index => $entity) { + foreach ($field_names as $field_name) { + if (!$entity->hasField($field_name)) { + continue; + } + // The field value loaded matches the one inserted. + $this->assertEqual($entity->{$field_name}->value, $values[$index][$field_name], format_string('Entity %index: expected value was found.', array('%index' => $index))); + } + } + } + + /** + * Tests insert and update with empty or NULL fields. + */ + function testFieldAttachSaveEmptyData() { + $entity_type = 'entity_test'; + $this->createFieldWithStorage('', $entity_type); + + $entity_init = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('id' => 1)); + + // Insert: Field is NULL. + $entity = clone $entity_init; + $entity->{$this->fieldTestData->field_name} = NULL; + $entity->enforceIsNew(); + $entity = $this->entitySaveReload($entity); + $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Insert: NULL field results in no value saved'); + + // All saves after this point should be updates, not inserts. + $entity_init->enforceIsNew(FALSE); + + // Add some real data. + $entity = clone($entity_init); + $values = $this->_generateTestFieldValues(1); + $entity->{$this->fieldTestData->field_name} = $values; + $entity = $this->entitySaveReload($entity); + $this->assertEqual($entity->{$this->fieldTestData->field_name}->getValue(), $values, 'Field data saved'); + + // Update: Field is NULL. Data should be wiped. + $entity = clone($entity_init); + $entity->{$this->fieldTestData->field_name} = NULL; + $entity = $this->entitySaveReload($entity); + $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Update: NULL field removes existing values'); + + // Re-add some data. + $entity = clone($entity_init); + $values = $this->_generateTestFieldValues(1); + $entity->{$this->fieldTestData->field_name} = $values; + $entity = $this->entitySaveReload($entity); + $this->assertEqual($entity->{$this->fieldTestData->field_name}->getValue(), $values, 'Field data saved'); + + // Update: Field is empty array. Data should be wiped. + $entity = clone($entity_init); + $entity->{$this->fieldTestData->field_name} = array(); + $entity = $this->entitySaveReload($entity); + $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Update: empty array removes existing values'); + } + + /** + * Test insert with empty or NULL fields, with default value. + */ + function testFieldAttachSaveEmptyDataDefaultValue() { + $entity_type = 'entity_test_rev'; + $this->createFieldWithStorage('', $entity_type); + + // Add a default value function. + $this->fieldTestData->field->set('default_value_callback', 'field_test_default_value'); + $this->fieldTestData->field->save(); + + // Verify that fields are populated with default values. + $entity_init = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('id' => 1, 'revision_id' => 1)); + $default = field_test_default_value($entity_init, $this->fieldTestData->field); + $this->assertEqual($entity_init->{$this->fieldTestData->field_name}->getValue(), $default, 'Default field value correctly populated.'); + + // Insert: Field is NULL. + $entity = clone($entity_init); + $entity->{$this->fieldTestData->field_name} = NULL; + $entity->enforceIsNew(); + $entity = $this->entitySaveReload($entity); + $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Insert: NULL field results in no value saved'); + + // Verify that prepopulated field values are not overwritten by defaults. + $value = array(array('value' => $default[0]['value'] - mt_rand(1, 127))); + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('type' => $entity_init->bundle(), $this->fieldTestData->field_name => $value)); + $this->assertEqual($entity->{$this->fieldTestData->field_name}->getValue(), $value, 'Prepopulated field value correctly maintained.'); + } + + /** + * Test entity deletion. + */ + function testFieldAttachDelete() { + $entity_type = 'entity_test_rev'; + $this->createFieldWithStorage('', $entity_type); + $cardinality = $this->fieldTestData->field_storage->getCardinality(); + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('type' => $this->fieldTestData->field->getTargetBundle())); + $vids = array(); + + // Create revision 0 + $values = $this->_generateTestFieldValues($cardinality); + $entity->{$this->fieldTestData->field_name} = $values; + $entity->save(); + $vids[] = $entity->getRevisionId(); + + // Create revision 1 + $entity->setNewRevision(); + $entity->save(); + $vids[] = $entity->getRevisionId(); + + // Create revision 2 + $entity->setNewRevision(); + $entity->save(); + $vids[] = $entity->getRevisionId(); + $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); + $controller->resetCache(); + + // Confirm each revision loads + foreach ($vids as $vid) { + $revision = $controller->loadRevision($vid); + $this->assertEqual(count($revision->{$this->fieldTestData->field_name}), $cardinality, "The test entity revision $vid has $cardinality values."); + } + + // Delete revision 1, confirm the other two still load. + $controller->deleteRevision($vids[1]); + $controller->resetCache(); + foreach (array(0, 2) as $key) { + $vid = $vids[$key]; + $revision = $controller->loadRevision($vid); + $this->assertEqual(count($revision->{$this->fieldTestData->field_name}), $cardinality, "The test entity revision $vid has $cardinality values."); + } + + // Confirm the current revision still loads + $controller->resetCache(); + $current = $controller->load($entity->id()); + $this->assertEqual(count($current->{$this->fieldTestData->field_name}), $cardinality, "The test entity current revision has $cardinality values."); + + // Delete all field data, confirm nothing loads + $entity->delete(); + $controller->resetCache(); + foreach (array(0, 1, 2) as $vid) { + $revision = $controller->loadRevision($vid); + $this->assertFalse($revision); + } + $this->assertFalse($controller->load($entity->id())); + } + + /** + * Test entity_bundle_create(). + */ + function testEntityCreateBundle() { + $entity_type = 'entity_test_rev'; + $this->createFieldWithStorage('', $entity_type); + $cardinality = $this->fieldTestData->field_storage->getCardinality(); + + // Create a new bundle. + $new_bundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName()); + entity_test_create_bundle($new_bundle, NULL, $entity_type); + + // Add a field to that bundle. + $this->fieldTestData->field_definition['bundle'] = $new_bundle; + FieldConfig::create($this->fieldTestData->field_definition)->save(); + + // Save an entity with data in the field. + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('type' => $this->fieldTestData->field->getTargetBundle())); + $values = $this->_generateTestFieldValues($cardinality); + $entity->{$this->fieldTestData->field_name} = $values; + + // Verify the field data is present on load. + $entity = $this->entitySaveReload($entity); + $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, "Data is retrieved for the new bundle"); + } + + /** + * Test entity_bundle_delete(). + */ + function testEntityDeleteBundle() { + $entity_type = 'entity_test_rev'; + $this->createFieldWithStorage('', $entity_type); + + // Create a new bundle. + $new_bundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName()); + entity_test_create_bundle($new_bundle, NULL, $entity_type); + + // Add a field to that bundle. + $this->fieldTestData->field_definition['bundle'] = $new_bundle; + FieldConfig::create($this->fieldTestData->field_definition)->save(); + + // Create a second field for the test bundle + $field_name = Unicode::strtolower($this->randomMachineName() . '_field_name'); + $field_storage = array( + 'field_name' => $field_name, + 'entity_type' => $entity_type, + 'type' => 'test_field', + 'cardinality' => 1, + ); + FieldStorageConfig::create($field_storage)->save(); + $field = array( + 'field_name' => $field_name, + 'entity_type' => $entity_type, + 'bundle' => $this->fieldTestData->field->getTargetBundle(), + 'label' => $this->randomMachineName() . '_label', + 'description' => $this->randomMachineName() . '_description', + 'weight' => mt_rand(0, 127), + ); + FieldConfig::create($field)->save(); + + // Save an entity with data for both fields + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('type' => $this->fieldTestData->field->getTargetBundle())); + $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage->getCardinality()); + $entity->{$this->fieldTestData->field_name} = $values; + $entity->{$field_name} = $this->_generateTestFieldValues(1); + $entity = $this->entitySaveReload($entity); + + // Verify the fields are present on load + $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), 4, 'First field got loaded'); + $this->assertEqual(count($entity->{$field_name}), 1, 'Second field got loaded'); + + // Delete the bundle. + entity_test_delete_bundle($this->fieldTestData->field->getTargetBundle(), $entity_type); + + // Verify no data gets loaded + $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); + $controller->resetCache(); + $entity= $controller->load($entity->id()); + + $this->assertTrue(empty($entity->{$this->fieldTestData->field_name}), 'No data for first field'); + $this->assertTrue(empty($entity->{$field_name}), 'No data for second field'); + + // Verify that the fields are gone. + $this->assertFalse(FieldConfig::load('entity_test.' . $this->fieldTestData->field->getTargetBundle() . '.' . $this->fieldTestData->field_name), "First field is deleted"); + $this->assertFalse(FieldConfig::load('entity_test.' . $field['bundle']. '.' . $field_name), "Second field is deleted"); + } + +} diff --git a/core/modules/field/src/Tests/FieldCrudTest.php b/core/modules/field/src/Tests/FieldCrudTest.php new file mode 100644 index 0000000..72738ad --- /dev/null +++ b/core/modules/field/src/Tests/FieldCrudTest.php @@ -0,0 +1,308 @@ +fieldStorageDefinition = array( + 'field_name' => Unicode::strtolower($this->randomMachineName()), + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + $this->fieldStorage = FieldStorageConfig::create($this->fieldStorageDefinition); + $this->fieldStorage->save(); + $this->fieldDefinition = array( + 'field_name' => $this->fieldStorage->getName(), + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + ); + } + + // TODO : test creation with + // - a full fledged $field structure, check that all the values are there + // - a minimal $field structure, check all default values are set + // defer actual $field comparison to a helper function, used for the two cases above, + // and for testUpdateField + + /** + * Test the creation of a field. + */ + function testCreateField() { + // Set a state flag so that field_test.module knows to add an in-memory + // constraint for this field. + \Drupal::state()->set('field_test_add_constraint', $this->fieldStorage->getName()); + /** @var \Drupal\Core\Field\FieldConfigInterface $field */ + $field = FieldConfig::create($this->fieldDefinition); + $field->save(); + + $field = FieldConfig::load($field->id()); + $this->assertTrue($field->getSetting('field_setting_from_config_data')); + $this->assertNull($field->getSetting('config_data_from_field_setting')); + + // Read the configuration. Check against raw configuration data rather than + // the loaded ConfigEntity, to be sure we check that the defaults are + // applied on write. + $config = $this->config('field.field.' . $field->id())->get(); + $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); + + $this->assertTrue($config['settings']['config_data_from_field_setting']); + $this->assertTrue(!isset($config['settings']['field_setting_from_config_data'])); + + // Since we are working with raw configuration, this needs to be unset + // manually. + // @see Drupal\field_test\Plugin\Field\FieldType\TestItem::fieldSettingsFromConfigData() + unset($config['settings']['config_data_from_field_setting']); + + // Check that default values are set. + $this->assertEqual($config['required'], FALSE, 'Required defaults to false.'); + $this->assertIdentical($config['label'], $this->fieldDefinition['field_name'], 'Label defaults to field name.'); + $this->assertIdentical($config['description'], '', 'Description defaults to empty string.'); + + // Check that default settings are set. + $this->assertEqual($config['settings'], $field_type_manager->getDefaultFieldSettings($this->fieldStorageDefinition['type']) , 'Default field settings have been written.'); + + // Check that the denormalized 'field_type' was properly written. + $this->assertEqual($config['field_type'], $this->fieldStorageDefinition['type']); + + // Test constraints are applied. A Range constraint is added dynamically to + // limit the field to values between 0 and 32. + // @see field_test_entity_bundle_field_info_alter() + $this->doFieldValidationTests(); + + // Test FieldConfigBase::setPropertyConstraints(). + \Drupal::state()->set('field_test_set_constraint', $this->fieldStorage->getName()); + \Drupal::state()->set('field_test_add_constraint', FALSE); + \Drupal::entityManager()->clearCachedFieldDefinitions(); + $this->doFieldValidationTests(); + + // Guarantee that the field/bundle combination is unique. + try { + FieldConfig::create($this->fieldDefinition)->save(); + $this->fail(t('Cannot create two fields with the same field / bundle combination.')); + } + catch (EntityStorageException $e) { + $this->pass(t('Cannot create two fields with the same field / bundle combination.')); + } + + // Check that the specified field exists. + try { + $this->fieldDefinition['field_name'] = $this->randomMachineName(); + FieldConfig::create($this->fieldDefinition)->save(); + $this->fail(t('Cannot create a field with a non-existing storage.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot create a field with a non-existing storage.')); + } + + // TODO: test other failures. + } + + /** + * Test creating a field with custom storage set. + */ + public function testCreateFieldCustomStorage() { + $field_name = Unicode::strtolower($this->randomMachineName()); + \Drupal::state()->set('field_test_custom_storage', $field_name); + + $field_storage = FieldStorageConfig::create([ + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'custom_storage' => TRUE, + ]); + $field_storage->save(); + + $field = FieldConfig::create([ + 'field_name' => $field_storage->getName(), + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + ]); + $field->save(); + + \Drupal::entityManager()->clearCachedFieldDefinitions(); + + // Check that no table has been created for the field. + $this->assertFalse(\Drupal::database()->schema()->tableExists('entity_test__' . $field_storage->getName())); + + // Save an entity with a value in the custom storage field and verify no + // data is retrieved on load. + $entity = EntityTest::create(['name' => $this->randomString(), $field_name => 'Test value']); + $this->assertIdentical('Test value', $entity->{$field_name}->value, 'The test value is set on the field.'); + + $entity->save(); + $entity = EntityTest::load($entity->id()); + + $this->assertNull($entity->{$field_name}->value, 'The loaded entity field value is NULL.'); + } + + /** + * Test reading back a field definition. + */ + function testReadField() { + FieldConfig::create($this->fieldDefinition)->save(); + + // Read the field back. + $field = FieldConfig::load('entity_test.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); + $this->assertTrue($this->fieldDefinition['field_name'] == $field->getName(), 'The field was properly read.'); + $this->assertTrue($this->fieldDefinition['entity_type'] == $field->getTargetEntityTypeId(), 'The field was properly read.'); + $this->assertTrue($this->fieldDefinition['bundle'] == $field->getTargetBundle(), 'The field was properly read.'); + } + + /** + * Test the update of a field. + */ + function testUpdateField() { + FieldConfig::create($this->fieldDefinition)->save(); + + // Check that basic changes are saved. + $field = FieldConfig::load('entity_test.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); + $field->setRequired(!$field->isRequired()); + $field->setLabel($this->randomMachineName()); + $field->set('description', $this->randomMachineName()); + $field->setSetting('test_field_setting', $this->randomMachineName()); + $field->save(); + + $field_new = FieldConfig::load('entity_test.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); + $this->assertEqual($field->isRequired(), $field_new->isRequired(), '"required" change is saved'); + $this->assertEqual($field->getLabel(), $field_new->getLabel(), '"label" change is saved'); + $this->assertEqual($field->getDescription(), $field_new->getDescription(), '"description" change is saved'); + + // TODO: test failures. + } + + /** + * Test the deletion of a field. + */ + function testDeleteField() { + // TODO: Test deletion of the data stored in the field also. + // Need to check that data for a 'deleted' field / storage doesn't get loaded + // Need to check data marked deleted is cleaned on cron (not implemented yet...) + + // Create two fields for the same field storage so we can test that only one + // is deleted. + FieldConfig::create($this->fieldDefinition)->save(); + $another_field_definition = $this->fieldDefinition; + $another_field_definition['bundle'] .= '_another_bundle'; + entity_test_create_bundle($another_field_definition['bundle']); + FieldConfig::create($another_field_definition)->save(); + + // Test that the first field is not deleted, and then delete it. + $field = current(entity_load_multiple_by_properties('field_config', array('entity_type' => 'entity_test', 'field_name' => $this->fieldDefinition['field_name'], 'bundle' => $this->fieldDefinition['bundle'], 'include_deleted' => TRUE))); + $this->assertTrue(!empty($field) && empty($field->deleted), 'A new field is not marked for deletion.'); + $field->delete(); + + // Make sure the field is marked as deleted when it is specifically loaded. + $field = current(entity_load_multiple_by_properties('field_config', array('entity_type' => 'entity_test', 'field_name' => $this->fieldDefinition['field_name'], 'bundle' => $this->fieldDefinition['bundle'], 'include_deleted' => TRUE))); + $this->assertTrue($field->isDeleted(), 'A deleted field is marked for deletion.'); + + // Try to load the field normally and make sure it does not show up. + $field = FieldConfig::load('entity_test.' . '.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); + $this->assertTrue(empty($field), 'A deleted field is not loaded by default.'); + + // Make sure the other field is not deleted. + $another_field = FieldConfig::load('entity_test.' . $another_field_definition['bundle'] . '.' . $another_field_definition['field_name']); + $this->assertTrue(!empty($another_field) && empty($another_field->deleted), 'A non-deleted field is not marked for deletion.'); + } + + /** + * Tests the cross deletion behavior between field storages and fields. + */ + function testDeleteFieldCrossDeletion() { + $field_definition_2 = $this->fieldDefinition; + $field_definition_2['bundle'] .= '_another_bundle'; + entity_test_create_bundle($field_definition_2['bundle']); + + // Check that deletion of a field storage deletes its fields. + $field_storage = $this->fieldStorage; + FieldConfig::create($this->fieldDefinition)->save(); + FieldConfig::create($field_definition_2)->save(); + $field_storage->delete(); + $this->assertFalse(FieldConfig::loadByName('entity_test', $this->fieldDefinition['bundle'], $field_storage->getName())); + $this->assertFalse(FieldConfig::loadByName('entity_test', $field_definition_2['bundle'], $field_storage->getName())); + + // Check that deletion of the last field deletes the storage. + $field_storage = FieldStorageConfig::create($this->fieldStorageDefinition); + $field_storage->save(); + $field = FieldConfig::create($this->fieldDefinition); + $field->save(); + $field_2 = FieldConfig::create($field_definition_2); + $field_2->save(); + $field->delete(); + $this->assertTrue(FieldStorageConfig::loadByName('entity_test', $field_storage->getName())); + $field_2->delete(); + $this->assertFalse(FieldStorageConfig::loadByName('entity_test', $field_storage->getName())); + + // Check that deletion of all fields using a storage simultaneously deletes + // the storage. + $field_storage = FieldStorageConfig::create($this->fieldStorageDefinition); + $field_storage->save(); + $field = FieldConfig::create($this->fieldDefinition); + $field->save(); + $field_2 = FieldConfig::create($field_definition_2); + $field_2->save(); + $this->container->get('entity.manager')->getStorage('field_config')->delete(array($field, $field_2)); + $this->assertFalse(FieldStorageConfig::loadByName('entity_test', $field_storage->getName())); + } + + /** + * Tests configurable field validation. + * + * @see field_test_entity_bundle_field_info_alter() + */ + protected function doFieldValidationTests() { + $entity = EntityTest::create(); + $entity->set($this->fieldStorage->getName(), 1); + $violations = $entity->validate(); + $this->assertEqual(count($violations), 0, 'No violations found when in-range value passed.'); + + $entity->set($this->fieldStorage->getName(), 33); + $violations = $entity->validate(); + $this->assertEqual(count($violations), 1, 'Violations found when using value outside the range.'); + $this->assertEqual($violations[0]->getPropertyPath(), $this->fieldStorage->getName() . '.0.value'); + $this->assertEqual($violations[0]->getMessage(), t('This value should be %limit or less.', [ + '%limit' => 32, + ])); + } + +} diff --git a/core/modules/field/src/Tests/FieldDataCountTest.php b/core/modules/field/src/Tests/FieldDataCountTest.php new file mode 100644 index 0000000..c146289 --- /dev/null +++ b/core/modules/field/src/Tests/FieldDataCountTest.php @@ -0,0 +1,186 @@ +installEntitySchema('entity_test_rev'); + $this->storage = \Drupal::entityManager()->getStorage('entity_test'); + $this->storageRev = \Drupal::entityManager()->getStorage('entity_test_rev'); + $this->storageUser = \Drupal::entityManager()->getStorage('user'); + } + + /** + * Tests entityCount() and hadData() methods. + */ + public function testEntityCountAndHasData() { + // Create a field with a cardinality of 2 to show that we are counting + // entities and not rows in a table. + /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */ + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_int', + 'entity_type' => 'entity_test', + 'type' => 'integer', + 'cardinality' => 2, + )); + $field_storage->save(); + FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => 'entity_test', + ])->save(); + + $this->assertIdentical($field_storage->hasdata(), FALSE, 'There are no entities with field data.'); + $this->assertIdentical($this->storage->countFieldData($field_storage), 0, 'There are 0 entities with field data.'); + + // Create 1 entity without the field. + $entity = EntityTest::create(); + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + $this->assertIdentical($field_storage->hasdata(), FALSE, 'There are no entities with field data.'); + $this->assertIdentical($this->storage->countFieldData($field_storage), 0, 'There are 0 entities with field data.'); + + // Create 12 entities to ensure that the purging works as expected. + for ($i=0; $i < 12; $i++) { + $entity = EntityTest::create(); + $entity->field_int[] = mt_rand(1, 99); + $entity->field_int[] = mt_rand(1, 99); + $entity->name[] = $this->randomMachineName(); + $entity->save(); + } + + $storage = \Drupal::entityManager()->getStorage('entity_test'); + if ($storage instanceof SqlContentEntityStorage) { + // Count the actual number of rows in the field table. + $table_mapping = $storage->getTableMapping(); + $field_table_name = $table_mapping->getDedicatedDataTableName($field_storage); + $result = db_select($field_table_name, 't') + ->fields('t') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertEqual($result, 24, 'The field table has 24 rows.'); + } + + $this->assertIdentical($field_storage->hasdata(), TRUE, 'There are entities with field data.'); + $this->assertEqual($this->storage->countFieldData($field_storage), 12, 'There are 12 entities with field data.'); + + // Ensure the methods work on deleted fields. + $field_storage->delete(); + $this->assertIdentical($field_storage->hasdata(), TRUE, 'There are entities with deleted field data.'); + $this->assertEqual($this->storage->countFieldData($field_storage), 12, 'There are 12 entities with deleted field data.'); + + field_purge_batch(6); + $this->assertIdentical($field_storage->hasdata(), TRUE, 'There are entities with deleted field data.'); + $this->assertEqual($this->storage->countFieldData($field_storage), 6, 'There are 6 entities with deleted field data.'); + + $entity_type = 'entity_test_rev'; + $this->createFieldWithStorage('_2', $entity_type); + + $entity_init = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(array('type' => $entity_type,)); + $cardinality = $this->fieldTestData->field_storage_2->getCardinality(); + + $this->assertIdentical($this->fieldTestData->field_storage_2->hasData(), FALSE, 'There are no entities with field data.'); + $this->assertIdentical($this->storageRev->countFieldData($this->fieldTestData->field_storage_2), 0, 'There are 0 entities with field data.'); + + // Create 1 entity with the field. + $entity = clone($entity_init); + $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); + $entity->{$this->fieldTestData->field_name_2} = $values; + $entity->setNewRevision(); + $entity->save(); + $first_revision = $entity->getRevisionId(); + + $this->assertIdentical($this->fieldTestData->field_storage_2->hasData(), TRUE, 'There are entities with field data.'); + $this->assertIdentical($this->storageRev->countFieldData($this->fieldTestData->field_storage_2), 1, 'There is 1 entity with field data.'); + + $entity->{$this->fieldTestData->field_name_2} = array(); + $entity->setNewRevision(); + $entity->save(); + + $this->assertIdentical($this->fieldTestData->field_storage_2->hasData(), TRUE, 'There are entities with field data.'); + + $storage = $this->container->get('entity.manager')->getStorage($entity_type); + $entity = $storage->loadRevision($first_revision); + $this->assertEqual(count($entity->{$this->fieldTestData->field_name_2}), $cardinality, format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $first_revision))); + } + + /** + * Verify that we can count a table that contains an entry with index 0. + */ + public function testCountWithIndex0() { + // Create a field that will require dedicated storage. + /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */ + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_int', + 'entity_type' => 'user', + 'type' => 'integer', + 'cardinality' => 2, + )); + $field_storage->save(); + FieldConfig::create(array( + 'field_storage' => $field_storage, + 'bundle' => 'user', + ))->save(); + + // Create an entry for the anonymous user, who has user ID 0. + $user = $this->storageUser + ->create(array( + 'uid' => 0, + 'name' => 'anonymous', + 'mail' => NULL, + 'status' => FALSE, + 'field_int' => 42, + )); + $user->save(); + + // Test shared table storage. + $storage = $user->getFieldDefinition('name')->getFieldStorageDefinition(); + $this->assertIdentical(TRUE, $this->storageUser->countFieldData($storage, TRUE)); + + // Test dedicated table storage. + $storage = $user->getFieldDefinition('field_int')->getFieldStorageDefinition(); + $this->assertIdentical(TRUE, $this->storageUser->countFieldData($storage, TRUE)); + } + +} diff --git a/core/modules/field/src/Tests/FieldImportChangeTest.php b/core/modules/field/src/Tests/FieldImportChangeTest.php new file mode 100644 index 0000000..8cf3f9c --- /dev/null +++ b/core/modules/field/src/Tests/FieldImportChangeTest.php @@ -0,0 +1,57 @@ +installConfig(['field_test_config']); + $field_storage_id = 'field_test_import'; + $field_id = "entity_test.entity_test.$field_storage_id"; + $field_config_name = "field.field.$field_id"; + + $active = $this->container->get('config.storage'); + $sync = $this->container->get('config.storage.sync'); + $this->copyConfig($active, $sync); + + // Save as files in the sync directory. + $field = $active->read($field_config_name); + $new_label = 'Test update import field'; + $field['label'] = $new_label; + $sync->write($field_config_name, $field); + + // Import the content of the sync directory. + $this->configImporter()->import(); + + // Check that the updated config was correctly imported. + $field = FieldConfig::load($field_id); + $this->assertEqual($field->getLabel(), $new_label, 'field label updated'); + } +} + diff --git a/core/modules/field/src/Tests/FieldImportCreateTest.php b/core/modules/field/src/Tests/FieldImportCreateTest.php new file mode 100644 index 0000000..82cb962 --- /dev/null +++ b/core/modules/field/src/Tests/FieldImportCreateTest.php @@ -0,0 +1,124 @@ +assertFalse(FieldStorageConfig::load($field_storage_id)); + $this->assertFalse(FieldConfig::load($field_id)); + $this->assertFalse(FieldStorageConfig::load($field_storage_id_2)); + $this->assertFalse(FieldConfig::load($field_id_2a)); + $this->assertFalse(FieldConfig::load($field_id_2b)); + + // Create a second bundle for the 'Entity test' entity type. + entity_test_create_bundle('test_bundle'); + + // Enable field_test_config module and check that the field and storage + // shipped in the module's default config were created. + \Drupal::service('module_installer')->install(array('field_test_config')); + + // A field storage with one single field. + $field_storage = FieldStorageConfig::load($field_storage_id); + $this->assertTrue($field_storage, 'The field was created.'); + $field = FieldConfig::load($field_id); + $this->assertTrue($field, 'The field was deleted.'); + + // A field storage with two fields. + $field_storage_2 = FieldStorageConfig::load($field_storage_id_2); + $this->assertTrue($field_storage_2, 'The second field was created.'); + $this->assertTrue($field->getTargetBundle(), 'test_bundle', 'The second field was created on bundle test_bundle.'); + $this->assertTrue($field->getTargetBundle(), 'test_bundle_2', 'The second field was created on bundle test_bundle_2.'); + + // Tests fields. + $ids = \Drupal::entityQuery('field_config') + ->condition('entity_type', 'entity_test') + ->condition('bundle', 'entity_test') + ->execute(); + $this->assertEqual(count($ids), 2); + $this->assertTrue(isset($ids['entity_test.entity_test.field_test_import'])); + $this->assertTrue(isset($ids['entity_test.entity_test.field_test_import_2'])); + $ids = \Drupal::entityQuery('field_config') + ->condition('entity_type', 'entity_test') + ->condition('bundle', 'test_bundle') + ->execute(); + $this->assertEqual(count($ids), 1); + $this->assertTrue(isset($ids['entity_test.test_bundle.field_test_import_2'])); + } + + /** + * Tests creating field storages and fields during config import. + */ + function testImportCreate() { + // A field storage with one single field. + $field_name = 'field_test_import_sync'; + $field_storage_id = "entity_test.$field_name"; + $field_id = "entity_test.entity_test.$field_name"; + $field_storage_config_name = "field.storage.$field_storage_id"; + $field_config_name = "field.field.$field_id"; + + // A field storage with two fields. + $field_name_2 = 'field_test_import_sync_2'; + $field_storage_id_2 = "entity_test.$field_name_2"; + $field_id_2a = "entity_test.test_bundle.$field_name_2"; + $field_id_2b = "entity_test.test_bundle_2.$field_name_2"; + $field_storage_config_name_2 = "field.storage.$field_storage_id_2"; + $field_config_name_2a = "field.field.$field_id_2a"; + $field_config_name_2b = "field.field.$field_id_2b"; + + $active = $this->container->get('config.storage'); + $sync = $this->container->get('config.storage.sync'); + $this->copyConfig($active, $sync); + + // Add the new files to the sync directory. + $src_dir = drupal_get_path('module', 'field_test_config') . '/sync'; + $target_dir = $this->configDirectories[CONFIG_SYNC_DIRECTORY]; + $this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name.yml", "$target_dir/$field_storage_config_name.yml")); + $this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name.yml", "$target_dir/$field_config_name.yml")); + $this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name_2.yml", "$target_dir/$field_storage_config_name_2.yml")); + $this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2a.yml", "$target_dir/$field_config_name_2a.yml")); + $this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2b.yml", "$target_dir/$field_config_name_2b.yml")); + + // Import the content of the sync directory. + $this->configImporter()->import(); + + // Check that the field and storage were created. + $field_storage = FieldStorageConfig::load($field_storage_id); + $this->assertTrue($field_storage, 'Test import storage field from sync exists'); + $field = FieldConfig::load($field_id); + $this->assertTrue($field, 'Test import field from sync exists'); + $field_storage = FieldStorageConfig::load($field_storage_id_2); + $this->assertTrue($field_storage, 'Test import storage field 2 from sync exists'); + $field = FieldConfig::load($field_id_2a); + $this->assertTrue($field, 'Test import field 2a from sync exists'); + $field = FieldConfig::load($field_id_2b); + $this->assertTrue($field, 'Test import field 2b from sync exists'); + } +} + diff --git a/core/modules/field/src/Tests/FieldImportDeleteTest.php b/core/modules/field/src/Tests/FieldImportDeleteTest.php new file mode 100644 index 0000000..279be69 --- /dev/null +++ b/core/modules/field/src/Tests/FieldImportDeleteTest.php @@ -0,0 +1,117 @@ +installConfig(['field_test_config']); + // At this point there are 5 field configuration objects in the active + // storage. + // - field.storage.entity_test.field_test_import + // - field.storage.entity_test.field_test_import_2 + // - field.field.entity_test.entity_test.field_test_import + // - field.field.entity_test.entity_test.field_test_import_2 + // - field.field.entity_test.test_bundle.field_test_import_2 + + $field_name = 'field_test_import'; + $field_storage_id = "entity_test.$field_name"; + $field_name_2 = 'field_test_import_2'; + $field_storage_id_2 = "entity_test.$field_name_2"; + $field_id = "entity_test.entity_test.$field_name"; + $field_id_2a = "entity_test.entity_test.$field_name_2"; + $field_id_2b = "entity_test.test_bundle.$field_name_2"; + $field_storage_config_name = "field.storage.$field_storage_id"; + $field_storage_config_name_2 = "field.storage.$field_storage_id_2"; + $field_config_name = "field.field.$field_id"; + $field_config_name_2a = "field.field.$field_id_2a"; + $field_config_name_2b = "field.field.$field_id_2b"; + + // Create a second bundle for the 'Entity test' entity type. + entity_test_create_bundle('test_bundle'); + + // Get the uuid's for the field storages. + $field_storage_uuid = FieldStorageConfig::load($field_storage_id)->uuid(); + $field_storage_uuid_2 = FieldStorageConfig::load($field_storage_id_2)->uuid(); + + $active = $this->container->get('config.storage'); + $sync = $this->container->get('config.storage.sync'); + $this->copyConfig($active, $sync); + $this->assertTrue($sync->delete($field_storage_config_name), SafeMarkup::format('Deleted field storage: @field_storage', array('@field_storage' => $field_storage_config_name))); + $this->assertTrue($sync->delete($field_storage_config_name_2), SafeMarkup::format('Deleted field storage: @field_storage', array('@field_storage' => $field_storage_config_name_2))); + $this->assertTrue($sync->delete($field_config_name), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name))); + $this->assertTrue($sync->delete($field_config_name_2a), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name_2a))); + $this->assertTrue($sync->delete($field_config_name_2b), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name_2b))); + + $deletes = $this->configImporter()->getUnprocessedConfiguration('delete'); + $this->assertEqual(count($deletes), 5, 'Importing configuration will delete 3 fields and 2 field storages.'); + + // Import the content of the sync directory. + $this->configImporter()->import(); + + // Check that the field storages and fields are gone. + \Drupal::entityManager()->getStorage('field_storage_config')->resetCache(array($field_storage_id)); + $field_storage = FieldStorageConfig::load($field_storage_id); + $this->assertFalse($field_storage, 'The field storage was deleted.'); + \Drupal::entityManager()->getStorage('field_storage_config')->resetCache(array($field_storage_id_2)); + $field_storage_2 = FieldStorageConfig::load($field_storage_id_2); + $this->assertFalse($field_storage_2, 'The second field storage was deleted.'); + \Drupal::entityManager()->getStorage('field_config')->resetCache(array($field_id)); + $field = FieldConfig::load($field_id); + $this->assertFalse($field, 'The field was deleted.'); + \Drupal::entityManager()->getStorage('field_config')->resetCache(array($field_id_2a)); + $field_2a = FieldConfig::load($field_id_2a); + $this->assertFalse($field_2a, 'The second field on test bundle was deleted.'); + \Drupal::entityManager()->getStorage('field_config')->resetCache(array($field_id_2b)); + $field_2b = FieldConfig::load($field_id_2b); + $this->assertFalse($field_2b, 'The second field on test bundle 2 was deleted.'); + + // Check that all config files are gone. + $active = $this->container->get('config.storage'); + $this->assertIdentical($active->listAll($field_storage_config_name), array()); + $this->assertIdentical($active->listAll($field_storage_config_name_2), array()); + $this->assertIdentical($active->listAll($field_config_name), array()); + $this->assertIdentical($active->listAll($field_config_name_2a), array()); + $this->assertIdentical($active->listAll($field_config_name_2b), array()); + + // Check that the storage definition is preserved in state. + $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); + $this->assertTrue(isset($deleted_storages[$field_storage_uuid])); + $this->assertTrue(isset($deleted_storages[$field_storage_uuid_2])); + + // Purge field data, and check that the storage definition has been + // completely removed once the data is purged. + field_purge_batch(10); + $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); + $this->assertTrue(empty($deleted_storages), 'Fields are deleted'); + } +} + diff --git a/core/modules/field/src/Tests/FieldImportDeleteUninstallTest.php b/core/modules/field/src/Tests/FieldImportDeleteUninstallTest.php new file mode 100644 index 0000000..7cfed64 --- /dev/null +++ b/core/modules/field/src/Tests/FieldImportDeleteUninstallTest.php @@ -0,0 +1,173 @@ +installSchema('user', array('users_data')); + } + + /** + * Tests deleting field storages and fields as part of config import. + */ + public function testImportDeleteUninstall() { + // Create a field to delete to prove that + // \Drupal\field\ConfigImporterFieldPurger does not purge fields that are + // not related to the configuration synchronization. + $unrelated_field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_int', + 'entity_type' => 'entity_test', + 'type' => 'integer', + )); + $unrelated_field_storage->save(); + FieldConfig::create([ + 'field_storage' => $unrelated_field_storage, + 'bundle' => 'entity_test', + ])->save(); + + // Create a telephone field for validation. + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_test', + 'entity_type' => 'entity_test', + 'type' => 'telephone', + )); + $field_storage->save(); + FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => 'entity_test', + ])->save(); + + $entity = EntityTest::create(); + $value = '+0123456789'; + $entity->field_test = $value; + $entity->field_int = '99'; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_test->value, $value); + $this->assertEqual($entity->field_test[0]->value, $value); + $this->assertEqual($entity->field_int->value, '99'); + + // Delete unrelated field before copying configuration and running the + // synchronization. + $unrelated_field_storage->delete(); + + $active = $this->container->get('config.storage'); + $sync = $this->container->get('config.storage.sync'); + $this->copyConfig($active, $sync); + + // Stage uninstall of the Telephone module. + $core_extension = $this->config('core.extension')->get(); + unset($core_extension['module']['telephone']); + $sync->write('core.extension', $core_extension); + + // Stage the field deletion + $sync->delete('field.storage.entity_test.field_test'); + $sync->delete('field.field.entity_test.entity_test.field_test'); + + $steps = $this->configImporter()->initialize(); + $this->assertIdentical($steps[0], array('\Drupal\field\ConfigImporterFieldPurger', 'process'), 'The additional process configuration synchronization step has been added.'); + + // This will purge all the data, delete the field and uninstall the + // Telephone module. + $this->configImporter()->import(); + + $this->assertFalse(\Drupal::moduleHandler()->moduleExists('telephone')); + $this->assertFalse(\Drupal::entityManager()->loadEntityByUuid('field_storage_config', $field_storage->uuid()), 'The test field has been deleted by the configuration synchronization'); + $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); + $this->assertFalse(isset($deleted_storages[$field_storage->uuid()]), 'Telephone field has been completed removed from the system.'); + $this->assertTrue(isset($deleted_storages[$unrelated_field_storage->uuid()]), 'Unrelated field not purged by configuration synchronization.'); + } + + /** + * Tests purging already deleted field storages and fields during a config + * import. + */ + public function testImportAlreadyDeletedUninstall() { + // Create a telephone field for validation. + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_test', + 'entity_type' => 'entity_test', + 'type' => 'telephone', + )); + $field_storage->save(); + $field_storage_uuid = $field_storage->uuid(); + FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => 'entity_test', + ])->save(); + + // Create 12 entities to ensure that the purging works as expected. + for ($i=0; $i < 12; $i++) { + $entity = EntityTest::create(); + $value = '+0123456789'; + $entity->field_test = $value; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_test->value, $value); + } + + // Delete the field. + $field_storage->delete(); + + $active = $this->container->get('config.storage'); + $sync = $this->container->get('config.storage.sync'); + $this->copyConfig($active, $sync); + + // Stage uninstall of the Telephone module. + $core_extension = $this->config('core.extension')->get(); + unset($core_extension['module']['telephone']); + $sync->write('core.extension', $core_extension); + + $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); + $this->assertTrue(isset($deleted_storages[$field_storage_uuid]), 'Field has been deleted and needs purging before configuration synchronization.'); + + $steps = $this->configImporter()->initialize(); + $this->assertIdentical($steps[0], array('\Drupal\field\ConfigImporterFieldPurger', 'process'), 'The additional process configuration synchronization step has been added.'); + + // This will purge all the data, delete the field and uninstall the + // Telephone module. + $this->configImporter()->import(); + + $this->assertFalse(\Drupal::moduleHandler()->moduleExists('telephone')); + $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); + $this->assertFalse(isset($deleted_storages[$field_storage_uuid]), 'Field has been completed removed from the system.'); + } + +} diff --git a/core/modules/field/src/Tests/FieldStorageCrudTest.php b/core/modules/field/src/Tests/FieldStorageCrudTest.php new file mode 100644 index 0000000..2b1dcee --- /dev/null +++ b/core/modules/field/src/Tests/FieldStorageCrudTest.php @@ -0,0 +1,462 @@ + 'field_2', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + field_test_memorize(); + $field_storage = FieldStorageConfig::create($field_storage_definition); + $field_storage->save(); + + $field_storage = FieldStorageConfig::load($field_storage->id()); + $this->assertTrue($field_storage->getSetting('storage_setting_from_config_data')); + $this->assertNull($field_storage->getSetting('config_data_from_storage_setting')); + + $mem = field_test_memorize(); + $this->assertIdentical($mem['field_test_field_storage_config_create'][0][0]->getName(), $field_storage_definition['field_name'], 'hook_entity_create() called with correct arguments.'); + $this->assertIdentical($mem['field_test_field_storage_config_create'][0][0]->getType(), $field_storage_definition['type'], 'hook_entity_create() called with correct arguments.'); + + // Read the configuration. Check against raw configuration data rather than + // the loaded ConfigEntity, to be sure we check that the defaults are + // applied on write. + $field_storage_config = $this->config('field.storage.' . $field_storage->id())->get(); + + $this->assertTrue($field_storage_config['settings']['config_data_from_storage_setting']); + $this->assertTrue(!isset($field_storage_config['settings']['storage_setting_from_config_data'])); + + // Since we are working with raw configuration, this needs to be unset + // manually. + // @see Drupal\field_test\Plugin\Field\FieldType\TestItem::storageSettingsFromConfigData() + unset($field_storage_config['settings']['config_data_from_storage_setting']); + + // Ensure that basic properties are preserved. + $this->assertEqual($field_storage_config['field_name'], $field_storage_definition['field_name'], 'The field name is properly saved.'); + $this->assertEqual($field_storage_config['entity_type'], $field_storage_definition['entity_type'], 'The field entity type is properly saved.'); + $this->assertEqual($field_storage_config['id'], $field_storage_definition['entity_type'] . '.' . $field_storage_definition['field_name'], 'The field id is properly saved.'); + $this->assertEqual($field_storage_config['type'], $field_storage_definition['type'], 'The field type is properly saved.'); + + // Ensure that cardinality defaults to 1. + $this->assertEqual($field_storage_config['cardinality'], 1, 'Cardinality defaults to 1.'); + + // Ensure that default settings are present. + $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); + $this->assertEqual($field_storage_config['settings'], $field_type_manager->getDefaultStorageSettings($field_storage_definition['type']), 'Default storage settings have been written.'); + + // Guarantee that the name is unique. + try { + FieldStorageConfig::create($field_storage_definition)->save(); + $this->fail(t('Cannot create two fields with the same name.')); + } + catch (EntityStorageException $e) { + $this->pass(t('Cannot create two fields with the same name.')); + } + + // Check that field type is required. + try { + $field_storage_definition = array( + 'field_name' => 'field_1', + 'entity_type' => 'entity_type', + ); + FieldStorageConfig::create($field_storage_definition)->save(); + $this->fail(t('Cannot create a field with no type.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot create a field with no type.')); + } + + // Check that field name is required. + try { + $field_storage_definition = array( + 'type' => 'test_field', + 'entity_type' => 'entity_test', + ); + FieldStorageConfig::create($field_storage_definition)->save(); + $this->fail(t('Cannot create an unnamed field.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot create an unnamed field.')); + } + // Check that entity type is required. + try { + $field_storage_definition = array( + 'field_name' => 'test_field', + 'type' => 'test_field' + ); + FieldStorageConfig::create($field_storage_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_storage_definition = array( + 'field_name' => '2field_2', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + FieldStorageConfig::create($field_storage_definition)->save(); + $this->fail(t('Cannot create a field with a name starting with a digit.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot create a field with a name starting with a digit.')); + } + + // Check that field name must only contain lowercase alphanumeric or _. + try { + $field_storage_definition = array( + 'field_name' => 'field#_3', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + FieldStorageConfig::create($field_storage_definition)->save(); + $this->fail(t('Cannot create a field with a name containing an illegal character.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot create a field with a name containing an illegal character.')); + } + + // Check that field name cannot be longer than 32 characters long. + try { + $field_storage_definition = array( + 'field_name' => '_12345678901234567890123456789012', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + FieldStorageConfig::create($field_storage_definition)->save(); + $this->fail(t('Cannot create a field with a name longer than 32 characters.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot create a field with a name longer than 32 characters.')); + } + + // Check that field name can not be an entity key. + // "id" is known as an entity key from the "entity_test" type. + try { + $field_storage_definition = array( + 'type' => 'test_field', + 'field_name' => 'id', + 'entity_type' => 'entity_test', + ); + FieldStorageConfig::create($field_storage_definition)->save(); + $this->fail(t('Cannot create a field bearing the name of an entity key.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot create a field bearing the name of an entity key.')); + } + } + + /** + * Tests that an explicit schema can be provided on creation. + * + * This behavior is needed to allow field storage creation within updates, + * since plugin classes (and thus the field type schema) cannot be accessed. + */ + function testCreateWithExplicitSchema() { + $schema = array( + 'dummy' => 'foobar' + ); + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_2', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'schema' => $schema, + )); + $this->assertEqual($field_storage->getSchema(), $schema); + } + + /** + * Tests reading field storage definitions. + */ + function testRead() { + $field_storage_definition = array( + 'field_name' => 'field_1', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ); + $field_storage = FieldStorageConfig::create($field_storage_definition); + $field_storage->save(); + $id = $field_storage->id(); + + // Check that 'single column' criteria works. + $fields = entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'])); + $this->assertTrue(count($fields) == 1 && isset($fields[$id]), 'The field was properly read.'); + + // Check that 'multi column' criteria works. + $fields = entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'type' => $field_storage_definition['type'])); + $this->assertTrue(count($fields) == 1 && isset($fields[$id]), 'The field was properly read.'); + $fields = entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'type' => 'foo')); + $this->assertTrue(empty($fields), 'No field was found.'); + + // Create a field from the field storage. + $field_definition = array( + 'field_name' => $field_storage_definition['field_name'], + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + ); + FieldConfig::create($field_definition)->save(); + } + + /** + * Test creation of indexes on data column. + */ + function testIndexes() { + // Check that indexes specified by the field type are used by default. + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_1', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + )); + $field_storage->save(); + $field_storage = FieldStorageConfig::load($field_storage->id()); + $schema = $field_storage->getSchema(); + $expected_indexes = array('value' => array('value')); + $this->assertEqual($schema['indexes'], $expected_indexes, 'Field type indexes saved by default'); + + // Check that indexes specified by the field definition override the field + // type indexes. + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_2', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'indexes' => array( + 'value' => array(), + ), + )); + $field_storage->save(); + $field_storage = FieldStorageConfig::load($field_storage->id()); + $schema = $field_storage->getSchema(); + $expected_indexes = array('value' => array()); + $this->assertEqual($schema['indexes'], $expected_indexes, 'Field definition indexes override field type indexes'); + + // Check that indexes specified by the field definition add to the field + // type indexes. + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_3', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'indexes' => array( + 'value_2' => array('value'), + ), + )); + $field_storage->save(); + $id = $field_storage->id(); + $field_storage = FieldStorageConfig::load($id); + $schema = $field_storage->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'); + } + + /** + * Test the deletion of a field storage. + */ + function testDelete() { + // TODO: Also test deletion of the data stored in the field ? + + // Create two fields (so we can test that only one is deleted). + $field_storage_definition = array( + 'field_name' => 'field_1', + 'type' => 'test_field', + 'entity_type' => 'entity_test', + ); + FieldStorageConfig::create($field_storage_definition)->save(); + $another_field_storage_definition = array( + 'field_name' => 'field_2', + 'type' => 'test_field', + 'entity_type' => 'entity_test', + ); + FieldStorageConfig::create($another_field_storage_definition)->save(); + + // Create fields for each. + $field_definition = array( + 'field_name' => $field_storage_definition['field_name'], + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + ); + FieldConfig::create($field_definition)->save(); + $another_field_definition = $field_definition; + $another_field_definition['field_name'] = $another_field_storage_definition['field_name']; + FieldConfig::create($another_field_definition)->save(); + + // Test that the first field is not deleted, and then delete it. + $field_storage = current(entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'include_deleted' => TRUE))); + $this->assertTrue(!empty($field_storage) && !$field_storage->isDeleted(), 'A new storage is not marked for deletion.'); + FieldStorageConfig::loadByName('entity_test', $field_storage_definition['field_name'])->delete(); + + // Make sure that the field is marked as deleted when it is specifically + // loaded. + $field_storage = current(entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'include_deleted' => TRUE))); + $this->assertTrue($field_storage->isDeleted(), 'A deleted storage is marked for deletion.'); + + // Make sure that this field is marked as deleted when it is + // specifically loaded. + $field = current(entity_load_multiple_by_properties('field_config', array('entity_type' => 'entity_test', 'field_name' => $field_definition['field_name'], 'bundle' => $field_definition['bundle'], 'include_deleted' => TRUE))); + $this->assertTrue($field->isDeleted(), 'A field whose storage was deleted is marked for deletion.'); + + // Try to load the storage normally and make sure it does not show up. + $field_storage = FieldStorageConfig::load('entity_test.' . $field_storage_definition['field_name']); + $this->assertTrue(empty($field_storage), 'A deleted storage is not loaded by default.'); + + // Try to load the field normally and make sure it does not show up. + $field = FieldConfig::load('entity_test.' . '.' . $field_definition['bundle'] . '.' . $field_definition['field_name']); + $this->assertTrue(empty($field), 'A field whose storage was deleted is not loaded by default.'); + + // Make sure the other field and its storage are not deleted. + $another_field_storage = FieldStorageConfig::load('entity_test.' . $another_field_storage_definition['field_name']); + $this->assertTrue(!empty($another_field_storage) && !$another_field_storage->isDeleted(), 'A non-deleted storage is not marked for deletion.'); + $another_field = FieldConfig::load('entity_test.' . $another_field_definition['bundle'] . '.' . $another_field_definition['field_name']); + $this->assertTrue(!empty($another_field) && !$another_field->isDeleted(), 'A field whose storage was not deleted is not marked for deletion.'); + + // Try to create a new field the same name as a deleted field and + // write data into it. + FieldStorageConfig::create($field_storage_definition)->save(); + FieldConfig::create($field_definition)->save(); + $field_storage = FieldStorageConfig::load('entity_test.' . $field_storage_definition['field_name']); + $this->assertTrue(!empty($field_storage) && !$field_storage->isDeleted(), 'A new storage with a previously used name is created.'); + $field = FieldConfig::load('entity_test.' . $field_definition['bundle'] . '.' . $field_definition['field_name'] ); + $this->assertTrue(!empty($field) && !$field->isDeleted(), 'A new field for a previously used field name is created.'); + + // Save an entity with data for the field + $entity = EntityTest::create(); + $values[0]['value'] = mt_rand(1, 127); + $entity->{$field_storage->getName()}->value = $values[0]['value']; + $entity = $this->entitySaveReload($entity); + + // Verify the field is present on load + $this->assertIdentical(count($entity->{$field_storage->getName()}), count($values), "Data in previously deleted field saves and loads correctly"); + foreach ($values as $delta => $value) { + $this->assertEqual($entity->{$field_storage->getName()}[$delta]->value, $values[$delta]['value'], "Data in previously deleted field saves and loads correctly"); + } + } + + function testUpdateFieldType() { + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_type', + 'entity_type' => 'entity_test', + 'type' => 'decimal', + )); + $field_storage->save(); + + try { + $field_storage->set('type', 'integer'); + $field_storage->save(); + $this->fail(t('Cannot update a field to a different type.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot update a field to a different type.')); + } + } + + /** + * Test updating a field storage. + */ + function testUpdate() { + // Create a field with a defined cardinality, so that we can ensure it's + // respected. Since cardinality enforcement is consistent across database + // systems, it makes a good test case. + $cardinality = 4; + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'field_update', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'cardinality' => $cardinality, + )); + $field_storage->save(); + $field = FieldConfig::create([ + 'field_storage' => $field_storage, + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + ]); + $field->save(); + + do { + $entity = EntityTest::create(); + // Fill in the entity with more values than $cardinality. + for ($i = 0; $i < 20; $i++) { + // We can not use $i here because 0 values are filtered out. + $entity->field_update[] = $i + 1; + } + // Load back and assert there are $cardinality number of values. + $entity = $this->entitySaveReload($entity); + $this->assertEqual(count($entity->field_update), $field_storage->getCardinality()); + // Now check the values themselves. + for ($delta = 0; $delta < $cardinality; $delta++) { + $this->assertEqual($entity->field_update[$delta]->value, $delta + 1); + } + // Increase $cardinality and set the field cardinality to the new value. + $field_storage->setCardinality(++$cardinality); + $field_storage->save(); + } while ($cardinality < 6); + } + + /** + * Test field type modules forbidding an update. + */ + function testUpdateForbid() { + $field_storage = FieldStorageConfig::create(array( + 'field_name' => 'forbidden', + 'entity_type' => 'entity_test', + 'type' => 'test_field', + 'settings' => array( + 'changeable' => 0, + 'unchangeable' => 0 + ))); + $field_storage->save(); + $field_storage->setSetting('changeable', $field_storage->getSetting('changeable') + 1); + try { + $field_storage->save(); + $this->pass(t("A changeable setting can be updated.")); + } + catch (FieldStorageDefinitionUpdateForbiddenException $e) { + $this->fail(t("An unchangeable setting cannot be updated.")); + } + $field_storage->setSetting('unchangeable', $field_storage->getSetting('unchangeable') + 1); + try { + $field_storage->save(); + $this->fail(t("An unchangeable setting can be updated.")); + } + catch (FieldStorageDefinitionUpdateForbiddenException $e) { + $this->pass(t("An unchangeable setting cannot be updated.")); + } + } + +} diff --git a/core/modules/field/src/Tests/FieldTypePluginManagerTest.php b/core/modules/field/src/Tests/FieldTypePluginManagerTest.php new file mode 100644 index 0000000..68e09d8 --- /dev/null +++ b/core/modules/field/src/Tests/FieldTypePluginManagerTest.php @@ -0,0 +1,92 @@ +getDefinition($type); + $this->assertIdentical($field_type_manager->getDefaultStorageSettings($type), $definition['class']::defaultStorageSettings(), format_string("%type storage settings were returned", array('%type' => $type))); + $this->assertIdentical($field_type_manager->getDefaultFieldSettings($type), $definition['class']::defaultFieldSettings(), format_string(" %type field settings were returned", array('%type' => $type))); + } + } + + /** + * Tests creation of field item instances. + */ + public function testCreateInstance() { + /** @var \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager */ + $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); + foreach (array('test_field', 'shape', 'hidden_test_field') as $type) { + $definition = $field_type_manager->getDefinition($type); + + $class = $definition['class']; + $field_name = 'field_' . $type; + + $field_definition = BaseFieldDefinition::create($type); + + $configuration = array( + 'field_definition' => $field_definition, + 'name' => $field_name, + 'parent' => NULL, + ); + + $instance = $field_type_manager->createInstance($type, $configuration); + + $this->assertTrue($instance instanceof $class, SafeMarkup::format('Created a @class instance', array('@class' => $class))); + $this->assertEqual($field_name, $instance->getName(), SafeMarkup::format('Instance name is @name', array('@name' => $field_name))); + } + } + + /** + * Tests creation of field item instances. + */ + public function testCreateInstanceWithConfig() { + /** @var \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager */ + $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); + $type = 'test_field'; + $definition = $field_type_manager->getDefinition($type); + + $class = $definition['class']; + $field_name = 'field_' . $type; + + $field_definition = BaseFieldDefinition::create($type) + ->setLabel('Jenny') + ->setDefaultValue(8675309); + + $configuration = array( + 'field_definition' => $field_definition, + 'name' => $field_name, + 'parent' => NULL, + ); + + $entity = EntityTest::create(); + + $instance = $field_type_manager->createInstance($type, $configuration); + + $this->assertTrue($instance instanceof $class, SafeMarkup::format('Created a @class instance', array('@class' => $class))); + $this->assertEqual($field_name, $instance->getName(), SafeMarkup::format('Instance name is @name', array('@name' => $field_name))); + $this->assertEqual($instance->getFieldDefinition()->getLabel(), 'Jenny', 'Instance label is Jenny'); + $this->assertEqual($instance->getFieldDefinition()->getDefaultValue($entity), [['value' => 8675309]], 'Instance default_value is 8675309'); + } + +} diff --git a/core/modules/field/src/Tests/FieldUnitTestBase.php b/core/modules/field/src/Tests/FieldUnitTestBase.php new file mode 100644 index 0000000..3b05f98 --- /dev/null +++ b/core/modules/field/src/Tests/FieldUnitTestBase.php @@ -0,0 +1,208 @@ +fieldTestData->field_name[suffix] + * - $this->fieldTestData->field_storage[suffix] + * - $this->fieldTestData->field_storage_uuid[suffix] + * - $this->fieldTestData->field[suffix] + * - $this->fieldTestData->field_definition[suffix] + * + * @see \Drupal\field\Tests\FieldUnitTestBase::createFieldWithStorage() + * + * @var \ArrayObject + */ + protected $fieldTestData; + + /** + * Set the default field storage backend for fields created during tests. + */ + protected function setUp() { + parent::setUp(); + + $this->fieldTestData = new \ArrayObject(array(), \ArrayObject::ARRAY_AS_PROPS); + + $this->installEntitySchema('entity_test'); + $this->installEntitySchema('user'); + $this->installSchema('system', ['sequences', 'key_value']); + + // Set default storage backend and configure the theme system. + $this->installConfig(array('field', 'system')); + + // Create user 1. + $storage = \Drupal::entityManager()->getStorage('user'); + $storage + ->create(array( + 'uid' => 1, + 'name' => 'entity-test', + 'mail' => 'entity@localhost', + 'status' => TRUE, + )) + ->save(); + } + + /** + * Create a field and an associated field storage. + * + * @param string $suffix + * (optional) A string that should only contain characters that are valid in + * PHP variable names as well. + * @param string $entity_type + * (optional) The entity type on which the field should be created. + * Defaults to "entity_test". + * @param string $bundle + * (optional) The entity type on which the field should be created. + * Defaults to the default bundle of the entity type. + */ + protected function createFieldWithStorage($suffix = '', $entity_type = 'entity_test', $bundle = NULL) { + if (empty($bundle)) { + $bundle = $entity_type; + } + $field_name = 'field_name' . $suffix; + $field_storage = 'field_storage' . $suffix; + $field_storage_uuid = 'field_storage_uuid' . $suffix; + $field = 'field' . $suffix; + $field_definition = 'field_definition' . $suffix; + + $this->fieldTestData->$field_name = Unicode::strtolower($this->randomMachineName() . '_field_name' . $suffix); + $this->fieldTestData->$field_storage = FieldStorageConfig::create(array( + 'field_name' => $this->fieldTestData->$field_name, + 'entity_type' => $entity_type, + 'type' => 'test_field', + 'cardinality' => 4, + )); + $this->fieldTestData->$field_storage->save(); + $this->fieldTestData->$field_storage_uuid = $this->fieldTestData->$field_storage->uuid(); + $this->fieldTestData->$field_definition = array( + 'field_storage' => $this->fieldTestData->$field_storage, + 'bundle' => $bundle, + 'label' => $this->randomMachineName() . '_label', + 'description' => $this->randomMachineName() . '_description', + 'settings' => array( + 'test_field_setting' => $this->randomMachineName(), + ), + ); + $this->fieldTestData->$field = FieldConfig::create($this->fieldTestData->$field_definition); + $this->fieldTestData->$field->save(); + + entity_get_form_display($entity_type, $bundle, 'default') + ->setComponent($this->fieldTestData->$field_name, array( + 'type' => 'test_field_widget', + 'settings' => array( + 'test_widget_setting' => $this->randomMachineName(), + ) + )) + ->save(); + } + + /** + * Saves and reloads an entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity to save. + * + * @return \Drupal\Core\Entity\EntityInterface + * The entity, freshly reloaded from storage. + */ + protected function entitySaveReload(EntityInterface $entity) { + $entity->save(); + $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); + $controller->resetCache(); + return $controller->load($entity->id()); + } + + /** + * Validate and save entity. Fail if violations are found. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity to save. + * + * @return void + */ + protected function entityValidateAndSave(EntityInterface $entity) { + $violations = $entity->validate(); + if ($violations->count()) { + $this->fail($violations); + } + else { + $entity->save(); + } + } + + /** + * Generate random values for a field_test field. + * + * @param $cardinality + * Number of values to generate. + * @return + * An array of random values, in the format expected for field values. + */ + protected function _generateTestFieldValues($cardinality) { + $values = array(); + for ($i = 0; $i < $cardinality; $i++) { + // field_test fields treat 0 as 'empty value'. + $values[$i]['value'] = mt_rand(1, 127); + } + return $values; + } + + /** + * Assert that a field has the expected values in an entity. + * + * This function only checks a single column in the field values. + * + * @param EntityInterface $entity + * The entity to test. + * @param $field_name + * The name of the field to test + * @param $expected_values + * The array of expected values. + * @param $langcode + * (Optional) The language code for the values. Defaults to + * \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED. + * @param $column + * (Optional) The name of the column to check. Defaults to 'value'. + */ + protected function assertFieldValues(EntityInterface $entity, $field_name, $expected_values, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $column = 'value') { + // Re-load the entity to make sure we have the latest changes. + \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->resetCache(array($entity->id())); + $e = entity_load($entity->getEntityTypeId(), $entity->id()); + $field = $values = $e->getTranslation($langcode)->$field_name; + // Filter out empty values so that they don't mess with the assertions. + $field->filterEmptyItems(); + $values = $field->getValue(); + $this->assertEqual(count($values), count($expected_values), 'Expected number of values were saved.'); + foreach ($expected_values as $key => $value) { + $this->assertEqual($values[$key][$column], $value, format_string('Value @value was saved correctly.', array('@value' => $value))); + } + } + +} diff --git a/core/modules/field/src/Tests/FieldValidationTest.php b/core/modules/field/src/Tests/FieldValidationTest.php new file mode 100644 index 0000000..8f51b7a --- /dev/null +++ b/core/modules/field/src/Tests/FieldValidationTest.php @@ -0,0 +1,102 @@ +entityType = 'entity_test'; + $this->bundle = 'entity_test'; + $this->createFieldWithStorage('', $this->entityType, $this->bundle); + + // Create an 'entity_test' entity. + $this->entity = entity_create($this->entityType, array( + 'type' => $this->bundle, + )); + } + + /** + * Tests that the number of values is validated against the field cardinality. + */ + function testCardinalityConstraint() { + $cardinality = $this->fieldTestData->field_storage->getCardinality(); + $entity = $this->entity; + + for ($delta = 0; $delta < $cardinality + 1; $delta++) { + $entity->{$this->fieldTestData->field_name}[] = array('value' => 1); + } + + // Validate the field. + $violations = $entity->{$this->fieldTestData->field_name}->validate(); + + // Check that the expected constraint violations are reported. + $this->assertEqual(count($violations), 1); + $this->assertEqual($violations[0]->getPropertyPath(), ''); + $this->assertEqual($violations[0]->getMessage(), t('%name: this field cannot hold more than @count values.', array('%name' => $this->fieldTestData->field->getLabel(), '@count' => $cardinality))); + } + + /** + * Tests that constraints defined by the field type are validated. + */ + function testFieldConstraints() { + $cardinality = $this->fieldTestData->field_storage->getCardinality(); + $entity = $this->entity; + + // The test is only valid if the field cardinality is greater than 2. + $this->assertTrue($cardinality >= 2); + + // Set up values for the field. + $expected_violations = array(); + for ($delta = 0; $delta < $cardinality; $delta++) { + // All deltas except '1' have incorrect values. + if ($delta == 1) { + $value = 1; + } + else { + $value = -1; + $expected_violations[$delta . '.value'][] = t('%name does not accept the value -1.', array('%name' => $this->fieldTestData->field->getLabel())); + } + $entity->{$this->fieldTestData->field_name}[] = $value; + } + + // Validate the field. + $violations = $entity->{$this->fieldTestData->field_name}->validate(); + + // Check that the expected constraint violations are reported. + $violations_by_path = array(); + foreach ($violations as $violation) { + $violations_by_path[$violation->getPropertyPath()][] = $violation->getMessage(); + } + $this->assertEqual($violations_by_path, $expected_violations); + } + +} diff --git a/core/modules/field/src/Tests/FormatterPluginManagerTest.php b/core/modules/field/src/Tests/FormatterPluginManagerTest.php new file mode 100644 index 0000000..bc1c635 --- /dev/null +++ b/core/modules/field/src/Tests/FormatterPluginManagerTest.php @@ -0,0 +1,52 @@ +setName('field_test_field'); + + $formatter_options = array( + 'field_definition' => $base_field_definition, + 'view_mode' => 'default', + 'configuration' => array( + 'type' => 'field_test_applicable', + ), + ); + + $instance = $formatter_plugin_manager->getInstance($formatter_options); + $this->assertEqual($instance->getPluginId(), 'field_test_applicable'); + + // Now set name to something that makes isApplicable() return FALSE. + $base_field_definition->setName('deny_applicable'); + $instance = $formatter_plugin_manager->getInstance($formatter_options); + + // Instance should be default widget. + $this->assertNotEqual($instance->getPluginId(), 'field_test_applicable'); + $this->assertEqual($instance->getPluginId(), 'field_test_default'); + } + +} diff --git a/core/modules/field/src/Tests/Number/NumberItemTest.php b/core/modules/field/src/Tests/Number/NumberItemTest.php new file mode 100644 index 0000000..8e99d97 --- /dev/null +++ b/core/modules/field/src/Tests/Number/NumberItemTest.php @@ -0,0 +1,109 @@ + 'entity_test', + 'field_name' => 'field_' . $type, + 'type' => $type, + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'field_' . $type, + 'bundle' => 'entity_test', + ])->save(); + } + } + + /** + * Tests using entity fields of the number field type. + */ + public function testNumberItem() { + // Verify entity creation. + $entity = EntityTest::create(); + $integer = rand(0, 10); + $entity->field_integer = $integer; + $float = 3.14; + $entity->field_float = $float; + $entity->field_decimal = '20-40'; + $violations = $entity->validate(); + $this->assertIdentical(1, count($violations), 'Wrong decimal value causes validation error'); + $decimal = '31.3'; + $entity->field_decimal = $decimal; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->field_integer instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_integer[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_integer->value, $integer); + $this->assertEqual($entity->field_integer[0]->value, $integer); + $this->assertTrue($entity->field_float instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_float[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_float->value, $float); + $this->assertEqual($entity->field_float[0]->value, $float); + $this->assertTrue($entity->field_decimal instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_decimal[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_decimal->value, $decimal); + $this->assertEqual($entity->field_decimal[0]->value, $decimal); + + // Verify changing the number value. + $new_integer = rand(11, 20); + $new_float = rand(1001, 2000) / 100; + $new_decimal = '18.2'; + $entity->field_integer->value = $new_integer; + $this->assertEqual($entity->field_integer->value, $new_integer); + $entity->field_float->value = $new_float; + $this->assertEqual($entity->field_float->value, $new_float); + $entity->field_decimal->value = $new_decimal; + $this->assertEqual($entity->field_decimal->value, $new_decimal); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_integer->value, $new_integer); + $this->assertEqual($entity->field_float->value, $new_float); + $this->assertEqual($entity->field_decimal->value, $new_decimal); + + /// Test sample item generation. + $entity = EntityTest::create(); + $entity->field_integer->generateSampleItems(); + $entity->field_float->generateSampleItems(); + $entity->field_decimal->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + +} diff --git a/core/modules/field/src/Tests/ShapeItemTest.php b/core/modules/field/src/Tests/ShapeItemTest.php new file mode 100644 index 0000000..0a000ad --- /dev/null +++ b/core/modules/field/src/Tests/ShapeItemTest.php @@ -0,0 +1,91 @@ + $this->fieldName, + 'entity_type' => 'entity_test', + 'type' => 'shape', + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => $this->fieldName, + 'bundle' => 'entity_test', + ])->save(); + } + + /** + * Tests using entity fields of the field field type. + */ + public function testShapeItem() { + // Verify entity creation. + $entity = EntityTest::create(); + $shape = 'cube'; + $color = 'blue'; + $entity->{$this->fieldName}->shape = $shape; + $entity->{$this->fieldName}->color = $color; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->{$this->fieldName} instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->{$this->fieldName}[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->{$this->fieldName}->shape, $shape); + $this->assertEqual($entity->{$this->fieldName}->color, $color); + $this->assertEqual($entity->{$this->fieldName}[0]->shape, $shape); + $this->assertEqual($entity->{$this->fieldName}[0]->color, $color); + + // Verify changing the field value. + $new_shape = 'circle'; + $new_color = 'red'; + $entity->{$this->fieldName}->shape = $new_shape; + $entity->{$this->fieldName}->color = $new_color; + $this->assertEqual($entity->{$this->fieldName}->shape, $new_shape); + $this->assertEqual($entity->{$this->fieldName}->color, $new_color); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->{$this->fieldName}->shape, $new_shape); + $this->assertEqual($entity->{$this->fieldName}->color, $new_color); + } + +} diff --git a/core/modules/field/src/Tests/String/RawStringFormatterTest.php b/core/modules/field/src/Tests/String/RawStringFormatterTest.php new file mode 100644 index 0000000..a11b9f6 --- /dev/null +++ b/core/modules/field/src/Tests/String/RawStringFormatterTest.php @@ -0,0 +1,128 @@ +installConfig(array('system', 'field')); + \Drupal::service('router.builder')->rebuild(); + $this->installEntitySchema('entity_test'); + + $this->entityType = 'entity_test'; + $this->bundle = $this->entityType; + $this->fieldName = Unicode::strtolower($this->randomMachineName()); + + $field_storage = FieldStorageConfig::create(array( + 'field_name' => $this->fieldName, + 'entity_type' => $this->entityType, + 'type' => 'string_long', + )); + $field_storage->save(); + + $instance = FieldConfig::create(array( + 'field_storage' => $field_storage, + 'bundle' => $this->bundle, + 'label' => $this->randomMachineName(), + )); + $instance->save(); + + $this->display = entity_get_display($this->entityType, $this->bundle, 'default') + ->setComponent($this->fieldName, array( + 'type' => 'string', + 'settings' => array(), + )); + $this->display->save(); + } + + /** + * Renders fields of a given entity with a given display. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity object with attached fields to render. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The display to render the fields in. + * + * @return string + * The rendered entity fields. + */ + protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { + $content = $display->build($entity); + $content = $this->render($content); + return $content; + } + + /** + * Tests string formatter output. + */ + public function testStringFormatter() { + $value = $this->randomString(); + $value .= "\n\n" . $this->randomString() . ''; + $value .= "\n\n" . $this->randomString(); + + $entity = EntityTest::create(array()); + $entity->{$this->fieldName}->value = $value; + + // Verify that all HTML is escaped and newlines are retained. + $this->renderEntityFields($entity, $this->display); + $this->assertNoRaw($value); + $this->assertRaw(nl2br(Html::escape($value))); + + // Verify the cache tags. + $build = $entity->{$this->fieldName}->view(); + $this->assertTrue(!isset($build[0]['#cache']), 'The string formatter has no cache tags.'); + } + +} diff --git a/core/modules/field/src/Tests/String/StringFormatterTest.php b/core/modules/field/src/Tests/String/StringFormatterTest.php new file mode 100644 index 0000000..c61e4bf --- /dev/null +++ b/core/modules/field/src/Tests/String/StringFormatterTest.php @@ -0,0 +1,164 @@ +installConfig(array('system', 'field')); + \Drupal::service('router.builder')->rebuild(); + $this->installEntitySchema('entity_test_rev'); + + $this->entityType = 'entity_test_rev'; + $this->bundle = $this->entityType; + $this->fieldName = Unicode::strtolower($this->randomMachineName()); + + $field_storage = FieldStorageConfig::create(array( + 'field_name' => $this->fieldName, + 'entity_type' => $this->entityType, + 'type' => 'string', + )); + $field_storage->save(); + + $instance = FieldConfig::create(array( + 'field_storage' => $field_storage, + 'bundle' => $this->bundle, + 'label' => $this->randomMachineName(), + )); + $instance->save(); + + $this->display = entity_get_display($this->entityType, $this->bundle, 'default') + ->setComponent($this->fieldName, array( + 'type' => 'string', + 'settings' => array(), + )); + $this->display->save(); + } + + /** + * Renders fields of a given entity with a given display. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity object with attached fields to render. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The display to render the fields in. + * + * @return string + * The rendered entity fields. + */ + protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { + $content = $display->build($entity); + $content = $this->render($content); + return $content; + } + + /** + * Tests string formatter output. + */ + public function testStringFormatter() { + $value = $this->randomString(); + $value .= "\n\n" . $this->randomString() . ''; + $value .= "\n\n" . $this->randomString(); + + $entity = EntityTestRev::create(array()); + $entity->{$this->fieldName}->value = $value; + + // Verify that all HTML is escaped and newlines are retained. + $this->renderEntityFields($entity, $this->display); + $this->assertNoRaw($value); + $this->assertRaw(nl2br(Html::escape($value))); + + // Verify the cache tags. + $build = $entity->{$this->fieldName}->view(); + $this->assertTrue(!isset($build[0]['#cache']), 'The string formatter has no cache tags.'); + + $value = $this->randomMachineName(); + $entity->{$this->fieldName}->value = $value; + $entity->save(); + + // Set the formatter to link to the entity. + $this->display->setComponent($this->fieldName, [ + 'type' => 'string', + 'settings' => [ + 'link_to_entity' => TRUE, + ], + ]); + $this->display->save(); + + $this->renderEntityFields($entity, $this->display); + $this->assertLink($value, 0); + $this->assertLinkByHref($entity->url()); + + // $entity->url('revision') falls back to the canonical URL if this is no + // revision. + $this->assertLinkByHref($entity->url('revision')); + + // Make the entity a new revision. + $old_revision_id = $entity->getRevisionId(); + $entity->setNewRevision(TRUE); + $value2 = $this->randomMachineName(); + $entity->{$this->fieldName}->value = $value2; + $entity->save(); + $entity_new_revision = \Drupal::entityManager()->getStorage('entity_test_rev')->loadRevision($old_revision_id); + + $this->renderEntityFields($entity, $this->display); + $this->assertLink($value2, 0); + $this->assertLinkByHref($entity->url('revision')); + + $this->renderEntityFields($entity_new_revision, $this->display); + $this->assertLink($value, 0); + $this->assertLinkByHref('/entity_test_rev/' . $entity_new_revision->id() . '/revision/' . $entity_new_revision->getRevisionId() . '/view'); + } +} diff --git a/core/modules/field/src/Tests/String/UuidFormatterTest.php b/core/modules/field/src/Tests/String/UuidFormatterTest.php new file mode 100644 index 0000000..def8060 --- /dev/null +++ b/core/modules/field/src/Tests/String/UuidFormatterTest.php @@ -0,0 +1,63 @@ +installConfig(['system', 'field']); + \Drupal::service('router.builder')->rebuild(); + $this->installEntitySchema('entity_test'); + } + + /** + * Tests string formatter output. + */ + public function testUuidStringFormatter() { + $entity = EntityTest::create([]); + $entity->save(); + + $uuid_field = $entity->get('uuid'); + + // Verify default render. + $render_array = $uuid_field->view([]); + $this->assertIdentical($render_array[0]['#context']['value'], $entity->uuid(), 'The rendered UUID matches the entity UUID.'); + $this->assertTrue(strpos($this->render($render_array), $entity->uuid()), 'The rendered UUID found.'); + + // Verify customized render. + $render_array = $uuid_field->view(['settings' => ['link_to_entity' => TRUE]]); + $this->assertIdentical($render_array[0]['#type'], 'link'); + $this->assertIdentical($render_array[0]['#title']['#context']['value'], $entity->uuid()); + $this->assertIdentical($render_array[0]['#url']->toString(), $entity->url()); + $rendered = $this->render($render_array); + $this->assertTrue(strpos($rendered, $entity->uuid()), 'The rendered UUID found.'); + $this->assertTrue(strpos($rendered, $entity->url()), 'The rendered entity URL found.'); + } + +} diff --git a/core/modules/field/src/Tests/TestItemTest.php b/core/modules/field/src/Tests/TestItemTest.php new file mode 100644 index 0000000..08b0bae --- /dev/null +++ b/core/modules/field/src/Tests/TestItemTest.php @@ -0,0 +1,101 @@ + $this->fieldName, + 'entity_type' => 'entity_test', + 'type' => 'test_field', + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => $this->fieldName, + 'bundle' => 'entity_test', + ])->save(); + } + + /** + * Tests using entity fields of the field field type. + */ + public function testTestItem() { + // Verify entity creation. + $entity = EntityTest::create(); + $value = rand(1, 10); + $entity->field_test = $value; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->{$this->fieldName} instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->{$this->fieldName}[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->{$this->fieldName}->value, $value); + $this->assertEqual($entity->{$this->fieldName}[0]->value, $value); + + // Verify changing the field value. + $new_value = rand(1, 10); + $entity->field_test->value = $new_value; + $this->assertEqual($entity->{$this->fieldName}->value, $new_value); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->{$this->fieldName}->value, $new_value); + + // Test the schema for this field type. + $expected_schema = array( + 'columns' => array( + 'value' => array( + 'type' => 'int', + 'size' => 'medium', + ), + ), + 'unique keys' => array(), + 'indexes' => array( + 'value' => array('value'), + ), + 'foreign keys' => array(), + ); + $field_schema = BaseFieldDefinition::create('test_field')->getSchema(); + $this->assertEqual($field_schema, $expected_schema); + } + +} diff --git a/core/modules/field/src/Tests/TestItemWithDependenciesTest.php b/core/modules/field/src/Tests/TestItemWithDependenciesTest.php new file mode 100644 index 0000000..16d5a78 --- /dev/null +++ b/core/modules/field/src/Tests/TestItemWithDependenciesTest.php @@ -0,0 +1,60 @@ + $this->fieldName, + 'entity_type' => 'entity_test', + 'type' => 'test_field_with_dependencies', + ))->save(); + $field = FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => $this->fieldName, + 'bundle' => 'entity_test', + ]); + $field->save(); + + // Validate that the field configuration entity has the expected + // dependencies. + $this->assertEqual([ + 'content' => ['node:article:uuid'], + 'config' => ['field.storage.entity_test.field_test'], + 'module' => ['entity_test', 'field_test', 'test_module'] + ], $field->getDependencies()); + } + +} diff --git a/core/modules/field/src/Tests/Timestamp/TimestampFormatterTest.php b/core/modules/field/src/Tests/Timestamp/TimestampFormatterTest.php new file mode 100644 index 0000000..2323b15 --- /dev/null +++ b/core/modules/field/src/Tests/Timestamp/TimestampFormatterTest.php @@ -0,0 +1,194 @@ +installConfig(['system']); + $this->installConfig(['field']); + $this->installEntitySchema('entity_test'); + + $this->entityType = 'entity_test'; + $this->bundle = $this->entityType; + $this->fieldName = Unicode::strtolower($this->randomMachineName()); + + $field_storage = FieldStorageConfig::create([ + 'field_name' => $this->fieldName, + 'entity_type' => $this->entityType, + 'type' => 'timestamp', + ]); + $field_storage->save(); + + $instance = FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => $this->bundle, + 'label' => $this->randomMachineName(), + ]); + $instance->save(); + + $this->display = entity_get_display($this->entityType, $this->bundle, 'default') + ->setComponent($this->fieldName, [ + 'type' => 'boolean', + 'settings' => [], + ]); + $this->display->save(); + } + + /** + * Renders fields of a given entity with a given display. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The entity object with attached fields to render. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The display to render the fields in. + * + * @return string + * The rendered entity fields. + */ + protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { + $content = $display->build($entity); + $content = $this->render($content); + return $content; + } + + /** + * Tests TimestampFormatter. + */ + protected function testTimestampFormatter() { + $data = []; + + // Test standard formats. + $date_formats = array_keys(\Drupal::entityManager()->getStorage('date_format')->loadMultiple()); + + foreach ($date_formats as $date_format) { + $data[] = ['date_format' => $date_format, 'custom_date_format' => '', 'timezone' => '']; + } + + $data[] = ['date_format' => 'custom', 'custom_date_format' => 'r', 'timezone' => '']; + $data[] = ['date_format' => 'custom', 'custom_date_format' => 'e', 'timezone' => 'Asia/Tokyo']; + + foreach ($data as $settings) { + list($date_format, $custom_date_format, $timezone) = array_values($settings); + if (empty($timezone)) { + $timezone = NULL; + } + + $value = REQUEST_TIME - 87654321; + $expected = \Drupal::service('date.formatter')->format($value, $date_format, $custom_date_format, $timezone); + + $component = $this->display->getComponent($this->fieldName); + $component['type'] = 'timestamp'; + $component['settings'] = $settings; + $this->display->setComponent($this->fieldName, $component); + + $entity = EntityTest::create([]); + $entity->{$this->fieldName}->value = $value; + + $this->renderEntityFields($entity, $this->display); + $this->assertRaw($expected); + } + } + + /** + * Tests TimestampAgoFormatter. + */ + protected function testTimestampAgoFormatter() { + $data = []; + + foreach (array(1, 2, 3, 4, 5, 6) as $granularity) { + $data[] = [ + 'future_format' => '@interval hence', + 'past_format' => '@interval ago', + 'granularity' => $granularity, + ]; + } + + foreach ($data as $settings) { + $future_format = $settings['future_format']; + $past_format = $settings['past_format']; + $granularity = $settings['granularity']; + $request_time = \Drupal::requestStack()->getCurrentRequest()->server->get('REQUEST_TIME'); + + // Test a timestamp in the past + $value = $request_time - 87654321; + $expected = SafeMarkup::format($past_format, ['@interval' => \Drupal::service('date.formatter')->formatTimeDiffSince($value, ['granularity' => $granularity])]); + + $component = $this->display->getComponent($this->fieldName); + $component['type'] = 'timestamp_ago'; + $component['settings'] = $settings; + $this->display->setComponent($this->fieldName, $component); + + $entity = EntityTest::create([]); + $entity->{$this->fieldName}->value = $value; + + $this->renderEntityFields($entity, $this->display); + $this->assertRaw($expected); + + // Test a timestamp in the future + $value = $request_time + 87654321; + $expected = SafeMarkup::format($future_format, ['@interval' => \Drupal::service('date.formatter')->formatTimeDiffUntil($value, ['granularity' => $granularity])]); + + $component = $this->display->getComponent($this->fieldName); + $component['type'] = 'timestamp_ago'; + $component['settings'] = $settings; + $this->display->setComponent($this->fieldName, $component); + + $entity = EntityTest::create([]); + $entity->{$this->fieldName}->value = $value; + + $this->renderEntityFields($entity, $this->display); + $this->assertRaw($expected); + } + } + +} diff --git a/core/modules/field/src/Tests/TranslationTest.php b/core/modules/field/src/Tests/TranslationTest.php new file mode 100644 index 0000000..efe1b7a --- /dev/null +++ b/core/modules/field/src/Tests/TranslationTest.php @@ -0,0 +1,214 @@ +installConfig(array('language')); + + $this->fieldName = Unicode::strtolower($this->randomMachineName()); + + $this->entityType = 'entity_test'; + + $this->fieldStorageDefinition = array( + 'field_name' => $this->fieldName, + 'entity_type' => $this->entityType, + 'type' => 'test_field', + 'cardinality' => 4, + ); + $this->fieldStorage = FieldStorageConfig::create($this->fieldStorageDefinition); + $this->fieldStorage->save(); + + $this->fieldDefinition = array( + 'field_storage' => $this->fieldStorage, + 'bundle' => 'entity_test', + ); + $this->field = FieldConfig::create($this->fieldDefinition); + $this->field->save(); + + for ($i = 0; $i < 3; ++$i) { + ConfigurableLanguage::create(array( + 'id' => 'l' . $i, + 'label' => $this->randomString(), + ))->save(); + } + } + + /** + * Test translatable fields storage/retrieval. + */ + function testTranslatableFieldSaveLoad() { + // Enable field translations for nodes. + field_test_entity_info_translatable('node', TRUE); + $entity_type = \Drupal::entityManager()->getDefinition('node'); + $this->assertTrue($entity_type->isTranslatable(), 'Nodes are translatable.'); + + // Prepare the field translations. + $entity_type_id = 'entity_test'; + field_test_entity_info_translatable($entity_type_id, TRUE); + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type_id) + ->create(array('type' => $this->field->getTargetBundle())); + $field_translations = array(); + $available_langcodes = array_keys($this->container->get('language_manager')->getLanguages()); + $entity->langcode->value = reset($available_langcodes); + foreach ($available_langcodes as $langcode) { + $field_translations[$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality()); + $translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode); + $translation->{$this->fieldName}->setValue($field_translations[$langcode]); + } + + // Save and reload the field translations. + $entity = $this->entitySaveReload($entity); + + // Check if the correct values were saved/loaded. + foreach ($field_translations as $langcode => $items) { + $result = TRUE; + foreach ($items as $delta => $item) { + $result = $result && $item['value'] == $entity->getTranslation($langcode)->{$this->fieldName}[$delta]->value; + } + $this->assertTrue($result, format_string('%language translation correctly handled.', array('%language' => $langcode))); + } + + // Test default values. + $field_name_default = Unicode::strtolower($this->randomMachineName() . '_field_name'); + $field_storage_definition = $this->fieldStorageDefinition; + $field_storage_definition['field_name'] = $field_name_default; + $field_storage = FieldStorageConfig::create($field_storage_definition); + $field_storage->save(); + + $field_definition = $this->fieldDefinition; + $field_definition['field_storage'] = $field_storage; + $field_definition['default_value'] = array(array('value' => rand(1, 127))); + $field = FieldConfig::create($field_definition); + $field->save(); + + $translation_langcodes = array_slice($available_langcodes, 0, 2); + asort($translation_langcodes); + $translation_langcodes = array_values($translation_langcodes); + + $values = array('type' => $field->getTargetBundle(), 'langcode' => $translation_langcodes[0]); + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type_id) + ->create($values); + foreach ($translation_langcodes as $langcode) { + $values[$this->fieldName][$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality()); + $translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode); + $translation->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]); + } + + $field_langcodes = array_keys($entity->getTranslationLanguages()); + sort($field_langcodes); + $this->assertEqual($translation_langcodes, $field_langcodes, 'Missing translations did not get a default value.'); + + // @todo Test every translation once the Entity Translation API allows for + // multilingual defaults. + $langcode = $entity->language()->getId(); + $this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $field->getDefaultValueLiteral(), format_string('Default value correctly populated for language %language.', array('%language' => $langcode))); + + // Check that explicit empty values are not overridden with default values. + foreach (array(NULL, array()) as $empty_items) { + $values = array('type' => $field->getTargetBundle(), 'langcode' => $translation_langcodes[0]); + $entity = entity_create($entity_type_id, $values); + foreach ($translation_langcodes as $langcode) { + $values[$this->fieldName][$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality()); + $translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode); + $translation->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]); + $translation->{$field_name_default}->setValue($empty_items); + $values[$field_name_default][$langcode] = $empty_items; + } + + foreach ($entity->getTranslationLanguages() as $langcode => $language) { + $this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $empty_items, format_string('Empty value correctly populated for language %language.', array('%language' => $langcode))); + } + } + } + + /** + * Tests field access. + * + * Regression test to verify that fieldAccess() can be called while only + * passing the required parameters. + * + * @see https://www.drupal.org/node/2404739 + */ + public function testFieldAccess() { + $access_control_handler = \Drupal::entityManager()->getAccessControlHandler($this->entityType); + $this->assertTrue($access_control_handler->fieldAccess('view', $this->field)); + } + +} diff --git a/core/modules/field/src/Tests/Uri/UriItemTest.php b/core/modules/field/src/Tests/Uri/UriItemTest.php new file mode 100644 index 0000000..ddef127 --- /dev/null +++ b/core/modules/field/src/Tests/Uri/UriItemTest.php @@ -0,0 +1,79 @@ +randomMachineName(); + + // Create a field with settings to validate. + $field_name = Unicode::strtolower($this->randomMachineName()); + $this->fieldStorage = FieldStorageConfig::create([ + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'type' => 'uri', + ]); + $this->fieldStorage->save(); + $this->field = FieldConfig::create([ + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + 'label' => $label, + 'required' => TRUE, + 'settings' => [ + 'size' => 123, + 'placeholder' => '', + ], + ]); + $this->field->save(); + + // Create a form display for the default form mode. + entity_get_form_display('entity_test', 'entity_test', 'default') + ->setComponent($field_name, [ + 'type' => 'uri', + ]) + ->save(); + + // Test the generateSampleValue() method. + $entity = EntityTest::create(); + $entity->$field_name->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + +} diff --git a/core/modules/field/src/Tests/WidgetPluginManagerTest.php b/core/modules/field/src/Tests/WidgetPluginManagerTest.php new file mode 100644 index 0000000..d475541 --- /dev/null +++ b/core/modules/field/src/Tests/WidgetPluginManagerTest.php @@ -0,0 +1,63 @@ +getDefinition('test_field_widget_multiple'); + + // Test if hook_field_widget_info_alter is being called. + $this->assertTrue(in_array('test_field', $widget_definition['field_types']), "The 'test_field_widget_multiple' widget is enabled for the 'test_field' field type in field_test_field_widget_info_alter()."); + } + + /** + * Tests that getInstance falls back on default if current is not applicable. + * + * @see \Drupal\field\Tests\FormatterPluginManagerTest::testNotApplicableFallback() + */ + public function testNotApplicableFallback() { + /** @var WidgetPluginManager $widget_plugin_manager */ + $widget_plugin_manager = \Drupal::service('plugin.manager.field.widget'); + + $base_field_definition = BaseFieldDefinition::create('test_field') + // Set a name that will make isApplicable() return TRUE. + ->setName('field_multiwidgetfield'); + + $widget_options = array( + 'field_definition' => $base_field_definition, + 'form_mode' => 'default', + 'configuration' => array( + 'type' => 'test_field_widget_multiple', + ), + ); + + $instance = $widget_plugin_manager->getInstance($widget_options); + $this->assertEqual($instance->getPluginId(), 'test_field_widget_multiple'); + + // Now do the same but with machine name field_onewidgetfield, because that + // makes isApplicable() return FALSE. + $base_field_definition->setName('field_onewidgetfield'); + $instance = $widget_plugin_manager->getInstance($widget_options); + + // Instance should be default widget. + $this->assertNotEqual($instance->getPluginId(), 'test_field_widget_multiple'); + $this->assertEqual($instance->getPluginId(), 'test_field_widget'); + } + +} diff --git a/core/modules/field/tests/src/Kernel/Boolean/BooleanFormatterTest.php b/core/modules/field/tests/src/Kernel/Boolean/BooleanFormatterTest.php deleted file mode 100644 index fb04f97..0000000 --- a/core/modules/field/tests/src/Kernel/Boolean/BooleanFormatterTest.php +++ /dev/null @@ -1,144 +0,0 @@ -installConfig(['field']); - $this->installEntitySchema('entity_test'); - - $this->entityType = 'entity_test'; - $this->bundle = $this->entityType; - $this->fieldName = Unicode::strtolower($this->randomMachineName()); - - $field_storage = FieldStorageConfig::create([ - 'field_name' => $this->fieldName, - 'entity_type' => $this->entityType, - 'type' => 'boolean', - ]); - $field_storage->save(); - - $instance = FieldConfig::create([ - 'field_storage' => $field_storage, - 'bundle' => $this->bundle, - 'label' => $this->randomMachineName(), - ]); - $instance->save(); - - $this->display = entity_get_display($this->entityType, $this->bundle, 'default') - ->setComponent($this->fieldName, [ - 'type' => 'boolean', - 'settings' => [], - ]); - $this->display->save(); - } - - /** - * Renders fields of a given entity with a given display. - * - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity object with attached fields to render. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The display to render the fields in. - * - * @return string - * The rendered entity fields. - */ - protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { - $content = $display->build($entity); - $content = $this->render($content); - return $content; - } - - /** - * Tests boolean formatter output. - */ - public function testBooleanFormatter() { - $data = []; - $data[] = [0, [], 'Off']; - $data[] = [1, [], 'On']; - - $format = ['format' => 'enabled-disabled']; - $data[] = [0, $format, 'Disabled']; - $data[] = [1, $format, 'Enabled']; - - $format = ['format' => 'unicode-yes-no']; - $data[] = [1, $format, '✔']; - $data[] = [0, $format, '✖']; - - $format = [ - 'format' => 'custom', - 'format_custom_false' => 'FALSE', - 'format_custom_true' => 'TRUE' - ]; - $data[] = [0, $format, 'FALSE']; - $data[] = [1, $format, 'TRUE']; - - foreach ($data as $test_data) { - list($value, $settings, $expected) = $test_data; - - $component = $this->display->getComponent($this->fieldName); - $component['settings'] = $settings; - $this->display->setComponent($this->fieldName, $component); - - $entity = EntityTest::create([]); - $entity->{$this->fieldName}->value = $value; - - // Verify that all HTML is escaped and newlines are retained. - $this->renderEntityFields($entity, $this->display); - $this->assertRaw($expected); - } - } - -} diff --git a/core/modules/field/tests/src/Kernel/Boolean/BooleanItemTest.php b/core/modules/field/tests/src/Kernel/Boolean/BooleanItemTest.php deleted file mode 100644 index 68d6670..0000000 --- a/core/modules/field/tests/src/Kernel/Boolean/BooleanItemTest.php +++ /dev/null @@ -1,85 +0,0 @@ - 'field_boolean', - 'entity_type' => 'entity_test', - 'type' => 'boolean', - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'field_boolean', - 'bundle' => 'entity_test', - ])->save(); - - // Create a form display for the default form mode. - entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent('field_boolean', array( - 'type' => 'boolean_checkbox', - )) - ->save(); - } - - /** - * Tests using entity fields of the boolean field type. - */ - public function testBooleanItem() { - // Verify entity creation. - $entity = EntityTest::create(); - $value = '1'; - $entity->field_boolean = $value; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->field_boolean instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_boolean[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_boolean->value, $value); - $this->assertEqual($entity->field_boolean[0]->value, $value); - - // Verify changing the boolean value. - $new_value = 0; - $entity->field_boolean->value = $new_value; - $this->assertEqual($entity->field_boolean->value, $new_value); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_boolean->value, $new_value); - - // Test sample item generation. - $entity = EntityTest::create(); - $entity->field_boolean->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - -} diff --git a/core/modules/field/tests/src/Kernel/BulkDeleteTest.php b/core/modules/field/tests/src/Kernel/BulkDeleteTest.php deleted file mode 100644 index 73479d1..0000000 --- a/core/modules/field/tests/src/Kernel/BulkDeleteTest.php +++ /dev/null @@ -1,365 +0,0 @@ - $invocations) { - $actual_invocations = $actual_hooks[$hook]; - - // Check that the number of invocations is correct. - $this->assertEqual(count($actual_invocations), count($invocations), "$hook() was called the expected number of times."); - - // Check that the hook was called for each expected argument. - foreach ($invocations as $argument) { - $found = FALSE; - foreach ($actual_invocations as $actual_arguments) { - // The argument we are looking for is either an array of entities as - // the second argument or a single entity object as the first. - if ($argument instanceof EntityInterface && $actual_arguments[0]->id() == $argument->id()) { - $found = TRUE; - break; - } - // In case of an array, compare the array size and make sure it - // contains the same elements. - elseif (is_array($argument) && count($actual_arguments[1]) == count($argument) && count(array_diff_key($actual_arguments[1], $argument)) == 0) { - $found = TRUE; - break; - } - } - $this->assertTrue($found, "$hook() was called on expected argument"); - } - } - } - - protected function setUp() { - parent::setUp(); - - $this->fieldStorages = array(); - $this->entities = array(); - $this->entitiesByBundles = array(); - - // Create two bundles. - $this->bundles = array('bb_1' => 'bb_1', 'bb_2' => 'bb_2'); - foreach ($this->bundles as $name => $desc) { - entity_test_create_bundle($name, $desc); - } - - // Create two field storages. - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'bf_1', - 'entity_type' => $this->entityTypeId, - 'type' => 'test_field', - 'cardinality' => 1 - )); - $field_storage->save(); - $this->fieldStorages[] = $field_storage; - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'bf_2', - 'entity_type' => $this->entityTypeId, - 'type' => 'test_field', - 'cardinality' => 4 - )); - $field_storage->save(); - $this->fieldStorages[] = $field_storage; - - // For each bundle, create each field, and 10 entities with values for the - // fields. - foreach ($this->bundles as $bundle) { - foreach ($this->fieldStorages as $field_storage) { - FieldConfig::create([ - 'field_storage' => $field_storage, - 'bundle' => $bundle, - ])->save(); - } - for ($i = 0; $i < 10; $i++) { - $entity = $this->container->get('entity_type.manager') - ->getStorage($this->entityTypeId) - ->create(array('type' => $bundle)); - foreach ($this->fieldStorages as $field_storage) { - $entity->{$field_storage->getName()}->setValue($this->_generateTestFieldValues($field_storage->getCardinality())); - } - $entity->save(); - } - } - $this->entities = entity_load_multiple($this->entityTypeId); - foreach ($this->entities as $entity) { - // This test relies on the entities having stale field definitions - // so that the deleted field can be accessed on them. Access the field - // now, so that they are always loaded. - $entity->bf_1->value; - - // Also keep track of the entities per bundle. - $this->entitiesByBundles[$entity->bundle()][$entity->id()] = $entity; - } - } - - /** - * Verify that deleting a field leaves the field data items in the database - * and that the appropriate Field API functions can operate on the deleted - * data and field definition. - * - * This tests how EntityFieldQuery interacts with field deletion and could be - * moved to FieldCrudTestCase, but depends on this class's setUp(). - */ - function testDeleteField() { - $bundle = reset($this->bundles); - $field_storage = reset($this->fieldStorages); - $field_name = $field_storage->getName(); - $factory = \Drupal::service('entity.query'); - - // There are 10 entities of this bundle. - $found = $factory->get('entity_test') - ->condition('type', $bundle) - ->execute(); - $this->assertEqual(count($found), 10, 'Correct number of entities found before deleting'); - - // Delete the field. - $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); - $field->delete(); - - // The field still exists, deleted. - $fields = entity_load_multiple_by_properties('field_config', array('field_storage_uuid' => $field_storage->uuid(), 'deleted' => TRUE, 'include_deleted' => TRUE)); - $this->assertEqual(count($fields), 1, 'There is one deleted field'); - $field = $fields[$field->uuid()]; - $this->assertEqual($field->getTargetBundle(), $bundle, 'The deleted field is for the correct bundle'); - - // Check that the actual stored content did not change during delete. - $storage = \Drupal::entityManager()->getStorage($this->entityTypeId); - /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ - $table_mapping = $storage->getTableMapping(); - $table = $table_mapping->getDedicatedDataTableName($field_storage); - $column = $table_mapping->getFieldColumnName($field_storage, 'value'); - $result = db_select($table, 't') - ->fields('t') - ->execute(); - foreach ($result as $row) { - $this->assertEqual($this->entities[$row->entity_id]->{$field_name}->value, $row->$column); - } - - // There are 0 entities of this bundle with non-deleted data. - $found = $factory->get('entity_test') - ->condition('type', $bundle) - ->condition("$field_name.deleted", 0) - ->execute(); - $this->assertFalse($found, 'No entities found after deleting'); - - // There are 10 entities of this bundle when deleted fields are allowed, and - // their values are correct. - $found = $factory->get('entity_test') - ->condition('type', $bundle) - ->condition("$field_name.deleted", 1) - ->sort('id') - ->execute(); - $this->assertEqual(count($found), 10, 'Correct number of entities found after deleting'); - $this->assertFalse(array_diff($found, array_keys($this->entities))); - } - - /** - * Verify that field data items and fields are purged when a field storage is - * deleted. - */ - function testPurgeField() { - // Start recording hook invocations. - field_test_memorize(); - - $bundle = reset($this->bundles); - $field_storage = reset($this->fieldStorages); - $field_name = $field_storage->getName(); - - // Delete the field. - $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); - $field->delete(); - - // No field hooks were called. - $mem = field_test_memorize(); - $this->assertEqual(count($mem), 0, 'No field hooks were called'); - - $batch_size = 2; - for ($count = 8; $count >= 0; $count -= $batch_size) { - // Purge two entities. - field_purge_batch($batch_size); - - // There are $count deleted entities left. - $found = \Drupal::entityQuery('entity_test') - ->condition('type', $bundle) - ->condition($field_name . '.deleted', 1) - ->execute(); - $this->assertEqual(count($found), $count, 'Correct number of entities found after purging 2'); - } - - // Check hooks invocations. - // FieldItemInterface::delete() should have been called once for each entity in the - // bundle. - $actual_hooks = field_test_memorize(); - $hooks = array(); - $entities = $this->entitiesByBundles[$bundle]; - foreach ($entities as $id => $entity) { - $hooks['field_test_field_delete'][] = $entity; - } - $this->checkHooksInvocations($hooks, $actual_hooks); - - // The field still exists, deleted. - $fields = entity_load_multiple_by_properties('field_config', array('field_storage_uuid' => $field_storage->uuid(), 'deleted' => TRUE, 'include_deleted' => TRUE)); - $this->assertEqual(count($fields), 1, 'There is one deleted field'); - - // Purge the field. - field_purge_batch($batch_size); - - // The field is gone. - $fields = entity_load_multiple_by_properties('field_config', array('field_storage_uuid' => $field_storage->uuid(), 'deleted' => TRUE, 'include_deleted' => TRUE)); - $this->assertEqual(count($fields), 0, 'The field is gone'); - - // The field storage still exists, not deleted, because it has a second - // field. - $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); - $this->assertTrue(isset($storages[$field_storage->uuid()]), 'The field storage exists and is not deleted'); - } - - /** - * Verify that field storages are preserved and purged correctly as multiple - * fields are deleted and purged. - */ - function testPurgeFieldStorage() { - // Start recording hook invocations. - field_test_memorize(); - - $field_storage = reset($this->fieldStorages); - $field_name = $field_storage->getName(); - - // Delete the first field. - $bundle = reset($this->bundles); - $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); - $field->delete(); - - // Assert that FieldItemInterface::delete() was not called yet. - $mem = field_test_memorize(); - $this->assertEqual(count($mem), 0, 'No field hooks were called.'); - - // Purge the data. - field_purge_batch(10); - - // Check hooks invocations. - // FieldItemInterface::delete() should have been called once for each entity in the - // bundle. - $actual_hooks = field_test_memorize(); - $hooks = array(); - $entities = $this->entitiesByBundles[$bundle]; - foreach ($entities as $id => $entity) { - $hooks['field_test_field_delete'][] = $entity; - } - $this->checkHooksInvocations($hooks, $actual_hooks); - - // The field still exists, deleted. - $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); - $this->assertTrue(isset($fields[$field->uuid()]) && $fields[$field->uuid()]->isDeleted(), 'The field exists and is deleted'); - - // Purge again to purge the field. - field_purge_batch(0); - - // The field is gone. - $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); - $this->assertEqual(count($fields), 0, 'The field is purged.'); - // The field storage still exists, not deleted. - $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); - $this->assertTrue(isset($storages[$field_storage->uuid()]) && !$storages[$field_storage->uuid()]->isDeleted(), 'The field storage exists and is not deleted'); - - // Delete the second field. - $bundle = next($this->bundles); - $field = FieldConfig::loadByName($this->entityTypeId, $bundle, $field_name); - $field->delete(); - - // Assert that FieldItemInterface::delete() was not called yet. - $mem = field_test_memorize(); - $this->assertEqual(count($mem), 0, 'No field hooks were called.'); - - // Purge the data. - field_purge_batch(10); - - // Check hooks invocations (same as above, for the 2nd bundle). - $actual_hooks = field_test_memorize(); - $hooks = array(); - $entities = $this->entitiesByBundles[$bundle]; - foreach ($entities as $id => $entity) { - $hooks['field_test_field_delete'][] = $entity; - } - $this->checkHooksInvocations($hooks, $actual_hooks); - - // The field and the storage still exist, deleted. - $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); - $this->assertTrue(isset($fields[$field->uuid()]) && $fields[$field->uuid()]->isDeleted(), 'The field exists and is deleted'); - $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); - $this->assertTrue(isset($storages[$field_storage->uuid()]) && $storages[$field_storage->uuid()]->isDeleted(), 'The field storage exists and is deleted'); - - // Purge again to purge the field and the storage. - field_purge_batch(0); - - // The field and the storage are gone. - $fields = entity_load_multiple_by_properties('field_config', array('uuid' => $field->uuid(), 'include_deleted' => TRUE)); - $this->assertEqual(count($fields), 0, 'The field is purged.'); - $storages = entity_load_multiple_by_properties('field_storage_config', array('uuid' => $field_storage->uuid(), 'include_deleted' => TRUE)); - $this->assertEqual(count($storages), 0, 'The field storage is purged.'); - } - -} diff --git a/core/modules/field/tests/src/Kernel/ConfigFieldDefinitionTest.php b/core/modules/field/tests/src/Kernel/ConfigFieldDefinitionTest.php deleted file mode 100644 index 62fb2c3..0000000 --- a/core/modules/field/tests/src/Kernel/ConfigFieldDefinitionTest.php +++ /dev/null @@ -1,77 +0,0 @@ -entityType = 'entity_test'; - $this->bundle = 'entity_test'; - $this->createFieldWithStorage('', $this->entityType, $this->bundle); - $this->entityManager = $this->container->get('entity.manager'); - - // Create a second field on 'entity_test_rev'. - $this->createFieldWithStorage('_rev', 'entity_test_rev', 'entity_test_rev'); - } - - /** - * Makes sure a field definition is exposed for a configurable field. - */ - public function testBundleFieldDefinition() { - $definitions = $this->entityManager->getFieldDefinitions($this->entityType, $this->bundle); - $this->assertTrue(isset($definitions[$this->fieldTestData->field->getName()])); - $this->assertTrue($definitions[$this->fieldTestData->field->getName()] instanceof FieldDefinitionInterface); - // Make sure fields on other entity types are not exposed. - $this->assertFalse(isset($definitions[$this->fieldTestData->field_rev->getName()])); - } - - /** - * Makes sure a field storage definition is exposed for a configurable field. - */ - public function testFieldStorageDefinition() { - $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->entityType); - $this->assertTrue(isset($field_storage_definitions[$this->fieldTestData->field->getName()])); - $this->assertTrue($field_storage_definitions[$this->fieldTestData->field->getName()] instanceof FieldStorageDefinitionInterface); - // Make sure storages on other entity types are not exposed. - $this->assertFalse(isset($field_storage_definitions[$this->fieldTestData->field_rev->getName()])); - } - -} diff --git a/core/modules/field/tests/src/Kernel/DisplayApiTest.php b/core/modules/field/tests/src/Kernel/DisplayApiTest.php deleted file mode 100644 index 71373c4..0000000 --- a/core/modules/field/tests/src/Kernel/DisplayApiTest.php +++ /dev/null @@ -1,317 +0,0 @@ -fieldName = 'test_field'; - $this->label = $this->randomMachineName(); - $this->cardinality = 4; - - $field_storage = array( - 'field_name' => $this->fieldName, - 'entity_type' => 'entity_test', - 'type' => 'test_field', - 'cardinality' => $this->cardinality, - ); - $field = array( - 'field_name' => $this->fieldName, - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - 'label' => $this->label, - ); - - $this->displayOptions = array( - 'default' => array( - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $this->randomMachineName(), - ), - ), - 'teaser' => array( - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $this->randomMachineName(), - ), - ), - ); - - FieldStorageConfig::create($field_storage)->save(); - FieldConfig::create($field)->save(); - // Create a display for the default view mode. - entity_get_display($field['entity_type'], $field['bundle'], 'default') - ->setComponent($this->fieldName, $this->displayOptions['default']) - ->save(); - // Create a display for the teaser view mode. - EntityViewMode::create(array('id' => 'entity_test.teaser', 'targetEntityType' => 'entity_test'))->save(); - entity_get_display($field['entity_type'], $field['bundle'], 'teaser') - ->setComponent($this->fieldName, $this->displayOptions['teaser']) - ->save(); - - // Create an entity with values. - $this->values = $this->_generateTestFieldValues($this->cardinality); - $this->entity = EntityTest::create(); - $this->entity->{$this->fieldName}->setValue($this->values); - $this->entity->save(); - } - - /** - * Tests the FieldItemListInterface::view() method. - */ - function testFieldItemListView() { - $items = $this->entity->get($this->fieldName); - - \Drupal::service('theme_handler')->install(['classy']); - \Drupal::service('theme_handler')->setDefault('classy'); - - // No display settings: check that default display settings are used. - $build = $items->view(); - $this->render($build); - $settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings('field_test_default'); - $setting = $settings['test_formatter_setting']; - $this->assertText($this->label, 'Label was displayed.'); - foreach ($this->values as $delta => $value) { - $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - - // Display settings: Check hidden field. - $display = array( - 'label' => 'hidden', - 'type' => 'field_test_multiple', - 'settings' => array( - 'test_formatter_setting_multiple' => $this->randomMachineName(), - 'alter' => TRUE, - ), - ); - $build = $items->view($display); - $this->render($build); - $setting = $display['settings']['test_formatter_setting_multiple']; - $this->assertNoText($this->label, 'Label was not displayed.'); - $this->assertText('field_test_entity_display_build_alter', 'Alter fired, display passed.'); - $this->assertText('entity language is en', 'Language is placed onto the context.'); - $array = array(); - foreach ($this->values as $delta => $value) { - $array[] = $delta . ':' . $value['value']; - } - $this->assertText($setting . '|' . implode('|', $array), 'Values were displayed with expected setting.'); - - // Display settings: Check visually_hidden field. - $display = array( - 'label' => 'visually_hidden', - 'type' => 'field_test_multiple', - 'settings' => array( - 'test_formatter_setting_multiple' => $this->randomMachineName(), - 'alter' => TRUE, - ), - ); - $build = $items->view($display); - $this->render($build); - $setting = $display['settings']['test_formatter_setting_multiple']; - $this->assertRaw('visually-hidden', 'Label was visually hidden.'); - $this->assertText('field_test_entity_display_build_alter', 'Alter fired, display passed.'); - $this->assertText('entity language is en', 'Language is placed onto the context.'); - $array = array(); - foreach ($this->values as $delta => $value) { - $array[] = $delta . ':' . $value['value']; - } - $this->assertText($setting . '|' . implode('|', $array), 'Values were displayed with expected setting.'); - - // Check the prepare_view steps are invoked. - $display = array( - 'label' => 'hidden', - 'type' => 'field_test_with_prepare_view', - 'settings' => array( - 'test_formatter_setting_additional' => $this->randomMachineName(), - ), - ); - $build = $items->view($display); - $this->render($build); - $setting = $display['settings']['test_formatter_setting_additional']; - $this->assertNoText($this->label, 'Label was not displayed.'); - $this->assertNoText('field_test_entity_display_build_alter', 'Alter not fired.'); - foreach ($this->values as $delta => $value) { - $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - - // View mode: check that display settings specified in the display object - // are used. - $build = $items->view('teaser'); - $this->render($build); - $setting = $this->displayOptions['teaser']['settings']['test_formatter_setting']; - $this->assertText($this->label, 'Label was displayed.'); - foreach ($this->values as $delta => $value) { - $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - - // Unknown view mode: check that display settings for 'default' view mode - // are used. - $build = $items->view('unknown_view_mode'); - $this->render($build); - $setting = $this->displayOptions['default']['settings']['test_formatter_setting']; - $this->assertText($this->label, 'Label was displayed.'); - foreach ($this->values as $delta => $value) { - $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - } - - /** - * Tests the FieldItemInterface::view() method. - */ - function testFieldItemView() { - // No display settings: check that default display settings are used. - $settings = \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings('field_test_default'); - $setting = $settings['test_formatter_setting']; - foreach ($this->values as $delta => $value) { - $item = $this->entity->{$this->fieldName}[$delta]; - $build = $item->view(); - $this->render($build); - $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - - // Check that explicit display settings are used. - $display = array( - 'type' => 'field_test_multiple', - 'settings' => array( - 'test_formatter_setting_multiple' => $this->randomMachineName(), - ), - ); - $setting = $display['settings']['test_formatter_setting_multiple']; - foreach ($this->values as $delta => $value) { - $item = $this->entity->{$this->fieldName}[$delta]; - $build = $item->view($display); - $this->render($build); - $this->assertText($setting . '|0:' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - - // Check that prepare_view steps are invoked. - $display = array( - 'type' => 'field_test_with_prepare_view', - 'settings' => array( - 'test_formatter_setting_additional' => $this->randomMachineName(), - ), - ); - $setting = $display['settings']['test_formatter_setting_additional']; - foreach ($this->values as $delta => $value) { - $item = $this->entity->{$this->fieldName}[$delta]; - $build = $item->view($display); - $this->render($build); - $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - - // View mode: check that display settings specified in the field are used. - $setting = $this->displayOptions['teaser']['settings']['test_formatter_setting']; - foreach ($this->values as $delta => $value) { - $item = $this->entity->{$this->fieldName}[$delta]; - $build = $item->view('teaser'); - $this->render($build); - $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - - // Unknown view mode: check that display settings for 'default' view mode - // are used. - $setting = $this->displayOptions['default']['settings']['test_formatter_setting']; - foreach ($this->values as $delta => $value) { - $item = $this->entity->{$this->fieldName}[$delta]; - $build = $item->view('unknown_view_mode'); - $this->render($build); - $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta))); - } - } - - /** - * Tests that the prepareView() formatter method still fires for empty values. - */ - function testFieldEmpty() { - // Uses \Drupal\field_test\Plugin\Field\FieldFormatter\TestFieldEmptyFormatter. - $display = array( - 'label' => 'hidden', - 'type' => 'field_empty_test', - 'settings' => array( - 'test_empty_string' => '**EMPTY FIELD**' . $this->randomMachineName(), - ), - ); - // $this->entity is set by the setUp() method and by default contains 4 - // numeric values. We only want to test the display of this one field. - $build = $this->entity->get($this->fieldName)->view($display); - $this->render($build); - // The test field by default contains values, so should not display the - // default "empty" text. - $this->assertNoText($display['settings']['test_empty_string']); - - // Now remove the values from the test field and retest. - $this->entity->{$this->fieldName} = array(); - $this->entity->save(); - $build = $this->entity->get($this->fieldName)->view($display); - $this->render($build); - // This time, as the field values have been removed, we *should* show the - // default "empty" text. - $this->assertText($display['settings']['test_empty_string']); - } -} diff --git a/core/modules/field/tests/src/Kernel/Email/EmailItemTest.php b/core/modules/field/tests/src/Kernel/Email/EmailItemTest.php deleted file mode 100644 index 76ed172..0000000 --- a/core/modules/field/tests/src/Kernel/Email/EmailItemTest.php +++ /dev/null @@ -1,82 +0,0 @@ - 'field_email', - 'entity_type' => 'entity_test', - 'type' => 'email', - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'field_email', - 'bundle' => 'entity_test', - ])->save(); - - // Create a form display for the default form mode. - entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent('field_email', array( - 'type' => 'email_default', - )) - ->save(); - } - - /** - * Tests using entity fields of the email field type. - */ - public function testEmailItem() { - // Verify entity creation. - $entity = EntityTest::create(); - $value = 'test@example.com'; - $entity->field_email = $value; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->field_email instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_email[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_email->value, $value); - $this->assertEqual($entity->field_email[0]->value, $value); - - // Verify changing the email value. - $new_value = $this->randomMachineName(); - $entity->field_email->value = $new_value; - $this->assertEqual($entity->field_email->value, $new_value); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_email->value, $new_value); - - // Test sample item generation. - $entity = EntityTest::create(); - $entity->field_email->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - -} diff --git a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceItemTest.php b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceItemTest.php deleted file mode 100644 index d949a9e..0000000 --- a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceItemTest.php +++ /dev/null @@ -1,541 +0,0 @@ -installEntitySchema('entity_test_string_id'); - $this->installEntitySchema('taxonomy_term'); - $this->installEntitySchema('node'); - $this->installEntitySchema('comment'); - $this->installEntitySchema('file'); - - $this->installSchema('comment', ['comment_entity_statistics']); - $this->installSchema('node', ['node_access']); - - $this->vocabulary = Vocabulary::create([ - 'name' => $this->randomMachineName(), - 'vid' => Unicode::strtolower($this->randomMachineName()), - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - ]); - $this->vocabulary->save(); - - $this->term = Term::create([ - 'name' => $this->randomMachineName(), - 'vid' => $this->vocabulary->id(), - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - ]); - $this->term->save(); - - $this->entityStringId = EntityTestStringId::create([ - 'id' => $this->randomMachineName(), - ]); - $this->entityStringId->save(); - - // Use the util to create an instance. - $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_taxonomy_term', 'Test content entity reference', 'taxonomy_term'); - $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_entity_test_string_id', 'Test content entity reference with string ID', 'entity_test_string_id'); - $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_taxonomy_vocabulary', 'Test config entity reference', 'taxonomy_vocabulary'); - $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_node', 'Test node entity reference', 'node', 'default', [], FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); - $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_user', 'Test user entity reference', 'user'); - $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_comment', 'Test comment entity reference', 'comment'); - $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_file', 'Test file entity reference', 'file'); - } - - /** - * Tests the entity reference field type for referencing content entities. - */ - public function testContentEntityReferenceItem() { - $tid = $this->term->id(); - - // Just being able to create the entity like this verifies a lot of code. - $entity = EntityTest::create(); - $entity->field_test_taxonomy_term->target_id = $tid; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - $entity = entity_load('entity_test', $entity->id()); - $this->assertTrue($entity->field_test_taxonomy_term instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_test_taxonomy_term[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_test_taxonomy_term->target_id, $tid); - $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $this->term->getName()); - $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $tid); - $this->assertEqual($entity->field_test_taxonomy_term->entity->uuid(), $this->term->uuid()); - // Verify that the label for the target ID property definition is correct. - $label = $entity->field_test_taxonomy_term->getFieldDefinition()->getFieldStorageDefinition()->getPropertyDefinition('target_id')->getLabel(); - $this->assertTrue($label instanceof TranslatableMarkup); - $this->assertEqual($label->render(), 'Taxonomy term ID'); - - // Change the name of the term via the reference. - $new_name = $this->randomMachineName(); - $entity->field_test_taxonomy_term->entity->setName($new_name); - $entity->field_test_taxonomy_term->entity->save(); - // Verify it is the correct name. - $term = Term::load($tid); - $this->assertEqual($term->getName(), $new_name); - - // Make sure the computed term reflects updates to the term id. - $term2 = Term::create([ - 'name' => $this->randomMachineName(), - 'vid' => $this->term->bundle(), - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - ]); - $term2->save(); - - // Test all the possible ways of assigning a value. - $entity->field_test_taxonomy_term->target_id = $term->id(); - $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term->id()); - $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term->getName()); - - $entity->field_test_taxonomy_term = [['target_id' => $term2->id()]]; - $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term2->id()); - $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term2->getName()); - - // Test value assignment via the computed 'entity' property. - $entity->field_test_taxonomy_term->entity = $term; - $this->assertEqual($entity->field_test_taxonomy_term->target_id, $term->id()); - $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term->getName()); - - $entity->field_test_taxonomy_term = [['entity' => $term2]]; - $this->assertEqual($entity->field_test_taxonomy_term->target_id, $term2->id()); - $this->assertEqual($entity->field_test_taxonomy_term->entity->getName(), $term2->getName()); - - // Test assigning an invalid item throws an exception. - try { - $entity->field_test_taxonomy_term = ['target_id' => 'invalid', 'entity' => $term2]; - $this->fail('Assigning an invalid item throws an exception.'); - } - catch (\InvalidArgumentException $e) { - $this->pass('Assigning an invalid item throws an exception.'); - } - - // Delete terms so we have nothing to reference and try again - $term->delete(); - $term2->delete(); - $entity = EntityTest::create(array('name' => $this->randomMachineName())); - $entity->save(); - - // Test the generateSampleValue() method. - $entity = EntityTest::create(); - $entity->field_test_taxonomy_term->generateSampleItems(); - $entity->field_test_taxonomy_vocabulary->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - - /** - * Tests referencing content entities with string IDs. - */ - public function testContentEntityReferenceItemWithStringId() { - $entity = EntityTest::create(); - $entity->field_test_entity_test_string_id->target_id = $this->entityStringId->id(); - $entity->save(); - $storage = \Drupal::entityManager()->getStorage('entity_test'); - $storage->resetCache(); - $this->assertEqual($this->entityStringId->id(), $storage->load($entity->id())->field_test_entity_test_string_id->target_id); - // Verify that the label for the target ID property definition is correct. - $label = $entity->field_test_taxonomy_term->getFieldDefinition()->getFieldStorageDefinition()->getPropertyDefinition('target_id')->getLabel(); - $this->assertTrue($label instanceof TranslatableMarkup); - $this->assertEqual($label->render(), 'Taxonomy term ID'); - } - - /** - * Tests the entity reference field type for referencing config entities. - */ - public function testConfigEntityReferenceItem() { - $referenced_entity_id = $this->vocabulary->id(); - - // Just being able to create the entity like this verifies a lot of code. - $entity = EntityTest::create(); - $entity->field_test_taxonomy_vocabulary->target_id = $referenced_entity_id; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - $entity = entity_load('entity_test', $entity->id()); - $this->assertTrue($entity->field_test_taxonomy_vocabulary instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_test_taxonomy_vocabulary[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_test_taxonomy_vocabulary->target_id, $referenced_entity_id); - $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->label(), $this->vocabulary->label()); - $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->id(), $referenced_entity_id); - $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->uuid(), $this->vocabulary->uuid()); - - // Change the name of the term via the reference. - $new_name = $this->randomMachineName(); - $entity->field_test_taxonomy_vocabulary->entity->set('name', $new_name); - $entity->field_test_taxonomy_vocabulary->entity->save(); - // Verify it is the correct name. - $vocabulary = Vocabulary::load($referenced_entity_id); - $this->assertEqual($vocabulary->label(), $new_name); - - // Make sure the computed term reflects updates to the term id. - $vocabulary2 = $vocabulary = Vocabulary::create([ - 'name' => $this->randomMachineName(), - 'vid' => Unicode::strtolower($this->randomMachineName()), - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - ]); - $vocabulary2->save(); - - $entity->field_test_taxonomy_vocabulary->target_id = $vocabulary2->id(); - $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->id(), $vocabulary2->id()); - $this->assertEqual($entity->field_test_taxonomy_vocabulary->entity->label(), $vocabulary2->label()); - - // Delete terms so we have nothing to reference and try again - $this->vocabulary->delete(); - $vocabulary2->delete(); - $entity = EntityTest::create(array('name' => $this->randomMachineName())); - $entity->save(); - } - - /** - * Tests entity auto create. - */ - public function testEntityAutoCreate() { - // The term entity is unsaved here. - $term = Term::create(array( - 'name' => $this->randomMachineName(), - 'vid' => $this->term->bundle(), - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - )); - $entity = EntityTest::create(); - // Now assign the unsaved term to the field. - $entity->field_test_taxonomy_term->entity = $term; - $entity->name->value = $this->randomMachineName(); - // This is equal to storing an entity to tempstore or cache and retrieving - // it back. An example for this is node preview. - $entity = serialize($entity); - $entity = unserialize($entity); - // And then the entity. - $entity->save(); - $term = \Drupal::entityManager()->loadEntityByUuid($term->getEntityTypeId(), $term->uuid()); - $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term->id()); - } - - /** - * Test saving order sequence doesn't matter. - */ - public function testEntitySaveOrder() { - // The term entity is unsaved here. - $term = Term::create([ - 'name' => $this->randomMachineName(), - 'vid' => $this->term->bundle(), - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - ]); - $entity = EntityTest::create(); - // Now assign the unsaved term to the field. - $entity->field_test_taxonomy_term->entity = $term; - $entity->name->value = $this->randomMachineName(); - // Now get the field value. - $value = $entity->get('field_test_taxonomy_term'); - $this->assertTrue(empty($value['target_id'])); - $this->assertNull($entity->field_test_taxonomy_term->target_id); - // And then set it. - $entity->field_test_taxonomy_term = $value; - // Now save the term. - $term->save(); - // And then the entity. - $entity->save(); - $this->assertEqual($entity->field_test_taxonomy_term->entity->id(), $term->id()); - } - - /** - * Tests that the 'handler' field setting stores the proper plugin ID. - */ - public function testSelectionHandlerSettings() { - $field_name = Unicode::strtolower($this->randomMachineName()); - $field_storage = FieldStorageConfig::create(array( - 'field_name' => $field_name, - 'entity_type' => 'entity_test', - 'type' => 'entity_reference', - 'settings' => array( - 'target_type' => 'entity_test' - ), - )); - $field_storage->save(); - - // Do not specify any value for the 'handler' setting in order to verify - // that the default handler with the correct derivative is used. - $field = FieldConfig::create(array( - 'field_storage' => $field_storage, - 'bundle' => 'entity_test', - )); - $field->save(); - $field = FieldConfig::load($field->id()); - $this->assertEqual($field->getSetting('handler'), 'default:entity_test'); - - // Change the target_type in the field storage, and check that the handler - // was correctly reassigned in the field. - $field_storage->setSetting('target_type', 'entity_test_rev'); - $field_storage->save(); - $field = FieldConfig::load($field->id()); - $this->assertEqual($field->getSetting('handler'), 'default:entity_test_rev'); - - // Change the handler to another, non-derivative plugin. - $field->setSetting('handler', 'views'); - $field->save(); - $field = FieldConfig::load($field->id()); - $this->assertEqual($field->getSetting('handler'), 'views'); - - // Change the target_type in the field storage again, and check that the - // non-derivative handler was unchanged. - $field_storage->setSetting('target_type', 'entity_test_rev'); - $field_storage->save(); - $field = FieldConfig::load($field->id()); - $this->assertEqual($field->getSetting('handler'), 'views'); - } - - /** - * Tests ValidReferenceConstraint with newly created and unsaved entities. - */ - public function testAutocreateValidation() { - // The term entity is unsaved here. - $term = Term::create(array( - 'name' => $this->randomMachineName(), - 'vid' => $this->term->bundle(), - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - )); - $entity = EntityTest::create([ - 'field_test_taxonomy_term' => [ - 'entity' => $term, - 'target_id' => NULL, - ], - ]); - $errors = $entity->validate(); - // Using target_id of NULL is valid with an unsaved entity. - $this->assertEqual(0, count($errors)); - // Using target_id of NULL is not valid with a saved entity. - $term->save(); - $entity = EntityTest::create([ - 'field_test_taxonomy_term' => [ - 'entity' => $term, - 'target_id' => NULL, - ], - ]); - $errors = $entity->validate(); - $this->assertEqual(1, count($errors)); - $this->assertEqual($errors[0]->getMessage(), 'This value should not be null.'); - $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_taxonomy_term.0'); - // This should rectify the issue, favoring the entity over the target_id. - $entity->save(); - $errors = $entity->validate(); - $this->assertEqual(0, count($errors)); - - // Test with an unpublished and unsaved node. - $title = $this->randomString(); - $node = Node::create([ - 'title' => $title, - 'type' => 'node', - 'status' => NODE_NOT_PUBLISHED, - ]); - - $entity = EntityTest::create([ - 'field_test_node' => [ - 'entity' => $node, - ], - ]); - - $errors = $entity->validate(); - $this->assertEqual(1, count($errors)); - $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $title])); - $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_node.0.entity'); - - // Publish the node and try again. - $node->setPublished(TRUE); - $errors = $entity->validate(); - $this->assertEqual(0, count($errors)); - - // Test with a mix of valid and invalid nodes. - $unsaved_unpublished_node_title = $this->randomString(); - $unsaved_unpublished_node = Node::create([ - 'title' => $unsaved_unpublished_node_title, - 'type' => 'node', - 'status' => NODE_NOT_PUBLISHED, - ]); - - $saved_unpublished_node_title = $this->randomString(); - $saved_unpublished_node = Node::create([ - 'title' => $saved_unpublished_node_title, - 'type' => 'node', - 'status' => NODE_NOT_PUBLISHED, - ]); - $saved_unpublished_node->save(); - - $saved_published_node_title = $this->randomString(); - $saved_published_node = Node::create([ - 'title' => $saved_published_node_title, - 'type' => 'node', - 'status' => NODE_PUBLISHED, - ]); - $saved_published_node->save(); - - $entity = EntityTest::create([ - 'field_test_node' => [ - [ - 'entity' => $unsaved_unpublished_node, - ], - [ - 'target_id' => $saved_unpublished_node->id(), - ], - [ - 'target_id' => $saved_published_node->id(), - ], - ], - ]); - - $errors = $entity->validate(); - $this->assertEqual(2, count($errors)); - $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $unsaved_unpublished_node_title])); - $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_node.0.entity'); - $this->assertEqual($errors[1]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $saved_unpublished_node->id()])); - $this->assertEqual($errors[1]->getPropertyPath(), 'field_test_node.1.target_id'); - - // Publish one of the nodes and try again. - $saved_unpublished_node->setPublished(TRUE); - $saved_unpublished_node->save(); - $errors = $entity->validate(); - $this->assertEqual(1, count($errors)); - $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'node', '%label' => $unsaved_unpublished_node_title])); - $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_node.0.entity'); - - // Publish the last invalid node and try again. - $unsaved_unpublished_node->setPublished(TRUE); - $errors = $entity->validate(); - $this->assertEqual(0, count($errors)); - - // Test with an unpublished and unsaved comment. - $title = $this->randomString(); - $comment = Comment::create([ - 'subject' => $title, - 'comment_type' => 'comment', - 'status' => 0, - ]); - - $entity = EntityTest::create([ - 'field_test_comment' => [ - 'entity' => $comment, - ], - ]); - - $errors = $entity->validate(); - $this->assertEqual(1, count($errors)); - $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'comment', '%label' => $title])); - $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_comment.0.entity'); - - // Publish the comment and try again. - $comment->setPublished(TRUE); - $errors = $entity->validate(); - $this->assertEqual(0, count($errors)); - - // Test with an inactive and unsaved user. - $name = $this->randomString(); - $user = User::create([ - 'name' => $name, - 'status' => 0, - ]); - - $entity = EntityTest::create([ - 'field_test_user' => [ - 'entity' => $user, - ], - ]); - - $errors = $entity->validate(); - $this->assertEqual(1, count($errors)); - $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'user', '%label' => $name])); - $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_user.0.entity'); - - // Activate the user and try again. - $user->activate(); - $errors = $entity->validate(); - $this->assertEqual(0, count($errors)); - - // Test with a temporary and unsaved file. - $filename = $this->randomMachineName() . '.txt'; - $file = File::create([ - 'filename' => $filename, - 'status' => 0, - ]); - - $entity = EntityTest::create([ - 'field_test_file' => [ - 'entity' => $file, - ], - ]); - - $errors = $entity->validate(); - $this->assertEqual(1, count($errors)); - $this->assertEqual($errors[0]->getMessage(), new FormattableMarkup('This entity (%type: %label) cannot be referenced.', ['%type' => 'file', '%label' => $filename])); - $this->assertEqual($errors[0]->getPropertyPath(), 'field_test_file.0.entity'); - - // Set the file as permanent and try again. - $file->setPermanent(); - $errors = $entity->validate(); - $this->assertEqual(0, count($errors)); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldAttachOtherTest.php b/core/modules/field/tests/src/Kernel/FieldAttachOtherTest.php deleted file mode 100644 index 6ee13af..0000000 --- a/core/modules/field/tests/src/Kernel/FieldAttachOtherTest.php +++ /dev/null @@ -1,387 +0,0 @@ -container->get('router.builder')->rebuild(); - $this->installEntitySchema('entity_test_rev'); - $this->createFieldWithStorage(); - } - - /** - * Test rendering fields with EntityDisplay build(). - */ - function testEntityDisplayBuild() { - $this->createFieldWithStorage('_2'); - - $entity_type = 'entity_test'; - $entity_init = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(); - - // Populate values to be displayed. - $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage->getCardinality()); - $entity_init->{$this->fieldTestData->field_name}->setValue($values); - $values_2 = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); - $entity_init->{$this->fieldTestData->field_name_2}->setValue($values_2); - - // Simple formatter, label displayed. - $entity = clone($entity_init); - $display = entity_get_display($entity_type, $entity->bundle(), 'full'); - - $formatter_setting = $this->randomMachineName(); - $display_options = array( - 'label' => 'above', - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $formatter_setting, - ), - ); - $display->setComponent($this->fieldTestData->field_name, $display_options); - - $formatter_setting_2 = $this->randomMachineName(); - $display_options_2 = array( - 'label' => 'above', - 'type' => 'field_test_default', - 'settings' => array( - 'test_formatter_setting' => $formatter_setting_2, - ), - ); - $display->setComponent($this->fieldTestData->field_name_2, $display_options_2); - - // View all fields. - $content = $display->build($entity); - $this->render($content); - $this->assertRaw($this->fieldTestData->field->getLabel(), "First field's label is displayed."); - foreach ($values as $delta => $value) { - $this->assertRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); - } - $this->assertRaw($this->fieldTestData->field_2->getLabel(), "Second field's label is displayed."); - foreach ($values_2 as $delta => $value) { - $this->assertRaw("$formatter_setting_2|{$value['value']}", "Value $delta is displayed, formatter settings are applied."); - } - - // Label hidden. - $entity = clone($entity_init); - $display_options['label'] = 'hidden'; - $display->setComponent($this->fieldTestData->field_name, $display_options); - $content = $display->build($entity); - $this->render($content); - $this->assertNoRaw($this->fieldTestData->field->getLabel(), "Hidden label: label is not displayed."); - - // Field hidden. - $entity = clone($entity_init); - $display->removeComponent($this->fieldTestData->field_name); - $content = $display->build($entity); - $this->render($content); - $this->assertNoRaw($this->fieldTestData->field->getLabel(), "Hidden field: label is not displayed."); - foreach ($values as $delta => $value) { - $this->assertNoRaw("$formatter_setting|{$value['value']}", "Hidden field: value $delta is not displayed."); - } - - // Multiple formatter. - $entity = clone($entity_init); - $formatter_setting = $this->randomMachineName(); - $display->setComponent($this->fieldTestData->field_name, array( - 'label' => 'above', - 'type' => 'field_test_multiple', - 'settings' => array( - 'test_formatter_setting_multiple' => $formatter_setting, - ), - )); - $content = $display->build($entity); - $this->render($content); - $expected_output = $formatter_setting; - foreach ($values as $delta => $value) { - $expected_output .= "|$delta:{$value['value']}"; - } - $this->assertRaw($expected_output, "Multiple formatter: all values are displayed, formatter settings are applied."); - - // Test a formatter that uses hook_field_formatter_prepare_view(). - $entity = clone($entity_init); - $formatter_setting = $this->randomMachineName(); - $display->setComponent($this->fieldTestData->field_name, array( - 'label' => 'above', - 'type' => 'field_test_with_prepare_view', - 'settings' => array( - 'test_formatter_setting_additional' => $formatter_setting, - ), - )); - $content = $display->build($entity); - $this->render($content); - foreach ($values as $delta => $value) { - $expected = $formatter_setting . '|' . $value['value'] . '|' . ($value['value'] + 1); - $this->assertRaw($expected, "Value $delta is displayed, formatter settings are applied."); - } - - // TODO: - // - check display order with several fields - } - - /** - * Tests rendering fields with EntityDisplay::buildMultiple(). - */ - function testEntityDisplayViewMultiple() { - // Use a formatter that has a prepareView() step. - $display = entity_get_display('entity_test', 'entity_test', 'full') - ->setComponent($this->fieldTestData->field_name, array( - 'type' => 'field_test_with_prepare_view', - )); - - // Create two entities. - $entity1 = EntityTest::create(array('id' => 1, 'type' => 'entity_test')); - $entity1->{$this->fieldTestData->field_name}->setValue($this->_generateTestFieldValues(1)); - $entity2 = EntityTest::create(array('id' => 2, 'type' => 'entity_test')); - $entity2->{$this->fieldTestData->field_name}->setValue($this->_generateTestFieldValues(1)); - - // Run buildMultiple(), and check that the entities come out as expected. - $display->buildMultiple(array($entity1, $entity2)); - $item1 = $entity1->{$this->fieldTestData->field_name}[0]; - $this->assertEqual($item1->additional_formatter_value, $item1->value + 1, 'Entity 1 ran through the prepareView() formatter method.'); - $item2 = $entity2->{$this->fieldTestData->field_name}[0]; - $this->assertEqual($item2->additional_formatter_value, $item2->value + 1, 'Entity 2 ran through the prepareView() formatter method.'); - } - - /** - * Test entity cache. - * - * Complements unit test coverage in - * \Drupal\Tests\Core\Entity\Sql\SqlContentEntityStorageTest. - */ - function testEntityCache() { - // Initialize random values and a test entity. - $entity_init = EntityTest::create(array('type' => $this->fieldTestData->field->getTargetBundle())); - $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage->getCardinality()); - - // Non-cacheable entity type. - $entity_type = 'entity_test'; - $cid = "values:$entity_type:" . $entity_init->id(); - - // Check that no initial cache entry is present. - $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Non-cached: no initial cache entry'); - - // Save, and check that no cache entry is present. - $entity = clone($entity_init); - $entity->{$this->fieldTestData->field_name}->setValue($values); - $entity = $this->entitySaveReload($entity); - $cid = "values:$entity_type:" . $entity->id(); - $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Non-cached: no cache entry on insert and load'); - - // Cacheable entity type. - $entity_type = 'entity_test_rev'; - $this->createFieldWithStorage('_2', $entity_type); - - $entity_init = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array( - 'type' => $entity_type, - )); - - // Check that no initial cache entry is present. - $cid = "values:$entity_type:" . $entity->id(); - $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no initial cache entry'); - - // Save, and check that no cache entry is present. - $entity = clone($entity_init); - $entity->{$this->fieldTestData->field_name_2} = $values; - $entity->save(); - $cid = "values:$entity_type:" . $entity->id(); - - $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry on insert'); - // Load, and check that a cache entry is present with the expected values. - $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); - $controller->resetCache(); - $cached_entity = $controller->load($entity->id()); - $cache = \Drupal::cache('entity')->get($cid); - $this->assertEqual($cache->data, $cached_entity, 'Cached: correct cache entry on load'); - - // Update with different values, and check that the cache entry is wiped. - $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); - $entity->{$this->fieldTestData->field_name_2} = $values; - $entity->save(); - $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry on update'); - - // Load, and check that a cache entry is present with the expected values. - $controller->resetCache(); - $cached_entity = $controller->load($entity->id()); - $cache = \Drupal::cache('entity')->get($cid); - $this->assertEqual($cache->data, $cached_entity, 'Cached: correct cache entry on load'); - - // Create a new revision, and check that the cache entry is wiped. - $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); - $entity->{$this->fieldTestData->field_name_2} = $values; - $entity->setNewRevision(); - $entity->save(); - $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry on new revision creation'); - - // Load, and check that a cache entry is present with the expected values. - $controller->resetCache(); - $cached_entity = $controller->load($entity->id()); - $cache = \Drupal::cache('entity')->get($cid); - $this->assertEqual($cache->data, $cached_entity, 'Cached: correct cache entry on load'); - - // Delete, and check that the cache entry is wiped. - $entity->delete(); - $this->assertFalse(\Drupal::cache('entity')->get($cid), 'Cached: no cache entry after delete'); - } - - /** - * Tests \Drupal\Core\Entity\Display\EntityFormDisplayInterface::buildForm(). - * - * This could be much more thorough, but it does verify that the correct - * widgets show up. - */ - function testEntityFormDisplayBuildForm() { - $this->createFieldWithStorage('_2'); - - $entity_type = 'entity_test'; - $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $this->fieldTestData->field->getTargetBundle())); - - // Test generating widgets for all fields. - $display = entity_get_form_display($entity_type, $this->fieldTestData->field->getTargetBundle(), 'default'); - $form = array(); - $form_state = new FormState(); - $display->buildForm($entity, $form, $form_state); - - $this->assertEqual($form[$this->fieldTestData->field_name]['widget']['#title'], $this->fieldTestData->field->getLabel(), "First field's form title is {$this->fieldTestData->field->getLabel()}"); - $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget']['#title'], $this->fieldTestData->field_2->getLabel(), "Second field's form title is {$this->fieldTestData->field_2->getLabel()}"); - for ($delta = 0; $delta < $this->fieldTestData->field_storage->getCardinality(); $delta++) { - // field_test_widget uses 'textfield' - $this->assertEqual($form[$this->fieldTestData->field_name]['widget'][$delta]['value']['#type'], 'textfield', "First field's form delta $delta widget is textfield"); - } - for ($delta = 0; $delta < $this->fieldTestData->field_storage_2->getCardinality(); $delta++) { - // field_test_widget uses 'textfield' - $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget'][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield"); - } - - // Test generating widgets for all fields. - $display = entity_get_form_display($entity_type, $this->fieldTestData->field->getTargetBundle(), 'default'); - foreach ($display->getComponents() as $name => $options) { - if ($name != $this->fieldTestData->field_name_2) { - $display->removeComponent($name); - } - } - $form = array(); - $form_state = new FormState(); - $display->buildForm($entity, $form, $form_state); - - $this->assertFalse(isset($form[$this->fieldTestData->field_name]), 'The first field does not exist in the form'); - $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget']['#title'], $this->fieldTestData->field_2->getLabel(), "Second field's form title is {$this->fieldTestData->field_2->getLabel()}"); - for ($delta = 0; $delta < $this->fieldTestData->field_storage_2->getCardinality(); $delta++) { - // field_test_widget uses 'textfield' - $this->assertEqual($form[$this->fieldTestData->field_name_2]['widget'][$delta]['value']['#type'], 'textfield', "Second field's form delta $delta widget is textfield"); - } - } - - /** - * Tests \Drupal\Core\Entity\Display\EntityFormDisplayInterface::extractFormValues(). - */ - function testEntityFormDisplayExtractFormValues() { - $this->createFieldWithStorage('_2'); - - $entity_type = 'entity_test'; - $entity_init = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('id' => 1, 'revision_id' => 1, 'type' => $this->fieldTestData->field->getTargetBundle())); - - // Build the form for all fields. - $display = entity_get_form_display($entity_type, $this->fieldTestData->field->getTargetBundle(), 'default'); - $form = array(); - $form_state = new FormState(); - $display->buildForm($entity_init, $form, $form_state); - - // Simulate incoming values. - // First field. - $values = array(); - $weights = array(); - for ($delta = 0; $delta < $this->fieldTestData->field_storage->getCardinality(); $delta++) { - $values[$delta]['value'] = mt_rand(1, 127); - // Assign random weight. - do { - $weight = mt_rand(0, $this->fieldTestData->field_storage->getCardinality()); - } while (in_array($weight, $weights)); - $weights[$delta] = $weight; - $values[$delta]['_weight'] = $weight; - } - // Leave an empty value. 'field_test' fields are empty if empty(). - $values[1]['value'] = 0; - // Second field. - $values_2 = array(); - $weights_2 = array(); - for ($delta = 0; $delta < $this->fieldTestData->field_storage_2->getCardinality(); $delta++) { - $values_2[$delta]['value'] = mt_rand(1, 127); - // Assign random weight. - do { - $weight = mt_rand(0, $this->fieldTestData->field_storage_2->getCardinality()); - } while (in_array($weight, $weights_2)); - $weights_2[$delta] = $weight; - $values_2[$delta]['_weight'] = $weight; - } - // Leave an empty value. 'field_test' fields are empty if empty(). - $values_2[1]['value'] = 0; - - // Pretend the form has been built. - $form_state->setFormObject(\Drupal::entityManager()->getFormObject($entity_type, 'default')); - \Drupal::formBuilder()->prepareForm('field_test_entity_form', $form, $form_state); - \Drupal::formBuilder()->processForm('field_test_entity_form', $form, $form_state); - $form_state->setValue($this->fieldTestData->field_name, $values); - $form_state->setValue($this->fieldTestData->field_name_2, $values_2); - - // Extract values for all fields. - $entity = clone($entity_init); - $display->extractFormValues($entity, $form, $form_state); - - asort($weights); - asort($weights_2); - $expected_values = array(); - $expected_values_2 = array(); - foreach ($weights as $key => $value) { - if ($key != 1) { - $expected_values[] = array('value' => $values[$key]['value']); - } - } - $this->assertIdentical($entity->{$this->fieldTestData->field_name}->getValue(), $expected_values, 'Submit filters empty values'); - foreach ($weights_2 as $key => $value) { - if ($key != 1) { - $expected_values_2[] = array('value' => $values_2[$key]['value']); - } - } - $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values'); - - // Call EntityFormDisplayInterface::extractFormValues() for a single field (the second field). - foreach ($display->getComponents() as $name => $options) { - if ($name != $this->fieldTestData->field_name_2) { - $display->removeComponent($name); - } - } - $entity = clone($entity_init); - $display->extractFormValues($entity, $form, $form_state); - $expected_values_2 = array(); - foreach ($weights_2 as $key => $value) { - if ($key != 1) { - $expected_values_2[] = array('value' => $values_2[$key]['value']); - } - } - $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'The first field is empty in the entity object'); - $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values'); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldAttachStorageTest.php b/core/modules/field/tests/src/Kernel/FieldAttachStorageTest.php deleted file mode 100644 index b9a4e45..0000000 --- a/core/modules/field/tests/src/Kernel/FieldAttachStorageTest.php +++ /dev/null @@ -1,382 +0,0 @@ -installEntitySchema('entity_test_rev'); - } - - /** - * Check field values insert, update and load. - * - * Works independently of the underlying field storage backend. Inserts or - * updates random field data and then loads and verifies the data. - */ - function testFieldAttachSaveLoad() { - $entity_type = 'entity_test_rev'; - $this->createFieldWithStorage('', $entity_type); - $cardinality = $this->fieldTestData->field_storage->getCardinality(); - - // TODO : test empty values filtering and "compression" (store consecutive deltas). - // Preparation: create three revisions and store them in $revision array. - $values = array(); - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(); - for ($revision_id = 0; $revision_id < 3; $revision_id++) { - // Note: we try to insert one extra value. - $current_values = $this->_generateTestFieldValues($cardinality + 1); - $entity->{$this->fieldTestData->field_name}->setValue($current_values); - $entity->setNewRevision(); - $entity->save(); - $entity_id = $entity->id(); - $current_revision = $entity->getRevisionId(); - $values[$current_revision] = $current_values; - } - - $storage = $this->container->get('entity.manager')->getStorage($entity_type); - $storage->resetCache(); - $entity = $storage->load($entity_id); - // Confirm current revision loads the correct data. - // Number of values per field loaded equals the field cardinality. - $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, 'Current revision: expected number of values'); - for ($delta = 0; $delta < $cardinality; $delta++) { - // The field value loaded matches the one inserted or updated. - $this->assertEqual($entity->{$this->fieldTestData->field_name}[$delta]->value , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta))); - } - - // Confirm each revision loads the correct data. - foreach (array_keys($values) as $revision_id) { - $entity = $storage->loadRevision($revision_id); - // Number of values per field loaded equals the field cardinality. - $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id))); - for ($delta = 0; $delta < $cardinality; $delta++) { - // The field value loaded matches the one inserted or updated. - $this->assertEqual($entity->{$this->fieldTestData->field_name}[$delta]->value, $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta))); - } - } - } - - /** - * Test the 'multiple' load feature. - */ - function testFieldAttachLoadMultiple() { - $entity_type = 'entity_test_rev'; - - // Define 2 bundles. - $bundles = array( - 1 => 'test_bundle_1', - 2 => 'test_bundle_2', - ); - entity_test_create_bundle($bundles[1]); - entity_test_create_bundle($bundles[2]); - // Define 3 fields: - // - field_1 is in bundle_1 and bundle_2, - // - field_2 is in bundle_1, - // - field_3 is in bundle_2. - $field_bundles_map = array( - 1 => array(1, 2), - 2 => array(1), - 3 => array(2), - ); - for ($i = 1; $i <= 3; $i++) { - $field_names[$i] = 'field_' . $i; - $field_storage = FieldStorageConfig::create(array( - 'field_name' => $field_names[$i], - 'entity_type' => $entity_type, - 'type' => 'test_field', - )); - $field_storage->save(); - $field_ids[$i] = $field_storage->uuid(); - foreach ($field_bundles_map[$i] as $bundle) { - FieldConfig::create([ - 'field_name' => $field_names[$i], - 'entity_type' => $entity_type, - 'bundle' => $bundles[$bundle], - ])->save(); - } - } - - // Create one test entity per bundle, with random values. - foreach ($bundles as $index => $bundle) { - $entities[$index] = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('id' => $index, 'revision_id' => $index, 'type' => $bundle)); - $entity = clone($entities[$index]); - foreach ($field_names as $field_name) { - if (!$entity->hasField($field_name)) { - continue; - } - $values[$index][$field_name] = mt_rand(1, 127); - $entity->$field_name->setValue(array('value' => $values[$index][$field_name])); - } - $entity->enforceIsnew(); - $entity->save(); - } - - // Check that a single load correctly loads field values for both entities. - $controller = \Drupal::entityManager()->getStorage($entity->getEntityTypeId()); - $controller->resetCache(); - $entities = $controller->loadMultiple(); - foreach ($entities as $index => $entity) { - foreach ($field_names as $field_name) { - if (!$entity->hasField($field_name)) { - continue; - } - // The field value loaded matches the one inserted. - $this->assertEqual($entity->{$field_name}->value, $values[$index][$field_name], format_string('Entity %index: expected value was found.', array('%index' => $index))); - } - } - } - - /** - * Tests insert and update with empty or NULL fields. - */ - function testFieldAttachSaveEmptyData() { - $entity_type = 'entity_test'; - $this->createFieldWithStorage('', $entity_type); - - $entity_init = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('id' => 1)); - - // Insert: Field is NULL. - $entity = clone $entity_init; - $entity->{$this->fieldTestData->field_name} = NULL; - $entity->enforceIsNew(); - $entity = $this->entitySaveReload($entity); - $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Insert: NULL field results in no value saved'); - - // All saves after this point should be updates, not inserts. - $entity_init->enforceIsNew(FALSE); - - // Add some real data. - $entity = clone($entity_init); - $values = $this->_generateTestFieldValues(1); - $entity->{$this->fieldTestData->field_name} = $values; - $entity = $this->entitySaveReload($entity); - $this->assertEqual($entity->{$this->fieldTestData->field_name}->getValue(), $values, 'Field data saved'); - - // Update: Field is NULL. Data should be wiped. - $entity = clone($entity_init); - $entity->{$this->fieldTestData->field_name} = NULL; - $entity = $this->entitySaveReload($entity); - $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Update: NULL field removes existing values'); - - // Re-add some data. - $entity = clone($entity_init); - $values = $this->_generateTestFieldValues(1); - $entity->{$this->fieldTestData->field_name} = $values; - $entity = $this->entitySaveReload($entity); - $this->assertEqual($entity->{$this->fieldTestData->field_name}->getValue(), $values, 'Field data saved'); - - // Update: Field is empty array. Data should be wiped. - $entity = clone($entity_init); - $entity->{$this->fieldTestData->field_name} = array(); - $entity = $this->entitySaveReload($entity); - $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Update: empty array removes existing values'); - } - - /** - * Test insert with empty or NULL fields, with default value. - */ - function testFieldAttachSaveEmptyDataDefaultValue() { - $entity_type = 'entity_test_rev'; - $this->createFieldWithStorage('', $entity_type); - - // Add a default value function. - $this->fieldTestData->field->set('default_value_callback', 'field_test_default_value'); - $this->fieldTestData->field->save(); - - // Verify that fields are populated with default values. - $entity_init = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('id' => 1, 'revision_id' => 1)); - $default = field_test_default_value($entity_init, $this->fieldTestData->field); - $this->assertEqual($entity_init->{$this->fieldTestData->field_name}->getValue(), $default, 'Default field value correctly populated.'); - - // Insert: Field is NULL. - $entity = clone($entity_init); - $entity->{$this->fieldTestData->field_name} = NULL; - $entity->enforceIsNew(); - $entity = $this->entitySaveReload($entity); - $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'Insert: NULL field results in no value saved'); - - // Verify that prepopulated field values are not overwritten by defaults. - $value = array(array('value' => $default[0]['value'] - mt_rand(1, 127))); - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('type' => $entity_init->bundle(), $this->fieldTestData->field_name => $value)); - $this->assertEqual($entity->{$this->fieldTestData->field_name}->getValue(), $value, 'Prepopulated field value correctly maintained.'); - } - - /** - * Test entity deletion. - */ - function testFieldAttachDelete() { - $entity_type = 'entity_test_rev'; - $this->createFieldWithStorage('', $entity_type); - $cardinality = $this->fieldTestData->field_storage->getCardinality(); - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('type' => $this->fieldTestData->field->getTargetBundle())); - $vids = array(); - - // Create revision 0 - $values = $this->_generateTestFieldValues($cardinality); - $entity->{$this->fieldTestData->field_name} = $values; - $entity->save(); - $vids[] = $entity->getRevisionId(); - - // Create revision 1 - $entity->setNewRevision(); - $entity->save(); - $vids[] = $entity->getRevisionId(); - - // Create revision 2 - $entity->setNewRevision(); - $entity->save(); - $vids[] = $entity->getRevisionId(); - $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); - $controller->resetCache(); - - // Confirm each revision loads - foreach ($vids as $vid) { - $revision = $controller->loadRevision($vid); - $this->assertEqual(count($revision->{$this->fieldTestData->field_name}), $cardinality, "The test entity revision $vid has $cardinality values."); - } - - // Delete revision 1, confirm the other two still load. - $controller->deleteRevision($vids[1]); - $controller->resetCache(); - foreach (array(0, 2) as $key) { - $vid = $vids[$key]; - $revision = $controller->loadRevision($vid); - $this->assertEqual(count($revision->{$this->fieldTestData->field_name}), $cardinality, "The test entity revision $vid has $cardinality values."); - } - - // Confirm the current revision still loads - $controller->resetCache(); - $current = $controller->load($entity->id()); - $this->assertEqual(count($current->{$this->fieldTestData->field_name}), $cardinality, "The test entity current revision has $cardinality values."); - - // Delete all field data, confirm nothing loads - $entity->delete(); - $controller->resetCache(); - foreach (array(0, 1, 2) as $vid) { - $revision = $controller->loadRevision($vid); - $this->assertFalse($revision); - } - $this->assertFalse($controller->load($entity->id())); - } - - /** - * Test entity_bundle_create(). - */ - function testEntityCreateBundle() { - $entity_type = 'entity_test_rev'; - $this->createFieldWithStorage('', $entity_type); - $cardinality = $this->fieldTestData->field_storage->getCardinality(); - - // Create a new bundle. - $new_bundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName()); - entity_test_create_bundle($new_bundle, NULL, $entity_type); - - // Add a field to that bundle. - $this->fieldTestData->field_definition['bundle'] = $new_bundle; - FieldConfig::create($this->fieldTestData->field_definition)->save(); - - // Save an entity with data in the field. - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('type' => $this->fieldTestData->field->getTargetBundle())); - $values = $this->_generateTestFieldValues($cardinality); - $entity->{$this->fieldTestData->field_name} = $values; - - // Verify the field data is present on load. - $entity = $this->entitySaveReload($entity); - $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), $cardinality, "Data is retrieved for the new bundle"); - } - - /** - * Test entity_bundle_delete(). - */ - function testEntityDeleteBundle() { - $entity_type = 'entity_test_rev'; - $this->createFieldWithStorage('', $entity_type); - - // Create a new bundle. - $new_bundle = 'test_bundle_' . Unicode::strtolower($this->randomMachineName()); - entity_test_create_bundle($new_bundle, NULL, $entity_type); - - // Add a field to that bundle. - $this->fieldTestData->field_definition['bundle'] = $new_bundle; - FieldConfig::create($this->fieldTestData->field_definition)->save(); - - // Create a second field for the test bundle - $field_name = Unicode::strtolower($this->randomMachineName() . '_field_name'); - $field_storage = array( - 'field_name' => $field_name, - 'entity_type' => $entity_type, - 'type' => 'test_field', - 'cardinality' => 1, - ); - FieldStorageConfig::create($field_storage)->save(); - $field = array( - 'field_name' => $field_name, - 'entity_type' => $entity_type, - 'bundle' => $this->fieldTestData->field->getTargetBundle(), - 'label' => $this->randomMachineName() . '_label', - 'description' => $this->randomMachineName() . '_description', - 'weight' => mt_rand(0, 127), - ); - FieldConfig::create($field)->save(); - - // Save an entity with data for both fields - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('type' => $this->fieldTestData->field->getTargetBundle())); - $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage->getCardinality()); - $entity->{$this->fieldTestData->field_name} = $values; - $entity->{$field_name} = $this->_generateTestFieldValues(1); - $entity = $this->entitySaveReload($entity); - - // Verify the fields are present on load - $this->assertEqual(count($entity->{$this->fieldTestData->field_name}), 4, 'First field got loaded'); - $this->assertEqual(count($entity->{$field_name}), 1, 'Second field got loaded'); - - // Delete the bundle. - entity_test_delete_bundle($this->fieldTestData->field->getTargetBundle(), $entity_type); - - // Verify no data gets loaded - $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); - $controller->resetCache(); - $entity= $controller->load($entity->id()); - - $this->assertTrue(empty($entity->{$this->fieldTestData->field_name}), 'No data for first field'); - $this->assertTrue(empty($entity->{$field_name}), 'No data for second field'); - - // Verify that the fields are gone. - $this->assertFalse(FieldConfig::load('entity_test.' . $this->fieldTestData->field->getTargetBundle() . '.' . $this->fieldTestData->field_name), "First field is deleted"); - $this->assertFalse(FieldConfig::load('entity_test.' . $field['bundle']. '.' . $field_name), "Second field is deleted"); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldCrudTest.php b/core/modules/field/tests/src/Kernel/FieldCrudTest.php deleted file mode 100644 index 6959225..0000000 --- a/core/modules/field/tests/src/Kernel/FieldCrudTest.php +++ /dev/null @@ -1,309 +0,0 @@ -fieldStorageDefinition = array( - 'field_name' => Unicode::strtolower($this->randomMachineName()), - 'entity_type' => 'entity_test', - 'type' => 'test_field', - ); - $this->fieldStorage = FieldStorageConfig::create($this->fieldStorageDefinition); - $this->fieldStorage->save(); - $this->fieldDefinition = array( - 'field_name' => $this->fieldStorage->getName(), - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - ); - } - - // TODO : test creation with - // - a full fledged $field structure, check that all the values are there - // - a minimal $field structure, check all default values are set - // defer actual $field comparison to a helper function, used for the two cases above, - // and for testUpdateField - - /** - * Test the creation of a field. - */ - function testCreateField() { - // Set a state flag so that field_test.module knows to add an in-memory - // constraint for this field. - \Drupal::state()->set('field_test_add_constraint', $this->fieldStorage->getName()); - /** @var \Drupal\Core\Field\FieldConfigInterface $field */ - $field = FieldConfig::create($this->fieldDefinition); - $field->save(); - - $field = FieldConfig::load($field->id()); - $this->assertTrue($field->getSetting('field_setting_from_config_data')); - $this->assertNull($field->getSetting('config_data_from_field_setting')); - - // Read the configuration. Check against raw configuration data rather than - // the loaded ConfigEntity, to be sure we check that the defaults are - // applied on write. - $config = $this->config('field.field.' . $field->id())->get(); - $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); - - $this->assertTrue($config['settings']['config_data_from_field_setting']); - $this->assertTrue(!isset($config['settings']['field_setting_from_config_data'])); - - // Since we are working with raw configuration, this needs to be unset - // manually. - // @see Drupal\field_test\Plugin\Field\FieldType\TestItem::fieldSettingsFromConfigData() - unset($config['settings']['config_data_from_field_setting']); - - // Check that default values are set. - $this->assertEqual($config['required'], FALSE, 'Required defaults to false.'); - $this->assertIdentical($config['label'], $this->fieldDefinition['field_name'], 'Label defaults to field name.'); - $this->assertIdentical($config['description'], '', 'Description defaults to empty string.'); - - // Check that default settings are set. - $this->assertEqual($config['settings'], $field_type_manager->getDefaultFieldSettings($this->fieldStorageDefinition['type']) , 'Default field settings have been written.'); - - // Check that the denormalized 'field_type' was properly written. - $this->assertEqual($config['field_type'], $this->fieldStorageDefinition['type']); - - // Test constraints are applied. A Range constraint is added dynamically to - // limit the field to values between 0 and 32. - // @see field_test_entity_bundle_field_info_alter() - $this->doFieldValidationTests(); - - // Test FieldConfigBase::setPropertyConstraints(). - \Drupal::state()->set('field_test_set_constraint', $this->fieldStorage->getName()); - \Drupal::state()->set('field_test_add_constraint', FALSE); - \Drupal::entityManager()->clearCachedFieldDefinitions(); - $this->doFieldValidationTests(); - - // Guarantee that the field/bundle combination is unique. - try { - FieldConfig::create($this->fieldDefinition)->save(); - $this->fail(t('Cannot create two fields with the same field / bundle combination.')); - } - catch (EntityStorageException $e) { - $this->pass(t('Cannot create two fields with the same field / bundle combination.')); - } - - // Check that the specified field exists. - try { - $this->fieldDefinition['field_name'] = $this->randomMachineName(); - FieldConfig::create($this->fieldDefinition)->save(); - $this->fail(t('Cannot create a field with a non-existing storage.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create a field with a non-existing storage.')); - } - - // TODO: test other failures. - } - - /** - * Test creating a field with custom storage set. - */ - public function testCreateFieldCustomStorage() { - $field_name = Unicode::strtolower($this->randomMachineName()); - \Drupal::state()->set('field_test_custom_storage', $field_name); - - $field_storage = FieldStorageConfig::create([ - 'field_name' => $field_name, - 'entity_type' => 'entity_test', - 'type' => 'test_field', - 'custom_storage' => TRUE, - ]); - $field_storage->save(); - - $field = FieldConfig::create([ - 'field_name' => $field_storage->getName(), - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - ]); - $field->save(); - - \Drupal::entityManager()->clearCachedFieldDefinitions(); - - // Check that no table has been created for the field. - $this->assertFalse(\Drupal::database()->schema()->tableExists('entity_test__' . $field_storage->getName())); - - // Save an entity with a value in the custom storage field and verify no - // data is retrieved on load. - $entity = EntityTest::create(['name' => $this->randomString(), $field_name => 'Test value']); - $this->assertIdentical('Test value', $entity->{$field_name}->value, 'The test value is set on the field.'); - - $entity->save(); - $entity = EntityTest::load($entity->id()); - - $this->assertNull($entity->{$field_name}->value, 'The loaded entity field value is NULL.'); - } - - /** - * Test reading back a field definition. - */ - function testReadField() { - FieldConfig::create($this->fieldDefinition)->save(); - - // Read the field back. - $field = FieldConfig::load('entity_test.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); - $this->assertTrue($this->fieldDefinition['field_name'] == $field->getName(), 'The field was properly read.'); - $this->assertTrue($this->fieldDefinition['entity_type'] == $field->getTargetEntityTypeId(), 'The field was properly read.'); - $this->assertTrue($this->fieldDefinition['bundle'] == $field->getTargetBundle(), 'The field was properly read.'); - } - - /** - * Test the update of a field. - */ - function testUpdateField() { - FieldConfig::create($this->fieldDefinition)->save(); - - // Check that basic changes are saved. - $field = FieldConfig::load('entity_test.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); - $field->setRequired(!$field->isRequired()); - $field->setLabel($this->randomMachineName()); - $field->set('description', $this->randomMachineName()); - $field->setSetting('test_field_setting', $this->randomMachineName()); - $field->save(); - - $field_new = FieldConfig::load('entity_test.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); - $this->assertEqual($field->isRequired(), $field_new->isRequired(), '"required" change is saved'); - $this->assertEqual($field->getLabel(), $field_new->getLabel(), '"label" change is saved'); - $this->assertEqual($field->getDescription(), $field_new->getDescription(), '"description" change is saved'); - - // TODO: test failures. - } - - /** - * Test the deletion of a field. - */ - function testDeleteField() { - // TODO: Test deletion of the data stored in the field also. - // Need to check that data for a 'deleted' field / storage doesn't get loaded - // Need to check data marked deleted is cleaned on cron (not implemented yet...) - - // Create two fields for the same field storage so we can test that only one - // is deleted. - FieldConfig::create($this->fieldDefinition)->save(); - $another_field_definition = $this->fieldDefinition; - $another_field_definition['bundle'] .= '_another_bundle'; - entity_test_create_bundle($another_field_definition['bundle']); - FieldConfig::create($another_field_definition)->save(); - - // Test that the first field is not deleted, and then delete it. - $field = current(entity_load_multiple_by_properties('field_config', array('entity_type' => 'entity_test', 'field_name' => $this->fieldDefinition['field_name'], 'bundle' => $this->fieldDefinition['bundle'], 'include_deleted' => TRUE))); - $this->assertTrue(!empty($field) && empty($field->deleted), 'A new field is not marked for deletion.'); - $field->delete(); - - // Make sure the field is marked as deleted when it is specifically loaded. - $field = current(entity_load_multiple_by_properties('field_config', array('entity_type' => 'entity_test', 'field_name' => $this->fieldDefinition['field_name'], 'bundle' => $this->fieldDefinition['bundle'], 'include_deleted' => TRUE))); - $this->assertTrue($field->isDeleted(), 'A deleted field is marked for deletion.'); - - // Try to load the field normally and make sure it does not show up. - $field = FieldConfig::load('entity_test.' . '.' . $this->fieldDefinition['bundle'] . '.' . $this->fieldDefinition['field_name']); - $this->assertTrue(empty($field), 'A deleted field is not loaded by default.'); - - // Make sure the other field is not deleted. - $another_field = FieldConfig::load('entity_test.' . $another_field_definition['bundle'] . '.' . $another_field_definition['field_name']); - $this->assertTrue(!empty($another_field) && empty($another_field->deleted), 'A non-deleted field is not marked for deletion.'); - } - - /** - * Tests the cross deletion behavior between field storages and fields. - */ - function testDeleteFieldCrossDeletion() { - $field_definition_2 = $this->fieldDefinition; - $field_definition_2['bundle'] .= '_another_bundle'; - entity_test_create_bundle($field_definition_2['bundle']); - - // Check that deletion of a field storage deletes its fields. - $field_storage = $this->fieldStorage; - FieldConfig::create($this->fieldDefinition)->save(); - FieldConfig::create($field_definition_2)->save(); - $field_storage->delete(); - $this->assertFalse(FieldConfig::loadByName('entity_test', $this->fieldDefinition['bundle'], $field_storage->getName())); - $this->assertFalse(FieldConfig::loadByName('entity_test', $field_definition_2['bundle'], $field_storage->getName())); - - // Check that deletion of the last field deletes the storage. - $field_storage = FieldStorageConfig::create($this->fieldStorageDefinition); - $field_storage->save(); - $field = FieldConfig::create($this->fieldDefinition); - $field->save(); - $field_2 = FieldConfig::create($field_definition_2); - $field_2->save(); - $field->delete(); - $this->assertTrue(FieldStorageConfig::loadByName('entity_test', $field_storage->getName())); - $field_2->delete(); - $this->assertFalse(FieldStorageConfig::loadByName('entity_test', $field_storage->getName())); - - // Check that deletion of all fields using a storage simultaneously deletes - // the storage. - $field_storage = FieldStorageConfig::create($this->fieldStorageDefinition); - $field_storage->save(); - $field = FieldConfig::create($this->fieldDefinition); - $field->save(); - $field_2 = FieldConfig::create($field_definition_2); - $field_2->save(); - $this->container->get('entity.manager')->getStorage('field_config')->delete(array($field, $field_2)); - $this->assertFalse(FieldStorageConfig::loadByName('entity_test', $field_storage->getName())); - } - - /** - * Tests configurable field validation. - * - * @see field_test_entity_bundle_field_info_alter() - */ - protected function doFieldValidationTests() { - $entity = EntityTest::create(); - $entity->set($this->fieldStorage->getName(), 1); - $violations = $entity->validate(); - $this->assertEqual(count($violations), 0, 'No violations found when in-range value passed.'); - - $entity->set($this->fieldStorage->getName(), 33); - $violations = $entity->validate(); - $this->assertEqual(count($violations), 1, 'Violations found when using value outside the range.'); - $this->assertEqual($violations[0]->getPropertyPath(), $this->fieldStorage->getName() . '.0.value'); - $this->assertEqual($violations[0]->getMessage(), t('This value should be %limit or less.', [ - '%limit' => 32, - ])); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldDataCountTest.php b/core/modules/field/tests/src/Kernel/FieldDataCountTest.php deleted file mode 100644 index 4f9e4bc..0000000 --- a/core/modules/field/tests/src/Kernel/FieldDataCountTest.php +++ /dev/null @@ -1,187 +0,0 @@ -installEntitySchema('entity_test_rev'); - $this->storage = \Drupal::entityManager()->getStorage('entity_test'); - $this->storageRev = \Drupal::entityManager()->getStorage('entity_test_rev'); - $this->storageUser = \Drupal::entityManager()->getStorage('user'); - } - - /** - * Tests entityCount() and hadData() methods. - */ - public function testEntityCountAndHasData() { - // Create a field with a cardinality of 2 to show that we are counting - // entities and not rows in a table. - /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */ - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_int', - 'entity_type' => 'entity_test', - 'type' => 'integer', - 'cardinality' => 2, - )); - $field_storage->save(); - FieldConfig::create([ - 'field_storage' => $field_storage, - 'bundle' => 'entity_test', - ])->save(); - - $this->assertIdentical($field_storage->hasdata(), FALSE, 'There are no entities with field data.'); - $this->assertIdentical($this->storage->countFieldData($field_storage), 0, 'There are 0 entities with field data.'); - - // Create 1 entity without the field. - $entity = EntityTest::create(); - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - $this->assertIdentical($field_storage->hasdata(), FALSE, 'There are no entities with field data.'); - $this->assertIdentical($this->storage->countFieldData($field_storage), 0, 'There are 0 entities with field data.'); - - // Create 12 entities to ensure that the purging works as expected. - for ($i=0; $i < 12; $i++) { - $entity = EntityTest::create(); - $entity->field_int[] = mt_rand(1, 99); - $entity->field_int[] = mt_rand(1, 99); - $entity->name[] = $this->randomMachineName(); - $entity->save(); - } - - $storage = \Drupal::entityManager()->getStorage('entity_test'); - if ($storage instanceof SqlContentEntityStorage) { - // Count the actual number of rows in the field table. - $table_mapping = $storage->getTableMapping(); - $field_table_name = $table_mapping->getDedicatedDataTableName($field_storage); - $result = db_select($field_table_name, 't') - ->fields('t') - ->countQuery() - ->execute() - ->fetchField(); - $this->assertEqual($result, 24, 'The field table has 24 rows.'); - } - - $this->assertIdentical($field_storage->hasdata(), TRUE, 'There are entities with field data.'); - $this->assertEqual($this->storage->countFieldData($field_storage), 12, 'There are 12 entities with field data.'); - - // Ensure the methods work on deleted fields. - $field_storage->delete(); - $this->assertIdentical($field_storage->hasdata(), TRUE, 'There are entities with deleted field data.'); - $this->assertEqual($this->storage->countFieldData($field_storage), 12, 'There are 12 entities with deleted field data.'); - - field_purge_batch(6); - $this->assertIdentical($field_storage->hasdata(), TRUE, 'There are entities with deleted field data.'); - $this->assertEqual($this->storage->countFieldData($field_storage), 6, 'There are 6 entities with deleted field data.'); - - $entity_type = 'entity_test_rev'; - $this->createFieldWithStorage('_2', $entity_type); - - $entity_init = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(array('type' => $entity_type,)); - $cardinality = $this->fieldTestData->field_storage_2->getCardinality(); - - $this->assertIdentical($this->fieldTestData->field_storage_2->hasData(), FALSE, 'There are no entities with field data.'); - $this->assertIdentical($this->storageRev->countFieldData($this->fieldTestData->field_storage_2), 0, 'There are 0 entities with field data.'); - - // Create 1 entity with the field. - $entity = clone($entity_init); - $values = $this->_generateTestFieldValues($this->fieldTestData->field_storage_2->getCardinality()); - $entity->{$this->fieldTestData->field_name_2} = $values; - $entity->setNewRevision(); - $entity->save(); - $first_revision = $entity->getRevisionId(); - - $this->assertIdentical($this->fieldTestData->field_storage_2->hasData(), TRUE, 'There are entities with field data.'); - $this->assertIdentical($this->storageRev->countFieldData($this->fieldTestData->field_storage_2), 1, 'There is 1 entity with field data.'); - - $entity->{$this->fieldTestData->field_name_2} = array(); - $entity->setNewRevision(); - $entity->save(); - - $this->assertIdentical($this->fieldTestData->field_storage_2->hasData(), TRUE, 'There are entities with field data.'); - - $storage = $this->container->get('entity.manager')->getStorage($entity_type); - $entity = $storage->loadRevision($first_revision); - $this->assertEqual(count($entity->{$this->fieldTestData->field_name_2}), $cardinality, format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $first_revision))); - } - - /** - * Verify that we can count a table that contains an entry with index 0. - */ - public function testCountWithIndex0() { - // Create a field that will require dedicated storage. - /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */ - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_int', - 'entity_type' => 'user', - 'type' => 'integer', - 'cardinality' => 2, - )); - $field_storage->save(); - FieldConfig::create(array( - 'field_storage' => $field_storage, - 'bundle' => 'user', - ))->save(); - - // Create an entry for the anonymous user, who has user ID 0. - $user = $this->storageUser - ->create(array( - 'uid' => 0, - 'name' => 'anonymous', - 'mail' => NULL, - 'status' => FALSE, - 'field_int' => 42, - )); - $user->save(); - - // Test shared table storage. - $storage = $user->getFieldDefinition('name')->getFieldStorageDefinition(); - $this->assertIdentical(TRUE, $this->storageUser->countFieldData($storage, TRUE)); - - // Test dedicated table storage. - $storage = $user->getFieldDefinition('field_int')->getFieldStorageDefinition(); - $this->assertIdentical(TRUE, $this->storageUser->countFieldData($storage, TRUE)); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldImportChangeTest.php b/core/modules/field/tests/src/Kernel/FieldImportChangeTest.php deleted file mode 100644 index e22b1f3..0000000 --- a/core/modules/field/tests/src/Kernel/FieldImportChangeTest.php +++ /dev/null @@ -1,58 +0,0 @@ -installConfig(['field_test_config']); - $field_storage_id = 'field_test_import'; - $field_id = "entity_test.entity_test.$field_storage_id"; - $field_config_name = "field.field.$field_id"; - - $active = $this->container->get('config.storage'); - $sync = $this->container->get('config.storage.sync'); - $this->copyConfig($active, $sync); - - // Save as files in the sync directory. - $field = $active->read($field_config_name); - $new_label = 'Test update import field'; - $field['label'] = $new_label; - $sync->write($field_config_name, $field); - - // Import the content of the sync directory. - $this->configImporter()->import(); - - // Check that the updated config was correctly imported. - $field = FieldConfig::load($field_id); - $this->assertEqual($field->getLabel(), $new_label, 'field label updated'); - } -} - diff --git a/core/modules/field/tests/src/Kernel/FieldImportCreateTest.php b/core/modules/field/tests/src/Kernel/FieldImportCreateTest.php deleted file mode 100644 index 98b1e25..0000000 --- a/core/modules/field/tests/src/Kernel/FieldImportCreateTest.php +++ /dev/null @@ -1,124 +0,0 @@ -assertFalse(FieldStorageConfig::load($field_storage_id)); - $this->assertFalse(FieldConfig::load($field_id)); - $this->assertFalse(FieldStorageConfig::load($field_storage_id_2)); - $this->assertFalse(FieldConfig::load($field_id_2a)); - $this->assertFalse(FieldConfig::load($field_id_2b)); - - // Create a second bundle for the 'Entity test' entity type. - entity_test_create_bundle('test_bundle'); - - // Enable field_test_config module and check that the field and storage - // shipped in the module's default config were created. - \Drupal::service('module_installer')->install(array('field_test_config')); - - // A field storage with one single field. - $field_storage = FieldStorageConfig::load($field_storage_id); - $this->assertTrue($field_storage, 'The field was created.'); - $field = FieldConfig::load($field_id); - $this->assertTrue($field, 'The field was deleted.'); - - // A field storage with two fields. - $field_storage_2 = FieldStorageConfig::load($field_storage_id_2); - $this->assertTrue($field_storage_2, 'The second field was created.'); - $this->assertTrue($field->getTargetBundle(), 'test_bundle', 'The second field was created on bundle test_bundle.'); - $this->assertTrue($field->getTargetBundle(), 'test_bundle_2', 'The second field was created on bundle test_bundle_2.'); - - // Tests fields. - $ids = \Drupal::entityQuery('field_config') - ->condition('entity_type', 'entity_test') - ->condition('bundle', 'entity_test') - ->execute(); - $this->assertEqual(count($ids), 2); - $this->assertTrue(isset($ids['entity_test.entity_test.field_test_import'])); - $this->assertTrue(isset($ids['entity_test.entity_test.field_test_import_2'])); - $ids = \Drupal::entityQuery('field_config') - ->condition('entity_type', 'entity_test') - ->condition('bundle', 'test_bundle') - ->execute(); - $this->assertEqual(count($ids), 1); - $this->assertTrue(isset($ids['entity_test.test_bundle.field_test_import_2'])); - } - - /** - * Tests creating field storages and fields during config import. - */ - function testImportCreate() { - // A field storage with one single field. - $field_name = 'field_test_import_sync'; - $field_storage_id = "entity_test.$field_name"; - $field_id = "entity_test.entity_test.$field_name"; - $field_storage_config_name = "field.storage.$field_storage_id"; - $field_config_name = "field.field.$field_id"; - - // A field storage with two fields. - $field_name_2 = 'field_test_import_sync_2'; - $field_storage_id_2 = "entity_test.$field_name_2"; - $field_id_2a = "entity_test.test_bundle.$field_name_2"; - $field_id_2b = "entity_test.test_bundle_2.$field_name_2"; - $field_storage_config_name_2 = "field.storage.$field_storage_id_2"; - $field_config_name_2a = "field.field.$field_id_2a"; - $field_config_name_2b = "field.field.$field_id_2b"; - - $active = $this->container->get('config.storage'); - $sync = $this->container->get('config.storage.sync'); - $this->copyConfig($active, $sync); - - // Add the new files to the sync directory. - $src_dir = __DIR__ . '/../../modules/field_test_config/sync'; - $target_dir = config_get_config_directory(CONFIG_SYNC_DIRECTORY); - $this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name.yml", "$target_dir/$field_storage_config_name.yml")); - $this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name.yml", "$target_dir/$field_config_name.yml")); - $this->assertTrue(file_unmanaged_copy("$src_dir/$field_storage_config_name_2.yml", "$target_dir/$field_storage_config_name_2.yml")); - $this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2a.yml", "$target_dir/$field_config_name_2a.yml")); - $this->assertTrue(file_unmanaged_copy("$src_dir/$field_config_name_2b.yml", "$target_dir/$field_config_name_2b.yml")); - - // Import the content of the sync directory. - $this->configImporter()->import(); - - // Check that the field and storage were created. - $field_storage = FieldStorageConfig::load($field_storage_id); - $this->assertTrue($field_storage, 'Test import storage field from sync exists'); - $field = FieldConfig::load($field_id); - $this->assertTrue($field, 'Test import field from sync exists'); - $field_storage = FieldStorageConfig::load($field_storage_id_2); - $this->assertTrue($field_storage, 'Test import storage field 2 from sync exists'); - $field = FieldConfig::load($field_id_2a); - $this->assertTrue($field, 'Test import field 2a from sync exists'); - $field = FieldConfig::load($field_id_2b); - $this->assertTrue($field, 'Test import field 2b from sync exists'); - } -} - diff --git a/core/modules/field/tests/src/Kernel/FieldImportDeleteTest.php b/core/modules/field/tests/src/Kernel/FieldImportDeleteTest.php deleted file mode 100644 index ca3ef45..0000000 --- a/core/modules/field/tests/src/Kernel/FieldImportDeleteTest.php +++ /dev/null @@ -1,118 +0,0 @@ -installConfig(['field_test_config']); - // At this point there are 5 field configuration objects in the active - // storage. - // - field.storage.entity_test.field_test_import - // - field.storage.entity_test.field_test_import_2 - // - field.field.entity_test.entity_test.field_test_import - // - field.field.entity_test.entity_test.field_test_import_2 - // - field.field.entity_test.test_bundle.field_test_import_2 - - $field_name = 'field_test_import'; - $field_storage_id = "entity_test.$field_name"; - $field_name_2 = 'field_test_import_2'; - $field_storage_id_2 = "entity_test.$field_name_2"; - $field_id = "entity_test.entity_test.$field_name"; - $field_id_2a = "entity_test.entity_test.$field_name_2"; - $field_id_2b = "entity_test.test_bundle.$field_name_2"; - $field_storage_config_name = "field.storage.$field_storage_id"; - $field_storage_config_name_2 = "field.storage.$field_storage_id_2"; - $field_config_name = "field.field.$field_id"; - $field_config_name_2a = "field.field.$field_id_2a"; - $field_config_name_2b = "field.field.$field_id_2b"; - - // Create a second bundle for the 'Entity test' entity type. - entity_test_create_bundle('test_bundle'); - - // Get the uuid's for the field storages. - $field_storage_uuid = FieldStorageConfig::load($field_storage_id)->uuid(); - $field_storage_uuid_2 = FieldStorageConfig::load($field_storage_id_2)->uuid(); - - $active = $this->container->get('config.storage'); - $sync = $this->container->get('config.storage.sync'); - $this->copyConfig($active, $sync); - $this->assertTrue($sync->delete($field_storage_config_name), SafeMarkup::format('Deleted field storage: @field_storage', array('@field_storage' => $field_storage_config_name))); - $this->assertTrue($sync->delete($field_storage_config_name_2), SafeMarkup::format('Deleted field storage: @field_storage', array('@field_storage' => $field_storage_config_name_2))); - $this->assertTrue($sync->delete($field_config_name), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name))); - $this->assertTrue($sync->delete($field_config_name_2a), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name_2a))); - $this->assertTrue($sync->delete($field_config_name_2b), SafeMarkup::format('Deleted field: @field', array('@field' => $field_config_name_2b))); - - $deletes = $this->configImporter()->getUnprocessedConfiguration('delete'); - $this->assertEqual(count($deletes), 5, 'Importing configuration will delete 3 fields and 2 field storages.'); - - // Import the content of the sync directory. - $this->configImporter()->import(); - - // Check that the field storages and fields are gone. - \Drupal::entityManager()->getStorage('field_storage_config')->resetCache(array($field_storage_id)); - $field_storage = FieldStorageConfig::load($field_storage_id); - $this->assertFalse($field_storage, 'The field storage was deleted.'); - \Drupal::entityManager()->getStorage('field_storage_config')->resetCache(array($field_storage_id_2)); - $field_storage_2 = FieldStorageConfig::load($field_storage_id_2); - $this->assertFalse($field_storage_2, 'The second field storage was deleted.'); - \Drupal::entityManager()->getStorage('field_config')->resetCache(array($field_id)); - $field = FieldConfig::load($field_id); - $this->assertFalse($field, 'The field was deleted.'); - \Drupal::entityManager()->getStorage('field_config')->resetCache(array($field_id_2a)); - $field_2a = FieldConfig::load($field_id_2a); - $this->assertFalse($field_2a, 'The second field on test bundle was deleted.'); - \Drupal::entityManager()->getStorage('field_config')->resetCache(array($field_id_2b)); - $field_2b = FieldConfig::load($field_id_2b); - $this->assertFalse($field_2b, 'The second field on test bundle 2 was deleted.'); - - // Check that all config files are gone. - $active = $this->container->get('config.storage'); - $this->assertIdentical($active->listAll($field_storage_config_name), array()); - $this->assertIdentical($active->listAll($field_storage_config_name_2), array()); - $this->assertIdentical($active->listAll($field_config_name), array()); - $this->assertIdentical($active->listAll($field_config_name_2a), array()); - $this->assertIdentical($active->listAll($field_config_name_2b), array()); - - // Check that the storage definition is preserved in state. - $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); - $this->assertTrue(isset($deleted_storages[$field_storage_uuid])); - $this->assertTrue(isset($deleted_storages[$field_storage_uuid_2])); - - // Purge field data, and check that the storage definition has been - // completely removed once the data is purged. - field_purge_batch(10); - $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); - $this->assertTrue(empty($deleted_storages), 'Fields are deleted'); - } -} - diff --git a/core/modules/field/tests/src/Kernel/FieldImportDeleteUninstallTest.php b/core/modules/field/tests/src/Kernel/FieldImportDeleteUninstallTest.php deleted file mode 100644 index 6e96fc5..0000000 --- a/core/modules/field/tests/src/Kernel/FieldImportDeleteUninstallTest.php +++ /dev/null @@ -1,174 +0,0 @@ -installSchema('user', array('users_data')); - } - - /** - * Tests deleting field storages and fields as part of config import. - */ - public function testImportDeleteUninstall() { - // Create a field to delete to prove that - // \Drupal\field\ConfigImporterFieldPurger does not purge fields that are - // not related to the configuration synchronization. - $unrelated_field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_int', - 'entity_type' => 'entity_test', - 'type' => 'integer', - )); - $unrelated_field_storage->save(); - FieldConfig::create([ - 'field_storage' => $unrelated_field_storage, - 'bundle' => 'entity_test', - ])->save(); - - // Create a telephone field for validation. - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_test', - 'entity_type' => 'entity_test', - 'type' => 'telephone', - )); - $field_storage->save(); - FieldConfig::create([ - 'field_storage' => $field_storage, - 'bundle' => 'entity_test', - ])->save(); - - $entity = EntityTest::create(); - $value = '+0123456789'; - $entity->field_test = $value; - $entity->field_int = '99'; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_test->value, $value); - $this->assertEqual($entity->field_test[0]->value, $value); - $this->assertEqual($entity->field_int->value, '99'); - - // Delete unrelated field before copying configuration and running the - // synchronization. - $unrelated_field_storage->delete(); - - $active = $this->container->get('config.storage'); - $sync = $this->container->get('config.storage.sync'); - $this->copyConfig($active, $sync); - - // Stage uninstall of the Telephone module. - $core_extension = $this->config('core.extension')->get(); - unset($core_extension['module']['telephone']); - $sync->write('core.extension', $core_extension); - - // Stage the field deletion - $sync->delete('field.storage.entity_test.field_test'); - $sync->delete('field.field.entity_test.entity_test.field_test'); - - $steps = $this->configImporter()->initialize(); - $this->assertIdentical($steps[0], array('\Drupal\field\ConfigImporterFieldPurger', 'process'), 'The additional process configuration synchronization step has been added.'); - - // This will purge all the data, delete the field and uninstall the - // Telephone module. - $this->configImporter()->import(); - - $this->assertFalse(\Drupal::moduleHandler()->moduleExists('telephone')); - $this->assertFalse(\Drupal::entityManager()->loadEntityByUuid('field_storage_config', $field_storage->uuid()), 'The test field has been deleted by the configuration synchronization'); - $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); - $this->assertFalse(isset($deleted_storages[$field_storage->uuid()]), 'Telephone field has been completed removed from the system.'); - $this->assertTrue(isset($deleted_storages[$unrelated_field_storage->uuid()]), 'Unrelated field not purged by configuration synchronization.'); - } - - /** - * Tests purging already deleted field storages and fields during a config - * import. - */ - public function testImportAlreadyDeletedUninstall() { - // Create a telephone field for validation. - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_test', - 'entity_type' => 'entity_test', - 'type' => 'telephone', - )); - $field_storage->save(); - $field_storage_uuid = $field_storage->uuid(); - FieldConfig::create([ - 'field_storage' => $field_storage, - 'bundle' => 'entity_test', - ])->save(); - - // Create 12 entities to ensure that the purging works as expected. - for ($i=0; $i < 12; $i++) { - $entity = EntityTest::create(); - $value = '+0123456789'; - $entity->field_test = $value; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_test->value, $value); - } - - // Delete the field. - $field_storage->delete(); - - $active = $this->container->get('config.storage'); - $sync = $this->container->get('config.storage.sync'); - $this->copyConfig($active, $sync); - - // Stage uninstall of the Telephone module. - $core_extension = $this->config('core.extension')->get(); - unset($core_extension['module']['telephone']); - $sync->write('core.extension', $core_extension); - - $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); - $this->assertTrue(isset($deleted_storages[$field_storage_uuid]), 'Field has been deleted and needs purging before configuration synchronization.'); - - $steps = $this->configImporter()->initialize(); - $this->assertIdentical($steps[0], array('\Drupal\field\ConfigImporterFieldPurger', 'process'), 'The additional process configuration synchronization step has been added.'); - - // This will purge all the data, delete the field and uninstall the - // Telephone module. - $this->configImporter()->import(); - - $this->assertFalse(\Drupal::moduleHandler()->moduleExists('telephone')); - $deleted_storages = \Drupal::state()->get('field.storage.deleted') ?: array(); - $this->assertFalse(isset($deleted_storages[$field_storage_uuid]), 'Field has been completed removed from the system.'); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldKernelTestBase.php b/core/modules/field/tests/src/Kernel/FieldKernelTestBase.php deleted file mode 100644 index 0fc8cff..0000000 --- a/core/modules/field/tests/src/Kernel/FieldKernelTestBase.php +++ /dev/null @@ -1,208 +0,0 @@ -fieldTestData->field_name[suffix] - * - $this->fieldTestData->field_storage[suffix] - * - $this->fieldTestData->field_storage_uuid[suffix] - * - $this->fieldTestData->field[suffix] - * - $this->fieldTestData->field_definition[suffix] - * - * @see \Drupal\field\Tests\FieldUnitTestBase::createFieldWithStorage() - * - * @var \ArrayObject - */ - protected $fieldTestData; - - /** - * Set the default field storage backend for fields created during tests. - */ - protected function setUp() { - parent::setUp(); - - $this->fieldTestData = new \ArrayObject(array(), \ArrayObject::ARRAY_AS_PROPS); - - $this->installEntitySchema('entity_test'); - $this->installEntitySchema('user'); - $this->installSchema('system', ['sequences', 'key_value']); - - // Set default storage backend and configure the theme system. - $this->installConfig(array('field', 'system')); - - // Create user 1. - $storage = \Drupal::entityManager()->getStorage('user'); - $storage - ->create(array( - 'uid' => 1, - 'name' => 'entity-test', - 'mail' => 'entity@localhost', - 'status' => TRUE, - )) - ->save(); - } - - /** - * Create a field and an associated field storage. - * - * @param string $suffix - * (optional) A string that should only contain characters that are valid in - * PHP variable names as well. - * @param string $entity_type - * (optional) The entity type on which the field should be created. - * Defaults to "entity_test". - * @param string $bundle - * (optional) The entity type on which the field should be created. - * Defaults to the default bundle of the entity type. - */ - protected function createFieldWithStorage($suffix = '', $entity_type = 'entity_test', $bundle = NULL) { - if (empty($bundle)) { - $bundle = $entity_type; - } - $field_name = 'field_name' . $suffix; - $field_storage = 'field_storage' . $suffix; - $field_storage_uuid = 'field_storage_uuid' . $suffix; - $field = 'field' . $suffix; - $field_definition = 'field_definition' . $suffix; - - $this->fieldTestData->$field_name = Unicode::strtolower($this->randomMachineName() . '_field_name' . $suffix); - $this->fieldTestData->$field_storage = FieldStorageConfig::create(array( - 'field_name' => $this->fieldTestData->$field_name, - 'entity_type' => $entity_type, - 'type' => 'test_field', - 'cardinality' => 4, - )); - $this->fieldTestData->$field_storage->save(); - $this->fieldTestData->$field_storage_uuid = $this->fieldTestData->$field_storage->uuid(); - $this->fieldTestData->$field_definition = array( - 'field_storage' => $this->fieldTestData->$field_storage, - 'bundle' => $bundle, - 'label' => $this->randomMachineName() . '_label', - 'description' => $this->randomMachineName() . '_description', - 'settings' => array( - 'test_field_setting' => $this->randomMachineName(), - ), - ); - $this->fieldTestData->$field = FieldConfig::create($this->fieldTestData->$field_definition); - $this->fieldTestData->$field->save(); - - entity_get_form_display($entity_type, $bundle, 'default') - ->setComponent($this->fieldTestData->$field_name, array( - 'type' => 'test_field_widget', - 'settings' => array( - 'test_widget_setting' => $this->randomMachineName(), - ) - )) - ->save(); - } - - /** - * Saves and reloads an entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity to save. - * - * @return \Drupal\Core\Entity\EntityInterface - * The entity, freshly reloaded from storage. - */ - protected function entitySaveReload(EntityInterface $entity) { - $entity->save(); - $controller = $this->container->get('entity.manager')->getStorage($entity->getEntityTypeId()); - $controller->resetCache(); - return $controller->load($entity->id()); - } - - /** - * Validate and save entity. Fail if violations are found. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity to save. - * - * @return void - */ - protected function entityValidateAndSave(EntityInterface $entity) { - $violations = $entity->validate(); - if ($violations->count()) { - $this->fail($violations); - } - else { - $entity->save(); - } - } - - /** - * Generate random values for a field_test field. - * - * @param $cardinality - * Number of values to generate. - * @return - * An array of random values, in the format expected for field values. - */ - protected function _generateTestFieldValues($cardinality) { - $values = array(); - for ($i = 0; $i < $cardinality; $i++) { - // field_test fields treat 0 as 'empty value'. - $values[$i]['value'] = mt_rand(1, 127); - } - return $values; - } - - /** - * Assert that a field has the expected values in an entity. - * - * This function only checks a single column in the field values. - * - * @param EntityInterface $entity - * The entity to test. - * @param $field_name - * The name of the field to test - * @param $expected_values - * The array of expected values. - * @param $langcode - * (Optional) The language code for the values. Defaults to - * \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED. - * @param $column - * (Optional) The name of the column to check. Defaults to 'value'. - */ - protected function assertFieldValues(EntityInterface $entity, $field_name, $expected_values, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $column = 'value') { - // Re-load the entity to make sure we have the latest changes. - \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->resetCache(array($entity->id())); - $e = entity_load($entity->getEntityTypeId(), $entity->id()); - $field = $values = $e->getTranslation($langcode)->$field_name; - // Filter out empty values so that they don't mess with the assertions. - $field->filterEmptyItems(); - $values = $field->getValue(); - $this->assertEqual(count($values), count($expected_values), 'Expected number of values were saved.'); - foreach ($expected_values as $key => $value) { - $this->assertEqual($values[$key][$column], $value, format_string('Value @value was saved correctly.', array('@value' => $value))); - } - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldStorageCrudTest.php b/core/modules/field/tests/src/Kernel/FieldStorageCrudTest.php deleted file mode 100644 index 1548af8..0000000 --- a/core/modules/field/tests/src/Kernel/FieldStorageCrudTest.php +++ /dev/null @@ -1,463 +0,0 @@ - 'field_2', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - ); - field_test_memorize(); - $field_storage = FieldStorageConfig::create($field_storage_definition); - $field_storage->save(); - - $field_storage = FieldStorageConfig::load($field_storage->id()); - $this->assertTrue($field_storage->getSetting('storage_setting_from_config_data')); - $this->assertNull($field_storage->getSetting('config_data_from_storage_setting')); - - $mem = field_test_memorize(); - $this->assertIdentical($mem['field_test_field_storage_config_create'][0][0]->getName(), $field_storage_definition['field_name'], 'hook_entity_create() called with correct arguments.'); - $this->assertIdentical($mem['field_test_field_storage_config_create'][0][0]->getType(), $field_storage_definition['type'], 'hook_entity_create() called with correct arguments.'); - - // Read the configuration. Check against raw configuration data rather than - // the loaded ConfigEntity, to be sure we check that the defaults are - // applied on write. - $field_storage_config = $this->config('field.storage.' . $field_storage->id())->get(); - - $this->assertTrue($field_storage_config['settings']['config_data_from_storage_setting']); - $this->assertTrue(!isset($field_storage_config['settings']['storage_setting_from_config_data'])); - - // Since we are working with raw configuration, this needs to be unset - // manually. - // @see Drupal\field_test\Plugin\Field\FieldType\TestItem::storageSettingsFromConfigData() - unset($field_storage_config['settings']['config_data_from_storage_setting']); - - // Ensure that basic properties are preserved. - $this->assertEqual($field_storage_config['field_name'], $field_storage_definition['field_name'], 'The field name is properly saved.'); - $this->assertEqual($field_storage_config['entity_type'], $field_storage_definition['entity_type'], 'The field entity type is properly saved.'); - $this->assertEqual($field_storage_config['id'], $field_storage_definition['entity_type'] . '.' . $field_storage_definition['field_name'], 'The field id is properly saved.'); - $this->assertEqual($field_storage_config['type'], $field_storage_definition['type'], 'The field type is properly saved.'); - - // Ensure that cardinality defaults to 1. - $this->assertEqual($field_storage_config['cardinality'], 1, 'Cardinality defaults to 1.'); - - // Ensure that default settings are present. - $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); - $this->assertEqual($field_storage_config['settings'], $field_type_manager->getDefaultStorageSettings($field_storage_definition['type']), 'Default storage settings have been written.'); - - // Guarantee that the name is unique. - try { - FieldStorageConfig::create($field_storage_definition)->save(); - $this->fail(t('Cannot create two fields with the same name.')); - } - catch (EntityStorageException $e) { - $this->pass(t('Cannot create two fields with the same name.')); - } - - // Check that field type is required. - try { - $field_storage_definition = array( - 'field_name' => 'field_1', - 'entity_type' => 'entity_type', - ); - FieldStorageConfig::create($field_storage_definition)->save(); - $this->fail(t('Cannot create a field with no type.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create a field with no type.')); - } - - // Check that field name is required. - try { - $field_storage_definition = array( - 'type' => 'test_field', - 'entity_type' => 'entity_test', - ); - FieldStorageConfig::create($field_storage_definition)->save(); - $this->fail(t('Cannot create an unnamed field.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create an unnamed field.')); - } - // Check that entity type is required. - try { - $field_storage_definition = array( - 'field_name' => 'test_field', - 'type' => 'test_field' - ); - FieldStorageConfig::create($field_storage_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_storage_definition = array( - 'field_name' => '2field_2', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - ); - FieldStorageConfig::create($field_storage_definition)->save(); - $this->fail(t('Cannot create a field with a name starting with a digit.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create a field with a name starting with a digit.')); - } - - // Check that field name must only contain lowercase alphanumeric or _. - try { - $field_storage_definition = array( - 'field_name' => 'field#_3', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - ); - FieldStorageConfig::create($field_storage_definition)->save(); - $this->fail(t('Cannot create a field with a name containing an illegal character.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create a field with a name containing an illegal character.')); - } - - // Check that field name cannot be longer than 32 characters long. - try { - $field_storage_definition = array( - 'field_name' => '_12345678901234567890123456789012', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - ); - FieldStorageConfig::create($field_storage_definition)->save(); - $this->fail(t('Cannot create a field with a name longer than 32 characters.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create a field with a name longer than 32 characters.')); - } - - // Check that field name can not be an entity key. - // "id" is known as an entity key from the "entity_test" type. - try { - $field_storage_definition = array( - 'type' => 'test_field', - 'field_name' => 'id', - 'entity_type' => 'entity_test', - ); - FieldStorageConfig::create($field_storage_definition)->save(); - $this->fail(t('Cannot create a field bearing the name of an entity key.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot create a field bearing the name of an entity key.')); - } - } - - /** - * Tests that an explicit schema can be provided on creation. - * - * This behavior is needed to allow field storage creation within updates, - * since plugin classes (and thus the field type schema) cannot be accessed. - */ - function testCreateWithExplicitSchema() { - $schema = array( - 'dummy' => 'foobar' - ); - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_2', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - 'schema' => $schema, - )); - $this->assertEqual($field_storage->getSchema(), $schema); - } - - /** - * Tests reading field storage definitions. - */ - function testRead() { - $field_storage_definition = array( - 'field_name' => 'field_1', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - ); - $field_storage = FieldStorageConfig::create($field_storage_definition); - $field_storage->save(); - $id = $field_storage->id(); - - // Check that 'single column' criteria works. - $fields = entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'])); - $this->assertTrue(count($fields) == 1 && isset($fields[$id]), 'The field was properly read.'); - - // Check that 'multi column' criteria works. - $fields = entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'type' => $field_storage_definition['type'])); - $this->assertTrue(count($fields) == 1 && isset($fields[$id]), 'The field was properly read.'); - $fields = entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'type' => 'foo')); - $this->assertTrue(empty($fields), 'No field was found.'); - - // Create a field from the field storage. - $field_definition = array( - 'field_name' => $field_storage_definition['field_name'], - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - ); - FieldConfig::create($field_definition)->save(); - } - - /** - * Test creation of indexes on data column. - */ - function testIndexes() { - // Check that indexes specified by the field type are used by default. - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_1', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - )); - $field_storage->save(); - $field_storage = FieldStorageConfig::load($field_storage->id()); - $schema = $field_storage->getSchema(); - $expected_indexes = array('value' => array('value')); - $this->assertEqual($schema['indexes'], $expected_indexes, 'Field type indexes saved by default'); - - // Check that indexes specified by the field definition override the field - // type indexes. - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_2', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - 'indexes' => array( - 'value' => array(), - ), - )); - $field_storage->save(); - $field_storage = FieldStorageConfig::load($field_storage->id()); - $schema = $field_storage->getSchema(); - $expected_indexes = array('value' => array()); - $this->assertEqual($schema['indexes'], $expected_indexes, 'Field definition indexes override field type indexes'); - - // Check that indexes specified by the field definition add to the field - // type indexes. - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_3', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - 'indexes' => array( - 'value_2' => array('value'), - ), - )); - $field_storage->save(); - $id = $field_storage->id(); - $field_storage = FieldStorageConfig::load($id); - $schema = $field_storage->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'); - } - - /** - * Test the deletion of a field storage. - */ - function testDelete() { - // TODO: Also test deletion of the data stored in the field ? - - // Create two fields (so we can test that only one is deleted). - $field_storage_definition = array( - 'field_name' => 'field_1', - 'type' => 'test_field', - 'entity_type' => 'entity_test', - ); - FieldStorageConfig::create($field_storage_definition)->save(); - $another_field_storage_definition = array( - 'field_name' => 'field_2', - 'type' => 'test_field', - 'entity_type' => 'entity_test', - ); - FieldStorageConfig::create($another_field_storage_definition)->save(); - - // Create fields for each. - $field_definition = array( - 'field_name' => $field_storage_definition['field_name'], - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - ); - FieldConfig::create($field_definition)->save(); - $another_field_definition = $field_definition; - $another_field_definition['field_name'] = $another_field_storage_definition['field_name']; - FieldConfig::create($another_field_definition)->save(); - - // Test that the first field is not deleted, and then delete it. - $field_storage = current(entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'include_deleted' => TRUE))); - $this->assertTrue(!empty($field_storage) && !$field_storage->isDeleted(), 'A new storage is not marked for deletion.'); - FieldStorageConfig::loadByName('entity_test', $field_storage_definition['field_name'])->delete(); - - // Make sure that the field is marked as deleted when it is specifically - // loaded. - $field_storage = current(entity_load_multiple_by_properties('field_storage_config', array('field_name' => $field_storage_definition['field_name'], 'include_deleted' => TRUE))); - $this->assertTrue($field_storage->isDeleted(), 'A deleted storage is marked for deletion.'); - - // Make sure that this field is marked as deleted when it is - // specifically loaded. - $field = current(entity_load_multiple_by_properties('field_config', array('entity_type' => 'entity_test', 'field_name' => $field_definition['field_name'], 'bundle' => $field_definition['bundle'], 'include_deleted' => TRUE))); - $this->assertTrue($field->isDeleted(), 'A field whose storage was deleted is marked for deletion.'); - - // Try to load the storage normally and make sure it does not show up. - $field_storage = FieldStorageConfig::load('entity_test.' . $field_storage_definition['field_name']); - $this->assertTrue(empty($field_storage), 'A deleted storage is not loaded by default.'); - - // Try to load the field normally and make sure it does not show up. - $field = FieldConfig::load('entity_test.' . '.' . $field_definition['bundle'] . '.' . $field_definition['field_name']); - $this->assertTrue(empty($field), 'A field whose storage was deleted is not loaded by default.'); - - // Make sure the other field and its storage are not deleted. - $another_field_storage = FieldStorageConfig::load('entity_test.' . $another_field_storage_definition['field_name']); - $this->assertTrue(!empty($another_field_storage) && !$another_field_storage->isDeleted(), 'A non-deleted storage is not marked for deletion.'); - $another_field = FieldConfig::load('entity_test.' . $another_field_definition['bundle'] . '.' . $another_field_definition['field_name']); - $this->assertTrue(!empty($another_field) && !$another_field->isDeleted(), 'A field whose storage was not deleted is not marked for deletion.'); - - // Try to create a new field the same name as a deleted field and - // write data into it. - FieldStorageConfig::create($field_storage_definition)->save(); - FieldConfig::create($field_definition)->save(); - $field_storage = FieldStorageConfig::load('entity_test.' . $field_storage_definition['field_name']); - $this->assertTrue(!empty($field_storage) && !$field_storage->isDeleted(), 'A new storage with a previously used name is created.'); - $field = FieldConfig::load('entity_test.' . $field_definition['bundle'] . '.' . $field_definition['field_name'] ); - $this->assertTrue(!empty($field) && !$field->isDeleted(), 'A new field for a previously used field name is created.'); - - // Save an entity with data for the field - $entity = EntityTest::create(); - $values[0]['value'] = mt_rand(1, 127); - $entity->{$field_storage->getName()}->value = $values[0]['value']; - $entity = $this->entitySaveReload($entity); - - // Verify the field is present on load - $this->assertIdentical(count($entity->{$field_storage->getName()}), count($values), "Data in previously deleted field saves and loads correctly"); - foreach ($values as $delta => $value) { - $this->assertEqual($entity->{$field_storage->getName()}[$delta]->value, $values[$delta]['value'], "Data in previously deleted field saves and loads correctly"); - } - } - - function testUpdateFieldType() { - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_type', - 'entity_type' => 'entity_test', - 'type' => 'decimal', - )); - $field_storage->save(); - - try { - $field_storage->set('type', 'integer'); - $field_storage->save(); - $this->fail(t('Cannot update a field to a different type.')); - } - catch (FieldException $e) { - $this->pass(t('Cannot update a field to a different type.')); - } - } - - /** - * Test updating a field storage. - */ - function testUpdate() { - // Create a field with a defined cardinality, so that we can ensure it's - // respected. Since cardinality enforcement is consistent across database - // systems, it makes a good test case. - $cardinality = 4; - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'field_update', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - 'cardinality' => $cardinality, - )); - $field_storage->save(); - $field = FieldConfig::create([ - 'field_storage' => $field_storage, - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - ]); - $field->save(); - - do { - $entity = EntityTest::create(); - // Fill in the entity with more values than $cardinality. - for ($i = 0; $i < 20; $i++) { - // We can not use $i here because 0 values are filtered out. - $entity->field_update[] = $i + 1; - } - // Load back and assert there are $cardinality number of values. - $entity = $this->entitySaveReload($entity); - $this->assertEqual(count($entity->field_update), $field_storage->getCardinality()); - // Now check the values themselves. - for ($delta = 0; $delta < $cardinality; $delta++) { - $this->assertEqual($entity->field_update[$delta]->value, $delta + 1); - } - // Increase $cardinality and set the field cardinality to the new value. - $field_storage->setCardinality(++$cardinality); - $field_storage->save(); - } while ($cardinality < 6); - } - - /** - * Test field type modules forbidding an update. - */ - function testUpdateForbid() { - $field_storage = FieldStorageConfig::create(array( - 'field_name' => 'forbidden', - 'entity_type' => 'entity_test', - 'type' => 'test_field', - 'settings' => array( - 'changeable' => 0, - 'unchangeable' => 0 - ))); - $field_storage->save(); - $field_storage->setSetting('changeable', $field_storage->getSetting('changeable') + 1); - try { - $field_storage->save(); - $this->pass(t("A changeable setting can be updated.")); - } - catch (FieldStorageDefinitionUpdateForbiddenException $e) { - $this->fail(t("An unchangeable setting cannot be updated.")); - } - $field_storage->setSetting('unchangeable', $field_storage->getSetting('unchangeable') + 1); - try { - $field_storage->save(); - $this->fail(t("An unchangeable setting can be updated.")); - } - catch (FieldStorageDefinitionUpdateForbiddenException $e) { - $this->pass(t("An unchangeable setting cannot be updated.")); - } - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldTypePluginManagerTest.php b/core/modules/field/tests/src/Kernel/FieldTypePluginManagerTest.php deleted file mode 100644 index 76afec4..0000000 --- a/core/modules/field/tests/src/Kernel/FieldTypePluginManagerTest.php +++ /dev/null @@ -1,93 +0,0 @@ -getDefinition($type); - $this->assertIdentical($field_type_manager->getDefaultStorageSettings($type), $definition['class']::defaultStorageSettings(), format_string("%type storage settings were returned", array('%type' => $type))); - $this->assertIdentical($field_type_manager->getDefaultFieldSettings($type), $definition['class']::defaultFieldSettings(), format_string(" %type field settings were returned", array('%type' => $type))); - } - } - - /** - * Tests creation of field item instances. - */ - public function testCreateInstance() { - /** @var \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager */ - $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); - foreach (array('test_field', 'shape', 'hidden_test_field') as $type) { - $definition = $field_type_manager->getDefinition($type); - - $class = $definition['class']; - $field_name = 'field_' . $type; - - $field_definition = BaseFieldDefinition::create($type); - - $configuration = array( - 'field_definition' => $field_definition, - 'name' => $field_name, - 'parent' => NULL, - ); - - $instance = $field_type_manager->createInstance($type, $configuration); - - $this->assertTrue($instance instanceof $class, SafeMarkup::format('Created a @class instance', array('@class' => $class))); - $this->assertEqual($field_name, $instance->getName(), SafeMarkup::format('Instance name is @name', array('@name' => $field_name))); - } - } - - /** - * Tests creation of field item instances. - */ - public function testCreateInstanceWithConfig() { - /** @var \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager */ - $field_type_manager = \Drupal::service('plugin.manager.field.field_type'); - $type = 'test_field'; - $definition = $field_type_manager->getDefinition($type); - - $class = $definition['class']; - $field_name = 'field_' . $type; - - $field_definition = BaseFieldDefinition::create($type) - ->setLabel('Jenny') - ->setDefaultValue(8675309); - - $configuration = array( - 'field_definition' => $field_definition, - 'name' => $field_name, - 'parent' => NULL, - ); - - $entity = EntityTest::create(); - - $instance = $field_type_manager->createInstance($type, $configuration); - - $this->assertTrue($instance instanceof $class, SafeMarkup::format('Created a @class instance', array('@class' => $class))); - $this->assertEqual($field_name, $instance->getName(), SafeMarkup::format('Instance name is @name', array('@name' => $field_name))); - $this->assertEqual($instance->getFieldDefinition()->getLabel(), 'Jenny', 'Instance label is Jenny'); - $this->assertEqual($instance->getFieldDefinition()->getDefaultValue($entity), [['value' => 8675309]], 'Instance default_value is 8675309'); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FieldValidationTest.php b/core/modules/field/tests/src/Kernel/FieldValidationTest.php deleted file mode 100644 index d3a5059..0000000 --- a/core/modules/field/tests/src/Kernel/FieldValidationTest.php +++ /dev/null @@ -1,102 +0,0 @@ -entityType = 'entity_test'; - $this->bundle = 'entity_test'; - $this->createFieldWithStorage('', $this->entityType, $this->bundle); - - // Create an 'entity_test' entity. - $this->entity = entity_create($this->entityType, array( - 'type' => $this->bundle, - )); - } - - /** - * Tests that the number of values is validated against the field cardinality. - */ - function testCardinalityConstraint() { - $cardinality = $this->fieldTestData->field_storage->getCardinality(); - $entity = $this->entity; - - for ($delta = 0; $delta < $cardinality + 1; $delta++) { - $entity->{$this->fieldTestData->field_name}[] = array('value' => 1); - } - - // Validate the field. - $violations = $entity->{$this->fieldTestData->field_name}->validate(); - - // Check that the expected constraint violations are reported. - $this->assertEqual(count($violations), 1); - $this->assertEqual($violations[0]->getPropertyPath(), ''); - $this->assertEqual($violations[0]->getMessage(), t('%name: this field cannot hold more than @count values.', array('%name' => $this->fieldTestData->field->getLabel(), '@count' => $cardinality))); - } - - /** - * Tests that constraints defined by the field type are validated. - */ - function testFieldConstraints() { - $cardinality = $this->fieldTestData->field_storage->getCardinality(); - $entity = $this->entity; - - // The test is only valid if the field cardinality is greater than 2. - $this->assertTrue($cardinality >= 2); - - // Set up values for the field. - $expected_violations = array(); - for ($delta = 0; $delta < $cardinality; $delta++) { - // All deltas except '1' have incorrect values. - if ($delta == 1) { - $value = 1; - } - else { - $value = -1; - $expected_violations[$delta . '.value'][] = t('%name does not accept the value -1.', array('%name' => $this->fieldTestData->field->getLabel())); - } - $entity->{$this->fieldTestData->field_name}[] = $value; - } - - // Validate the field. - $violations = $entity->{$this->fieldTestData->field_name}->validate(); - - // Check that the expected constraint violations are reported. - $violations_by_path = array(); - foreach ($violations as $violation) { - $violations_by_path[$violation->getPropertyPath()][] = $violation->getMessage(); - } - $this->assertEqual($violations_by_path, $expected_violations); - } - -} diff --git a/core/modules/field/tests/src/Kernel/FormatterPluginManagerTest.php b/core/modules/field/tests/src/Kernel/FormatterPluginManagerTest.php deleted file mode 100644 index 88edb05..0000000 --- a/core/modules/field/tests/src/Kernel/FormatterPluginManagerTest.php +++ /dev/null @@ -1,53 +0,0 @@ -setName('field_test_field'); - - $formatter_options = array( - 'field_definition' => $base_field_definition, - 'view_mode' => 'default', - 'configuration' => array( - 'type' => 'field_test_applicable', - ), - ); - - $instance = $formatter_plugin_manager->getInstance($formatter_options); - $this->assertEqual($instance->getPluginId(), 'field_test_applicable'); - - // Now set name to something that makes isApplicable() return FALSE. - $base_field_definition->setName('deny_applicable'); - $instance = $formatter_plugin_manager->getInstance($formatter_options); - - // Instance should be default widget. - $this->assertNotEqual($instance->getPluginId(), 'field_test_applicable'); - $this->assertEqual($instance->getPluginId(), 'field_test_default'); - } - -} diff --git a/core/modules/field/tests/src/Kernel/Number/NumberItemTest.php b/core/modules/field/tests/src/Kernel/Number/NumberItemTest.php deleted file mode 100644 index 1cdf05b..0000000 --- a/core/modules/field/tests/src/Kernel/Number/NumberItemTest.php +++ /dev/null @@ -1,109 +0,0 @@ - 'entity_test', - 'field_name' => 'field_' . $type, - 'type' => $type, - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'field_' . $type, - 'bundle' => 'entity_test', - ])->save(); - } - } - - /** - * Tests using entity fields of the number field type. - */ - public function testNumberItem() { - // Verify entity creation. - $entity = EntityTest::create(); - $integer = rand(0, 10); - $entity->field_integer = $integer; - $float = 3.14; - $entity->field_float = $float; - $entity->field_decimal = '20-40'; - $violations = $entity->validate(); - $this->assertIdentical(1, count($violations), 'Wrong decimal value causes validation error'); - $decimal = '31.3'; - $entity->field_decimal = $decimal; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->field_integer instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_integer[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_integer->value, $integer); - $this->assertEqual($entity->field_integer[0]->value, $integer); - $this->assertTrue($entity->field_float instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_float[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_float->value, $float); - $this->assertEqual($entity->field_float[0]->value, $float); - $this->assertTrue($entity->field_decimal instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_decimal[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_decimal->value, $decimal); - $this->assertEqual($entity->field_decimal[0]->value, $decimal); - - // Verify changing the number value. - $new_integer = rand(11, 20); - $new_float = rand(1001, 2000) / 100; - $new_decimal = '18.2'; - $entity->field_integer->value = $new_integer; - $this->assertEqual($entity->field_integer->value, $new_integer); - $entity->field_float->value = $new_float; - $this->assertEqual($entity->field_float->value, $new_float); - $entity->field_decimal->value = $new_decimal; - $this->assertEqual($entity->field_decimal->value, $new_decimal); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_integer->value, $new_integer); - $this->assertEqual($entity->field_float->value, $new_float); - $this->assertEqual($entity->field_decimal->value, $new_decimal); - - /// Test sample item generation. - $entity = EntityTest::create(); - $entity->field_integer->generateSampleItems(); - $entity->field_float->generateSampleItems(); - $entity->field_decimal->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - -} diff --git a/core/modules/field/tests/src/Kernel/ShapeItemTest.php b/core/modules/field/tests/src/Kernel/ShapeItemTest.php deleted file mode 100644 index ce96c82..0000000 --- a/core/modules/field/tests/src/Kernel/ShapeItemTest.php +++ /dev/null @@ -1,92 +0,0 @@ - $this->fieldName, - 'entity_type' => 'entity_test', - 'type' => 'shape', - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => $this->fieldName, - 'bundle' => 'entity_test', - ])->save(); - } - - /** - * Tests using entity fields of the field field type. - */ - public function testShapeItem() { - // Verify entity creation. - $entity = EntityTest::create(); - $shape = 'cube'; - $color = 'blue'; - $entity->{$this->fieldName}->shape = $shape; - $entity->{$this->fieldName}->color = $color; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->{$this->fieldName} instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->{$this->fieldName}[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->{$this->fieldName}->shape, $shape); - $this->assertEqual($entity->{$this->fieldName}->color, $color); - $this->assertEqual($entity->{$this->fieldName}[0]->shape, $shape); - $this->assertEqual($entity->{$this->fieldName}[0]->color, $color); - - // Verify changing the field value. - $new_shape = 'circle'; - $new_color = 'red'; - $entity->{$this->fieldName}->shape = $new_shape; - $entity->{$this->fieldName}->color = $new_color; - $this->assertEqual($entity->{$this->fieldName}->shape, $new_shape); - $this->assertEqual($entity->{$this->fieldName}->color, $new_color); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->{$this->fieldName}->shape, $new_shape); - $this->assertEqual($entity->{$this->fieldName}->color, $new_color); - } - -} diff --git a/core/modules/field/tests/src/Kernel/String/RawStringFormatterTest.php b/core/modules/field/tests/src/Kernel/String/RawStringFormatterTest.php deleted file mode 100644 index d47dbca..0000000 --- a/core/modules/field/tests/src/Kernel/String/RawStringFormatterTest.php +++ /dev/null @@ -1,128 +0,0 @@ -installConfig(array('system', 'field')); - \Drupal::service('router.builder')->rebuild(); - $this->installEntitySchema('entity_test'); - - $this->entityType = 'entity_test'; - $this->bundle = $this->entityType; - $this->fieldName = Unicode::strtolower($this->randomMachineName()); - - $field_storage = FieldStorageConfig::create(array( - 'field_name' => $this->fieldName, - 'entity_type' => $this->entityType, - 'type' => 'string_long', - )); - $field_storage->save(); - - $instance = FieldConfig::create(array( - 'field_storage' => $field_storage, - 'bundle' => $this->bundle, - 'label' => $this->randomMachineName(), - )); - $instance->save(); - - $this->display = entity_get_display($this->entityType, $this->bundle, 'default') - ->setComponent($this->fieldName, array( - 'type' => 'string', - 'settings' => array(), - )); - $this->display->save(); - } - - /** - * Renders fields of a given entity with a given display. - * - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity object with attached fields to render. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The display to render the fields in. - * - * @return string - * The rendered entity fields. - */ - protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { - $content = $display->build($entity); - $content = $this->render($content); - return $content; - } - - /** - * Tests string formatter output. - */ - public function testStringFormatter() { - $value = $this->randomString(); - $value .= "\n\n" . $this->randomString() . ''; - $value .= "\n\n" . $this->randomString(); - - $entity = EntityTest::create(array()); - $entity->{$this->fieldName}->value = $value; - - // Verify that all HTML is escaped and newlines are retained. - $this->renderEntityFields($entity, $this->display); - $this->assertNoRaw($value); - $this->assertRaw(nl2br(Html::escape($value))); - - // Verify the cache tags. - $build = $entity->{$this->fieldName}->view(); - $this->assertTrue(!isset($build[0]['#cache']), 'The string formatter has no cache tags.'); - } - -} diff --git a/core/modules/field/tests/src/Kernel/String/StringFormatterTest.php b/core/modules/field/tests/src/Kernel/String/StringFormatterTest.php deleted file mode 100644 index af2c679..0000000 --- a/core/modules/field/tests/src/Kernel/String/StringFormatterTest.php +++ /dev/null @@ -1,164 +0,0 @@ -installConfig(array('system', 'field')); - \Drupal::service('router.builder')->rebuild(); - $this->installEntitySchema('entity_test_rev'); - - $this->entityType = 'entity_test_rev'; - $this->bundle = $this->entityType; - $this->fieldName = Unicode::strtolower($this->randomMachineName()); - - $field_storage = FieldStorageConfig::create(array( - 'field_name' => $this->fieldName, - 'entity_type' => $this->entityType, - 'type' => 'string', - )); - $field_storage->save(); - - $instance = FieldConfig::create(array( - 'field_storage' => $field_storage, - 'bundle' => $this->bundle, - 'label' => $this->randomMachineName(), - )); - $instance->save(); - - $this->display = entity_get_display($this->entityType, $this->bundle, 'default') - ->setComponent($this->fieldName, array( - 'type' => 'string', - 'settings' => array(), - )); - $this->display->save(); - } - - /** - * Renders fields of a given entity with a given display. - * - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity object with attached fields to render. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The display to render the fields in. - * - * @return string - * The rendered entity fields. - */ - protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { - $content = $display->build($entity); - $content = $this->render($content); - return $content; - } - - /** - * Tests string formatter output. - */ - public function testStringFormatter() { - $value = $this->randomString(); - $value .= "\n\n" . $this->randomString() . ''; - $value .= "\n\n" . $this->randomString(); - - $entity = EntityTestRev::create(array()); - $entity->{$this->fieldName}->value = $value; - - // Verify that all HTML is escaped and newlines are retained. - $this->renderEntityFields($entity, $this->display); - $this->assertNoRaw($value); - $this->assertRaw(nl2br(Html::escape($value))); - - // Verify the cache tags. - $build = $entity->{$this->fieldName}->view(); - $this->assertTrue(!isset($build[0]['#cache']), 'The string formatter has no cache tags.'); - - $value = $this->randomMachineName(); - $entity->{$this->fieldName}->value = $value; - $entity->save(); - - // Set the formatter to link to the entity. - $this->display->setComponent($this->fieldName, [ - 'type' => 'string', - 'settings' => [ - 'link_to_entity' => TRUE, - ], - ]); - $this->display->save(); - - $this->renderEntityFields($entity, $this->display); - $this->assertLink($value, 0); - $this->assertLinkByHref($entity->url()); - - // $entity->url('revision') falls back to the canonical URL if this is no - // revision. - $this->assertLinkByHref($entity->url('revision')); - - // Make the entity a new revision. - $old_revision_id = $entity->getRevisionId(); - $entity->setNewRevision(TRUE); - $value2 = $this->randomMachineName(); - $entity->{$this->fieldName}->value = $value2; - $entity->save(); - $entity_new_revision = \Drupal::entityManager()->getStorage('entity_test_rev')->loadRevision($old_revision_id); - - $this->renderEntityFields($entity, $this->display); - $this->assertLink($value2, 0); - $this->assertLinkByHref($entity->url('revision')); - - $this->renderEntityFields($entity_new_revision, $this->display); - $this->assertLink($value, 0); - $this->assertLinkByHref('/entity_test_rev/' . $entity_new_revision->id() . '/revision/' . $entity_new_revision->getRevisionId() . '/view'); - } -} diff --git a/core/modules/field/tests/src/Kernel/String/UuidFormatterTest.php b/core/modules/field/tests/src/Kernel/String/UuidFormatterTest.php deleted file mode 100644 index f25b49d..0000000 --- a/core/modules/field/tests/src/Kernel/String/UuidFormatterTest.php +++ /dev/null @@ -1,63 +0,0 @@ -installConfig(['system', 'field']); - \Drupal::service('router.builder')->rebuild(); - $this->installEntitySchema('entity_test'); - } - - /** - * Tests string formatter output. - */ - public function testUuidStringFormatter() { - $entity = EntityTest::create([]); - $entity->save(); - - $uuid_field = $entity->get('uuid'); - - // Verify default render. - $render_array = $uuid_field->view([]); - $this->assertIdentical($render_array[0]['#context']['value'], $entity->uuid(), 'The rendered UUID matches the entity UUID.'); - $this->assertTrue(strpos($this->render($render_array), $entity->uuid()), 'The rendered UUID found.'); - - // Verify customized render. - $render_array = $uuid_field->view(['settings' => ['link_to_entity' => TRUE]]); - $this->assertIdentical($render_array[0]['#type'], 'link'); - $this->assertIdentical($render_array[0]['#title']['#context']['value'], $entity->uuid()); - $this->assertIdentical($render_array[0]['#url']->toString(), $entity->url()); - $rendered = $this->render($render_array); - $this->assertTrue(strpos($rendered, $entity->uuid()), 'The rendered UUID found.'); - $this->assertTrue(strpos($rendered, $entity->url()), 'The rendered entity URL found.'); - } - -} diff --git a/core/modules/field/tests/src/Kernel/TestItemTest.php b/core/modules/field/tests/src/Kernel/TestItemTest.php deleted file mode 100644 index 71ba07b..0000000 --- a/core/modules/field/tests/src/Kernel/TestItemTest.php +++ /dev/null @@ -1,102 +0,0 @@ - $this->fieldName, - 'entity_type' => 'entity_test', - 'type' => 'test_field', - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => $this->fieldName, - 'bundle' => 'entity_test', - ])->save(); - } - - /** - * Tests using entity fields of the field field type. - */ - public function testTestItem() { - // Verify entity creation. - $entity = EntityTest::create(); - $value = rand(1, 10); - $entity->field_test = $value; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->{$this->fieldName} instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->{$this->fieldName}[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->{$this->fieldName}->value, $value); - $this->assertEqual($entity->{$this->fieldName}[0]->value, $value); - - // Verify changing the field value. - $new_value = rand(1, 10); - $entity->field_test->value = $new_value; - $this->assertEqual($entity->{$this->fieldName}->value, $new_value); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->{$this->fieldName}->value, $new_value); - - // Test the schema for this field type. - $expected_schema = array( - 'columns' => array( - 'value' => array( - 'type' => 'int', - 'size' => 'medium', - ), - ), - 'unique keys' => array(), - 'indexes' => array( - 'value' => array('value'), - ), - 'foreign keys' => array(), - ); - $field_schema = BaseFieldDefinition::create('test_field')->getSchema(); - $this->assertEqual($field_schema, $expected_schema); - } - -} diff --git a/core/modules/field/tests/src/Kernel/TestItemWithDependenciesTest.php b/core/modules/field/tests/src/Kernel/TestItemWithDependenciesTest.php deleted file mode 100644 index b98471c..0000000 --- a/core/modules/field/tests/src/Kernel/TestItemWithDependenciesTest.php +++ /dev/null @@ -1,61 +0,0 @@ - $this->fieldName, - 'entity_type' => 'entity_test', - 'type' => 'test_field_with_dependencies', - ))->save(); - $field = FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => $this->fieldName, - 'bundle' => 'entity_test', - ]); - $field->save(); - - // Validate that the field configuration entity has the expected - // dependencies. - $this->assertEqual([ - 'content' => ['node:article:uuid'], - 'config' => ['field.storage.entity_test.field_test'], - 'module' => ['entity_test', 'field_test', 'test_module'] - ], $field->getDependencies()); - } - -} diff --git a/core/modules/field/tests/src/Kernel/Timestamp/TimestampFormatterTest.php b/core/modules/field/tests/src/Kernel/Timestamp/TimestampFormatterTest.php deleted file mode 100644 index 12f4653..0000000 --- a/core/modules/field/tests/src/Kernel/Timestamp/TimestampFormatterTest.php +++ /dev/null @@ -1,194 +0,0 @@ -installConfig(['system']); - $this->installConfig(['field']); - $this->installEntitySchema('entity_test'); - - $this->entityType = 'entity_test'; - $this->bundle = $this->entityType; - $this->fieldName = Unicode::strtolower($this->randomMachineName()); - - $field_storage = FieldStorageConfig::create([ - 'field_name' => $this->fieldName, - 'entity_type' => $this->entityType, - 'type' => 'timestamp', - ]); - $field_storage->save(); - - $instance = FieldConfig::create([ - 'field_storage' => $field_storage, - 'bundle' => $this->bundle, - 'label' => $this->randomMachineName(), - ]); - $instance->save(); - - $this->display = entity_get_display($this->entityType, $this->bundle, 'default') - ->setComponent($this->fieldName, [ - 'type' => 'boolean', - 'settings' => [], - ]); - $this->display->save(); - } - - /** - * Renders fields of a given entity with a given display. - * - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity object with attached fields to render. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The display to render the fields in. - * - * @return string - * The rendered entity fields. - */ - protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) { - $content = $display->build($entity); - $content = $this->render($content); - return $content; - } - - /** - * Tests TimestampFormatter. - */ - public function testTimestampFormatter() { - $data = []; - - // Test standard formats. - $date_formats = array_keys(\Drupal::entityManager()->getStorage('date_format')->loadMultiple()); - - foreach ($date_formats as $date_format) { - $data[] = ['date_format' => $date_format, 'custom_date_format' => '', 'timezone' => '']; - } - - $data[] = ['date_format' => 'custom', 'custom_date_format' => 'r', 'timezone' => '']; - $data[] = ['date_format' => 'custom', 'custom_date_format' => 'e', 'timezone' => 'Asia/Tokyo']; - - foreach ($data as $settings) { - list($date_format, $custom_date_format, $timezone) = array_values($settings); - if (empty($timezone)) { - $timezone = NULL; - } - - $value = REQUEST_TIME - 87654321; - $expected = \Drupal::service('date.formatter')->format($value, $date_format, $custom_date_format, $timezone); - - $component = $this->display->getComponent($this->fieldName); - $component['type'] = 'timestamp'; - $component['settings'] = $settings; - $this->display->setComponent($this->fieldName, $component); - - $entity = EntityTest::create([]); - $entity->{$this->fieldName}->value = $value; - - $this->renderEntityFields($entity, $this->display); - $this->assertRaw($expected); - } - } - - /** - * Tests TimestampAgoFormatter. - */ - public function testTimestampAgoFormatter() { - $data = []; - - foreach (array(1, 2, 3, 4, 5, 6) as $granularity) { - $data[] = [ - 'future_format' => '@interval hence', - 'past_format' => '@interval ago', - 'granularity' => $granularity, - ]; - } - - foreach ($data as $settings) { - $future_format = $settings['future_format']; - $past_format = $settings['past_format']; - $granularity = $settings['granularity']; - $request_time = \Drupal::requestStack()->getCurrentRequest()->server->get('REQUEST_TIME'); - - // Test a timestamp in the past - $value = $request_time - 87654321; - $expected = SafeMarkup::format($past_format, ['@interval' => \Drupal::service('date.formatter')->formatTimeDiffSince($value, ['granularity' => $granularity])]); - - $component = $this->display->getComponent($this->fieldName); - $component['type'] = 'timestamp_ago'; - $component['settings'] = $settings; - $this->display->setComponent($this->fieldName, $component); - - $entity = EntityTest::create([]); - $entity->{$this->fieldName}->value = $value; - - $this->renderEntityFields($entity, $this->display); - $this->assertRaw($expected); - - // Test a timestamp in the future - $value = $request_time + 87654321; - $expected = SafeMarkup::format($future_format, ['@interval' => \Drupal::service('date.formatter')->formatTimeDiffUntil($value, ['granularity' => $granularity])]); - - $component = $this->display->getComponent($this->fieldName); - $component['type'] = 'timestamp_ago'; - $component['settings'] = $settings; - $this->display->setComponent($this->fieldName, $component); - - $entity = EntityTest::create([]); - $entity->{$this->fieldName}->value = $value; - - $this->renderEntityFields($entity, $this->display); - $this->assertRaw($expected); - } - } - -} diff --git a/core/modules/field/tests/src/Kernel/TranslationTest.php b/core/modules/field/tests/src/Kernel/TranslationTest.php deleted file mode 100644 index 3a11b85..0000000 --- a/core/modules/field/tests/src/Kernel/TranslationTest.php +++ /dev/null @@ -1,215 +0,0 @@ -installConfig(array('language')); - - $this->fieldName = Unicode::strtolower($this->randomMachineName()); - - $this->entityType = 'entity_test'; - - $this->fieldStorageDefinition = array( - 'field_name' => $this->fieldName, - 'entity_type' => $this->entityType, - 'type' => 'test_field', - 'cardinality' => 4, - ); - $this->fieldStorage = FieldStorageConfig::create($this->fieldStorageDefinition); - $this->fieldStorage->save(); - - $this->fieldDefinition = array( - 'field_storage' => $this->fieldStorage, - 'bundle' => 'entity_test', - ); - $this->field = FieldConfig::create($this->fieldDefinition); - $this->field->save(); - - for ($i = 0; $i < 3; ++$i) { - ConfigurableLanguage::create(array( - 'id' => 'l' . $i, - 'label' => $this->randomString(), - ))->save(); - } - } - - /** - * Test translatable fields storage/retrieval. - */ - function testTranslatableFieldSaveLoad() { - // Enable field translations for nodes. - field_test_entity_info_translatable('node', TRUE); - $entity_type = \Drupal::entityManager()->getDefinition('node'); - $this->assertTrue($entity_type->isTranslatable(), 'Nodes are translatable.'); - - // Prepare the field translations. - $entity_type_id = 'entity_test'; - field_test_entity_info_translatable($entity_type_id, TRUE); - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type_id) - ->create(array('type' => $this->field->getTargetBundle())); - $field_translations = array(); - $available_langcodes = array_keys($this->container->get('language_manager')->getLanguages()); - $entity->langcode->value = reset($available_langcodes); - foreach ($available_langcodes as $langcode) { - $field_translations[$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality()); - $translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode); - $translation->{$this->fieldName}->setValue($field_translations[$langcode]); - } - - // Save and reload the field translations. - $entity = $this->entitySaveReload($entity); - - // Check if the correct values were saved/loaded. - foreach ($field_translations as $langcode => $items) { - $result = TRUE; - foreach ($items as $delta => $item) { - $result = $result && $item['value'] == $entity->getTranslation($langcode)->{$this->fieldName}[$delta]->value; - } - $this->assertTrue($result, format_string('%language translation correctly handled.', array('%language' => $langcode))); - } - - // Test default values. - $field_name_default = Unicode::strtolower($this->randomMachineName() . '_field_name'); - $field_storage_definition = $this->fieldStorageDefinition; - $field_storage_definition['field_name'] = $field_name_default; - $field_storage = FieldStorageConfig::create($field_storage_definition); - $field_storage->save(); - - $field_definition = $this->fieldDefinition; - $field_definition['field_storage'] = $field_storage; - $field_definition['default_value'] = array(array('value' => rand(1, 127))); - $field = FieldConfig::create($field_definition); - $field->save(); - - $translation_langcodes = array_slice($available_langcodes, 0, 2); - asort($translation_langcodes); - $translation_langcodes = array_values($translation_langcodes); - - $values = array('type' => $field->getTargetBundle(), 'langcode' => $translation_langcodes[0]); - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type_id) - ->create($values); - foreach ($translation_langcodes as $langcode) { - $values[$this->fieldName][$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality()); - $translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode); - $translation->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]); - } - - $field_langcodes = array_keys($entity->getTranslationLanguages()); - sort($field_langcodes); - $this->assertEqual($translation_langcodes, $field_langcodes, 'Missing translations did not get a default value.'); - - // @todo Test every translation once the Entity Translation API allows for - // multilingual defaults. - $langcode = $entity->language()->getId(); - $this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $field->getDefaultValueLiteral(), format_string('Default value correctly populated for language %language.', array('%language' => $langcode))); - - // Check that explicit empty values are not overridden with default values. - foreach (array(NULL, array()) as $empty_items) { - $values = array('type' => $field->getTargetBundle(), 'langcode' => $translation_langcodes[0]); - $entity = entity_create($entity_type_id, $values); - foreach ($translation_langcodes as $langcode) { - $values[$this->fieldName][$langcode] = $this->_generateTestFieldValues($this->fieldStorage->getCardinality()); - $translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode); - $translation->{$this->fieldName}->setValue($values[$this->fieldName][$langcode]); - $translation->{$field_name_default}->setValue($empty_items); - $values[$field_name_default][$langcode] = $empty_items; - } - - foreach ($entity->getTranslationLanguages() as $langcode => $language) { - $this->assertEquals([], $entity->getTranslation($langcode)->{$field_name_default}->getValue(), format_string('Empty value correctly populated for language %language.', array('%language' => $langcode))); - } - } - } - - /** - * Tests field access. - * - * Regression test to verify that fieldAccess() can be called while only - * passing the required parameters. - * - * @see https://www.drupal.org/node/2404739 - */ - public function testFieldAccess() { - $access_control_handler = \Drupal::entityManager()->getAccessControlHandler($this->entityType); - $this->assertTrue($access_control_handler->fieldAccess('view', $this->field)); - } - -} diff --git a/core/modules/field/tests/src/Kernel/Uri/UriItemTest.php b/core/modules/field/tests/src/Kernel/Uri/UriItemTest.php deleted file mode 100644 index 9d11ccd..0000000 --- a/core/modules/field/tests/src/Kernel/Uri/UriItemTest.php +++ /dev/null @@ -1,79 +0,0 @@ -randomMachineName(); - - // Create a field with settings to validate. - $field_name = Unicode::strtolower($this->randomMachineName()); - $this->fieldStorage = FieldStorageConfig::create([ - 'field_name' => $field_name, - 'entity_type' => 'entity_test', - 'type' => 'uri', - ]); - $this->fieldStorage->save(); - $this->field = FieldConfig::create([ - 'field_name' => $field_name, - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - 'label' => $label, - 'required' => TRUE, - 'settings' => [ - 'size' => 123, - 'placeholder' => '', - ], - ]); - $this->field->save(); - - // Create a form display for the default form mode. - entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($field_name, [ - 'type' => 'uri', - ]) - ->save(); - - // Test the generateSampleValue() method. - $entity = EntityTest::create(); - $entity->$field_name->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - -} diff --git a/core/modules/field/tests/src/Kernel/WidgetPluginManagerTest.php b/core/modules/field/tests/src/Kernel/WidgetPluginManagerTest.php deleted file mode 100644 index 564f4fa..0000000 --- a/core/modules/field/tests/src/Kernel/WidgetPluginManagerTest.php +++ /dev/null @@ -1,64 +0,0 @@ -getDefinition('test_field_widget_multiple'); - - // Test if hook_field_widget_info_alter is being called. - $this->assertTrue(in_array('test_field', $widget_definition['field_types']), "The 'test_field_widget_multiple' widget is enabled for the 'test_field' field type in field_test_field_widget_info_alter()."); - } - - /** - * Tests that getInstance falls back on default if current is not applicable. - * - * @see \Drupal\field\Tests\FormatterPluginManagerTest::testNotApplicableFallback() - */ - public function testNotApplicableFallback() { - /** @var WidgetPluginManager $widget_plugin_manager */ - $widget_plugin_manager = \Drupal::service('plugin.manager.field.widget'); - - $base_field_definition = BaseFieldDefinition::create('test_field') - // Set a name that will make isApplicable() return TRUE. - ->setName('field_multiwidgetfield'); - - $widget_options = array( - 'field_definition' => $base_field_definition, - 'form_mode' => 'default', - 'configuration' => array( - 'type' => 'test_field_widget_multiple', - ), - ); - - $instance = $widget_plugin_manager->getInstance($widget_options); - $this->assertEqual($instance->getPluginId(), 'test_field_widget_multiple'); - - // Now do the same but with machine name field_onewidgetfield, because that - // makes isApplicable() return FALSE. - $base_field_definition->setName('field_onewidgetfield'); - $instance = $widget_plugin_manager->getInstance($widget_options); - - // Instance should be default widget. - $this->assertNotEqual($instance->getPluginId(), 'test_field_widget_multiple'); - $this->assertEqual($instance->getPluginId(), 'test_field_widget'); - } - -} diff --git a/core/modules/file/src/Tests/FileItemTest.php b/core/modules/file/src/Tests/FileItemTest.php new file mode 100644 index 0000000..2941f4c --- /dev/null +++ b/core/modules/file/src/Tests/FileItemTest.php @@ -0,0 +1,147 @@ +installEntitySchema('file'); + $this->installSchema('file', array('file_usage')); + + FieldStorageConfig::create(array( + 'field_name' => 'file_test', + 'entity_type' => 'entity_test', + 'type' => 'file', + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + ))->save(); + $this->directory = $this->getRandomGenerator()->name(8); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'file_test', + 'bundle' => 'entity_test', + 'settings' => array('file_directory' => $this->directory), + ])->save(); + file_put_contents('public://example.txt', $this->randomMachineName()); + $this->file = File::create([ + 'uri' => 'public://example.txt', + ]); + $this->file->save(); + } + + /** + * Tests using entity fields of the file field type. + */ + public function testFileItem() { + // Check that the selection handler was automatically assigned to + // 'default:file'. + $field_definition = FieldConfig::load('entity_test.entity_test.file_test'); + $handler_id = $field_definition->getSetting('handler'); + $this->assertEqual($handler_id, 'default:file'); + + // Create a test entity with the + $entity = EntityTest::create(); + $entity->file_test->target_id = $this->file->id(); + $entity->file_test->display = 1; + $entity->file_test->description = $description = $this->randomMachineName(); + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + $entity = entity_load('entity_test', $entity->id()); + $this->assertTrue($entity->file_test instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->file_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->file_test->target_id, $this->file->id()); + $this->assertEqual($entity->file_test->display, 1); + $this->assertEqual($entity->file_test->description, $description); + $this->assertEqual($entity->file_test->entity->getFileUri(), $this->file->getFileUri()); + $this->assertEqual($entity->file_test->entity->url(), $url = file_create_url($this->file->getFileUri())); + $this->assertEqual($entity->file_test->entity->id(), $this->file->id()); + $this->assertEqual($entity->file_test->entity->uuid(), $this->file->uuid()); + + // Make sure the computed files reflects updates to the file. + file_put_contents('public://example-2.txt', $this->randomMachineName()); + $file2 = File::create([ + 'uri' => 'public://example-2.txt', + ]); + $file2->save(); + + $entity->file_test->target_id = $file2->id(); + $this->assertEqual($entity->file_test->entity->id(), $file2->id()); + $this->assertEqual($entity->file_test->entity->getFileUri(), $file2->getFileUri()); + + // Test the deletion of an entity having an entity reference field targeting + // a non-existing entity. + $file2->delete(); + $entity->delete(); + + // Test the generateSampleValue() method. + $entity = EntityTest::create(); + $entity->file_test->generateSampleItems(); + $this->entityValidateAndSave($entity); + // Verify that the sample file was stored in the correct directory. + $uri = $entity->file_test->entity->getFileUri(); + $this->assertEqual($this->directory, dirname(file_uri_target($uri))); + + // Make sure the computed files reflects updates to the file. + file_put_contents('public://example-3.txt', $this->randomMachineName()); + // Test unsaved file entity. + $file3 = File::create([ + 'uri' => 'public://example-3.txt', + ]); + $display = entity_get_display('entity_test', 'entity_test', 'default'); + $display->setComponent('file_test', [ + 'label' => 'above', + 'type' => 'file_default', + 'weight' => 1, + ])->save(); + $entity = EntityTest::create(); + $entity->file_test = array('entity' => $file3); + $uri = $file3->getFileUri(); + $output = entity_view($entity, 'default'); + \Drupal::service('renderer')->renderRoot($output); + $this->assertTrue(!empty($entity->file_test->entity)); + $this->assertEqual($entity->file_test->entity->getFileUri(), $uri); + } + +} diff --git a/core/modules/file/tests/src/Kernel/FileItemTest.php b/core/modules/file/tests/src/Kernel/FileItemTest.php deleted file mode 100644 index b74e227..0000000 --- a/core/modules/file/tests/src/Kernel/FileItemTest.php +++ /dev/null @@ -1,147 +0,0 @@ -installEntitySchema('file'); - $this->installSchema('file', array('file_usage')); - - FieldStorageConfig::create(array( - 'field_name' => 'file_test', - 'entity_type' => 'entity_test', - 'type' => 'file', - 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, - ))->save(); - $this->directory = $this->getRandomGenerator()->name(8); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'file_test', - 'bundle' => 'entity_test', - 'settings' => array('file_directory' => $this->directory), - ])->save(); - file_put_contents('public://example.txt', $this->randomMachineName()); - $this->file = File::create([ - 'uri' => 'public://example.txt', - ]); - $this->file->save(); - } - - /** - * Tests using entity fields of the file field type. - */ - public function testFileItem() { - // Check that the selection handler was automatically assigned to - // 'default:file'. - $field_definition = FieldConfig::load('entity_test.entity_test.file_test'); - $handler_id = $field_definition->getSetting('handler'); - $this->assertEqual($handler_id, 'default:file'); - - // Create a test entity with the - $entity = EntityTest::create(); - $entity->file_test->target_id = $this->file->id(); - $entity->file_test->display = 1; - $entity->file_test->description = $description = $this->randomMachineName(); - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - $entity = entity_load('entity_test', $entity->id()); - $this->assertTrue($entity->file_test instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->file_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->file_test->target_id, $this->file->id()); - $this->assertEqual($entity->file_test->display, 1); - $this->assertEqual($entity->file_test->description, $description); - $this->assertEqual($entity->file_test->entity->getFileUri(), $this->file->getFileUri()); - $this->assertEqual($entity->file_test->entity->url(), $url = file_create_url($this->file->getFileUri())); - $this->assertEqual($entity->file_test->entity->id(), $this->file->id()); - $this->assertEqual($entity->file_test->entity->uuid(), $this->file->uuid()); - - // Make sure the computed files reflects updates to the file. - file_put_contents('public://example-2.txt', $this->randomMachineName()); - $file2 = File::create([ - 'uri' => 'public://example-2.txt', - ]); - $file2->save(); - - $entity->file_test->target_id = $file2->id(); - $this->assertEqual($entity->file_test->entity->id(), $file2->id()); - $this->assertEqual($entity->file_test->entity->getFileUri(), $file2->getFileUri()); - - // Test the deletion of an entity having an entity reference field targeting - // a non-existing entity. - $file2->delete(); - $entity->delete(); - - // Test the generateSampleValue() method. - $entity = EntityTest::create(); - $entity->file_test->generateSampleItems(); - $this->entityValidateAndSave($entity); - // Verify that the sample file was stored in the correct directory. - $uri = $entity->file_test->entity->getFileUri(); - $this->assertEqual($this->directory, dirname(file_uri_target($uri))); - - // Make sure the computed files reflects updates to the file. - file_put_contents('public://example-3.txt', $this->randomMachineName()); - // Test unsaved file entity. - $file3 = File::create([ - 'uri' => 'public://example-3.txt', - ]); - $display = entity_get_display('entity_test', 'entity_test', 'default'); - $display->setComponent('file_test', [ - 'label' => 'above', - 'type' => 'file_default', - 'weight' => 1, - ])->save(); - $entity = EntityTest::create(); - $entity->file_test = array('entity' => $file3); - $uri = $file3->getFileUri(); - $output = entity_view($entity, 'default'); - \Drupal::service('renderer')->renderRoot($output); - $this->assertTrue(!empty($entity->file_test->entity)); - $this->assertEqual($entity->file_test->entity->getFileUri(), $uri); - } - -} diff --git a/core/modules/help/help.api.php b/core/modules/help/help.api.php index aff491c..09b2e0f 100644 --- a/core/modules/help/help.api.php +++ b/core/modules/help/help.api.php @@ -21,9 +21,9 @@ * The page-specific help information provided by this hook appears in the * Help block (provided by the core Help module), if the block is displayed on * that page. The module overview help information is displayed by the Help - * module. It can be accessed from the page at /admin/help or from the Extend - * page. If a module implements hook_help() the help system expects module - * overview help to be provided. + * module. It can be accessed from the page at admin/help or from the Extend + * Extend page. If a module implements hook_help() the help system expects + * module overview help to be provided. * * For detailed usage examples of: * - Module overview help, see content_translation_help(). Module overview @@ -57,24 +57,5 @@ function hook_help($route_name, \Drupal\Core\Routing\RouteMatchInterface $route_ } /** - * Perform alterations on help page section plugin definitions. - * - * Sections for the page at /admin/help are provided by plugins. This hook - * allows modules to alter the plugin definitions. - * - * @param array $info - * Array of plugin information exposed by hook page section plugins, altered - * by reference. - * - * @see \Drupal\help\HelpSectionPluginInterface - * @see \Drupal\help\Annotation\HelpSection - * @see \Drupal\help\HelpSectionManager - */ -function hook_help_section_info_alter(&$info) { - // Alter the header for the module overviews section. - $info['hook_help']['header'] = t('Overviews of modules'); -} - -/** * @} End of "addtogroup hooks". */ diff --git a/core/modules/help/help.module b/core/modules/help/help.module index c41cd98..9a7dc07 100644 --- a/core/modules/help/help.module +++ b/core/modules/help/help.module @@ -5,8 +5,8 @@ * Manages displaying online help. */ -use Drupal\Core\Block\BlockPluginInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Block\BlockPluginInterface; /** * Implements hook_help(). @@ -25,7 +25,7 @@ function help_help($route_name, RouteMatchInterface $route_match) { $output .= '
  • ' . t('Start posting content Finally, you may add new content to your website.', array(':content' => \Drupal::url('node.add_page'))) . '
  • '; } $output .= ''; - $output .= '

    ' . t('For more information, refer to the help listed on this page or to the online documentation and support pages at drupal.org.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org')) . '

    '; + $output .= '

    ' . t('For more information, refer to the subjects listed in the Help Topics section or to the online documentation and support pages at drupal.org.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org')) . '

    '; return ['#markup' => $output]; case 'help.page.help': @@ -44,22 +44,6 @@ function help_help($route_name, RouteMatchInterface $route_match) { } /** - * Implements hook_theme(). - */ -function help_theme($existing, $type, $theme, $path) { - return [ - 'help_section' => [ - 'variables' => [ - 'title' => NULL, - 'description' => NULL, - 'links' => NULL, - 'empty' => NULL, - ], - ], - ]; -} - -/** * Implements hook_preprocess_HOOK() for block templates. */ function help_preprocess_block(&$variables) { diff --git a/core/modules/help/help.services.yml b/core/modules/help/help.services.yml deleted file mode 100644 index 26a2c33..0000000 --- a/core/modules/help/help.services.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - plugin.manager.help_section: - class: Drupal\help\HelpSectionManager - parent: default_plugin_manager diff --git a/core/modules/help/src/Annotation/HelpSection.php b/core/modules/help/src/Annotation/HelpSection.php deleted file mode 100644 index d43156d..0000000 --- a/core/modules/help/src/Annotation/HelpSection.php +++ /dev/null @@ -1,65 +0,0 @@ -routeMatch = $route_match; - $this->helpManager = $help_manager; } /** @@ -51,57 +40,62 @@ public function __construct(RouteMatchInterface $route_match, HelpSectionManager */ public static function create(ContainerInterface $container) { return new static( - $container->get('current_route_match'), - $container->get('plugin.manager.help_section') + $container->get('current_route_match') ); } /** - * Prints a page listing various types of help. - * - * The page has sections defined by \Drupal\help\HelpSectionPluginInterface - * plugins. + * Prints a page listing a glossary of Drupal terminology. * - * @return array - * A render array for the help page. + * @return string + * An HTML string representing the contents of help page. */ public function helpMain() { - $output = []; - - // We are checking permissions, so add the user.permissions cache context. - $cacheability = new CacheableMetadata(); - $cacheability->addCacheContexts(['user.permissions']); - - $plugins = $this->helpManager->getDefinitions(); - $cacheability->addCacheableDependency($this->helpManager); + $output = array( + '#markup' => '

    ' . $this->t('Help topics') . '

    ' . $this->t('Help is available on the following items:') . '

    ', + 'links' => $this->helpLinksAsList(), + ); + return $output; + } - foreach ($plugins as $plugin_id => $plugin_definition) { - // Check the provided permission. - if (!empty($plugin_definition['permission']) && !$this->currentuser()->hasPermission($plugin_definition['permission'])) { - continue; - } + /** + * Provides a formatted list of available help topics. + * + * @return string + * A string containing the formatted list. + */ + protected function helpLinksAsList() { + $modules = array(); + foreach ($this->moduleHandler()->getImplementations('help') as $module) { + $modules[$module] = $this->moduleHandler->getName($module); + } + asort($modules); + + // Output pretty four-column list. + $count = count($modules); + $break = ceil($count / 4); + $column = array( + '#type' => 'container', + 'links' => array('#theme' => 'item_list'), + '#attributes' => array('class' => array('layout-column', 'layout-column--quarter')), + ); + $output = array( + '#prefix' => '
    ', + '#suffix' => '
    ', + 0 => $column, + ); - // Add the section to the page. - /** @var \Drupal\help\HelpSectionPluginInterface $plugin */ - $plugin = $this->helpManager->createInstance($plugin_id); - $this_output = [ - '#theme' => 'help_section', - '#title' => $plugin->getTitle(), - '#description' => $plugin->getDescription(), - '#empty' => $this->t('There is currently nothing in this section.'), - '#links' => [], - ]; - - $links = $plugin->listTopics(); - if (is_array($links) && count($links)) { - $this_output['#links'] = $links; + $i = 0; + $current_column = 0; + foreach ($modules as $module => $name) { + $output[$current_column]['links']['#items'][] = $this->l($name, new Url('help.page', array('name' => $module))); + if (($i + 1) % $break == 0 && ($i + 1) != $count) { + $current_column++; + $output[$current_column] = $column; } - - $cacheability->addCacheableDependency($plugin); - $output[$plugin_id] = $this_output; + $i++; } - $cacheability->applyTo($output); return $output; } diff --git a/core/modules/help/src/HelpSectionManager.php b/core/modules/help/src/HelpSectionManager.php deleted file mode 100644 index 45dfa3c..0000000 --- a/core/modules/help/src/HelpSectionManager.php +++ /dev/null @@ -1,42 +0,0 @@ -alterInfo('help_section_info'); - $this->setCacheBackend($cache_backend, 'help_section_plugins'); - } - -} diff --git a/core/modules/help/src/HelpSectionPluginInterface.php b/core/modules/help/src/HelpSectionPluginInterface.php deleted file mode 100644 index 49bc463..0000000 --- a/core/modules/help/src/HelpSectionPluginInterface.php +++ /dev/null @@ -1,54 +0,0 @@ -getPluginDefinition()['title']; - } - - /** - * {@inheritdoc} - */ - public function getDescription() { - return $this->getPluginDefinition()['description']; - } - -} diff --git a/core/modules/help/src/Plugin/HelpSection/HookHelpSection.php b/core/modules/help/src/Plugin/HelpSection/HookHelpSection.php deleted file mode 100644 index e4cf4eb..0000000 --- a/core/modules/help/src/Plugin/HelpSection/HookHelpSection.php +++ /dev/null @@ -1,77 +0,0 @@ -moduleHandler = $module_handler; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('module_handler') - ); - } - - /** - * {@inheritdoc} - */ - public function listTopics() { - $topics = []; - foreach ($this->moduleHandler->getImplementations('help') as $module) { - $title = $this->moduleHandler->getName($module); - $topics[$title] = Link::createFromRoute($title, 'help.page', ['name' => $module]); - } - - // Sort topics by title, which is the array key above. - ksort($topics); - return $topics; - } - -} diff --git a/core/modules/help/src/Tests/HelpTest.php b/core/modules/help/src/Tests/HelpTest.php index 4f90cb7..64ad4a7 100644 --- a/core/modules/help/src/Tests/HelpTest.php +++ b/core/modules/help/src/Tests/HelpTest.php @@ -20,12 +20,11 @@ class HelpTest extends WebTestBase { * Modules to enable. * * The help_test module implements hook_help() but does not provide a module - * overview page. The help_page_test module has a page section plugin that - * returns no links. + * overview page. * * @var array. */ - public static $modules = array('help_test', 'help_page_test'); + public static $modules = array('help_test'); /** * Use the Standard profile to test help implementations of many core modules. @@ -53,7 +52,7 @@ protected function setUp() { } /** - * Logs in users, tests help pages. + * Logs in users, creates dblog events, and tests dblog functionality. */ public function testHelp() { // Login the root user to ensure as many admin links appear as possible on @@ -68,16 +67,10 @@ public function testHelp() { // Verify that introductory help text exists, goes for 100% module coverage. $this->drupalLogin($this->adminUser); $this->drupalGet('admin/help'); - $this->assertRaw(t('For more information, refer to the help listed on this page or to the online documentation and support pages at drupal.org.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org'))); + $this->assertRaw(t('For more information, refer to the subjects listed in the Help Topics section or to the online documentation and support pages at drupal.org.', array(':docs' => 'https://www.drupal.org/documentation', ':support' => 'https://www.drupal.org/support', ':drupal' => 'https://www.drupal.org')), 'Help intro text correctly appears.'); - // Verify that hook_help() section title and description appear. - $this->assertRaw('

    ' . t('Module overviews') . '

    '); - $this->assertRaw('

    ' . t('Module overviews are provided by modules. Overviews available for your installed modules:'), '

    '); - - // Verify that an empty section is handled correctly. - $this->assertRaw('

    ' . t('Empty section') . '

    '); - $this->assertRaw('

    ' . t('This description should appear.'), '

    '); - $this->assertText(t('There is currently nothing in this section.')); + // Verify that help topics text appears. + $this->assertRaw('

    ' . t('Help topics') . '

    ' . t('Help is available on the following items:') . '

    ', 'Help topics text correctly appears.'); // Make sure links are properly added for modules implementing hook_help(). foreach ($this->getModuleList() as $module => $name) { @@ -88,25 +81,10 @@ public function testHelp() { // handled correctly. $this->clickLink(\Drupal::moduleHandler()->getName('help_test')); $this->assertRaw(t('No help is available for module %module.', array('%module' => \Drupal::moduleHandler()->getName('help_test')))); - - // Verify that the order of topics is alphabetical by displayed module - // name, by checking the order of some modules, including some that would - // have a different order if it was done by machine name instead. - $this->drupalGet('admin/help'); - $page_text = $this->getTextContent(); - $start = strpos($page_text, 'Module overviews'); - $pos = $start; - $list = ['Block', 'Color', 'Custom Block', 'History', 'Text Editor']; - foreach ($list as $name) { - $this->assertLink($name); - $new_pos = strpos($page_text, $name, $start); - $this->assertTrue($new_pos > $pos, 'Order of ' . $name . ' is correct on page'); - $pos = $new_pos; - } } /** - * Verifies the logged in user has access to the various help pages. + * Verifies the logged in user has access to the various help nodes. * * @param int $response * (optional) An HTTP response code. Defaults to 200. @@ -122,7 +100,7 @@ protected function verifyHelp($response = 200) { } foreach ($this->getModuleList() as $module => $name) { - // View module help page. + // View module help node. $this->drupalGet('admin/help/' . $module); $this->assertResponse($response); if ($response == 200) { diff --git a/core/modules/help/src/Tests/NoHelpTest.php b/core/modules/help/src/Tests/NoHelpTest.php index cce40b2..f0213a9 100644 --- a/core/modules/help/src/Tests/NoHelpTest.php +++ b/core/modules/help/src/Tests/NoHelpTest.php @@ -43,7 +43,7 @@ public function testMainPageNoHelp() { $this->drupalGet('admin/help'); $this->assertResponse(200); - $this->assertText('Module overviews are provided by modules'); + $this->assertText('Help is available on the following items', 'Help page is found.'); $this->assertFalse(\Drupal::moduleHandler()->implementsHook('menu_test', 'help'), 'The menu_test module does not implement hook_help'); $this->assertNoText(\Drupal::moduleHandler()->getName('menu_test'), 'Making sure the test module menu_test does not display a help link on admin/help.'); diff --git a/core/modules/help/templates/help-section.html.twig b/core/modules/help/templates/help-section.html.twig deleted file mode 100644 index 9d63b4b..0000000 --- a/core/modules/help/templates/help-section.html.twig +++ /dev/null @@ -1,25 +0,0 @@ -{# -/** - * @file - * Default theme implementation for a section of the help page. - * - * Available variables: - * - title: The section title. - * - description: The description text for the section. - * - links: Links to display in the section. - * - empty: Text to display if there are no links. - * - * @ingroup themeable - */ -#} -

    {{ title }}

    -

    {{ description }}

    -{% if links %} - -{% else %} -

    {{ empty }}

    -{% endif %} diff --git a/core/modules/help/tests/modules/help_page_test/src/Plugin/HelpSection/EmptyHelpSection.php b/core/modules/help/tests/modules/help_page_test/src/Plugin/HelpSection/EmptyHelpSection.php deleted file mode 100644 index f7adac7..0000000 --- a/core/modules/help/tests/modules/help_page_test/src/Plugin/HelpSection/EmptyHelpSection.php +++ /dev/null @@ -1,29 +0,0 @@ -installEntitySchema('file'); + $this->installSchema('file', array('file_usage')); + + FieldStorageConfig::create(array( + 'entity_type' => 'entity_test', + 'field_name' => 'image_test', + 'type' => 'image', + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'image_test', + 'bundle' => 'entity_test', + ])->save(); + file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg'); + $this->image = File::create([ + 'uri' => 'public://example.jpg', + ]); + $this->image->save(); + $this->imageFactory = $this->container->get('image.factory'); + } + + /** + * Tests using entity fields of the image field type. + */ + public function testImageItem() { + // Create a test entity with the image field set. + $entity = EntityTest::create(); + $entity->image_test->target_id = $this->image->id(); + $entity->image_test->alt = $alt = $this->randomMachineName(); + $entity->image_test->title = $title = $this->randomMachineName(); + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + $entity = entity_load('entity_test', $entity->id()); + $this->assertTrue($entity->image_test instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->image_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->image_test->target_id, $this->image->id()); + $this->assertEqual($entity->image_test->alt, $alt); + $this->assertEqual($entity->image_test->title, $title); + $image = $this->imageFactory->get('public://example.jpg'); + $this->assertEqual($entity->image_test->width, $image->getWidth()); + $this->assertEqual($entity->image_test->height, $image->getHeight()); + $this->assertEqual($entity->image_test->entity->id(), $this->image->id()); + $this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid()); + + // Make sure the computed entity reflects updates to the referenced file. + file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example-2.jpg'); + $image2 = File::create([ + 'uri' => 'public://example-2.jpg', + ]); + $image2->save(); + + $entity->image_test->target_id = $image2->id(); + $entity->image_test->alt = $new_alt = $this->randomMachineName(); + // The width and height is only updated when width is not set. + $entity->image_test->width = NULL; + $entity->save(); + $this->assertEqual($entity->image_test->entity->id(), $image2->id()); + $this->assertEqual($entity->image_test->entity->getFileUri(), $image2->getFileUri()); + $image = $this->imageFactory->get('public://example-2.jpg'); + $this->assertEqual($entity->image_test->width, $image->getWidth()); + $this->assertEqual($entity->image_test->height, $image->getHeight()); + $this->assertEqual($entity->image_test->alt, $new_alt); + + // Check that the image item can be set to the referenced file directly. + $entity->image_test = $this->image; + $this->assertEqual($entity->image_test->target_id, $this->image->id()); + + // Delete the image and try to save the entity again. + $this->image->delete(); + $entity = EntityTest::create(array('mame' => $this->randomMachineName())); + $entity->save(); + + // Test image item properties. + $expected = array('target_id', 'entity', 'alt', 'title', 'width', 'height'); + $properties = $entity->getFieldDefinition('image_test')->getFieldStorageDefinition()->getPropertyDefinitions(); + $this->assertEqual(array_keys($properties), $expected); + + // Test the generateSampleValue() method. + $entity = EntityTest::create(); + $entity->image_test->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + +} diff --git a/core/modules/image/tests/src/Kernel/ImageItemTest.php b/core/modules/image/tests/src/Kernel/ImageItemTest.php deleted file mode 100644 index 8eb7946..0000000 --- a/core/modules/image/tests/src/Kernel/ImageItemTest.php +++ /dev/null @@ -1,133 +0,0 @@ -installEntitySchema('file'); - $this->installSchema('file', array('file_usage')); - - FieldStorageConfig::create(array( - 'entity_type' => 'entity_test', - 'field_name' => 'image_test', - 'type' => 'image', - 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'image_test', - 'bundle' => 'entity_test', - ])->save(); - file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg'); - $this->image = File::create([ - 'uri' => 'public://example.jpg', - ]); - $this->image->save(); - $this->imageFactory = $this->container->get('image.factory'); - } - - /** - * Tests using entity fields of the image field type. - */ - public function testImageItem() { - // Create a test entity with the image field set. - $entity = EntityTest::create(); - $entity->image_test->target_id = $this->image->id(); - $entity->image_test->alt = $alt = $this->randomMachineName(); - $entity->image_test->title = $title = $this->randomMachineName(); - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - $entity = entity_load('entity_test', $entity->id()); - $this->assertTrue($entity->image_test instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->image_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->image_test->target_id, $this->image->id()); - $this->assertEqual($entity->image_test->alt, $alt); - $this->assertEqual($entity->image_test->title, $title); - $image = $this->imageFactory->get('public://example.jpg'); - $this->assertEqual($entity->image_test->width, $image->getWidth()); - $this->assertEqual($entity->image_test->height, $image->getHeight()); - $this->assertEqual($entity->image_test->entity->id(), $this->image->id()); - $this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid()); - - // Make sure the computed entity reflects updates to the referenced file. - file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example-2.jpg'); - $image2 = File::create([ - 'uri' => 'public://example-2.jpg', - ]); - $image2->save(); - - $entity->image_test->target_id = $image2->id(); - $entity->image_test->alt = $new_alt = $this->randomMachineName(); - // The width and height is only updated when width is not set. - $entity->image_test->width = NULL; - $entity->save(); - $this->assertEqual($entity->image_test->entity->id(), $image2->id()); - $this->assertEqual($entity->image_test->entity->getFileUri(), $image2->getFileUri()); - $image = $this->imageFactory->get('public://example-2.jpg'); - $this->assertEqual($entity->image_test->width, $image->getWidth()); - $this->assertEqual($entity->image_test->height, $image->getHeight()); - $this->assertEqual($entity->image_test->alt, $new_alt); - - // Check that the image item can be set to the referenced file directly. - $entity->image_test = $this->image; - $this->assertEqual($entity->image_test->target_id, $this->image->id()); - - // Delete the image and try to save the entity again. - $this->image->delete(); - $entity = EntityTest::create(array('mame' => $this->randomMachineName())); - $entity->save(); - - // Test image item properties. - $expected = array('target_id', 'entity', 'alt', 'title', 'width', 'height'); - $properties = $entity->getFieldDefinition('image_test')->getFieldStorageDefinition()->getPropertyDefinitions(); - $this->assertEqual(array_keys($properties), $expected); - - // Test the generateSampleValue() method. - $entity = EntityTest::create(); - $entity->image_test->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - -} diff --git a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php index 9245ba3..96064a1 100644 --- a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php +++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php @@ -207,7 +207,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { // field template wrapper, and set the URL value in a content // attribute. // @todo Does RDF need a URL rather than an internal URI here? - // @see \Drupal\Tests\rdf\Kernel\Field\LinkFieldRdfaTest. + // @see \Drupal\rdf\Tests\Field\LinkFieldRdfaTest. $content = str_replace('internal:/', '', $item->uri); $item->_attributes += array('content' => $content); } diff --git a/core/modules/link/src/Tests/LinkItemTest.php b/core/modules/link/src/Tests/LinkItemTest.php new file mode 100644 index 0000000..870dc1a --- /dev/null +++ b/core/modules/link/src/Tests/LinkItemTest.php @@ -0,0 +1,169 @@ + 'field_test', + 'entity_type' => 'entity_test', + 'type' => 'link', + ])->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'field_test', + 'bundle' => 'entity_test', + 'settings' => ['link_type' => LinkItemInterface::LINK_GENERIC], + ])->save(); + FieldStorageConfig::create([ + 'field_name' => 'field_test_external', + 'entity_type' => 'entity_test', + 'type' => 'link', + ])->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'field_test_external', + 'bundle' => 'entity_test', + 'settings' => ['link_type' => LinkItemInterface::LINK_EXTERNAL], + ])->save(); + FieldStorageConfig::create([ + 'field_name' => 'field_test_internal', + 'entity_type' => 'entity_test', + 'type' => 'link', + ])->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'field_test_internal', + 'bundle' => 'entity_test', + 'settings' => ['link_type' => LinkItemInterface::LINK_INTERNAL], + ])->save(); + } + + /** + * Tests using entity fields of the link field type. + */ + public function testLinkItem() { + // Create entity. + $entity = EntityTest::create(); + $url = 'https://www.drupal.org?test_param=test_value'; + $parsed_url = UrlHelper::parse($url); + $title = $this->randomMachineName(); + $class = $this->randomMachineName(); + $entity->field_test->uri = $parsed_url['path']; + $entity->field_test->title = $title; + $entity->field_test->first()->get('options')->set('query', $parsed_url['query']); + $entity->field_test->first()->get('options')->set('attributes', array('class' => $class)); + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify that the field value is changed. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->field_test instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_test->uri, $parsed_url['path']); + $this->assertEqual($entity->field_test[0]->uri, $parsed_url['path']); + $this->assertEqual($entity->field_test->title, $title); + $this->assertEqual($entity->field_test[0]->title, $title); + $this->assertEqual($entity->field_test->options['attributes']['class'], $class); + $this->assertEqual($entity->field_test->options['query'], $parsed_url['query']); + + // Update only the entity name property to check if the link field data will + // remain intact. + $entity->name->value = $this->randomMachineName(); + $entity->save(); + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_test->uri, $parsed_url['path']); + $this->assertEqual($entity->field_test->options['attributes']['class'], $class); + $this->assertEqual($entity->field_test->options['query'], $parsed_url['query']); + + // Verify changing the field value. + $new_url = 'https://www.drupal.org'; + $new_title = $this->randomMachineName(); + $new_class = $this->randomMachineName(); + $entity->field_test->uri = $new_url; + $entity->field_test->title = $new_title; + $entity->field_test->first()->get('options')->set('query', NULL); + $entity->field_test->first()->get('options')->set('attributes', array('class' => $new_class)); + $this->assertEqual($entity->field_test->uri, $new_url); + $this->assertEqual($entity->field_test->title, $new_title); + $this->assertEqual($entity->field_test->options['attributes']['class'], $new_class); + $this->assertNull($entity->field_test->options['query']); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_test->uri, $new_url); + $this->assertEqual($entity->field_test->title, $new_title); + $this->assertEqual($entity->field_test->options['attributes']['class'], $new_class); + + // Check that if we only set uri the default values for title and options + // are also initialized. + $entity->field_test = ['uri' => 'internal:/node/add']; + $this->assertEqual($entity->field_test->uri, 'internal:/node/add'); + $this->assertNull($entity->field_test->title); + $this->assertIdentical($entity->field_test->options, []); + + // Check that if set uri and serialize options then the default values are + // properly initialized. + $entity->field_test = [ + 'uri' => 'internal:/node/add', + 'options' => serialize(['query' => NULL]), + ]; + $this->assertEqual($entity->field_test->uri, 'internal:/node/add'); + $this->assertNull($entity->field_test->title); + $this->assertNull($entity->field_test->options['query']); + + // Check that if we set the direct value of link field it correctly set the + // uri and the default values of the field. + $entity->field_test = 'internal:/node/add'; + $this->assertEqual($entity->field_test->uri, 'internal:/node/add'); + $this->assertNull($entity->field_test->title); + $this->assertIdentical($entity->field_test->options, []); + + // Check that setting LinkItem value NULL doesn't generate any error or + // warning. + $entity->field_test[0] = NULL; + $this->assertNull($entity->field_test[0]->getValue()); + + // Test the generateSampleValue() method for generic, external, and internal + // link types. + $entity = EntityTest::create(); + $entity->field_test->generateSampleItems(); + $entity->field_test_external->generateSampleItems(); + $entity->field_test_internal->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + +} diff --git a/core/modules/link/tests/src/Kernel/LinkItemTest.php b/core/modules/link/tests/src/Kernel/LinkItemTest.php deleted file mode 100644 index 342d8ed..0000000 --- a/core/modules/link/tests/src/Kernel/LinkItemTest.php +++ /dev/null @@ -1,169 +0,0 @@ - 'field_test', - 'entity_type' => 'entity_test', - 'type' => 'link', - ])->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'field_test', - 'bundle' => 'entity_test', - 'settings' => ['link_type' => LinkItemInterface::LINK_GENERIC], - ])->save(); - FieldStorageConfig::create([ - 'field_name' => 'field_test_external', - 'entity_type' => 'entity_test', - 'type' => 'link', - ])->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'field_test_external', - 'bundle' => 'entity_test', - 'settings' => ['link_type' => LinkItemInterface::LINK_EXTERNAL], - ])->save(); - FieldStorageConfig::create([ - 'field_name' => 'field_test_internal', - 'entity_type' => 'entity_test', - 'type' => 'link', - ])->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'field_test_internal', - 'bundle' => 'entity_test', - 'settings' => ['link_type' => LinkItemInterface::LINK_INTERNAL], - ])->save(); - } - - /** - * Tests using entity fields of the link field type. - */ - public function testLinkItem() { - // Create entity. - $entity = EntityTest::create(); - $url = 'https://www.drupal.org?test_param=test_value'; - $parsed_url = UrlHelper::parse($url); - $title = $this->randomMachineName(); - $class = $this->randomMachineName(); - $entity->field_test->uri = $parsed_url['path']; - $entity->field_test->title = $title; - $entity->field_test->first()->get('options')->set('query', $parsed_url['query']); - $entity->field_test->first()->get('options')->set('attributes', array('class' => $class)); - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify that the field value is changed. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->field_test instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_test->uri, $parsed_url['path']); - $this->assertEqual($entity->field_test[0]->uri, $parsed_url['path']); - $this->assertEqual($entity->field_test->title, $title); - $this->assertEqual($entity->field_test[0]->title, $title); - $this->assertEqual($entity->field_test->options['attributes']['class'], $class); - $this->assertEqual($entity->field_test->options['query'], $parsed_url['query']); - - // Update only the entity name property to check if the link field data will - // remain intact. - $entity->name->value = $this->randomMachineName(); - $entity->save(); - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_test->uri, $parsed_url['path']); - $this->assertEqual($entity->field_test->options['attributes']['class'], $class); - $this->assertEqual($entity->field_test->options['query'], $parsed_url['query']); - - // Verify changing the field value. - $new_url = 'https://www.drupal.org'; - $new_title = $this->randomMachineName(); - $new_class = $this->randomMachineName(); - $entity->field_test->uri = $new_url; - $entity->field_test->title = $new_title; - $entity->field_test->first()->get('options')->set('query', NULL); - $entity->field_test->first()->get('options')->set('attributes', array('class' => $new_class)); - $this->assertEqual($entity->field_test->uri, $new_url); - $this->assertEqual($entity->field_test->title, $new_title); - $this->assertEqual($entity->field_test->options['attributes']['class'], $new_class); - $this->assertNull($entity->field_test->options['query']); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_test->uri, $new_url); - $this->assertEqual($entity->field_test->title, $new_title); - $this->assertEqual($entity->field_test->options['attributes']['class'], $new_class); - - // Check that if we only set uri the default values for title and options - // are also initialized. - $entity->field_test = ['uri' => 'internal:/node/add']; - $this->assertEqual($entity->field_test->uri, 'internal:/node/add'); - $this->assertNull($entity->field_test->title); - $this->assertIdentical($entity->field_test->options, []); - - // Check that if set uri and serialize options then the default values are - // properly initialized. - $entity->field_test = [ - 'uri' => 'internal:/node/add', - 'options' => serialize(['query' => NULL]), - ]; - $this->assertEqual($entity->field_test->uri, 'internal:/node/add'); - $this->assertNull($entity->field_test->title); - $this->assertNull($entity->field_test->options['query']); - - // Check that if we set the direct value of link field it correctly set the - // uri and the default values of the field. - $entity->field_test = 'internal:/node/add'; - $this->assertEqual($entity->field_test->uri, 'internal:/node/add'); - $this->assertNull($entity->field_test->title); - $this->assertIdentical($entity->field_test->options, []); - - // Check that setting LinkItem value NULL doesn't generate any error or - // warning. - $entity->field_test[0] = NULL; - $this->assertNull($entity->field_test[0]->getValue()); - - // Test the generateSampleValue() method for generic, external, and internal - // link types. - $entity = EntityTest::create(); - $entity->field_test->generateSampleItems(); - $entity->field_test_external->generateSampleItems(); - $entity->field_test_internal->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - -} diff --git a/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php b/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php index 736c020..54c9a20 100644 --- a/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php +++ b/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php @@ -51,7 +51,7 @@ public function fields() { 'link_path' => t('The Drupal path or external path this link points to.'), 'router_path' => t('For links corresponding to a Drupal path (external = 0), this connects the link to a {menu_router}.path for joins.'), 'link_title' => t('The text displayed for the link, which may be modified by a title callback stored in {menu_router}.'), - 'options' => t('A serialized array of options to set on the URL, such as a query string or HTML attributes.'), + 'options' => t('A serialized array of options to be passed to the url() or l() function, such as a query string or HTML attributes.'), 'module' => t('The name of the module that generated this link.'), 'hidden' => t('A flag for whether the link should be rendered in menus. (1 = a disabled menu item that may be shown on admin screens, -1 = a menu callback, 0 = a normal, visible link)'), 'external' => t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'), diff --git a/core/modules/options/src/Tests/OptionsFieldTest.php b/core/modules/options/src/Tests/OptionsFieldTest.php new file mode 100644 index 0000000..402c9b4 --- /dev/null +++ b/core/modules/options/src/Tests/OptionsFieldTest.php @@ -0,0 +1,104 @@ +getForm($entity); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists'); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists'); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists'); + + // Use one of the values in an actual entity, and check that this value + // cannot be removed from the list. + $entity = EntityTest::create(); + $entity->{$this->fieldName}->value = 1; + $entity->save(); + $this->fieldStorage->setSetting('allowed_values', [2 => 'Two']); + try { + $this->fieldStorage->save(); + $this->fail(t('Cannot update a list field storage to not include keys with existing data.')); + } + catch (FieldStorageDefinitionUpdateForbiddenException $e) { + $this->pass(t('Cannot update a list field storage to not include keys with existing data.')); + } + // Empty the value, so that we can actually remove the option. + unset($entity->{$this->fieldName}); + $entity->save(); + + // Removed options do not appear. + $this->fieldStorage->setSetting('allowed_values', [2 => 'Two']); + $this->fieldStorage->save(); + $entity = EntityTest::create(); + $form = \Drupal::service('entity.form_builder')->getForm($entity); + $this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist'); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists'); + $this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist'); + + // Completely new options appear. + $this->fieldStorage->setSetting('allowed_values', [10 => 'Update', 20 => 'Twenty']); + $this->fieldStorage->save(); + // The entity holds an outdated field object with the old allowed values + // setting, so we need to reinitialize the entity object. + $entity = EntityTest::create(); + $form = \Drupal::service('entity.form_builder')->getForm($entity); + $this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist'); + $this->assertTrue(empty($form[$this->fieldName]['widget'][2]), 'Option 2 does not exist'); + $this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist'); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][10]), 'Option 10 exists'); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][20]), 'Option 20 exists'); + + // Options are reset when a new field with the same name is created. + $this->fieldStorage->delete(); + FieldStorageConfig::create($this->fieldStorageDefinition)->save(); + FieldConfig::create([ + 'field_name' => $this->fieldName, + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + 'required' => TRUE, + ])->save(); + entity_get_form_display('entity_test', 'entity_test', 'default') + ->setComponent($this->fieldName, array( + 'type' => 'options_buttons', + )) + ->save(); + $entity = EntityTest::create(); + $form = \Drupal::service('entity.form_builder')->getForm($entity); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists'); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists'); + $this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists'); + + // Test the generateSampleValue() method. + $entity = EntityTest::create(); + $entity->{$this->fieldName}->generateSampleItems(); + $this->entityValidateAndSave($entity); + } +} diff --git a/core/modules/options/src/Tests/OptionsFieldUnitTestBase.php b/core/modules/options/src/Tests/OptionsFieldUnitTestBase.php new file mode 100644 index 0000000..14d4b8d --- /dev/null +++ b/core/modules/options/src/Tests/OptionsFieldUnitTestBase.php @@ -0,0 +1,86 @@ +container->get('router.builder')->rebuild(); + + $this->fieldStorageDefinition = array( + 'field_name' => $this->fieldName, + 'entity_type' => 'entity_test', + 'type' => 'list_integer', + 'cardinality' => 1, + 'settings' => array( + 'allowed_values' => array(1 => 'One', 2 => 'Two', 3 => 'Three'), + ), + ); + $this->fieldStorage = FieldStorageConfig::create($this->fieldStorageDefinition); + $this->fieldStorage->save(); + + $this->field = FieldConfig::create([ + 'field_storage' => $this->fieldStorage, + 'bundle' => 'entity_test', + ]); + $this->field->save(); + + entity_get_form_display('entity_test', 'entity_test', 'default') + ->setComponent($this->fieldName, array( + 'type' => 'options_buttons', + )) + ->save(); + } + +} diff --git a/core/modules/options/src/Tests/OptionsFormattersTest.php b/core/modules/options/src/Tests/OptionsFormattersTest.php new file mode 100644 index 0000000..eb63051 --- /dev/null +++ b/core/modules/options/src/Tests/OptionsFormattersTest.php @@ -0,0 +1,46 @@ +{$this->fieldName}->value = 1; + + $items = $entity->get($this->fieldName); + + $build = $items->view(); + $this->assertEqual($build['#formatter'], 'list_default', 'Ensure to fall back to the default formatter.'); + $this->assertEqual($build[0]['#markup'], 'One'); + + $build = $items->view(array('type' => 'list_key')); + $this->assertEqual($build['#formatter'], 'list_key', 'The chosen formatter is used.'); + $this->assertEqual((string) $build[0]['#markup'], 1); + } + +} diff --git a/core/modules/options/tests/src/Kernel/OptionsFieldTest.php b/core/modules/options/tests/src/Kernel/OptionsFieldTest.php deleted file mode 100644 index 4eb5f1d..0000000 --- a/core/modules/options/tests/src/Kernel/OptionsFieldTest.php +++ /dev/null @@ -1,105 +0,0 @@ -getForm($entity); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists'); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists'); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists'); - - // Use one of the values in an actual entity, and check that this value - // cannot be removed from the list. - $entity = EntityTest::create(); - $entity->{$this->fieldName}->value = 1; - $entity->save(); - $this->fieldStorage->setSetting('allowed_values', [2 => 'Two']); - try { - $this->fieldStorage->save(); - $this->fail(t('Cannot update a list field storage to not include keys with existing data.')); - } - catch (FieldStorageDefinitionUpdateForbiddenException $e) { - $this->pass(t('Cannot update a list field storage to not include keys with existing data.')); - } - // Empty the value, so that we can actually remove the option. - unset($entity->{$this->fieldName}); - $entity->save(); - - // Removed options do not appear. - $this->fieldStorage->setSetting('allowed_values', [2 => 'Two']); - $this->fieldStorage->save(); - $entity = EntityTest::create(); - $form = \Drupal::service('entity.form_builder')->getForm($entity); - $this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist'); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists'); - $this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist'); - - // Completely new options appear. - $this->fieldStorage->setSetting('allowed_values', [10 => 'Update', 20 => 'Twenty']); - $this->fieldStorage->save(); - // The entity holds an outdated field object with the old allowed values - // setting, so we need to reinitialize the entity object. - $entity = EntityTest::create(); - $form = \Drupal::service('entity.form_builder')->getForm($entity); - $this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist'); - $this->assertTrue(empty($form[$this->fieldName]['widget'][2]), 'Option 2 does not exist'); - $this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist'); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][10]), 'Option 10 exists'); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][20]), 'Option 20 exists'); - - // Options are reset when a new field with the same name is created. - $this->fieldStorage->delete(); - FieldStorageConfig::create($this->fieldStorageDefinition)->save(); - FieldConfig::create([ - 'field_name' => $this->fieldName, - 'entity_type' => 'entity_test', - 'bundle' => 'entity_test', - 'required' => TRUE, - ])->save(); - entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->fieldName, array( - 'type' => 'options_buttons', - )) - ->save(); - $entity = EntityTest::create(); - $form = \Drupal::service('entity.form_builder')->getForm($entity); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists'); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists'); - $this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists'); - - // Test the generateSampleValue() method. - $entity = EntityTest::create(); - $entity->{$this->fieldName}->generateSampleItems(); - $this->entityValidateAndSave($entity); - } -} diff --git a/core/modules/options/tests/src/Kernel/OptionsFieldUnitTestBase.php b/core/modules/options/tests/src/Kernel/OptionsFieldUnitTestBase.php deleted file mode 100644 index 33eab18..0000000 --- a/core/modules/options/tests/src/Kernel/OptionsFieldUnitTestBase.php +++ /dev/null @@ -1,86 +0,0 @@ -container->get('router.builder')->rebuild(); - - $this->fieldStorageDefinition = array( - 'field_name' => $this->fieldName, - 'entity_type' => 'entity_test', - 'type' => 'list_integer', - 'cardinality' => 1, - 'settings' => array( - 'allowed_values' => array(1 => 'One', 2 => 'Two', 3 => 'Three'), - ), - ); - $this->fieldStorage = FieldStorageConfig::create($this->fieldStorageDefinition); - $this->fieldStorage->save(); - - $this->field = FieldConfig::create([ - 'field_storage' => $this->fieldStorage, - 'bundle' => 'entity_test', - ]); - $this->field->save(); - - entity_get_form_display('entity_test', 'entity_test', 'default') - ->setComponent($this->fieldName, array( - 'type' => 'options_buttons', - )) - ->save(); - } - -} diff --git a/core/modules/options/tests/src/Kernel/OptionsFormattersTest.php b/core/modules/options/tests/src/Kernel/OptionsFormattersTest.php deleted file mode 100644 index 6e7ae11..0000000 --- a/core/modules/options/tests/src/Kernel/OptionsFormattersTest.php +++ /dev/null @@ -1,47 +0,0 @@ -{$this->fieldName}->value = 1; - - $items = $entity->get($this->fieldName); - - $build = $items->view(); - $this->assertEqual($build['#formatter'], 'list_default', 'Ensure to fall back to the default formatter.'); - $this->assertEqual($build[0]['#markup'], 'One'); - - $build = $items->view(array('type' => 'list_key')); - $this->assertEqual($build['#formatter'], 'list_key', 'The chosen formatter is used.'); - $this->assertEqual((string) $build[0]['#markup'], 1); - } - -} diff --git a/core/modules/rdf/src/Tests/Field/DateTimeFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/DateTimeFieldRdfaTest.php new file mode 100644 index 0000000..97b3c9a --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/DateTimeFieldRdfaTest.php @@ -0,0 +1,57 @@ +createTestField(); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:dateCreated'), + ))->save(); + + // Set up test entity. + $this->entity = EntityTest::create(array()); + $this->entity->{$this->fieldName}->value = $this->testValue; + } + + /** + * Tests the default formatter. + */ + public function testDefaultFormatter() { + $this->assertFormatterRdfa(array('type'=>'datetime_default'), 'http://schema.org/dateCreated', array('value' => $this->testValue . 'Z', 'type' => 'literal', 'datatype' => 'http://www.w3.org/2001/XMLSchema#dateTime')); + } +} diff --git a/core/modules/rdf/src/Tests/Field/EmailFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/EmailFieldRdfaTest.php new file mode 100644 index 0000000..872bd24 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/EmailFieldRdfaTest.php @@ -0,0 +1,54 @@ +createTestField(); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:email'), + ))->save(); + + // Set up test values. + $this->testValue = 'test@example.com'; + $this->entity = EntityTest::create(array()); + $this->entity->{$this->fieldName}->value = $this->testValue; + } + + /** + * Tests all email formatters. + */ + public function testAllFormatters() { + // Test the plain formatter. + $this->assertFormatterRdfa(array('type'=>'string'), 'http://schema.org/email', array('value' => $this->testValue)); + // Test the mailto formatter. + $this->assertFormatterRdfa(array('type'=>'email_mailto'), 'http://schema.org/email', array('value' => $this->testValue)); + } +} diff --git a/core/modules/rdf/src/Tests/Field/EntityReferenceRdfaTest.php b/core/modules/rdf/src/Tests/Field/EntityReferenceRdfaTest.php new file mode 100644 index 0000000..9a4ac05 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/EntityReferenceRdfaTest.php @@ -0,0 +1,99 @@ +installEntitySchema('entity_test_rev'); + + // Give anonymous users permission to view test entities. + $this->installConfig(array('user')); + Role::load(RoleInterface::ANONYMOUS_ID) + ->grantPermission('view test entity') + ->save(); + + $this->createEntityReferenceField($this->entityType, $this->bundle, $this->fieldName, 'Field test', $this->entityType); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:knows'), + ))->save(); + + // Create the entity to be referenced. + $this->targetEntity = $this->container->get('entity_type.manager') + ->getStorage($this->entityType) + ->create(array('name' => $this->randomMachineName())); + $this->targetEntity->save(); + + // Create the entity that will have the entity reference field. + $this->entity = $this->container->get('entity_type.manager') + ->getStorage($this->entityType) + ->create(array('name' => $this->randomMachineName())); + $this->entity->save(); + $this->entity->{$this->fieldName}->entity = $this->targetEntity; + $this->uri = $this->getAbsoluteUri($this->entity); + } + + /** + * Tests all the entity reference formatters. + */ + public function testAllFormatters() { + $entity_uri = $this->getAbsoluteUri($this->targetEntity); + + // Tests the label formatter. + $this->assertFormatterRdfa(array('type' => 'entity_reference_label'), 'http://schema.org/knows', array('value' => $entity_uri, 'type' => 'uri')); + // Tests the entity formatter. + $this->assertFormatterRdfa(array('type' => 'entity_reference_entity_view'), 'http://schema.org/knows', array('value' => $entity_uri, 'type' => 'uri')); + } + +} diff --git a/core/modules/rdf/src/Tests/Field/FieldRdfaDatatypeCallbackTest.php b/core/modules/rdf/src/Tests/Field/FieldRdfaDatatypeCallbackTest.php new file mode 100644 index 0000000..612fba9 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/FieldRdfaDatatypeCallbackTest.php @@ -0,0 +1,62 @@ +createTestField(); + + $this->installConfig(array('filter')); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:interactionCount'), + 'datatype_callback' => array( + 'callable' => 'Drupal\rdf\Tests\Field\TestDataConverter::convertFoo', + ), + ))->save(); + + // Set up test values. + $this->testValue = $this->randomMachineName(); + $this->entity = EntityTest::create(); + $this->entity->{$this->fieldName}->value = $this->testValue; + $this->entity->save(); + + $this->uri = $this->getAbsoluteUri($this->entity); + } + + /** + * Tests the default formatter. + */ + public function testDefaultFormatter() { + // Expected value is the output of the datatype callback, not the raw value. + $this->assertFormatterRdfa(array('type'=>'text_default'), 'http://schema.org/interactionCount', array('value' => 'foo' . $this->testValue)); + } + +} + diff --git a/core/modules/rdf/src/Tests/Field/FieldRdfaTestBase.php b/core/modules/rdf/src/Tests/Field/FieldRdfaTestBase.php new file mode 100644 index 0000000..f4d2240 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/FieldRdfaTestBase.php @@ -0,0 +1,193 @@ +rebuild(); + } + + /** + * Helper function to test the formatter's RDFa. + * + * @param array $formatter + * An associative array describing the formatter to test and its settings + * containing: + * - type: The machine name of the field formatter to test. + * - settings: The settings of the field formatter to test. + * @param string $property + * The property that should be found. + * @param array $expected_rdf_value + * An associative array describing the expected value of the property + * containing: + * - value: The actual value of the string or URI. + * - type: The type of RDF value, e.g. 'literal' for a string, or 'uri'. + * Defaults to 'literal'. + * - datatype: (optional) The datatype of the value (e.g. xsd:dateTime). + */ + protected function assertFormatterRdfa($formatter, $property, $expected_rdf_value) { + $expected_rdf_value += array('type' => 'literal'); + + // The field formatter will be rendered inside the entity. Set the field + // formatter in the entity display options before rendering the entity. + entity_get_display('entity_test', 'entity_test', 'default') + ->setComponent($this->fieldName, $formatter) + ->save(); + $build = entity_view($this->entity, 'default'); + $output = \Drupal::service('renderer')->renderRoot($build); + $graph = new \EasyRdf_Graph($this->uri, $output, 'rdfa'); + $this->setRawContent($output); + + // If verbose debugging is turned on, display the HTML and parsed RDF + // in the results. + if ($this->debug) { + debug($output); + debug($graph->toRdfPhp()); + } + + $this->assertTrue($graph->hasProperty($this->uri, $property, $expected_rdf_value), "Formatter {$formatter['type']} exposes data correctly for {$this->fieldType} fields."); + } + + /** + * Creates the field for testing. + * + * @param array $field_settings + * (optional) An array of field settings. + */ + protected function createTestField($field_settings = array()) { + FieldStorageConfig::create(array( + 'field_name' => $this->fieldName, + 'entity_type' => 'entity_test', + 'type' => $this->fieldType, + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => $this->fieldName, + 'bundle' => 'entity_test', + 'settings' => $field_settings, + ])->save(); + } + + /** + * Gets the absolute URI of an entity. + * + * @param \Drupal\Core\Entity\ContentEntityBase $entity + * The entity for which to generate the URI. + * + * @return string + * The absolute URI. + */ + protected function getAbsoluteUri($entity) { + return $entity->url('canonical', array('absolute' => TRUE)); + } + + /** + * Parses a content and return the html element. + * + * @param string $content + * The html to parse. + * + * @return array + * An array containing simplexml objects. + */ + protected function parseContent($content) { + $htmlDom = new \DOMDocument(); + @$htmlDom->loadHTML('' . $content); + $elements = simplexml_import_dom($htmlDom); + + return $elements; + } + + /** + * Performs an xpath search on a certain content. + * + * The search is relative to the root element of the $content variable. + * + * @param string $content + * The html to parse. + * @param string $xpath + * The xpath string to use in the search. + * @param array $arguments + * Some arguments for the xpath. + * + * @return array|FALSE + * The return value of the xpath search. For details on the xpath string + * format and return values see the SimpleXML documentation, + * http://php.net/manual/function.simplexml-element-xpath.php. + */ + protected function xpathContent($content, $xpath, array $arguments = array()) { + if ($elements = $this->parseContent($content)) { + $xpath = $this->buildXPathQuery($xpath, $arguments); + $result = $elements->xpath($xpath); + // Some combinations of PHP / libxml versions return an empty array + // instead of the documented FALSE. Forcefully convert any falsish values + // to an empty array to allow foreach(...) constructions. + return $result ? $result : array(); + } + else { + return FALSE; + } + } + +} diff --git a/core/modules/rdf/src/Tests/Field/LinkFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/LinkFieldRdfaTest.php new file mode 100644 index 0000000..01e6977 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/LinkFieldRdfaTest.php @@ -0,0 +1,188 @@ +createTestField(); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:link'), + ))->save(); + + } + + /** + * Tests all formatters with link to external page. + */ + public function testAllFormattersExternal() { + // Set up test values. + $this->testValue = 'http://test.me/foo/bar/neque/porro/quisquam/est/qui-dolorem?foo/bar/neque/porro/quisquam/est/qui-dolorem'; + $this->entity = EntityTest::create(array()); + $this->entity->{$this->fieldName}->uri = $this->testValue; + + // Set up the expected result. + $expected_rdf = array( + 'value' => $this->testValue, + 'type' => 'uri', + ); + + $this->runTestAllFormatters($expected_rdf, 'external'); + } + + /** + * Tests all formatters with link to internal page. + */ + public function testAllFormattersInternal() { + // Set up test values. + $this->testValue = 'admin'; + $this->entity = EntityTest::create(array()); + $this->entity->{$this->fieldName}->uri = 'internal:/admin'; + + // Set up the expected result. + // AssertFormatterRdfa looks for a full path. + $expected_rdf = array( + 'value' => $this->uri . '/' . $this->testValue, + 'type' => 'uri', + ); + + $this->runTestAllFormatters($expected_rdf, 'internal'); + } + + /** + * Tests all formatters with link to frontpage. + */ + public function testAllFormattersFront() { + // Set up test values. + $this->testValue = '/'; + $this->entity = EntityTest::create(array()); + $this->entity->{$this->fieldName}->uri = 'internal:/'; + + // Set up the expected result. + $expected_rdf = array( + 'value' => $this->uri . '/', + 'type' => 'uri', + ); + + $this->runTestAllFormatters($expected_rdf, 'front'); + } + + /** + * Helper function to test all link formatters. + */ + public function runTestAllFormatters($expected_rdf, $type = NULL) { + + // Test the link formatter: trim at 80, no other settings. + $formatter = array( + 'type' => 'link', + 'settings' => array( + 'trim_length' => 80, + 'url_only' => FALSE, + 'url_plain' => FALSE, + 'rel' => '', + 'target' => '', + ), + ); + $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); + + // Test the link formatter: trim at 40, nofollow, new window. + $formatter = array( + 'type' => 'link', + 'settings' => array( + 'trim_length' => 40, + 'url_only' => FALSE, + 'url_plain' => FALSE, + 'rel' => 'nofollow', + 'target' => '_blank', + ), + ); + $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); + + // Test the link formatter: trim at 40, URL only (not plaintext) nofollow, + // new window. + $formatter = array( + 'type' => 'link', + 'settings' => array( + 'trim_length' => 40, + 'url_only' => TRUE, + 'url_plain' => FALSE, + 'rel' => 'nofollow', + 'target' => '_blank', + ), + ); + $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); + + // Test the link_separate formatter: trim at 40, nofollow, new window. + $formatter = array( + 'type' => 'link_separate', + 'settings' => array( + 'trim_length' => 40, + 'rel' => 'nofollow', + 'target' => '_blank', + ), + ); + $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); + + // Change the expected value here to literal. When formatted as plaintext + // then the RDF is expecting a 'literal' not a 'uri'. + $expected_rdf = array( + 'value' => $this->testValue, + 'type' => 'literal', + ); + // Test the link formatter: trim at 20, url only (as plaintext.) + $formatter = array( + 'type' => 'link', + 'settings' => array( + 'trim_length' => 20, + 'url_only' => TRUE, + 'url_plain' => TRUE, + 'rel' => '0', + 'target' => '0', + ), + ); + $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); + + // Test the link formatter: do not trim, url only (as plaintext.) + $formatter = array( + 'type' => 'link', + 'settings' => array( + 'trim_length' => 0, + 'url_only' => TRUE, + 'url_plain' => TRUE, + 'rel' => '0', + 'target' => '0', + ), + ); + $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); + } + +} diff --git a/core/modules/rdf/src/Tests/Field/NumberFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/NumberFieldRdfaTest.php new file mode 100644 index 0000000..69d81a8 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/NumberFieldRdfaTest.php @@ -0,0 +1,207 @@ +fieldType = 'integer'; + $testValue = 3; + $this->createTestField(); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa(array('type' => 'number_integer'), 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is not created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); + $this->assertFalse($result); + } + + /** + * Tests the integer formatter with settings. + */ + public function testIntegerFormatterWithSettings() { + \Drupal::service('theme_handler')->install(['classy']); + \Drupal::service('theme_handler')->setDefault('classy'); + $this->fieldType = 'integer'; + $formatter = array( + 'type' => 'number_integer', + 'settings' => array( + 'thousand_separator' => '.', + 'prefix_suffix' => TRUE, + ), + ); + $testValue = 3333333.33; + $field_settings = array( + 'prefix' => '#', + 'suffix' => ' llamas.', + ); + $this->createTestField($field_settings); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); + $this->assertTrue($result); + } + + /** + * Tests the float formatter. + */ + public function testFloatFormatter() { + $this->fieldType = 'float'; + $testValue = 3.33; + $this->createTestField(); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa(array('type' => 'number_unformatted'), 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is not created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); + $this->assertFalse($result); + } + + /** + * Tests the float formatter with settings. + */ + public function testFloatFormatterWithSettings() { + \Drupal::service('theme_handler')->install(['classy']); + \Drupal::service('theme_handler')->setDefault('classy'); + $this->fieldType = 'float'; + $formatter = array( + 'type' => 'number_decimal', + 'settings' => array( + 'thousand_separator' => '.', + 'decimal_separator' => ',', + 'prefix_suffix' => TRUE, + ), + ); + $testValue = 3333333.33; + $field_settings = array( + 'prefix' => '$', + 'suffix' => ' more.', + ); + $this->createTestField($field_settings); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); + $this->assertTrue($result); + } + + /** + * Tests the float formatter with a scale. Scale is not exercised. + */ + public function testFloatFormatterWithScale() { + $this->fieldType = 'float'; + $formatter = array( + 'type' => 'number_decimal', + 'settings' => array( + 'scale' => 5, + ), + ); + $testValue = 3.33; + $this->createTestField(); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is not created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); + $this->assertFalse($result); + } + + /** + * Tests the float formatter with a scale. Scale is exercised. + */ + public function testFloatFormatterWithScaleExercised() { + \Drupal::service('theme_handler')->install(['classy']); + \Drupal::service('theme_handler')->setDefault('classy'); + $this->fieldType = 'float'; + $formatter = array( + 'type' => 'number_decimal', + 'settings' => array( + 'scale' => 5, + ), + ); + $testValue = 3.1234567; + $this->createTestField(); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); + $this->assertTrue($result); + } + + /** + * Tests the decimal formatter. + */ + public function testDecimalFormatter() { + $this->fieldType = 'decimal'; + $testValue = 3.33; + $this->createTestField(); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa(array('type' => 'number_decimal'), 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is not created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); + $this->assertFalse($result); + } + + /** + * Tests the decimal formatter with settings. + */ + public function testDecimalFormatterWithSettings() { + \Drupal::service('theme_handler')->install(['classy']); + \Drupal::service('theme_handler')->setDefault('classy'); + $this->fieldType = 'decimal'; + $formatter = array( + 'type' => 'number_decimal', + 'settings' => array( + 'thousand_separator' => 't', + 'decimal_separator' => '#', + 'prefix_suffix' => TRUE, + ), + ); + $testValue = 3333333.33; + $field_settings = array( + 'prefix' => '$', + 'suffix' => ' more.', + ); + $this->createTestField($field_settings); + $this->createTestEntity($testValue); + $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); + + // Test that the content attribute is created. + $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); + $this->assertTrue($result); + } + + /** + * Creates the RDF mapping for the field. + */ + protected function createTestEntity($testValue) { + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:baseSalary'), + ))->save(); + + // Set up test entity. + $this->entity = EntityTest::create(array()); + $this->entity->{$this->fieldName}->value = $testValue; + } +} diff --git a/core/modules/rdf/src/Tests/Field/StringFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/StringFieldRdfaTest.php new file mode 100644 index 0000000..8856c20 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/StringFieldRdfaTest.php @@ -0,0 +1,61 @@ +createTestField(); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:text'), + ))->save(); + + // Set up test entity. + $this->entity = EntityTest::create(); + $this->entity->{$this->fieldName}->value = $this->testValue; + $this->entity->{$this->fieldName}->summary = $this->testSummary; + } + + /** + * Tests string formatters. + */ + public function testStringFormatters() { + // Tests the string formatter. + $this->assertFormatterRdfa(array('type'=>'string'), 'http://schema.org/text', array('value' => $this->testValue)); + } +} diff --git a/core/modules/rdf/src/Tests/Field/TelephoneFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/TelephoneFieldRdfaTest.php new file mode 100644 index 0000000..dad5c4a --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/TelephoneFieldRdfaTest.php @@ -0,0 +1,72 @@ +createTestField(); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:telephone'), + ))->save(); + + // Set up test values. + $this->testValue = '555-555-5555'; + $this->entity = EntityTest::create(array()); + $this->entity->{$this->fieldName}->value = $this->testValue; + } + + /** + * Tests the field formatters. + */ + public function testAllFormatters() { + // Tests the plain formatter. + $this->assertFormatterRdfa(array('type' => 'string'), 'http://schema.org/telephone', array('value' => $this->testValue)); + // Tests the telephone link formatter. + $this->assertFormatterRdfa(array('type' => 'telephone_link'), 'http://schema.org/telephone', array('value' => 'tel:' . $this->testValue, 'type' => 'uri')); + + $formatter = array( + 'type' => 'telephone_link', + 'settings' => array('title' => 'Contact us'), + ); + $expected_rdf_value = array( + 'value' => 'tel:' . $this->testValue, + 'type' => 'uri', + ); + // Tests the telephone link formatter with custom title. + $this->assertFormatterRdfa($formatter, 'http://schema.org/telephone', $expected_rdf_value); + } +} diff --git a/core/modules/rdf/src/Tests/Field/TextFieldRdfaTest.php b/core/modules/rdf/src/Tests/Field/TextFieldRdfaTest.php new file mode 100644 index 0000000..2f0cd46 --- /dev/null +++ b/core/modules/rdf/src/Tests/Field/TextFieldRdfaTest.php @@ -0,0 +1,76 @@ +installConfig(array('filter')); + + $this->createTestField(); + + // Add the mapping. + $mapping = rdf_get_mapping('entity_test', 'entity_test'); + $mapping->setFieldMapping($this->fieldName, array( + 'properties' => array('schema:text'), + ))->save(); + + // Set up test entity. + $this->entity = EntityTest::create(); + $this->entity->{$this->fieldName}->value = $this->testValue; + $this->entity->{$this->fieldName}->summary = $this->testSummary; + } + + /** + * Tests all formatters. + * + * @todo Check for the summary mapping. + */ + public function testAllFormatters() { + $formatted_value = strip_tags($this->entity->{$this->fieldName}->processed); + + // Tests the default formatter. + $this->assertFormatterRdfa(array('type'=>'text_default'), 'http://schema.org/text', array('value' => $formatted_value)); + // Tests the summary formatter. + $this->assertFormatterRdfa(array('type'=>'text_summary_or_trimmed'), 'http://schema.org/text', array('value' => $formatted_value)); + // Tests the trimmed formatter. + $this->assertFormatterRdfa(array('type'=>'text_trimmed'), 'http://schema.org/text', array('value' => $formatted_value)); + } +} diff --git a/core/modules/rdf/tests/src/Kernel/Field/DateTimeFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/DateTimeFieldRdfaTest.php deleted file mode 100644 index 33f6d1c..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/DateTimeFieldRdfaTest.php +++ /dev/null @@ -1,58 +0,0 @@ -createTestField(); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:dateCreated'), - ))->save(); - - // Set up test entity. - $this->entity = EntityTest::create(array()); - $this->entity->{$this->fieldName}->value = $this->testValue; - } - - /** - * Tests the default formatter. - */ - public function testDefaultFormatter() { - $this->assertFormatterRdfa(array('type'=>'datetime_default'), 'http://schema.org/dateCreated', array('value' => $this->testValue . 'Z', 'type' => 'literal', 'datatype' => 'http://www.w3.org/2001/XMLSchema#dateTime')); - } -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/EmailFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/EmailFieldRdfaTest.php deleted file mode 100644 index 346df36..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/EmailFieldRdfaTest.php +++ /dev/null @@ -1,55 +0,0 @@ -createTestField(); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:email'), - ))->save(); - - // Set up test values. - $this->testValue = 'test@example.com'; - $this->entity = EntityTest::create(array()); - $this->entity->{$this->fieldName}->value = $this->testValue; - } - - /** - * Tests all email formatters. - */ - public function testAllFormatters() { - // Test the plain formatter. - $this->assertFormatterRdfa(array('type'=>'string'), 'http://schema.org/email', array('value' => $this->testValue)); - // Test the mailto formatter. - $this->assertFormatterRdfa(array('type'=>'email_mailto'), 'http://schema.org/email', array('value' => $this->testValue)); - } -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/EntityReferenceRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/EntityReferenceRdfaTest.php deleted file mode 100644 index 47cf20b..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/EntityReferenceRdfaTest.php +++ /dev/null @@ -1,100 +0,0 @@ -installEntitySchema('entity_test_rev'); - - // Give anonymous users permission to view test entities. - $this->installConfig(array('user')); - Role::load(RoleInterface::ANONYMOUS_ID) - ->grantPermission('view test entity') - ->save(); - - $this->createEntityReferenceField($this->entityType, $this->bundle, $this->fieldName, 'Field test', $this->entityType); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:knows'), - ))->save(); - - // Create the entity to be referenced. - $this->targetEntity = $this->container->get('entity_type.manager') - ->getStorage($this->entityType) - ->create(array('name' => $this->randomMachineName())); - $this->targetEntity->save(); - - // Create the entity that will have the entity reference field. - $this->entity = $this->container->get('entity_type.manager') - ->getStorage($this->entityType) - ->create(array('name' => $this->randomMachineName())); - $this->entity->save(); - $this->entity->{$this->fieldName}->entity = $this->targetEntity; - $this->uri = $this->getAbsoluteUri($this->entity); - } - - /** - * Tests all the entity reference formatters. - */ - public function testAllFormatters() { - $entity_uri = $this->getAbsoluteUri($this->targetEntity); - - // Tests the label formatter. - $this->assertFormatterRdfa(array('type' => 'entity_reference_label'), 'http://schema.org/knows', array('value' => $entity_uri, 'type' => 'uri')); - // Tests the entity formatter. - $this->assertFormatterRdfa(array('type' => 'entity_reference_entity_view'), 'http://schema.org/knows', array('value' => $entity_uri, 'type' => 'uri')); - } - -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/FieldRdfaDatatypeCallbackTest.php b/core/modules/rdf/tests/src/Kernel/Field/FieldRdfaDatatypeCallbackTest.php deleted file mode 100644 index 8a28bad..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/FieldRdfaDatatypeCallbackTest.php +++ /dev/null @@ -1,63 +0,0 @@ -createTestField(); - - $this->installConfig(array('filter')); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:interactionCount'), - 'datatype_callback' => array( - 'callable' => 'Drupal\rdf\Tests\Field\TestDataConverter::convertFoo', - ), - ))->save(); - - // Set up test values. - $this->testValue = $this->randomMachineName(); - $this->entity = EntityTest::create(); - $this->entity->{$this->fieldName}->value = $this->testValue; - $this->entity->save(); - - $this->uri = $this->getAbsoluteUri($this->entity); - } - - /** - * Tests the default formatter. - */ - public function testDefaultFormatter() { - // Expected value is the output of the datatype callback, not the raw value. - $this->assertFormatterRdfa(array('type'=>'text_default'), 'http://schema.org/interactionCount', array('value' => 'foo' . $this->testValue)); - } - -} - diff --git a/core/modules/rdf/tests/src/Kernel/Field/FieldRdfaTestBase.php b/core/modules/rdf/tests/src/Kernel/Field/FieldRdfaTestBase.php deleted file mode 100644 index 30f9cd1..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/FieldRdfaTestBase.php +++ /dev/null @@ -1,193 +0,0 @@ -rebuild(); - } - - /** - * Helper function to test the formatter's RDFa. - * - * @param array $formatter - * An associative array describing the formatter to test and its settings - * containing: - * - type: The machine name of the field formatter to test. - * - settings: The settings of the field formatter to test. - * @param string $property - * The property that should be found. - * @param array $expected_rdf_value - * An associative array describing the expected value of the property - * containing: - * - value: The actual value of the string or URI. - * - type: The type of RDF value, e.g. 'literal' for a string, or 'uri'. - * Defaults to 'literal'. - * - datatype: (optional) The datatype of the value (e.g. xsd:dateTime). - */ - protected function assertFormatterRdfa($formatter, $property, $expected_rdf_value) { - $expected_rdf_value += array('type' => 'literal'); - - // The field formatter will be rendered inside the entity. Set the field - // formatter in the entity display options before rendering the entity. - entity_get_display('entity_test', 'entity_test', 'default') - ->setComponent($this->fieldName, $formatter) - ->save(); - $build = entity_view($this->entity, 'default'); - $output = \Drupal::service('renderer')->renderRoot($build); - $graph = new \EasyRdf_Graph($this->uri, $output, 'rdfa'); - $this->setRawContent($output); - - // If verbose debugging is turned on, display the HTML and parsed RDF - // in the results. - if ($this->debug) { - print_r($output); - print_r($graph->toRdfPhp()); - } - - $this->assertTrue($graph->hasProperty($this->uri, $property, $expected_rdf_value), "Formatter {$formatter['type']} exposes data correctly for {$this->fieldType} fields."); - } - - /** - * Creates the field for testing. - * - * @param array $field_settings - * (optional) An array of field settings. - */ - protected function createTestField($field_settings = array()) { - FieldStorageConfig::create(array( - 'field_name' => $this->fieldName, - 'entity_type' => 'entity_test', - 'type' => $this->fieldType, - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => $this->fieldName, - 'bundle' => 'entity_test', - 'settings' => $field_settings, - ])->save(); - } - - /** - * Gets the absolute URI of an entity. - * - * @param \Drupal\Core\Entity\ContentEntityBase $entity - * The entity for which to generate the URI. - * - * @return string - * The absolute URI. - */ - protected function getAbsoluteUri($entity) { - return $entity->url('canonical', array('absolute' => TRUE)); - } - - /** - * Parses a content and return the html element. - * - * @param string $content - * The html to parse. - * - * @return array - * An array containing simplexml objects. - */ - protected function parseContent($content) { - $htmlDom = new \DOMDocument(); - @$htmlDom->loadHTML('' . $content); - $elements = simplexml_import_dom($htmlDom); - - return $elements; - } - - /** - * Performs an xpath search on a certain content. - * - * The search is relative to the root element of the $content variable. - * - * @param string $content - * The html to parse. - * @param string $xpath - * The xpath string to use in the search. - * @param array $arguments - * Some arguments for the xpath. - * - * @return array|FALSE - * The return value of the xpath search. For details on the xpath string - * format and return values see the SimpleXML documentation, - * http://php.net/manual/function.simplexml-element-xpath.php. - */ - protected function xpathContent($content, $xpath, array $arguments = array()) { - if ($elements = $this->parseContent($content)) { - $xpath = $this->buildXPathQuery($xpath, $arguments); - $result = $elements->xpath($xpath); - // Some combinations of PHP / libxml versions return an empty array - // instead of the documented FALSE. Forcefully convert any falsish values - // to an empty array to allow foreach(...) constructions. - return $result ? $result : array(); - } - else { - return FALSE; - } - } - -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php deleted file mode 100644 index 405ba23..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php +++ /dev/null @@ -1,189 +0,0 @@ -createTestField(); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:link'), - ))->save(); - - } - - /** - * Tests all formatters with link to external page. - */ - public function testAllFormattersExternal() { - // Set up test values. - $this->testValue = 'http://test.me/foo/bar/neque/porro/quisquam/est/qui-dolorem?foo/bar/neque/porro/quisquam/est/qui-dolorem'; - $this->entity = EntityTest::create(array()); - $this->entity->{$this->fieldName}->uri = $this->testValue; - - // Set up the expected result. - $expected_rdf = array( - 'value' => $this->testValue, - 'type' => 'uri', - ); - - $this->runTestAllFormatters($expected_rdf, 'external'); - } - - /** - * Tests all formatters with link to internal page. - */ - public function testAllFormattersInternal() { - // Set up test values. - $this->testValue = 'admin'; - $this->entity = EntityTest::create(array()); - $this->entity->{$this->fieldName}->uri = 'internal:/admin'; - - // Set up the expected result. - // AssertFormatterRdfa looks for a full path. - $expected_rdf = array( - 'value' => $this->uri . '/' . $this->testValue, - 'type' => 'uri', - ); - - $this->runTestAllFormatters($expected_rdf, 'internal'); - } - - /** - * Tests all formatters with link to frontpage. - */ - public function testAllFormattersFront() { - // Set up test values. - $this->testValue = '/'; - $this->entity = EntityTest::create(array()); - $this->entity->{$this->fieldName}->uri = 'internal:/'; - - // Set up the expected result. - $expected_rdf = array( - 'value' => $this->uri . '/', - 'type' => 'uri', - ); - - $this->runTestAllFormatters($expected_rdf, 'front'); - } - - /** - * Helper function to test all link formatters. - */ - public function runTestAllFormatters($expected_rdf, $type = NULL) { - - // Test the link formatter: trim at 80, no other settings. - $formatter = array( - 'type' => 'link', - 'settings' => array( - 'trim_length' => 80, - 'url_only' => FALSE, - 'url_plain' => FALSE, - 'rel' => '', - 'target' => '', - ), - ); - $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); - - // Test the link formatter: trim at 40, nofollow, new window. - $formatter = array( - 'type' => 'link', - 'settings' => array( - 'trim_length' => 40, - 'url_only' => FALSE, - 'url_plain' => FALSE, - 'rel' => 'nofollow', - 'target' => '_blank', - ), - ); - $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); - - // Test the link formatter: trim at 40, URL only (not plaintext) nofollow, - // new window. - $formatter = array( - 'type' => 'link', - 'settings' => array( - 'trim_length' => 40, - 'url_only' => TRUE, - 'url_plain' => FALSE, - 'rel' => 'nofollow', - 'target' => '_blank', - ), - ); - $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); - - // Test the link_separate formatter: trim at 40, nofollow, new window. - $formatter = array( - 'type' => 'link_separate', - 'settings' => array( - 'trim_length' => 40, - 'rel' => 'nofollow', - 'target' => '_blank', - ), - ); - $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); - - // Change the expected value here to literal. When formatted as plaintext - // then the RDF is expecting a 'literal' not a 'uri'. - $expected_rdf = array( - 'value' => $this->testValue, - 'type' => 'literal', - ); - // Test the link formatter: trim at 20, url only (as plaintext.) - $formatter = array( - 'type' => 'link', - 'settings' => array( - 'trim_length' => 20, - 'url_only' => TRUE, - 'url_plain' => TRUE, - 'rel' => '0', - 'target' => '0', - ), - ); - $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); - - // Test the link formatter: do not trim, url only (as plaintext.) - $formatter = array( - 'type' => 'link', - 'settings' => array( - 'trim_length' => 0, - 'url_only' => TRUE, - 'url_plain' => TRUE, - 'rel' => '0', - 'target' => '0', - ), - ); - $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf); - } - -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/NumberFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/NumberFieldRdfaTest.php deleted file mode 100644 index 31e66b0..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/NumberFieldRdfaTest.php +++ /dev/null @@ -1,208 +0,0 @@ -fieldType = 'integer'; - $testValue = 3; - $this->createTestField(); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa(array('type' => 'number_integer'), 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is not created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); - $this->assertFalse($result); - } - - /** - * Tests the integer formatter with settings. - */ - public function testIntegerFormatterWithSettings() { - \Drupal::service('theme_handler')->install(['classy']); - \Drupal::service('theme_handler')->setDefault('classy'); - $this->fieldType = 'integer'; - $formatter = array( - 'type' => 'number_integer', - 'settings' => array( - 'thousand_separator' => '.', - 'prefix_suffix' => TRUE, - ), - ); - $testValue = 3333333.33; - $field_settings = array( - 'prefix' => '#', - 'suffix' => ' llamas.', - ); - $this->createTestField($field_settings); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); - $this->assertTrue($result); - } - - /** - * Tests the float formatter. - */ - public function testFloatFormatter() { - $this->fieldType = 'float'; - $testValue = 3.33; - $this->createTestField(); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa(array('type' => 'number_unformatted'), 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is not created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); - $this->assertFalse($result); - } - - /** - * Tests the float formatter with settings. - */ - public function testFloatFormatterWithSettings() { - \Drupal::service('theme_handler')->install(['classy']); - \Drupal::service('theme_handler')->setDefault('classy'); - $this->fieldType = 'float'; - $formatter = array( - 'type' => 'number_decimal', - 'settings' => array( - 'thousand_separator' => '.', - 'decimal_separator' => ',', - 'prefix_suffix' => TRUE, - ), - ); - $testValue = 3333333.33; - $field_settings = array( - 'prefix' => '$', - 'suffix' => ' more.', - ); - $this->createTestField($field_settings); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); - $this->assertTrue($result); - } - - /** - * Tests the float formatter with a scale. Scale is not exercised. - */ - public function testFloatFormatterWithScale() { - $this->fieldType = 'float'; - $formatter = array( - 'type' => 'number_decimal', - 'settings' => array( - 'scale' => 5, - ), - ); - $testValue = 3.33; - $this->createTestField(); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is not created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); - $this->assertFalse($result); - } - - /** - * Tests the float formatter with a scale. Scale is exercised. - */ - public function testFloatFormatterWithScaleExercised() { - \Drupal::service('theme_handler')->install(['classy']); - \Drupal::service('theme_handler')->setDefault('classy'); - $this->fieldType = 'float'; - $formatter = array( - 'type' => 'number_decimal', - 'settings' => array( - 'scale' => 5, - ), - ); - $testValue = 3.1234567; - $this->createTestField(); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); - $this->assertTrue($result); - } - - /** - * Tests the decimal formatter. - */ - public function testDecimalFormatter() { - $this->fieldType = 'decimal'; - $testValue = 3.33; - $this->createTestField(); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa(array('type' => 'number_decimal'), 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is not created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__items") and @content]'); - $this->assertFalse($result); - } - - /** - * Tests the decimal formatter with settings. - */ - public function testDecimalFormatterWithSettings() { - \Drupal::service('theme_handler')->install(['classy']); - \Drupal::service('theme_handler')->setDefault('classy'); - $this->fieldType = 'decimal'; - $formatter = array( - 'type' => 'number_decimal', - 'settings' => array( - 'thousand_separator' => 't', - 'decimal_separator' => '#', - 'prefix_suffix' => TRUE, - ), - ); - $testValue = 3333333.33; - $field_settings = array( - 'prefix' => '$', - 'suffix' => ' more.', - ); - $this->createTestField($field_settings); - $this->createTestEntity($testValue); - $this->assertFormatterRdfa($formatter, 'http://schema.org/baseSalary', array('value' => $testValue)); - - // Test that the content attribute is created. - $result = $this->xpathContent($this->getRawContent(), '//div[contains(@class, "field__item") and @content=:testValue]', array(':testValue' => $testValue)); - $this->assertTrue($result); - } - - /** - * Creates the RDF mapping for the field. - */ - protected function createTestEntity($testValue) { - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:baseSalary'), - ))->save(); - - // Set up test entity. - $this->entity = EntityTest::create(array()); - $this->entity->{$this->fieldName}->value = $testValue; - } -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/StringFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/StringFieldRdfaTest.php deleted file mode 100644 index 958af46..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/StringFieldRdfaTest.php +++ /dev/null @@ -1,62 +0,0 @@ -createTestField(); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:text'), - ))->save(); - - // Set up test entity. - $this->entity = EntityTest::create(); - $this->entity->{$this->fieldName}->value = $this->testValue; - $this->entity->{$this->fieldName}->summary = $this->testSummary; - } - - /** - * Tests string formatters. - */ - public function testStringFormatters() { - // Tests the string formatter. - $this->assertFormatterRdfa(array('type'=>'string'), 'http://schema.org/text', array('value' => $this->testValue)); - } -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/TelephoneFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/TelephoneFieldRdfaTest.php deleted file mode 100644 index eb88699..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/TelephoneFieldRdfaTest.php +++ /dev/null @@ -1,73 +0,0 @@ -createTestField(); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:telephone'), - ))->save(); - - // Set up test values. - $this->testValue = '555-555-5555'; - $this->entity = EntityTest::create(array()); - $this->entity->{$this->fieldName}->value = $this->testValue; - } - - /** - * Tests the field formatters. - */ - public function testAllFormatters() { - // Tests the plain formatter. - $this->assertFormatterRdfa(array('type' => 'string'), 'http://schema.org/telephone', array('value' => $this->testValue)); - // Tests the telephone link formatter. - $this->assertFormatterRdfa(array('type' => 'telephone_link'), 'http://schema.org/telephone', array('value' => 'tel:' . $this->testValue, 'type' => 'uri')); - - $formatter = array( - 'type' => 'telephone_link', - 'settings' => array('title' => 'Contact us'), - ); - $expected_rdf_value = array( - 'value' => 'tel:' . $this->testValue, - 'type' => 'uri', - ); - // Tests the telephone link formatter with custom title. - $this->assertFormatterRdfa($formatter, 'http://schema.org/telephone', $expected_rdf_value); - } -} diff --git a/core/modules/rdf/tests/src/Kernel/Field/TextFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/TextFieldRdfaTest.php deleted file mode 100644 index 9a0a2cb..0000000 --- a/core/modules/rdf/tests/src/Kernel/Field/TextFieldRdfaTest.php +++ /dev/null @@ -1,77 +0,0 @@ -installConfig(array('filter')); - - $this->createTestField(); - - // Add the mapping. - $mapping = rdf_get_mapping('entity_test', 'entity_test'); - $mapping->setFieldMapping($this->fieldName, array( - 'properties' => array('schema:text'), - ))->save(); - - // Set up test entity. - $this->entity = EntityTest::create(); - $this->entity->{$this->fieldName}->value = $this->testValue; - $this->entity->{$this->fieldName}->summary = $this->testSummary; - } - - /** - * Tests all formatters. - * - * @todo Check for the summary mapping. - */ - public function testAllFormatters() { - $formatted_value = strip_tags($this->entity->{$this->fieldName}->processed); - - // Tests the default formatter. - $this->assertFormatterRdfa(array('type'=>'text_default'), 'http://schema.org/text', array('value' => $formatted_value)); - // Tests the summary formatter. - $this->assertFormatterRdfa(array('type'=>'text_summary_or_trimmed'), 'http://schema.org/text', array('value' => $formatted_value)); - // Tests the trimmed formatter. - $this->assertFormatterRdfa(array('type'=>'text_trimmed'), 'http://schema.org/text', array('value' => $formatted_value)); - } -} diff --git a/core/modules/simpletest/src/RouteProvider.php b/core/modules/simpletest/src/RouteProvider.php index 0784d72..acff99a 100644 --- a/core/modules/simpletest/src/RouteProvider.php +++ b/core/modules/simpletest/src/RouteProvider.php @@ -13,9 +13,6 @@ /** * Rebuilds the router when the provider is instantiated. - * - * @todo Move this outside of simpletest namespace to the Drupal\Tests, see - * https://www.drupal.org/node/2672762 */ class RouteProvider implements PreloadableRouteProviderInterface, PagedRouteProviderInterface { diff --git a/core/modules/simpletest/src/TestServiceProvider.php b/core/modules/simpletest/src/TestServiceProvider.php index ba65c37..5a1a398 100644 --- a/core/modules/simpletest/src/TestServiceProvider.php +++ b/core/modules/simpletest/src/TestServiceProvider.php @@ -33,25 +33,15 @@ function register(ContainerBuilder $container) { */ public function alter(ContainerBuilder $container) { if (static::$currentTest instanceof KernelTestBase) { - static::addRouteProvider($container); - } - } - - /** - * Add the on demand rebuild route provider service. - * - * @param \Drupal\Core\DependencyInjection\ContainerBuilder $container - */ - public static function addRouteProvider(ContainerBuilder $container) { - foreach (['router.route_provider' => 'RouteProvider'] as $original_id => $class) { // While $container->get() does a recursive resolve, getDefinition() does // not, so do it ourselves. - for ($id = $original_id; $container->hasAlias($id); $id = (string) $container->getAlias($id)); - $definition = $container->getDefinition($id); - $definition->clearTag('needs_destruction'); - $container->setDefinition("simpletest.$original_id", $definition); - $container->setDefinition($id, new Definition('Drupal\simpletest\\' . $class)); + foreach (['router.route_provider' => 'RouteProvider'] as $original_id => $class) { + for ($id = $original_id; $container->hasAlias($id); $id = (string) $container->getAlias($id)); + $definition = $container->getDefinition($id); + $definition->clearTag('needs_destruction'); + $container->setDefinition("simpletest.$original_id", $definition); + $container->setDefinition($id, new Definition('Drupal\simpletest\\' . $class)); + } } } - } diff --git a/core/modules/simpletest/tests/src/Unit/TestInfoParsingTest.php b/core/modules/simpletest/tests/src/Unit/TestInfoParsingTest.php index b96ea79..fda12f1 100644 --- a/core/modules/simpletest/tests/src/Unit/TestInfoParsingTest.php +++ b/core/modules/simpletest/tests/src/Unit/TestInfoParsingTest.php @@ -5,7 +5,7 @@ * Contains \Drupal\Tests\simpletest\Unit\TestInfoParsingTest. */ -namespace Drupal\Tests\simpletest\Unit { +namespace Drupal\Tests\simpletest\Unit; use Composer\Autoload\ClassLoader; use Drupal\Core\Extension\Extension; @@ -87,18 +87,18 @@ public function infoParserProvider() { $tests[] = [ // Expected result. [ - 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', - 'group' => 'simpletest', - 'description' => 'Tests the Simpletest UI internal browser.', + 'name' => 'Drupal\field\Tests\BulkDeleteTest', + 'group' => 'field', + 'description' => 'Bulk delete storages and fields, and clean up afterwards.', 'type' => 'Simpletest', ], // Classname. - 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'Drupal\field\Tests\BulkDeleteTest', // Doc block. "/** - * Tests the Simpletest UI internal browser. + * Bulk delete storages and fields, and clean up afterwards. * - * @group simpletest + * @group field */ ", ]; @@ -107,19 +107,18 @@ public function infoParserProvider() { $tests[] = [ // Expected result. [ - 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', - 'group' => 'simpletest', - 'description' => 'Tests the Simpletest UI internal browser.', - 'type' => 'Simpletest', + 'name' => 'Drupal\field\Tests\BulkDeleteTest', + 'group' => 'field', + 'description' => 'Bulk delete storages and fields, and clean up afterwards.', + 'type' => 'Simpletest' ], // Classname. - 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'Drupal\field\Tests\BulkDeleteTest', // Doc block. "/** - * Tests the Simpletest UI internal browser. + * Bulk delete storages and fields, and clean up afterwards. * - * @group simpletest - */ + * @group field */ ", ]; @@ -129,18 +128,18 @@ public function infoParserProvider() { $tests[] = [ // Expected result. [ - 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', - 'group' => 'simpletest', - 'description' => 'Tests the Simpletest UI internal browser. * @', - 'type' => 'Simpletest', + 'name' => 'Drupal\field\Tests\BulkDeleteTest', + 'group' => 'field', + 'description' => 'Bulk delete storages and fields, and clean up afterwards. * @', + 'type' => 'Simpletest' ], // Classname. - 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'Drupal\field\Tests\BulkDeleteTest', // Doc block. "/** - * Tests the Simpletest UI internal browser. * @ + * Bulk delete storages and fields, and clean up afterwards. * @ * - * @group simpletest + * @group field */ ", ]; @@ -149,19 +148,19 @@ public function infoParserProvider() { $tests[] = [ // Expected result. [ - 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'name' => 'Drupal\field\Tests\BulkDeleteTest', 'group' => 'Test', - 'description' => 'Tests the Simpletest UI internal browser.', - 'type' => 'Simpletest', + 'description' => 'Bulk delete storages and fields, and clean up afterwards.', + 'type' => 'Simpletest' ], // Classname. - 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'Drupal\field\Tests\BulkDeleteTest', // Doc block. "/** - * Tests the Simpletest UI internal browser. + * Bulk delete storages and fields, and clean up afterwards. * * @group Test - * @group simpletest + * @group field */ ", ]; @@ -170,20 +169,20 @@ public function infoParserProvider() { $tests[] = [ // Expected result. [ - 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', - 'description' => 'Tests the Simpletest UI internal browser.', - 'type' => 'Simpletest', + 'name' => 'Drupal\field\Tests\BulkDeleteTest', + 'group' => 'field', + 'description' => 'Bulk delete storages and fields, and clean up afterwards.', 'requires' => ['module' => ['test']], - 'group' => 'simpletest', + 'type' => 'Simpletest' ], // Classname. - 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'Drupal\field\Tests\BulkDeleteTest', // Doc block. "/** - * Tests the Simpletest UI internal browser. + * Bulk delete storages and fields, and clean up afterwards. * * @dependencies test - * @group simpletest + * @group field */ ", ]; @@ -192,20 +191,20 @@ public function infoParserProvider() { $tests[] = [ // Expected result. [ - 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', - 'description' => 'Tests the Simpletest UI internal browser.', - 'type' => 'Simpletest', + 'name' => 'Drupal\field\Tests\BulkDeleteTest', + 'group' => 'field', + 'description' => 'Bulk delete storages and fields, and clean up afterwards.', 'requires' => ['module' => ['test', 'test1', 'test2']], - 'group' => 'simpletest', + 'type' => 'Simpletest' ], // Classname. - 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'Drupal\field\Tests\BulkDeleteTest', // Doc block. "/** - * Tests the Simpletest UI internal browser. + * Bulk delete storages and fields, and clean up afterwards. * - * @dependencies test, test1, test2 - * @group simpletest + * @dependencies test, test1,test2 + * @group field */ ", ]; @@ -214,19 +213,18 @@ public function infoParserProvider() { $tests[] = [ // Expected result. [ - 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', - 'description' => 'Tests the Simpletest UI internal browser. And the summary line continues an there is no gap to the annotation.', - 'type' => 'Simpletest', - 'group' => 'simpletest', + 'name' => 'Drupal\field\Tests\BulkDeleteTest', + 'group' => 'field', + 'description' => 'Bulk delete storages and fields, and clean up afterwards. And the summary line continues and there is no gap to the annotation.', + 'type' => 'Simpletest' ], // Classname. - 'Drupal\simpletest\Tests\ExampleSimpleTest', + 'Drupal\field\Tests\BulkDeleteTest', // Doc block. "/** - * Tests the Simpletest UI internal browser. And the summary line continues an - * there is no gap to the annotation. - * - * @group simpletest + * Bulk delete storages and fields, and clean up afterwards. And the summary + * line continues and there is no gap to the annotation. + * @group field */ ", ]; @@ -236,10 +234,10 @@ public function infoParserProvider() { /** * @covers ::getTestInfo * @expectedException \Drupal\simpletest\Exception\MissingGroupException - * @expectedExceptionMessage Missing @group annotation in Drupal\KernelTests\field\BulkDeleteTest + * @expectedExceptionMessage Missing @group annotation in Drupal\field\Tests\BulkDeleteTest */ public function testTestInfoParserMissingGroup() { - $classname = 'Drupal\KernelTests\field\BulkDeleteTest'; + $classname = 'Drupal\field\Tests\BulkDeleteTest'; $doc_comment = << 'field_test', + 'entity_type' => 'entity_test', + 'type' => 'telephone', + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'field_test', + 'bundle' => 'entity_test', + ])->save(); + } + + /** + * Tests using entity fields of the telephone field type. + */ + public function testTestItem() { + // Verify entity creation. + $entity = EntityTest::create(); + $value = '+0123456789'; + $entity->field_test = $value; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + // Verify entity has been created properly. + $id = $entity->id(); + $entity = entity_load('entity_test', $id); + $this->assertTrue($entity->field_test instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->field_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->field_test->value, $value); + $this->assertEqual($entity->field_test[0]->value, $value); + + // Verify changing the field value. + $new_value = '+41' . rand(1000000, 9999999); + $entity->field_test->value = $new_value; + $this->assertEqual($entity->field_test->value, $new_value); + + // Read changed entity and assert changed values. + $entity->save(); + $entity = entity_load('entity_test', $id); + $this->assertEqual($entity->field_test->value, $new_value); + + // Test sample item generation. + $entity = EntityTest::create(); + $entity->field_test->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + +} diff --git a/core/modules/telephone/tests/src/Kernel/TelephoneItemTest.php b/core/modules/telephone/tests/src/Kernel/TelephoneItemTest.php deleted file mode 100644 index 2935607..0000000 --- a/core/modules/telephone/tests/src/Kernel/TelephoneItemTest.php +++ /dev/null @@ -1,82 +0,0 @@ - 'field_test', - 'entity_type' => 'entity_test', - 'type' => 'telephone', - ))->save(); - FieldConfig::create([ - 'entity_type' => 'entity_test', - 'field_name' => 'field_test', - 'bundle' => 'entity_test', - ])->save(); - } - - /** - * Tests using entity fields of the telephone field type. - */ - public function testTestItem() { - // Verify entity creation. - $entity = EntityTest::create(); - $value = '+0123456789'; - $entity->field_test = $value; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - // Verify entity has been created properly. - $id = $entity->id(); - $entity = entity_load('entity_test', $id); - $this->assertTrue($entity->field_test instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->field_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_test->value, $value); - $this->assertEqual($entity->field_test[0]->value, $value); - - // Verify changing the field value. - $new_value = '+41' . rand(1000000, 9999999); - $entity->field_test->value = $new_value; - $this->assertEqual($entity->field_test->value, $new_value); - - // Read changed entity and assert changed values. - $entity->save(); - $entity = entity_load('entity_test', $id); - $this->assertEqual($entity->field_test->value, $new_value); - - // Test sample item generation. - $entity = EntityTest::create(); - $entity->field_test->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - -} diff --git a/core/modules/text/src/Tests/TextWithSummaryItemTest.php b/core/modules/text/src/Tests/TextWithSummaryItemTest.php new file mode 100644 index 0000000..dcb765f --- /dev/null +++ b/core/modules/text/src/Tests/TextWithSummaryItemTest.php @@ -0,0 +1,124 @@ +installEntitySchema('entity_test_rev'); + + // Create the necessary formats. + $this->installConfig(array('filter')); + FilterFormat::create(array( + 'format' => 'no_filters', + 'filters' => array(), + ))->save(); + } + + /** + * Tests processed properties. + */ + public function testCrudAndUpdate() { + $entity_type = 'entity_test'; + $this->createField($entity_type); + + // Create an entity with a summary and no text format. + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(); + $entity->summary_field->value = $value = $this->randomMachineName(); + $entity->summary_field->summary = $summary = $this->randomMachineName(); + $entity->summary_field->format = NULL; + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + $entity = entity_load($entity_type, $entity->id()); + $this->assertTrue($entity->summary_field instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->summary_field[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->summary_field->value, $value); + $this->assertEqual($entity->summary_field->summary, $summary); + $this->assertNull($entity->summary_field->format); + // Even if no format is given, if text processing is enabled, the default + // format is used. + $this->assertEqual($entity->summary_field->processed, "

    $value

    \n"); + $this->assertEqual($entity->summary_field->summary_processed, "

    $summary

    \n"); + + // Change the format, this should update the processed properties. + $entity->summary_field->format = 'no_filters'; + $this->assertEqual($entity->summary_field->processed, $value); + $this->assertEqual($entity->summary_field->summary_processed, $summary); + + // Test the generateSampleValue() method. + $entity = $this->container->get('entity_type.manager') + ->getStorage($entity_type) + ->create(); + $entity->summary_field->generateSampleItems(); + $this->entityValidateAndSave($entity); + } + + /** + * Creates a text_with_summary field storage and field. + * + * @param string $entity_type + * Entity type for which the field should be created. + */ + protected function createField($entity_type) { + // Create a field . + $this->fieldStorage = FieldStorageConfig::create(array( + 'field_name' => 'summary_field', + 'entity_type' => $entity_type, + 'type' => 'text_with_summary', + 'settings' => array( + 'max_length' => 10, + ) + )); + $this->fieldStorage->save(); + $this->field = FieldConfig::create([ + 'field_storage' => $this->fieldStorage, + 'bundle' => $entity_type, + ]); + $this->field->save(); + } + +} diff --git a/core/modules/text/tests/src/Kernel/TextWithSummaryItemTest.php b/core/modules/text/tests/src/Kernel/TextWithSummaryItemTest.php deleted file mode 100644 index cb3519a..0000000 --- a/core/modules/text/tests/src/Kernel/TextWithSummaryItemTest.php +++ /dev/null @@ -1,124 +0,0 @@ -installEntitySchema('entity_test_rev'); - - // Create the necessary formats. - $this->installConfig(array('filter')); - FilterFormat::create(array( - 'format' => 'no_filters', - 'filters' => array(), - ))->save(); - } - - /** - * Tests processed properties. - */ - public function testCrudAndUpdate() { - $entity_type = 'entity_test'; - $this->createField($entity_type); - - // Create an entity with a summary and no text format. - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(); - $entity->summary_field->value = $value = $this->randomMachineName(); - $entity->summary_field->summary = $summary = $this->randomMachineName(); - $entity->summary_field->format = NULL; - $entity->name->value = $this->randomMachineName(); - $entity->save(); - - $entity = entity_load($entity_type, $entity->id()); - $this->assertTrue($entity->summary_field instanceof FieldItemListInterface, 'Field implements interface.'); - $this->assertTrue($entity->summary_field[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->summary_field->value, $value); - $this->assertEqual($entity->summary_field->summary, $summary); - $this->assertNull($entity->summary_field->format); - // Even if no format is given, if text processing is enabled, the default - // format is used. - $this->assertEqual($entity->summary_field->processed, "

    $value

    \n"); - $this->assertEqual($entity->summary_field->summary_processed, "

    $summary

    \n"); - - // Change the format, this should update the processed properties. - $entity->summary_field->format = 'no_filters'; - $this->assertEqual($entity->summary_field->processed, $value); - $this->assertEqual($entity->summary_field->summary_processed, $summary); - - // Test the generateSampleValue() method. - $entity = $this->container->get('entity_type.manager') - ->getStorage($entity_type) - ->create(); - $entity->summary_field->generateSampleItems(); - $this->entityValidateAndSave($entity); - } - - /** - * Creates a text_with_summary field storage and field. - * - * @param string $entity_type - * Entity type for which the field should be created. - */ - protected function createField($entity_type) { - // Create a field . - $this->fieldStorage = FieldStorageConfig::create(array( - 'field_name' => 'summary_field', - 'entity_type' => $entity_type, - 'type' => 'text_with_summary', - 'settings' => array( - 'max_length' => 10, - ) - )); - $this->fieldStorage->save(); - $this->field = FieldConfig::create([ - 'field_storage' => $this->fieldStorage, - 'bundle' => $entity_type, - ]); - $this->field->save(); - } - -} diff --git a/core/modules/tour/src/Plugin/HelpSection/TourHelpSection.php b/core/modules/tour/src/Plugin/HelpSection/TourHelpSection.php deleted file mode 100644 index 49c5da2..0000000 --- a/core/modules/tour/src/Plugin/HelpSection/TourHelpSection.php +++ /dev/null @@ -1,137 +0,0 @@ -entityTypeManager = $entity_type_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('entity_type.manager') - ); - } - - /** - * {@inheritdoc} - */ - public function getCacheMaxAge() { - // The calculation of which URL (if any) gets put on which tour depends - // on a route access check. This can have a lot of inputs, including user - // permissions and other factors. Rather than doing a complicated - // accounting of the cache metadata for all of these possible factors, set - // the max age of the cache to zero to prevent using incorrect cached - // information. - return 0; - } - - /** - * {@inheritdoc} - */ - public function listTopics() { - /** @var \Drupal\tour\TourInterface[] $tours */ - $tours = $this->entityTypeManager->getStorage('tour')->loadMultiple(); - // Sort in the manner defined by Tour. - uasort($tours, ['Drupal\tour\Entity\Tour', 'sort']); - - // Make a link to each tour, using the first of its routes that can - // be linked to by this user, if any. - $topics = []; - foreach ($tours as $tour) { - $title = $tour->label(); - $id = $tour->id(); - $routes = $tour->getRoutes(); - $made_link = FALSE; - foreach ($routes as $route) { - // Some tours are for routes with parameters. For instance, there is - // currently a tour in the Language module for the language edit page, - // which appears on all pages with URLs like: - // /admin/config/regional/language/edit/LANGCODE. - // There is no way to make a link to the page that displays the tour, - // because it is a set of pages. The easiest way to detect this is to - // use a try/catch exception -- try to make a link, and it will error - // out with a missing parameter exception if the route leads to a set - // of pages instead of a single page. - try { - $params = isset($route['route_params']) ? $route['route_params'] : []; - $url = Url::fromRoute($route['route_name'], $params); - // Skip this route if the current user cannot access it. - if (!$url->access()) { - continue; - } - - // Generate the link HTML directly, using toString(), to catch - // missing parameter exceptions now instead of at render time. - $topics[$id] = Link::fromTextAndUrl($title, $url)->toString(); - // If the line above didn't generate an exception, we have a good - // link that the user can access. - $made_link = TRUE; - break; - } - catch (\Exception $e) { - // Exceptions are normally due to routes that need parameters. If - // there is an exception, just try the next route and see if we can - // find one that will work for us. - } - } - if (!$made_link) { - // None of the routes worked to make a link, so at least display the - // tour title. - $topics[$id] = $title; - } - } - - return $topics; - } - -} diff --git a/core/modules/tour/src/Tests/TourHelpPageTest.php b/core/modules/tour/src/Tests/TourHelpPageTest.php deleted file mode 100644 index a39d6a6..0000000 --- a/core/modules/tour/src/Tests/TourHelpPageTest.php +++ /dev/null @@ -1,146 +0,0 @@ -tourUser = $this->drupalCreateUser(['access administration pages', 'access tour', 'administer languages']); - $this->noTourUser = $this->drupalCreateUser(['access administration pages']); - } - - /** - * Logs in users, tests help pages. - */ - public function testHelp() { - $this->drupalLogin($this->tourUser); - $this->verifyHelp(); - - $this->drupalLogin($this->noTourUser); - $this->verifyHelp(FALSE); - } - - /** - * Verifies the logged in user has access to the help properly. - * - * @param bool $tours_ok - * (optional) TRUE (default) if the user should see tours, FALSE if not. - */ - protected function verifyHelp($tours_ok = TRUE) { - $this->drupalGet('admin/help'); - - // All users should be able to see the module section. - $this->assertText('Module overviews are provided by modules'); - foreach ($this->getModuleList() as $name) { - $this->assertLink($name); - } - - // Some users should be able to see the tour section. - if ($tours_ok) { - $this->assertText('Tours guide you through workflows'); - } - else { - $this->assertNoText('Tours guide you through workflows'); - } - - $titles = $this->getTourList(); - - // Test the titles that should be links. - foreach ($titles[0] as $title) { - if ($tours_ok) { - $this->assertLink($title); - } - else { - $this->assertNoLink($title); - // Just test the first item in the list of links that should not - // be there, because the second matches the name of a module that is - // in the Module overviews section, so the link will be there and - // this test will fail. Testing one should be sufficient to verify - // the page is working correctly. - break; - } - } - - // Test the titles that should not be links. - foreach ($titles[1] as $title) { - if ($tours_ok) { - $this->assertText($title); - $this->assertNoLink($title); - } - else { - $this->assertNoText($title); - // Just test the first item in the list of text that should not - // be there, because the second matches part of the name of a module - // that is in the Module overviews section, so the text will be there - // and this test will fail. Testing one should be sufficient to verify - // the page is working correctly. - break; - } - } - } - - /** - * Gets a list of modules to test for hook_help() pages. - * - * @return array - * A list of module names to test. - */ - protected function getModuleList() { - return ['Help', 'Tour']; - } - - /** - * Gets a list of tours to test. - * - * @return array - * A list of tour titles to test. The first array element is a list of tours - * with links, and the second is a list of tours without links. Assumes - * that the user being tested has 'administer languages' permission but - * not 'translate interface'. - */ - protected function getTourList() { - return [['Adding languages', 'Language'], ['Editing languages', 'Translation']]; - } - -} diff --git a/core/modules/user/templates/username.html.twig b/core/modules/user/templates/username.html.twig index 6c1fccb..5d4f2f7 100644 --- a/core/modules/user/templates/username.html.twig +++ b/core/modules/user/templates/username.html.twig @@ -9,8 +9,8 @@ * - extra: Additional text to append to the user's name, sanitized. * - link_path: The path or URL of the user's profile page, home page, * or other desired page to link to for more information about the user. - * - link_options: Options to set on the \Drupal\Core\Url object if linking the - * user's name to the user's page. + * - link_options: Options to pass to the url() function's $options parameter if + * linking the user's name to the user's page. * - attributes: HTML attributes for the containing element. * * @see template_preprocess_username() diff --git a/core/modules/views/src/Annotation/ViewsAggregate.php b/core/modules/views/src/Annotation/ViewsAggregate.php new file mode 100644 index 0000000..55d702e --- /dev/null +++ b/core/modules/views/src/Annotation/ViewsAggregate.php @@ -0,0 +1,85 @@ + 'submit', '#value' => $this->t('Grouped filters'), '#submit' => array(array($this, 'buildGroupForm')), + '#attributes' => array('class' => array('use-ajax-submit')), ); $form['group_button']['radios']['radios']['#default_value'] = 0; } @@ -421,6 +422,7 @@ protected function showBuildGroupButton(&$form, FormStateInterface $form_state) '#type' => 'submit', '#value' => $this->t('Single filter'), '#submit' => array(array($this, 'buildGroupForm')), + '#attributes' => array('class' => array('use-ajax-submit')), ); $form['group_button']['radios']['radios']['#default_value'] = 1; } @@ -485,6 +487,7 @@ public function showExposeButton(&$form, FormStateInterface $form_state) { '#type' => 'submit', '#value' => $this->t('Expose filter'), '#submit' => array(array($this, 'displayExposedForm')), + '#attributes' => array('class' => array('use-ajax-submit')), ); $form['expose_button']['checkbox']['checkbox']['#default_value'] = 0; } @@ -497,6 +500,7 @@ public function showExposeButton(&$form, FormStateInterface $form_state) { '#type' => 'submit', '#value' => $this->t('Hide filter'), '#submit' => array(array($this, 'displayExposedForm')), + '#attributes' => array('class' => array('use-ajax-submit')), ); $form['expose_button']['checkbox']['checkbox']['#default_value'] = 1; } @@ -1088,6 +1092,7 @@ protected function buildExposedFiltersGroupForm(&$form, FormStateInterface $form '#type' => 'submit', '#value' => $this->t('Add another item'), '#submit' => array(array($this, 'addGroupForm')), + '#attributes' => array('class' => array('use-ajax-submit')), ); $js = array(); diff --git a/core/modules/views/src/Plugin/views/query/Sql.php b/core/modules/views/src/Plugin/views/query/Sql.php index 25374c0..5a3a370 100644 --- a/core/modules/views/src/Plugin/views/query/Sql.php +++ b/core/modules/views/src/Plugin/views/query/Sql.php @@ -1597,84 +1597,16 @@ public function addSignature(ViewExecutable $view) { } public function getAggregationInfo() { - // @todo -- need a way to get database specific and customized aggregation - // functions into here. + // Find plugins for database specific and customized aggregation. + $type = \Drupal::service('plugin.manager.views.aggregate'); + $plugin_definitions = $type->getDefinitions(); + asort($plugin_definitions); return array( 'group' => array( 'title' => $this->t('Group results together'), 'is aggregate' => FALSE, ), - 'count' => array( - 'title' => $this->t('Count'), - 'method' => 'aggregationMethodSimple', - 'handler' => array( - 'argument' => 'groupby_numeric', - 'field' => 'numeric', - 'filter' => 'groupby_numeric', - 'sort' => 'groupby_numeric', - ), - ), - 'count_distinct' => array( - 'title' => $this->t('Count DISTINCT'), - 'method' => 'aggregationMethodDistinct', - 'handler' => array( - 'argument' => 'groupby_numeric', - 'field' => 'numeric', - 'filter' => 'groupby_numeric', - 'sort' => 'groupby_numeric', - ), - ), - 'sum' => array( - 'title' => $this->t('Sum'), - 'method' => 'aggregationMethodSimple', - 'handler' => array( - 'argument' => 'groupby_numeric', - 'field' => 'numeric', - 'filter' => 'groupby_numeric', - 'sort' => 'groupby_numeric', - ), - ), - 'avg' => array( - 'title' => $this->t('Average'), - 'method' => 'aggregationMethodSimple', - 'handler' => array( - 'argument' => 'groupby_numeric', - 'field' => 'numeric', - 'filter' => 'groupby_numeric', - 'sort' => 'groupby_numeric', - ), - ), - 'min' => array( - 'title' => $this->t('Minimum'), - 'method' => 'aggregationMethodSimple', - 'handler' => array( - 'argument' => 'groupby_numeric', - 'field' => 'numeric', - 'filter' => 'groupby_numeric', - 'sort' => 'groupby_numeric', - ), - ), - 'max' => array( - 'title' => $this->t('Maximum'), - 'method' => 'aggregationMethodSimple', - 'handler' => array( - 'argument' => 'groupby_numeric', - 'field' => 'numeric', - 'filter' => 'groupby_numeric', - 'sort' => 'groupby_numeric', - ), - ), - 'stddev_pop' => array( - 'title' => $this->t('Standard deviation'), - 'method' => 'aggregationMethodSimple', - 'handler' => array( - 'argument' => 'groupby_numeric', - 'field' => 'numeric', - 'filter' => 'groupby_numeric', - 'sort' => 'groupby_numeric', - ), - ) - ); + ) + $plugin_definitions; } public function aggregationMethodSimple($group_type, $field) { diff --git a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php index db46791..ca595fb 100644 --- a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php +++ b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php @@ -125,6 +125,7 @@ public function showExposeButton(&$form, FormStateInterface $form_state) { '#type' => 'submit', '#value' => $this->t('Expose sort'), '#submit' => array(array($this, 'displayExposedForm')), + '#attributes' => array('class' => array('use-ajax-submit')), ); $form['expose_button']['checkbox']['checkbox']['#default_value'] = 0; } @@ -137,6 +138,7 @@ public function showExposeButton(&$form, FormStateInterface $form_state) { '#type' => 'submit', '#value' => $this->t('Hide sort'), '#submit' => array(array($this, 'displayExposedForm')), + '#attributes' => array('class' => array('use-ajax-submit')), ); $form['expose_button']['checkbox']['checkbox']['#default_value'] = 1; } diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml index 1a01543..a013188 100644 --- a/core/modules/views/views.services.yml +++ b/core/modules/views/views.services.yml @@ -56,6 +56,9 @@ services: plugin.manager.views.wizard: class: Drupal\views\Plugin\ViewsPluginManager arguments: [wizard, '@container.namespaces', '@cache.discovery', '@module_handler'] + plugin.manager.views.aggregate: + class: Drupal\views\Plugin\ViewsPluginManager + arguments: [aggregate, '@container.namespaces', '@cache.discovery', '@module_handler'] views.views_data: class: Drupal\views\ViewsData arguments: ['@cache.discovery', '@config.factory', '@module_handler', '@language_manager'] diff --git a/core/modules/views_ui/js/ajax.js b/core/modules/views_ui/js/ajax.js index b044688..0dc0a74 100644 --- a/core/modules/views_ui/js/ajax.js +++ b/core/modules/views_ui/js/ajax.js @@ -25,38 +25,6 @@ }; /** - * Ajax command to set the form submit action in the views modal edit form. - * - * @param {Drupal.Ajax} [ajax] - * An Ajax object. - * @param {object} response - * The Ajax response. Contains .url - * @param {string} [status] - * The XHR status code? - */ - Drupal.AjaxCommands.prototype.viewsSetForm = function (ajax, response, status) { - var $form = $('.js-views-ui-dialog form'); - // Identify the button that was clicked so that .ajaxSubmit() can use it. - // We need to do this for both .click() and .mousedown() since JavaScript - // code might trigger either behavior. - var $submit_buttons = $form.find('input[type=submit].js-form-submit, button.js-form-submit').once('views-ajax-submit'); - $submit_buttons.on('click mousedown', function () { - this.form.clk = this; - }); - $form.once('views-ajax-submit').each(function () { - var $form = $(this); - var element_settings = { - url: response.url, - event: 'submit', - base: $form.attr('id'), - element: this - }; - var ajaxForm = Drupal.ajax(element_settings); - ajaxForm.$form = $form; - }); - }; - - /** * Ajax command to show certain buttons in the views edit form. * * @param {Drupal.Ajax} [ajax] diff --git a/core/modules/views_ui/src/Ajax/SetFormCommand.php b/core/modules/views_ui/src/Ajax/SetFormCommand.php deleted file mode 100644 index e114529..0000000 --- a/core/modules/views_ui/src/Ajax/SetFormCommand.php +++ /dev/null @@ -1,46 +0,0 @@ -url = $url; - } - - /** - * {@inheritdoc} - */ - public function render() { - return array( - 'command' => 'viewsSetForm', - 'url' => $this->url, - ); - } - -} diff --git a/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php b/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php index e82dc42..8df344a 100644 --- a/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php +++ b/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php @@ -181,6 +181,9 @@ public function buildForm(array $form, FormStateInterface $form_state, Request $ '#value' => $this->t('Remove'), '#submit' => array(array($this, 'remove')), '#limit_validation_errors' => array(array('override')), + '#ajax' => array( + 'url' => Url::fromRoute(''), + ), '#button_type' => 'danger', ); } diff --git a/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php b/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php index 478dae1..f58484c 100644 --- a/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php +++ b/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php @@ -134,6 +134,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { 'class' => array('views-remove-group'), ), '#group' => $id, + '#ajax' => ['url' => NULL], ); } $group_options[$id] = $id == 1 ? $this->t('Default group') : $this->t('Group @group', array('@group' => $id)); diff --git a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php index b5497b6..b3edb64 100644 --- a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php +++ b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php @@ -16,7 +16,6 @@ use Drupal\Core\Render\RenderContext; use Drupal\views\ViewEntityInterface; use Drupal\views\Ajax; -use Drupal\views_ui\Ajax as AjaxUI; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\CloseModalDialogCommand; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -243,18 +242,12 @@ protected function ajaxFormWrapper($form_class, FormStateInterface &$form_state) $display .= $output; $options = array( - 'dialogClass' => 'views-ui-dialog js-views-ui-dialog', + 'dialogClass' => 'views-ui-dialog', 'width' => '75%', ); $response->addCommand(new OpenModalDialogCommand($title, $display, $options)); - // Views provides its own custom handling of AJAX form submissions. - // Usually this happens at the same path, but custom paths may be - // specified in $form_state. - $form_url = $form_state->has('url') ? $form_state->get('url')->toString() : $this->url(''); - $response->addCommand(new AjaxUI\SetFormCommand($form_url)); - if ($section = $form_state->get('#section')) { $response->addCommand(new Ajax\HighlightCommand('.' . Html::cleanCssIdentifier($section))); } diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php index 8783c3e..33c3284 100644 --- a/core/modules/views_ui/src/ViewUI.php +++ b/core/modules/views_ui/src/ViewUI.php @@ -295,6 +295,11 @@ public function getStandardButtons(&$form, FormStateInterface $form_state, $form $names = array(t('Apply'), t('Apply and continue')); } + // Views provides its own custom handling of AJAX form submissions. Usually + // this happens at the same path, but custom paths may be specified in + // $form_state. + $form_url = $form_state->get('url') ?: Url::fromRouteMatch(\Drupal::routeMatch()); + // Forms that are purely informational set an ok_button flag, so we know not // to create an "Apply" button for them. if (!$form_state->get('ok_button')) { @@ -309,6 +314,9 @@ public function getStandardButtons(&$form, FormStateInterface $form_state, $form // take care of running the regular submit handler as appropriate. '#submit' => array(array($this, 'standardSubmit')), '#button_type' => 'primary', + '#ajax' => array( + 'url' => $form_url, + ), ); // Form API button click detection requires the button's #value to be the // same between the form build of the initial page request, and the @@ -334,6 +342,9 @@ public function getStandardButtons(&$form, FormStateInterface $form_state, $form '#value' => !$form_state->get('ok_button') ? t('Cancel') : t('Ok'), '#submit' => array($cancel_submit), '#validate' => array(), + '#ajax' => array( + 'path' => $form_url, + ), '#limit_validation_errors' => array(), ); diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh index 1b7a45a..eba01b9 100755 --- a/core/scripts/run-tests.sh +++ b/core/scripts/run-tests.sh @@ -180,12 +180,6 @@ function simpletest_script_help() { Note that ':memory:' cannot be used, because this script spawns sub-processes. However, you may use e.g. '/tmpfs/test.sqlite' - --keep-results-table - - Boolean flag to indicate to not cleanup the simpletest result - table. For testbots or repeated execution of a single test it can - be helpful to not cleanup the simpletest result table. - --dburl A URI denoting the database driver, credentials, server hostname, and database name to use in tests. Required when running tests without a Drupal installation that @@ -309,7 +303,6 @@ function simpletest_script_parse_args() { 'color' => FALSE, 'verbose' => FALSE, 'keep-results' => FALSE, - 'keep-results-table' => FALSE, 'test_names' => array(), 'repeat' => 1, 'die-on-fail' => FALSE, @@ -546,8 +539,7 @@ function simpletest_script_setup_database($new = FALSE) { // Create the Simpletest schema. try { - $connection = Database::getConnection('default', 'test-runner'); - $schema = $connection->schema(); + $schema = Database::getConnection('default', 'test-runner')->schema(); } catch (\PDOException $e) { simpletest_script_print_error($databases['test-runner']['default']['driver'] . ': ' . $e->getMessage()); @@ -557,13 +549,10 @@ function simpletest_script_setup_database($new = FALSE) { require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'simpletest') . '/simpletest.install'; foreach (simpletest_schema() as $name => $table_spec) { try { - $table_exists = $schema->tableExists($name); - if (empty($args['keep-results-table']) && $table_exists) { - $connection->truncate($name)->execute(); - } - if (!$table_exists) { - $schema->createTable($name, $table_spec); + if ($schema->tableExists($name)) { + $schema->dropTable($name); } + $schema->createTable($name, $table_spec); } catch (Exception $e) { echo (string) $e; diff --git a/core/tests/Drupal/KernelTests/Core/Entity/RouteProviderTest.php b/core/tests/Drupal/KernelTests/Core/Entity/RouteProviderTest.php index c97f03a..9199c74 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/RouteProviderTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/RouteProviderTest.php @@ -37,6 +37,13 @@ protected function setUp() { $this->installEntitySchema('entity_test_mul'); $this->installEntitySchema('entity_test_admin_routes'); + $router_builder = \Drupal::service('router.builder'); + $router_builder->rebuild(); + + /** @var \Drupal\Core\Routing\RouteBuilderInterface $router_builder */ + $router_builder = \Drupal::service('router.builder'); + $router_builder->rebuild(); + /** @var \Drupal\user\RoleInterface $role */ $role = Role::create([ 'id' => RoleInterface::ANONYMOUS_ID diff --git a/core/tests/Drupal/KernelTests/KernelTestBase.php b/core/tests/Drupal/KernelTests/KernelTestBase.php index 9556fc6..25ca3b7 100644 --- a/core/tests/Drupal/KernelTests/KernelTestBase.php +++ b/core/tests/Drupal/KernelTests/KernelTestBase.php @@ -25,7 +25,6 @@ use Drupal\simpletest\AssertContentTrait; use Drupal\simpletest\AssertHelperTrait; use Drupal\simpletest\RandomGeneratorTrait; -use Drupal\simpletest\TestServiceProvider; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\Request; use org\bovigo\vfs\vfsStream; @@ -602,7 +601,6 @@ public function register(ContainerBuilder $container) { $container->getDefinition('password') ->setArguments(array(1)); } - TestServiceProvider::addRouteProvider($container); } /** @@ -925,12 +923,6 @@ protected function disableModules(array $modules) { * The rendered string output (typically HTML). */ protected function render(array &$elements) { - // \Drupal\Core\Render\BareHtmlPageRenderer::renderBarePage calls out to - // system_page_attachments() directly. - if (!\Drupal::moduleHandler()->moduleExists('system')) { - throw new \Exception(__METHOD__ . ' requires system module to be installed.'); - } - // Use the bare HTML page renderer to render our links. $renderer = $this->container->get('bare_html_page_renderer'); $response = $renderer->renderBarePage( diff --git a/core/themes/classy/templates/misc/help-section.html.twig b/core/themes/classy/templates/misc/help-section.html.twig deleted file mode 100644 index 6cfaa38..0000000 --- a/core/themes/classy/templates/misc/help-section.html.twig +++ /dev/null @@ -1,48 +0,0 @@ -{# -/** - * @file - * Theme override for a section of the help page. - * - * This implementation divides the links into 4 columns. - * - * Available variables: - * - title: The section title. - * - description: The description text for the section. - * - links: Links to display in the section. - * - empty: Text to display if there are no links. - */ -#} -
    -

    {{ title }}

    -

    {{ description }}

    - {% if links %} - {# Calculate the column length, to divide links into 4 columns. #} - {% set size = links|length // 4 %} - {% if size * 4 < links|length %} - {% set size = size + 1 %} - {% endif %} - - {# Output the links in 4 columns. #} - {% set count = 0 %} - {% for link in links %} - {% if count == 0 %} - {# Start a new column. #} -
      - {% endif %} -
    • {{ link }}
    • - {% set count = count + 1 %} - {% if count >= size %} - {# End the current column. #} - {% set count = 0 %} -
    - {% endif %} - {% endfor %} - - {# End the last column, if one is open. #} - {% if count > 0 %} -
    - {% endif %} - {% else %} -

    {{ empty }}

    - {% endif %} - diff --git a/core/themes/classy/templates/user/username.html.twig b/core/themes/classy/templates/user/username.html.twig index 5a6c3a5..3ed5c95 100644 --- a/core/themes/classy/templates/user/username.html.twig +++ b/core/themes/classy/templates/user/username.html.twig @@ -9,8 +9,8 @@ * - extra: Additional text to append to the user's name, sanitized. * - link_path: The path or URL of the user's profile page, home page, * or other desired page to link to for more information about the user. - * - link_options: Options to set on the \Drupal\Core\Url object if linking the - * user's name to the user's page. + * - link_options: Options to pass to the url() function's $options parameter if + * linking the user's name to the user's page. * - attributes: HTML attributes for the containing element. * * @see template_preprocess_username() diff --git a/core/themes/stable/templates/admin/help-section.html.twig b/core/themes/stable/templates/admin/help-section.html.twig deleted file mode 100644 index 4b0d7bd..0000000 --- a/core/themes/stable/templates/admin/help-section.html.twig +++ /dev/null @@ -1,23 +0,0 @@ -{# -/** - * @file - * Theme override for a section of the help page. - * - * Available variables: - * - title: The section title. - * - description: The description text for the section. - * - links: Links to display in the section. - * - empty: Text to display if there are no links. - */ -#} -

    {{ title }}

    -

    {{ description }}

    -{% if links %} -
      - {% for link in links %} -
    • {{ link }}
    • - {% endfor %} -
    -{% else %} -

    {{ empty }}

    -{% endif %} diff --git a/core/themes/stable/templates/user/username.html.twig b/core/themes/stable/templates/user/username.html.twig index 480225f..828f6c6 100644 --- a/core/themes/stable/templates/user/username.html.twig +++ b/core/themes/stable/templates/user/username.html.twig @@ -9,8 +9,8 @@ * - extra: Additional text to append to the user's name, sanitized. * - link_path: The path or URL of the user's profile page, home page, * or other desired page to link to for more information about the user. - * - link_options: Options to set on the \Drupal\Core\Url object if linking the - * user's name to the user's page. + * - link_options: Options to pass to the url() function's $options parameter if + * linking the user's name to the user's page. * - attributes: HTML attributes for the containing element. * * @see template_preprocess_username()