/** * Tests storage methods. */ public function testStorageMethods() { $entity_type = \Drupal::entityManager()->getDefinition('config_test'); // Test the static extractID() method. $expected_id = 'test_id'; $config_name = $entity_type->getConfigPrefix() . '.' . $expected_id; $storage = $this->storage; $this->assertIdentical($storage::getIDFromConfigName($config_name, $entity_type->getConfigPrefix()), $expected_id); // Create three entities, two with the same style. $style = $this->randomMachineName(8); for ($i = 0; $i < 2; $i++) { $entity = $this->storage->create(array('id' => $this->randomMachineName(), 'label' => $this->randomString(), 'style' => $style)); $entity->save(); } $entity = $this->storage->create(array('id' => $this->randomMachineName(), 'label' => $this->randomString(), 'style' => $this->randomMachineName(9))); $entity->save(); // Ensure that the configuration entity can be loaded by UUID. $entity_loaded_by_uuid = entity_load_by_uuid($entity_type->id(), $entity->uuid()); if (!$entity_loaded_by_uuid) { $this->fail(sprintf("Failed to load '%s' entity ID '%s' by UUID '%s'.", $entity_type->id(), $entity->id(), $entity->uuid())); } // Compare UUIDs as the objects are not identical since // $entity->enforceIsNew is FALSE and $entity_loaded_by_uuid->enforceIsNew // is NULL. $this->assertIdentical($entity->uuid(), $entity_loaded_by_uuid->uuid()); $entities = $this->storage->loadByProperties(); $this->assertEqual(count($entities), 3, 'Three entities are loaded when no properties are specified.'); $entities = $this->storage->loadByProperties(array('style' => $style)); $this->assertEqual(count($entities), 2, 'Two entities are loaded when the style property is specified.'); // Assert that both returned entities have a matching style property. foreach ($entities as $entity) { $this->assertIdentical($entity->get('style'), $style, 'The loaded entity has the correct style value specified.'); } }
/** * {@inheritdoc} * * @param \Drupal\filter\Entity\FilterFormat $filter_format * The filter format for which this dialog corresponds. */ public function buildForm(array $form, array &$form_state, FilterFormat $filter_format = NULL) { // The default values are set directly from \Drupal::request()->request, // provided by the editor plugin opening the dialog. if (!isset($form_state['image_element'])) { $form_state['image_element'] = isset($form_state['input']['editor_object']) ? $form_state['input']['editor_object'] : array(); } $image_element = $form_state['image_element']; $form['#tree'] = TRUE; $form['#attached']['library'][] = 'editor/drupal.editor.dialog'; $form['#prefix'] = '<div id="editor-image-dialog-form">'; $form['#suffix'] = '</div>'; $editor = editor_load($filter_format->format); // Construct strings to use in the upload validators. $image_upload = $editor->getImageUploadSettings(); if (!empty($image_upload['dimensions'])) { $max_dimensions = $image_upload['dimensions']['max_width'] . 'x' . $image_upload['dimensions']['max_height']; } else { $max_dimensions = 0; } $max_filesize = min(Bytes::toInt($image_upload['max_size']), file_upload_max_size()); $existing_file = isset($image_element['data-editor-file-uuid']) ? entity_load_by_uuid('file', $image_element['data-editor-file-uuid']) : NULL; $fid = $existing_file ? $existing_file->id() : NULL; $form['fid'] = array('#title' => $this->t('Image'), '#type' => 'managed_file', '#upload_location' => $image_upload['scheme'] . '://' . $image_upload['directory'], '#default_value' => $fid ? array($fid) : NULL, '#upload_validators' => array('file_validate_extensions' => array('gif png jpg jpeg'), 'file_validate_size' => array($max_filesize), 'file_validate_image_resolution' => array($max_dimensions)), '#required' => TRUE); $form['attributes']['src'] = array('#title' => $this->t('URL'), '#type' => 'textfield', '#default_value' => isset($image_element['src']) ? $image_element['src'] : '', '#maxlength' => 2048, '#required' => TRUE); // If the editor has image uploads enabled, show a managed_file form item, // otherwise show a (file URL) text form item. if ($image_upload['status']) { $form['attributes']['src']['#access'] = FALSE; $form['attributes']['src']['#required'] = FALSE; } else { $form['fid']['#access'] = FALSE; $form['fid']['#required'] = FALSE; } $form['attributes']['alt'] = array('#title' => $this->t('Alternative text'), '#type' => 'textfield', '#required' => TRUE, '#default_value' => isset($image_element['alt']) ? $image_element['alt'] : '', '#maxlength' => 2048); $form['dimensions'] = array('#type' => 'item', '#title' => $this->t('Image size'), '#field_prefix' => '<div class="container-inline">', '#field_suffix' => '</div>'); $form['dimensions']['width'] = array('#title' => $this->t('Width'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['width']) ? $image_element['width'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('width'), '#field_suffix' => ' x ', '#parents' => array('attributes', 'width')); $form['dimensions']['height'] = array('#title' => $this->t('Height'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['height']) ? $image_element['height'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('height'), '#field_suffix' => $this->t('pixels'), '#parents' => array('attributes', 'height')); // When Drupal core's filter_caption is being used, the text editor may // offer the ability to change the alignment. if (isset($image_element['data-align'])) { $form['align'] = array('#title' => $this->t('Align'), '#type' => 'radios', '#options' => array('none' => $this->t('None'), 'left' => $this->t('Left'), 'center' => $this->t('Center'), 'right' => $this->t('Right')), '#default_value' => $image_element['data-align'] === '' ? 'none' : $image_element['data-align'], '#wrapper_attributes' => array('class' => array('container-inline')), '#attributes' => array('class' => array('container-inline')), '#parents' => array('attributes', 'data-align')); } // When Drupal core's filter_caption is being used, the text editor may // offer the ability to in-place edit the image's caption: show a toggle. if (isset($image_element['hasCaption'])) { $form['caption'] = array('#title' => $this->t('Caption'), '#type' => 'checkbox', '#default_value' => $image_element['hasCaption'] === 'true', '#parents' => array('attributes', 'hasCaption')); } $form['actions'] = array('#type' => 'actions'); $form['actions']['save_modal'] = array('#type' => 'submit', '#value' => $this->t('Save'), '#submit' => array(), '#ajax' => array('callback' => array($this, 'submitForm'), 'event' => 'click')); return $form; }
/** * Executes the UUID CRUD tests for the given entity type. * * @param string $entity_type * The entity type to run the tests with. */ protected function assertCRUD($entity_type) { // Verify that no UUID is auto-generated when passing one for creation. $uuid_service = $this->container->get('uuid'); $uuid = $uuid_service->generate(); $custom_entity = entity_create($entity_type, array('name' => $this->randomMachineName(), 'uuid' => $uuid)); $this->assertIdentical($custom_entity->uuid(), $uuid); // Save this entity, so we have more than one later. $custom_entity->save(); // Verify that a new UUID is generated upon creating an entity. $entity = entity_create($entity_type, array('name' => $this->randomMachineName())); $uuid = $entity->uuid(); $this->assertTrue($uuid); // Verify that the new UUID is different. $this->assertNotEqual($custom_entity->uuid(), $uuid); // Verify that the UUID is retained upon saving. $entity->save(); $this->assertIdentical($entity->uuid(), $uuid); // Verify that the UUID is retained upon loading. $entity_loaded = entity_load($entity_type, $entity->id(), TRUE); $this->assertIdentical($entity_loaded->uuid(), $uuid); // Verify that entity_load_by_uuid() loads the same entity. $entity_loaded_by_uuid = entity_load_by_uuid($entity_type, $uuid, TRUE); $this->assertIdentical($entity_loaded_by_uuid->uuid(), $uuid); $this->assertEqual($entity_loaded_by_uuid->id(), $entity_loaded->id()); // Creating a duplicate needs to result in a new UUID. $entity_duplicate = $entity->createDuplicate(); foreach ($entity->getProperties() as $property => $value) { switch ($property) { case 'uuid': $this->assertNotNull($entity_duplicate->uuid()); $this->assertNotNull($entity->uuid()); $this->assertNotEqual($entity_duplicate->uuid(), $entity->uuid()); break; case 'id': $this->assertNull($entity_duplicate->id()); $this->assertNotNull($entity->id()); $this->assertNotEqual($entity_duplicate->id(), $entity->id()); break; case 'revision_id': $this->assertNull($entity_duplicate->getRevisionId()); $this->assertNotNull($entity->getRevisionId()); $this->assertNotEqual($entity_duplicate->getRevisionId(), $entity->getRevisionId()); $this->assertNotEqual($entity_duplicate->{$property}->getValue(), $entity->{$property}->getValue()); break; default: $this->assertEqual($entity_duplicate->{$property}->getValue(), $entity->{$property}->getValue()); } } $entity_duplicate->save(); $this->assertNotEqual($entity->id(), $entity_duplicate->id()); }
/** * Tests deleting fields and instances 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 = entity_create('field_storage_config', array('name' => 'field_int', 'entity_type' => 'entity_test', 'type' => 'integer')); $unrelated_field_storage->save(); entity_create('field_instance_config', array('field_storage' => $unrelated_field_storage, 'bundle' => 'entity_test'))->save(); // Create a telephone field and instance for validation. $field_storage = entity_create('field_storage_config', array('name' => 'field_test', 'entity_type' => 'entity_test', 'type' => 'telephone')); $field_storage->save(); entity_create('field_instance_config', array('field_storage' => $field_storage, 'bundle' => 'entity_test'))->save(); $entity = entity_create('entity_test'); $value = '+0123456789'; $entity->field_test = $value; $entity->field_int = '99'; $entity->name->value = $this->randomName(); $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'); $staging = $this->container->get('config.storage.staging'); $this->copyConfig($active, $staging); // Stage uninstall of the Telephone module. $core_extension = \Drupal::config('core.extension')->get(); unset($core_extension['module']['telephone']); $staging->write('core.extension', $core_extension); // Stage the field deletion $staging->delete('field.storage.entity_test.field_test'); $staging->delete('field.instance.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(entity_load_by_uuid('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 deleting field storages and fields as part of config import. */ public function testImportDeleteUninstall() { // Create a telephone field. $field_storage = entity_create('field_storage_config', array('field_name' => 'field_tel', 'entity_type' => 'entity_test', 'type' => 'telephone')); $field_storage->save(); entity_create('field_config', array('field_storage' => $field_storage, 'bundle' => 'entity_test'))->save(); // Create a text field. $text_field_storage = entity_create('field_storage_config', array('field_name' => 'field_text', 'entity_type' => 'entity_test', 'type' => 'text')); $text_field_storage->save(); entity_create('field_config', array('field_storage' => $text_field_storage, 'bundle' => 'entity_test'))->save(); // Create an entity which has values for the telephone and text field. $entity = entity_create('entity_test'); $value = '+0123456789'; $entity->field_tel = $value; $entity->field_text = $this->randomMachineName(20); $entity->name->value = $this->randomMachineName(); $entity->save(); // Delete the text field before exporting configuration so that we can test // that deleted fields that are provided by modules that will be uninstalled // are also purged and that the UI message includes such fields. $text_field_storage->delete(); // Verify entity has been created properly. $id = $entity->id(); $entity = entity_load('entity_test', $id); $this->assertEqual($entity->field_tel->value, $value); $this->assertEqual($entity->field_tel[0]->value, $value); $active = $this->container->get('config.storage'); $staging = $this->container->get('config.storage.staging'); $this->copyConfig($active, $staging); // Stage uninstall of the Telephone module. $core_extension = \Drupal::config('core.extension')->get(); unset($core_extension['module']['telephone']); $staging->write('core.extension', $core_extension); // Stage the field deletion $staging->delete('field.storage.entity_test.field_tel'); $staging->delete('field.field.entity_test.entity_test.field_tel'); $this->drupalGet('admin/config/development/configuration'); // Test that the message for one field being purged during a configuration // synchronization is correct. $this->assertText('This synchronization will delete data from the field entity_test.field_tel.'); // Stage an uninstall of the text module to test the message for multiple // fields. unset($core_extension['module']['text']); $staging->write('core.extension', $core_extension); $this->drupalGet('admin/config/development/configuration'); $this->assertText('This synchronization will delete data from the fields: entity_test.field_tel, entity_test.field_text.'); // Delete all the text fields in staging, entity_test_install() adds quite // a few. foreach (\Drupal::entityManager()->getFieldMap() as $entity_type => $fields) { foreach ($fields as $field_name => $info) { if ($info['type'] == 'text') { $staging->delete("field.storage.{$entity_type}.{$field_name}"); $staging->delete("field.field.{$entity_type}.{$entity_type}.{$field_name}"); } } } // This will purge all the data, delete the field and uninstall the // Telephone and Text modules. $this->drupalPostForm(NULL, array(), t('Import all')); $this->assertNoText('Field data will be deleted by this synchronization.'); $this->rebuildContainer(); $this->assertFalse(\Drupal::moduleHandler()->moduleExists('telephone')); $this->assertFalse(entity_load_by_uuid('field_storage_config', $field_storage->uuid()), 'The telephone 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->assertFalse(isset($deleted_storages[$field_storage->uuid()]), 'Text field has been completed removed from the system.'); }
/** * {@inheritdoc} */ public function build() { $uuid = $this->getDerivativeId(); if ($block = entity_load_by_uuid('block_content', $uuid)) { return entity_view($block, $this->configuration['view_mode']); } else { return array('#markup' => t('Block with uuid %uuid does not exist. <a href="!url">Add custom block</a>.', array('%uuid' => $uuid, '!url' => url('block/add'))), '#access' => $this->account->hasPermission('administer blocks')); } }
/** * Loads a single file and ensure that the correct values are returned. */ public function testUuidValues() { // Create a new file entity from scratch so we know the values. $file = $this->createFile('druplicon.txt', NULL, 'public'); $file->save(); file_test_reset(); $by_uuid_file = entity_load_by_uuid('file', $file->uuid()); $this->assertFileHookCalled('load'); $this->assertTrue(is_object($by_uuid_file), 'entity_load_by_uuid() returned a file object.'); if (is_object($by_uuid_file)) { $this->assertEqual($by_uuid_file->id(), $file->id(), 'Loading by UUID got the same fid.', 'File'); $this->assertTrue($by_uuid_file->file_test['loaded'], 'file_test_file_load() was able to modify the file during load.'); } }
/** * {@inheritdoc} * * @param \Drupal\filter\Entity\FilterFormat $filter_format * The filter format for which this dialog corresponds. */ public function buildForm(array $form, FormStateInterface $form_state, FilterFormat $filter_format = NULL) { // The default values are set directly from \Drupal::request()->request, // provided by the editor plugin opening the dialog. if (!($image_element = $form_state->get('image_element'))) { $user_input = $form_state->getUserInput(); $image_element = isset($user_input['editor_object']) ? $user_input['editor_object'] : []; $form_state->set('image_element', $image_element); } $form['#tree'] = TRUE; $form['#attached']['library'][] = 'editor/drupal.editor.dialog'; $form['#prefix'] = '<div id="editor-image-dialog-form">'; $form['#suffix'] = '</div>'; $editor = editor_load($filter_format->format); // Construct strings to use in the upload validators. $image_upload = $editor->getImageUploadSettings(); if (!empty($image_upload['dimensions'])) { $max_dimensions = $image_upload['dimensions']['max_width'] . '×' . $image_upload['dimensions']['max_height']; } else { $max_dimensions = 0; } $max_filesize = min(Bytes::toInt($image_upload['max_size']), file_upload_max_size()); $existing_file = isset($image_element['data-editor-file-uuid']) ? entity_load_by_uuid('file', $image_element['data-editor-file-uuid']) : NULL; $fid = $existing_file ? $existing_file->id() : NULL; $form['fid'] = array('#title' => $this->t('Image'), '#type' => 'managed_file', '#upload_location' => $image_upload['scheme'] . '://' . $image_upload['directory'], '#default_value' => $fid ? array($fid) : NULL, '#upload_validators' => array('file_validate_extensions' => array('gif png jpg jpeg'), 'file_validate_size' => array($max_filesize), 'file_validate_image_resolution' => array($max_dimensions)), '#required' => TRUE); $form['attributes']['src'] = array('#title' => $this->t('URL'), '#type' => 'textfield', '#default_value' => isset($image_element['src']) ? $image_element['src'] : '', '#maxlength' => 2048, '#required' => TRUE); // If the editor has image uploads enabled, show a managed_file form item, // otherwise show a (file URL) text form item. if ($image_upload['status']) { $form['attributes']['src']['#access'] = FALSE; $form['attributes']['src']['#required'] = FALSE; } else { $form['fid']['#access'] = FALSE; $form['fid']['#required'] = FALSE; } // The alt attribute is *required*, but we allow users to opt-in to empty // alt attributes for the very rare edge cases where that is valid by // specifying two double quotes as the alternative text in the dialog. // However, that *is* stored as an empty alt attribute, so if we're editing // an existing image (which means the src attribute is set) and its alt // attribute is empty, then we show that as two double quotes in the dialog. // @see https://www.drupal.org/node/2307647 $alt = isset($image_element['alt']) ? $image_element['alt'] : ''; if ($alt === '' && !empty($image_element['src'])) { $alt = '""'; } $form['attributes']['alt'] = array('#title' => $this->t('Alternative text'), '#placeholder' => $this->t('Short description for the visually impaired'), '#type' => 'textfield', '#required' => TRUE, '#required_error' => $this->t('Alternative text is required.<br><em>(Only in rare cases should this be left empty. To create empty alternative text, enter <code>""</code> — two double quotes without any content).'), '#default_value' => $alt, '#maxlength' => 2048); $form['dimensions'] = array('#type' => 'fieldset', '#title' => $this->t('Image size'), '#attributes' => array('class' => array('container-inline', 'fieldgroup', 'form-composite'))); $form['dimensions']['width'] = array('#title' => $this->t('Width'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['width']) ? $image_element['width'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('width'), '#field_suffix' => ' × ', '#parents' => array('attributes', 'width')); $form['dimensions']['height'] = array('#title' => $this->t('Height'), '#title_display' => 'invisible', '#type' => 'number', '#default_value' => isset($image_element['height']) ? $image_element['height'] : '', '#size' => 8, '#maxlength' => 8, '#min' => 1, '#max' => 99999, '#placeholder' => $this->t('height'), '#field_suffix' => $this->t('pixels'), '#parents' => array('attributes', 'height')); // When Drupal core's filter_align is being used, the text editor may // offer the ability to change the alignment. if (isset($image_element['data-align']) && $filter_format->filters('filter_align')->status) { $form['align'] = array('#title' => $this->t('Align'), '#type' => 'radios', '#options' => array('none' => $this->t('None'), 'left' => $this->t('Left'), 'center' => $this->t('Center'), 'right' => $this->t('Right')), '#default_value' => $image_element['data-align'] === '' ? 'none' : $image_element['data-align'], '#wrapper_attributes' => array('class' => array('container-inline')), '#attributes' => array('class' => array('container-inline')), '#parents' => array('attributes', 'data-align')); } // When Drupal core's filter_caption is being used, the text editor may // offer the ability to in-place edit the image's caption: show a toggle. if (isset($image_element['hasCaption']) && $filter_format->filters('filter_caption')->status) { $form['caption'] = array('#title' => $this->t('Caption'), '#type' => 'checkbox', '#default_value' => $image_element['hasCaption'] === 'true', '#parents' => array('attributes', 'hasCaption')); } $form['actions'] = array('#type' => 'actions'); $form['actions']['save_modal'] = array('#type' => 'submit', '#value' => $this->t('Save'), '#submit' => array(), '#ajax' => array('callback' => '::submitForm', 'event' => 'click')); return $form; }