/** * Tests simple IEF widget with different cardinality options. * * @throws \Exception */ protected function testSimpleCardinalityOptions() { $this->drupalLogin($this->user); $cardinality_options = [ 1 => 1, 2 => 2, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED => 3, ]; /** @var \Drupal\field\FieldStorageConfigInterface $field_storage */ $field_storage = $this->fieldStorageConfigStorage->load('node.single'); foreach ($cardinality_options as $cardinality => $limit) { $field_storage->setCardinality($cardinality); $field_storage->save(); $this->drupalGet('node/add/ief_simple_single'); $this->assertText('Single node', 'Inline entity field widget title found.'); $this->assertText('Reference a single node.', 'Inline entity field description found.'); $add_more_xpath = '//input[@data-drupal-selector="edit-single-add-more"]'; if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) { $this->assertFieldByXPath($add_more_xpath, NULL, 'Add more button exists'); } else { $this->assertNoFieldByXPath($add_more_xpath, NULL, 'Add more button does NOT exist'); } $edit = ['title[0][value]' => 'Host node']; for ($item_number = 0; $item_number < $limit; $item_number++) { $edit["single[$item_number][inline_entity_form][title][0][value]"] = 'Child node nr.' . $item_number; if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) { $next_item_number = $item_number + 1; $this->assertNoFieldByName("single[$next_item_number][inline_entity_form][title][0][value]", NULL, "Item $next_item_number does not appear before 'Add More' clicked"); if ($item_number < $limit - 1) { $this->drupalPostAjaxForm(NULL, $edit, 'single_add_more'); // This needed because the first time "add another item" is clicked it does not work // see https://www.drupal.org/node/2664626 if ($item_number == 0) { $this->drupalPostAjaxForm(NULL, $edit, 'single_add_more'); } $this->assertFieldByName("single[$next_item_number][inline_entity_form][title][0][value]", NULL, "Item $next_item_number does appear after 'Add More' clicked"); } } } $this->drupalPostForm(NULL, $edit, t('Save')); for ($item_number = 0; $item_number < $limit; $item_number++) { $this->assertText('Child node nr.' . $item_number, 'Label of referenced entity found.'); } } }
/** * @covers ::delete * @covers ::doDelete */ public function testDeleteNothing() { $this->moduleHandler->expects($this->never())->method($this->anything()); $this->configFactory->expects($this->never())->method('get'); $this->cacheTagsInvalidator->expects($this->never())->method('invalidateTags'); $this->entityStorage->delete(array()); }
/** * Constructs a FieldStorageConfigStorage object. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type * The entity type definition. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory service. * @param \Drupal\Core\Config\StorageInterface $config_storage * The config storage service. * @param \Drupal\Component\Uuid\UuidInterface $uuid_service * The UUID service. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. * @param \Drupal\Core\Extension\ModuleHandler $module_handler * The module handler. * @param \Drupal\Core\State\StateInterface $state * The state key value store. */ public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, ModuleHandler $module_handler, StateInterface $state) { parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service, $language_manager); $this->entityManager = $entity_manager; $this->moduleHandler = $module_handler; $this->state = $state; }
/** * Tests configuration renaming. */ public function testConfigurationRename() { $content_type = entity_create('node_type', array('type' => Unicode::strtolower($this->randomName(16)), 'name' => $this->randomName())); $content_type->save(); $staged_type = $content_type->type; $active = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); $config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id(); // Emulate a staging operation. $this->copyConfig($active, $staging); // Change the machine name of the content type. $content_type->type = Unicode::strtolower($this->randomName(8)); $content_type->save(); $active_type = $content_type->type; $renamed_config_name = $content_type->getEntityType()->getConfigPrefix() . '.' . $content_type->id(); $this->assertTrue($active->exists($renamed_config_name), 'The content type has the new name in the active store.'); $this->assertFalse($active->exists($config_name), "The content type's old name does not exist active store."); $this->configImporter()->reset(); $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('create')), 'There are no configuration items to create.'); $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('delete')), 'There are no configuration items to delete.'); $this->assertEqual(0, count($this->configImporter()->getUnprocessedConfiguration('update')), 'There are no configuration items to update.'); // We expect that changing the machine name of the content type will // rename five configuration entities: the node type, the body field // instance, two entity form displays, and the entity view display. // @see \Drupal\node\Entity\NodeType::postSave() $expected = array('node.type.' . $active_type . '::node.type.' . $staged_type, 'entity.form_display.node.' . $active_type . '.default::entity.form_display.node.' . $staged_type . '.default', 'entity.view_display.node.' . $active_type . '.default::entity.view_display.node.' . $staged_type . '.default', 'entity.view_display.node.' . $active_type . '.teaser::entity.view_display.node.' . $staged_type . '.teaser', 'field.instance.node.' . $active_type . '.body::field.instance.node.' . $staged_type . '.body'); $renames = $this->configImporter()->getUnprocessedConfiguration('rename'); $this->assertIdentical($expected, $renames); $this->drupalGet('admin/config/development/configuration'); foreach ($expected as $rename) { $names = $this->configImporter()->getStorageComparer()->extractRenameNames($rename); $this->assertText(String::format('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name']))); // Test that the diff link is present for each renamed item. $href = \Drupal::urlGenerator()->getPathFromRoute('config.diff', array('source_name' => $names['old_name'], 'target_name' => $names['new_name'])); $this->assertLinkByHref($href); $hrefs[$rename] = $href; } // Ensure that the diff works for each renamed item. foreach ($hrefs as $rename => $href) { $this->drupalGet($href); $names = $this->configImporter()->getStorageComparer()->extractRenameNames($rename); $config_entity_type = \Drupal::service('config.manager')->getEntityTypeIdByName($names['old_name']); $entity_type = \Drupal::entityManager()->getDefinition($config_entity_type); $old_id = ConfigEntityStorage::getIDFromConfigName($names['old_name'], $entity_type->getConfigPrefix()); $new_id = ConfigEntityStorage::getIDFromConfigName($names['new_name'], $entity_type->getConfigPrefix()); // Because table columns can be on multiple lines, need to assert a regex // pattern rather than normal text. $id_key = $entity_type->getKey('id'); $text = "{$id_key}: {$old_id}"; $this->assertTextPattern('/\\-\\s+' . preg_quote($text, '/') . '/', "'-{$text}' found."); $text = "{$id_key}: {$new_id}"; $this->assertTextPattern('/\\+\\s+' . preg_quote($text, '/') . '/', "'+{$text}' found."); } // Run the import. $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); $this->assertText(t('There are no configuration changes.')); $this->assertFalse(entity_load('node_type', $active_type), 'The content no longer exists with the old name.'); $content_type = entity_load('node_type', $staged_type); $this->assertIdentical($staged_type, $content_type->type); }
/** * {@inheritdoc} */ protected function mapToStorageRecord(EntityInterface $entity) { $record = parent::mapToStorageRecord($entity); $class = $this->fieldTypeManager->getPluginClass($record['field_type']); $record['settings'] = $class::fieldSettingsToConfigData($record['settings']); return $record; }
/** * {@inheritdoc} */ protected function doDelete($entities) { // ZZ is the fallback address format and it must always be present. if (array_key_exists('ZZ', $entities) && current($entities)->isUninstalling() === FALSE) { throw new EntityStorageException("The 'ZZ' address format can't be deleted."); } parent::doDelete($entities); }
/** * {@inheritdoc} */ public function loadMultiple(array $ids = NULL) { /** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */ $migrations = parent::loadMultiple($ids); foreach ($migrations as $migration) { $migration->set('migration_dependencies', $this->expandDependencies($migration->getMigrationDependencies())); } return $migrations; }
/** * {@inheritdoc} */ public function importDelete($name, Config $new_config, Config $old_config) { // If the field has been deleted in the same import, the instance will be // deleted by then, and there is nothing left to do. Just return TRUE so // that the file does not get written to active store. if (!$old_config->get()) { return TRUE; } return parent::importDelete($name, $new_config, $old_config); }
/** * {@inheritdoc} */ protected function mapFromStorageRecords(array $records) { $entities = parent::mapFromStorageRecords($records); $prefix = $this->entityTypeManager->getDefinition('moderation_state')->getConfigPrefix(); /* @var \Drupal\workbench_moderation\ModerationStateTransitionInterface $entity */ foreach ($entities as &$entity) { $entity->setModerationStateConfigPrefix($prefix); } reset($entities); return $entities; }
/** * {@inheritdoc} */ protected function doDelete($entities) { // ZZ is the fallback address format and it must always be present. if (isset($entities['ZZ'])) { $entity = $entities['ZZ']; if (!$entity->isUninstalling() && !$entity->isSyncing()) { throw new EntityStorageException("The 'ZZ' address format can't be deleted."); } } parent::doDelete($entities); }
/** * @covers ::loadByEntityTypeBundle * * @dataProvider providerLoadByEntityTypeBundle */ public function testLoadByEntityTypeBundle($config_id, ContentLanguageSettings $existing_config = NULL, $expected_langcode, $expected_language_alterable) { list($type, $bundle) = explode('.', $config_id); $nullConfig = new ContentLanguageSettings(array('target_entity_type_id' => $type, 'target_bundle' => $bundle), 'language_content_settings'); $this->configEntityStorageInterface->expects($this->any())->method('load')->with($config_id)->will($this->returnValue($existing_config)); $this->configEntityStorageInterface->expects($this->any())->method('create')->will($this->returnValue($nullConfig)); $this->entityManager->expects($this->any())->method('getStorage')->with('language_content_settings')->will($this->returnValue($this->configEntityStorageInterface)); $this->entityManager->expects($this->any())->method('getEntityTypeFromClass')->with('Drupal\\language\\Entity\\ContentLanguageSettings')->willReturn('language_content_settings'); $config = ContentLanguageSettings::loadByEntityTypeBundle($type, $bundle); $this->assertSame($expected_langcode, $config->getDefaultLangcode()); $this->assertSame($expected_language_alterable, $config->isLanguageAlterable()); }
/** * {@inheritdoc} */ public function loadMultiple(array $ids = NULL) { if ($ids) { $ids = $this->getVariantIds($ids); } /** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */ $migrations = parent::loadMultiple($ids); foreach ($migrations as $migration) { $dependencies = array_map([$this, 'getVariantIds'], $migration->getMigrationDependencies()); $migration->set('migration_dependencies', $dependencies); } // Build an array of dependencies and set the order of the migrations. return $this->buildDependencyMigration($migrations, []); }
/** * Ensures bundles that will be deleted are not in use. * * @param \Drupal\Core\Config\ConfigImporterEvent $event * The config import event. */ public function onConfigImporterValidate(ConfigImporterEvent $event) { foreach ($event->getChangelist('delete') as $config_name) { // Get the config entity type ID. This also ensure we are dealing with a // configuration entity. if ($entity_type_id = $this->configManager->getEntityTypeIdByName($config_name)) { $entity_type = $this->entityManager->getDefinition($entity_type_id); // Does this entity type define a bundle of another entity type. if ($bundle_of = $entity_type->getBundleOf()) { // Work out if there are entities with this bundle. $bundle_of_entity_type = $this->entityManager->getDefinition($bundle_of); $bundle_id = ConfigEntityStorage::getIDFromConfigName($config_name, $entity_type->getConfigPrefix()); $entity_query = $this->entityManager->getStorage($bundle_of)->getQuery(); $entity_ids = $entity_query->condition($bundle_of_entity_type->getKey('bundle'), $bundle_id)->accessCheck(FALSE)->range(0, 1)->execute(); if (!empty($entity_ids)) { $entity = $this->entityManager->getStorage($entity_type_id)->load($bundle_id); $event->getConfigImporter()->logError($this->t('Entities exist of type %entity_type and %bundle_label %bundle. These entities need to be deleted before importing.', array('%entity_type' => $bundle_of_entity_type->getLabel(), '%bundle_label' => $bundle_of_entity_type->getBundleLabel(), '%bundle' => $entity->label()))); } } } } }
/** * Constructs a GradeScaleStorageController object. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_info * The entity info for the entity type. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory service. * @param \Drupal\Component\Uuid\UuidInterface $uuid_service * The UUID service. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. */ public function __construct(EntityTypeInterface $entity_info, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager) { parent::__construct($entity_info, $config_factory, $uuid_service, $language_manager); $this->moduleHandler = $module_handler; }
/** * Overrides \Drupal\Core\Config\Entity\ConfigEntityStorage::importDelete(). */ public function importDelete($name, Config $new_config, Config $old_config) { // Set a global value we can check in test code. $GLOBALS['hook_config_import'] = __METHOD__; return parent::importDelete($name, $new_config, $old_config); }
/** * Tests the display related functions like getDisplaysList(). */ protected function displayMethodTests() { // Enable the system module so _l() can work using url_alias table. $this->installSchema('system', 'url_alias'); $config['display'] = array('page_1' => array('display_options' => array('path' => 'test'), 'display_plugin' => 'page', 'id' => 'page_2', 'display_title' => 'Page 1', 'position' => 1), 'feed_1' => array('display_options' => array('path' => 'test.xml'), 'display_plugin' => 'feed', 'id' => 'feed', 'display_title' => 'Feed', 'position' => 2), 'page_2' => array('display_options' => array('path' => 'test/%/extra'), 'display_plugin' => 'page', 'id' => 'page_2', 'display_title' => 'Page 2', 'position' => 3)); $view = $this->controller->create($config); // Tests Drupal\views\Entity\View::addDisplay() $view = $this->controller->create(array()); $random_title = $this->randomMachineName(); $id = $view->addDisplay('page', $random_title); $this->assertEqual($id, 'page_1', format_string('Make sure the first display (%id_new) has the expected ID (%id)', array('%id_new' => $id, '%id' => 'page_1'))); $display = $view->get('display'); $this->assertEqual($display[$id]['display_title'], $random_title); $random_title = $this->randomMachineName(); $id = $view->addDisplay('page', $random_title); $display = $view->get('display'); $this->assertEqual($id, 'page_2', format_string('Make sure the second display (%id_new) has the expected ID (%id)', array('%id_new' => $id, '%id' => 'page_2'))); $this->assertEqual($display[$id]['display_title'], $random_title); $id = $view->addDisplay('page'); $display = $view->get('display'); $this->assertEqual($display[$id]['display_title'], 'Page 3'); // Ensure the 'default' display always has position zero, regardless of when // it was set relative to other displays. Even if the 'default' display // exists, adding it again will overwrite it, which is asserted with the new // title. $view->addDisplay('default', $random_title); $displays = $view->get('display'); $this->assertEqual($displays['default']['display_title'], $random_title, 'Default display is defined with the new title'); $this->assertEqual($displays['default']['position'], 0, 'Default displays are always in position zero'); // Tests Drupal\views\Entity\View::generateDisplayId(). Since // generateDisplayId() is protected, we have to use reflection to unit-test // it. $view = $this->controller->create(array()); $ref_generate_display_id = new \ReflectionMethod($view, 'generateDisplayId'); $ref_generate_display_id->setAccessible(TRUE); $this->assertEqual($ref_generate_display_id->invoke($view, 'default'), 'default', 'The plugin ID for default is always default.'); $this->assertEqual($ref_generate_display_id->invoke($view, 'feed'), 'feed_1', 'The generated ID for the first instance of a plugin type should have an suffix of _1.'); $view->addDisplay('feed', 'feed title'); $this->assertEqual($ref_generate_display_id->invoke($view, 'feed'), 'feed_2', 'The generated ID for the first instance of a plugin type should have an suffix of _2.'); // Tests item related methods(). $view = $this->controller->create(array('base_table' => 'views_test_data')); $view->addDisplay('default'); $view = $view->getExecutable(); $display_id = 'default'; $expected_items = array(); // Tests addHandler with getItem. // Therefore add one item without any options and one item with some // options. $id1 = $view->addHandler($display_id, 'field', 'views_test_data', 'id'); $item1 = $view->getHandler($display_id, 'field', 'id'); $expected_items[$id1] = $expected_item = array('id' => 'id', 'table' => 'views_test_data', 'field' => 'id', 'plugin_id' => 'numeric'); $this->assertEqual($item1, $expected_item); $options = array('alter' => array('text' => $this->randomMachineName())); $id2 = $view->addHandler($display_id, 'field', 'views_test_data', 'name', $options); $item2 = $view->getHandler($display_id, 'field', 'name'); $expected_items[$id2] = $expected_item = array('id' => 'name', 'table' => 'views_test_data', 'field' => 'name', 'plugin_id' => 'standard') + $options; $this->assertEqual($item2, $expected_item); // Tests the expected fields from the previous additions. $this->assertEqual($view->getHandlers('field', $display_id), $expected_items); // Alter an existing item via setItem and check the result via getItem // and getItems. $item = array('alter' => array('text' => $this->randomMachineName())) + $item1; $expected_items[$id1] = $item; $view->setHandler($display_id, 'field', $id1, $item); $this->assertEqual($view->getHandler($display_id, 'field', 'id'), $item); $this->assertEqual($view->getHandlers('field', $display_id), $expected_items); // Test removeItem method. unset($expected_items[$id2]); $view->removeHandler($display_id, 'field', $id2); $this->assertEqual($view->getHandlers('field', $display_id), $expected_items); }
/** * Gets the list of fields to purge before configuration synchronization. * * If, during a configuration synchronization, a field is being deleted and * the module that provides the field type is being uninstalled then the field * data must be purged before the module is uninstalled. Also, if deleted * fields exist whose field types are provided by modules that are being * uninstalled their data need to be purged too. * * @param array $extensions * The list of extensions that will be enabled after the configuration * synchronization has finished. * @param array $deletes * The configuration that will be deleted by the configuration * synchronization. * * @return \Drupal\field\Entity\FieldStorageConfig[] * An array of field storages that need purging before configuration can be * synchronized. */ public static function getFieldStoragesToPurge(array $extensions, array $deletes) { $providers = array_keys($extensions['module']); $providers[] = 'core'; $storages_to_delete = array(); // Gather fields that will be deleted during configuration synchronization // where the module that provides the field type is also being uninstalled. $field_storage_ids = array(); foreach ($deletes as $config_name) { $field_storage_config_prefix = \Drupal::entityManager()->getDefinition('field_storage_config')->getConfigPrefix(); if (strpos($config_name, $field_storage_config_prefix . '.') === 0) { $field_storage_ids[] = ConfigEntityStorage::getIDFromConfigName($config_name, $field_storage_config_prefix); } } if (!empty($field_storage_ids)) { $field_storages = \Drupal::entityQuery('field_storage_config')->condition('id', $field_storage_ids, 'IN')->condition('module', $providers, 'NOT IN')->execute(); if (!empty($field_storages)) { $storages_to_delete = FieldStorageConfig::loadMultiple($field_storages); } } // Gather deleted fields from modules that are being uninstalled. /** @var \Drupal\field\FieldStorageConfigInterface[] $field_storages */ $field_storages = entity_load_multiple_by_properties('field_storage_config', array('deleted' => TRUE, 'include_deleted' => TRUE)); foreach ($field_storages as $field_storage) { if (!in_array($field_storage->getTypeProvider(), $providers)) { $storages_to_delete[$field_storage->id()] = $field_storage; } } return $storages_to_delete; }
/** * {@inheritdoc} */ public function delete(array $entities) { // After deleting a set of reaction rules, sometimes we may need to rebuild // the container, to clean it up, so that the generic subscriber is not // registered in the container for the rule events which we do not use // anymore. So we do that if there is any change in the registered events, // after the reaction rules are deleted. $events_before = $this->getRegisteredEvents(); $return = parent::delete($entities); $events_after = $this->getRegisteredEvents(); // Update the state of registered events and rebuild the container. if ($events_before != $events_after) { $this->stateService->set('rules.registered_events', $events_after); $this->drupalKernel->rebuildContainer(); } return $return; }
/** * {@inheritdoc} */ public function resetCache(array $ids = NULL) { drupal_static_reset('taxonomy_vocabulary_get_names'); parent::resetCache($ids); }
/** * {@inheritdoc} */ public function delete(array $entities) { $return = parent::delete($entities); // Update the state of registered events. // @todo Should we trigger a container rebuild here as well? Might be a bit // expensive on every delete? $this->stateService->set('rules.registered_events', $this->getRegisteredEvents()); return $return; }
/** * {@inheritdoc} */ public function delete(array $entities) { $return = parent::delete($entities); return $return; }