diff -u b/core/modules/media/src/Entity/MediaType.php b/core/modules/media/src/Entity/MediaType.php --- b/core/modules/media/src/Entity/MediaType.php +++ b/core/modules/media/src/Entity/MediaType.php @@ -3,13 +3,10 @@ namespace Drupal\media\Entity; use Drupal\Core\Config\Entity\ConfigEntityBundleBase; -use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityWithPluginCollectionInterface; use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection; -use Drupal\field\FieldStorageConfigInterface; use Drupal\media\MediaTypeInterface; use Drupal\media\MediaInterface; -use Drupal\media\SourceFieldInterface; /** * Defines the Media type configuration entity. @@ -225,68 +222,6 @@ /** * {@inheritdoc} */ - public function preSave(EntityStorageInterface $storage) { - // If the handler uses a source field, we'll need to store its name before - // saving. We'd need to double-save if we did this in postSave(). - $handler = $this->getHandler(); - if ($handler instanceof SourceFieldInterface) { - $field_storage = $handler->getSourceField($this)->getFieldStorageDefinition(); - // If the field storage is a new (unsaved) config entity, save it. - if ($field_storage instanceof FieldStorageConfigInterface && $field_storage->isNew()) { - $field_storage->save(); - } - } - - parent::preSave($storage); - } - - /** - * {@inheritdoc} - */ - public function postSave(EntityStorageInterface $storage, $update = TRUE) { - parent::postSave($storage, $update); - - // If the handler is using a source field, we may need to save it if it's - // new. The field storage is guaranteed to exist already because preSave() - // took care of that. - $handler = $this->getHandler(); - if ($handler instanceof SourceFieldInterface) { - $field = $handler->getSourceField($this); - - // If the field is new, save it and add it to this bundle's view and form - // displays. - if ($field->isNew()) { - // Ensure the field is saved correctly before adding it to the displays. - $field->save(); - - $entity_type = $field->getTargetEntityTypeId(); - $bundle = $field->getTargetBundle(); - - if ($field->isDisplayConfigurable('form')) { - // Use the default widget and settings. - $component = \Drupal::service('plugin.manager.field.widget') - ->prepareConfiguration($field->getType(), []); - - entity_get_form_display($entity_type, $bundle, 'default') - ->setComponent($field->getName(), $component) - ->save(); - } - if ($field->isDisplayConfigurable('view')) { - // Use the default formatter and settings. - $component = \Drupal::service('plugin.manager.field.formatter') - ->prepareConfiguration($field->getType(), []); - - entity_get_display($entity_type, $bundle, 'default') - ->setComponent($field->getName(), $component) - ->save(); - } - } - } - } - - /** - * {@inheritdoc} - */ public function getFieldMap() { return $this->field_map; } diff -u b/core/modules/media/src/MediaHandlerBase.php b/core/modules/media/src/MediaHandlerBase.php --- b/core/modules/media/src/MediaHandlerBase.php +++ b/core/modules/media/src/MediaHandlerBase.php @@ -10,6 +10,7 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\field\FieldStorageConfigInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -218,7 +219,7 @@ /** * {@inheritdoc} */ - public function getSourceField(MediaTypeInterface $type, $retry = TRUE) { + public function getSourceField(MediaTypeInterface $type) { // If we don't know the name of the source field, we definitely need to // create it. if (empty($this->configuration['source_field'])) { @@ -241,9 +242,7 @@ // If we don't know the name of the source field, we definitely need to // create its storage. if (empty($this->configuration['source_field'])) { - $storage = $this->createSourceFieldStorage(); - $this->configuration['source_field'] = $storage->getName(); - return $storage; + return $this->createSourceFieldStorage(); } // Even if we do know the name of the source field, we cannot guarantee that // its storage exists. So check for the storage and create it if needed. @@ -262,11 +261,13 @@ * The unsaved field storage definition. */ protected function createSourceFieldStorage() { + $this->configuration['source_field'] = $this->getSourceFieldName(); + return $this->entityTypeManager ->getStorage('field_storage_config') ->create([ 'entity_type' => 'media', - 'field_name' => $this->getSourceFieldName(), + 'field_name' => $this->configuration['source_field'], 'type' => reset($this->pluginDefinition['allowed_field_types']), 'locked' => TRUE, ]); diff -u b/core/modules/media/src/MediaTypeForm.php b/core/modules/media/src/MediaTypeForm.php --- b/core/modules/media/src/MediaTypeForm.php +++ b/core/modules/media/src/MediaTypeForm.php @@ -9,6 +9,7 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\SubformState; +use Drupal\field\FieldStorageConfigInterface; use Drupal\media\Entity\MediaType; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -262,10 +263,9 @@ * Sub-form state for the handler configuration form. */ protected function getHandlerSubFormState(array $form, FormStateInterface $form_state) { - $subform_state = SubformState::createForSubform($form['handler_dependent']['handler_configuration'], $form, $form_state); - $subform_state->set('operation', $this->operation); - $subform_state->set('type', $this->entity); - return $subform_state; + return SubformState::createForSubform($form['handler_dependent']['handler_configuration'], $form, $form_state) + ->set('operation', $this->operation) + ->set('type', $this->entity); } /** @@ -318,9 +318,55 @@ * {@inheritdoc} */ public function save(array $form, FormStateInterface $form_state) { - $status = parent::save($form, $form_state); $bundle = $this->entity; + // If the handler uses a source field, we'll need to store its name before + // saving. We'd need to double-save if we did this in postSave(). + $handler = $bundle->getHandler(); + if ($handler instanceof SourceFieldInterface) { + $field = $handler->getSourceField($bundle); + $status = parent::save($form, $form_state); + + $field_storage = $field->getFieldStorageDefinition(); + // If the field storage is a new (unsaved) config entity, save it. + if ($field_storage instanceof FieldStorageConfigInterface && $field_storage->isNew()) { + $field_storage->save(); + } + + // If the field is new, save it and add it to this bundle's view and form + // displays. + if ($field->isNew()) { + // Ensure the field is saved correctly before adding it to the displays. + $field->save(); + + $entity_type = $field->getTargetEntityTypeId(); + $targetBundle = $field->getTargetBundle(); + + if ($field->isDisplayConfigurable('form')) { + // Use the default widget and settings. + $component = \Drupal::service('plugin.manager.field.widget') + ->prepareConfiguration($field->getType(), []); + + entity_get_form_display($entity_type, $targetBundle, 'default') + ->setComponent($field->getName(), $component) + ->save(); + } + if ($field->isDisplayConfigurable('view')) { + // Use the default formatter and settings. + $component = \Drupal::service('plugin.manager.field.formatter') + ->prepareConfiguration($field->getType(), []); + + entity_get_display($entity_type, $targetBundle, 'default') + ->setComponent($field->getName(), $component) + ->save(); + } + } + } else { + $status = parent::save($form, $form_state); + } + + + $t_args = ['%name' => $bundle->label()]; if ($status == SAVED_UPDATED) { drupal_set_message($this->t('The media type %name has been updated.', $t_args)); diff -u b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php --- b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaJavascriptTestBase.php @@ -12,10 +12,6 @@ */ abstract class MediaJavascriptTestBase extends JavascriptTestBase { - use MediaFunctionalTestTrait { - createMediaType as drupalCreateMediaType; - } - /** * Modules to enable. * @@ -111,2 +107,42 @@ + /** + * Creates a media type over the UI. + * + * @param array $values + * The media type values. + * @param string $handler + * (optional) The handler plugin that is responsible for additional logic + * related to this media type. + * + * @return \Drupal\media\MediaTypeInterface + * A newly created media type. + */ + protected function createMediaTypeViaUi(array $values = [], $handler = 'test') { + if (!isset($values['bundle'])) { + $id = strtolower($this->randomMachineName()); + } + else { + $id = $values['bundle']; + } + + $session = $this->getSession(); + $page = $session->getPage(); + + $this->drupalGet('admin/structure/media/add'); + $page->fillField('label', $id); + $machine_name = strtolower($id); + $this->assertJsCondition("jQuery('.machine-name-value').html() == '$machine_name'"); + $page->selectFieldOption('handler', $handler); + $this->assertSession()->assertWaitOnAjaxRequest(); + + $page->pressButton('Save'); + + $assert_session = $this->assertSession(); + $assert_session->pageTextContains('The media type ' . $id . ' has been added.'); + + + return $this->container->get('entity_type.manager') + ->getStorage('media_type') + ->load($machine_name); + } } diff -u b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php --- b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php @@ -165,7 +165,7 @@ $assert_session->pageTextContains('The media type ' . $new_name . ' has been deleted.'); // Test bundle delete prevention when there is existing media. - $bundle2 = $this->drupalCreateMediaType(); + $bundle2 = $this->createMediaTypeViaUi(); $label2 = $bundle2->label(); $media = Media::create(['name' => 'lorem ipsum', 'bundle' => $bundle2->id()]); $media->save(); diff -u b/core/modules/media/tests/src/Kernel/BasicCreationTest.php b/core/modules/media/tests/src/Kernel/BasicCreationTest.php --- b/core/modules/media/tests/src/Kernel/BasicCreationTest.php +++ b/core/modules/media/tests/src/Kernel/BasicCreationTest.php @@ -76,7 +76,7 @@ $this->assertEquals('Test type', $test_bundle->get('label'), 'Could not assure the correct type name.'); $this->assertEquals('Test type.', $test_bundle->get('description'), 'Could not assure the correct type description.'); $this->assertEquals('test', $test_bundle->get('handler'), 'Could not assure the correct handler.'); - $this->assertEquals(['source_field' => 'field_media_test_1', 'test_config_value' => 'Kakec'], $test_bundle->get('handler_configuration'), 'Could not assure the correct handler configuration.'); + $this->assertEquals(['source_field' => '', 'test_config_value' => 'Kakec'], $test_bundle->get('handler_configuration'), 'Could not assure the correct handler configuration.'); $this->assertEquals([], $test_bundle->get('field_map'), 'Could not assure the correct field map.'); } @@ -112,14 +112,17 @@ */ public function testProgrammaticBundleManipulation() { // Creating a bundle programmatically without specifying a source field - // should create one automagically. + // should create one but it has to be saved programmatically too. /** @var FieldConfig $field */ $field = $this->testBundle->getHandler()->getSourceField($this->testBundle); $this->assertInstanceOf(FieldConfig::class, $field); $this->assertEquals('field_media_test', $field->getName()); + $field->getFieldStorageDefinition()->save(); + $field->save(); $this->assertFalse($field->isNew()); - // Saving with a non-existent source field should create it. + // Saving with a non-existent source field should create one but it has to + // be saved programmatically. $this->testBundle->getHandler()->setConfiguration([ 'source_field' => 'field_magick', ]); @@ -127,7 +130,7 @@ $field = $this->testBundle->getHandler()->getSourceField($this->testBundle); $this->assertInstanceOf(FieldConfig::class, $field); $this->assertEquals('field_magick', $field->getName()); - $this->assertFalse($field->isNew()); + $this->assertTrue($field->isNew()); // Trying to save without a source field should create a new, de-duped one. $this->testBundle->getHandler()->setConfiguration([]); @@ -135,6 +138,8 @@ $field = $this->testBundle->getHandler()->getSourceField($this->testBundle); $this->assertInstanceOf(FieldConfig::class, $field); $this->assertEquals('field_media_test_1', $field->getName()); + $field->getFieldStorageDefinition()->save(); + $field->save(); $this->assertFalse($field->isNew()); // Trying to reuse an existing field should, well, reuse the existing field. @@ -145,6 +150,8 @@ $field = $this->testBundle->getHandler()->getSourceField($this->testBundle); $this->assertInstanceOf(FieldConfig::class, $field); $this->assertEquals('field_magick', $field->getName()); + $field->getFieldStorageDefinition()->save(); + $field->save(); $this->assertFalse($field->isNew()); // No new de-duped fields should have been created. $duplicates = FieldConfig::loadMultiple([