diff --git a/core/modules/media/src/Entity/MediaType.php b/core/modules/media/src/Entity/MediaType.php index 7ea70a8..908b837 100644 --- a/core/modules/media/src/Entity/MediaType.php +++ b/core/modules/media/src/Entity/MediaType.php @@ -134,6 +134,13 @@ class MediaType extends ConfigEntityBundleBase implements MediaTypeInterface, En protected $field_map = []; /** + * Whether to auto-create source filed. + * + * @var bool + */ + protected $auto_create_source_field = FALSE; + + /** * {@inheritdoc} */ public function getPluginCollections() { @@ -229,7 +236,7 @@ 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) { + if ($this->auto_create_source_field && $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()) { @@ -250,7 +257,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) { // new. The field storage is guaranteed to exist already because preSave() // took care of that. $handler = $this->getHandler(); - if ($handler instanceof SourceFieldInterface) { + if ($this->auto_create_source_field && $handler instanceof SourceFieldInterface) { $field = $handler->getSourceField($this); // If the field is new, save it and add it to this bundle's view and form diff --git a/core/modules/media/src/MediaHandlerBase.php b/core/modules/media/src/MediaHandlerBase.php index 579e546..19887c1 100644 --- a/core/modules/media/src/MediaHandlerBase.php +++ b/core/modules/media/src/MediaHandlerBase.php @@ -333,4 +333,16 @@ public function mapFieldValue(MediaInterface $media, $source_field, $destination } } + /** + * {@inheritdoc} + */ + public function getSourceValue(MediaInterface $media) { + // Source value is stored as the main property of the source field in 99% of + // the cases so return that. 1% can override this function and tweak the + // logic. + /** @var \Drupal\Core\Field\FieldItemInterface $field_item */ + $field_item = $media->get($this->configuration['source_field'])->first(); + return $field_item->get($field_item->mainPropertyName()); + } + } diff --git a/core/modules/media/src/MediaTypeForm.php b/core/modules/media/src/MediaTypeForm.php index 0542917..399c27b 100644 --- a/core/modules/media/src/MediaTypeForm.php +++ b/core/modules/media/src/MediaTypeForm.php @@ -262,10 +262,9 @@ protected function getWorkflowOptions() { * 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,6 +317,7 @@ protected function actions(array $form, FormStateInterface $form_state) { * {@inheritdoc} */ public function save(array $form, FormStateInterface $form_state) { + $this->entity->set('auto_create_source_field', TRUE); $status = parent::save($form, $form_state); $bundle = $this->entity; diff --git a/core/modules/media/src/SourceFieldInterface.php b/core/modules/media/src/SourceFieldInterface.php index 2c35af5..d46d3d3 100644 --- a/core/modules/media/src/SourceFieldInterface.php +++ b/core/modules/media/src/SourceFieldInterface.php @@ -18,4 +18,17 @@ */ public function getSourceField(MediaTypeInterface $type); + /** + * Gets source value. + * + * Value that is stored in the source field. + * + * @param MediaInterface $media + * The media entity class. + * + * @return \Drupal\Core\TypedData\TypedDataInterface + * The source value. + */ + public function getSourceValue(MediaInterface $media); + } diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php index 097629a..c61ffe1 100644 --- a/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php +++ b/core/modules/media/tests/src/FunctionalJavascript/MediaUiJavascriptTest.php @@ -165,7 +165,7 @@ public function testMediaBundles() { $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->drupalCreateMediaType(['auto_create_source_field' => TRUE]); $label2 = $bundle2->label(); $media = Media::create(['name' => 'lorem ipsum', 'bundle' => $bundle2->id()]); $media->save(); diff --git a/core/modules/media/tests/src/Kernel/BasicCreationTest.php b/core/modules/media/tests/src/Kernel/BasicCreationTest.php index ab04078..8b2eb9b 100644 --- a/core/modules/media/tests/src/Kernel/BasicCreationTest.php +++ b/core/modules/media/tests/src/Kernel/BasicCreationTest.php @@ -2,6 +2,8 @@ namespace Drupal\Tests\media\Kernel; +use Drupal\Core\TypedData\PrimitiveInterface; +use Drupal\Core\TypedData\TypedDataInterface; use Drupal\field\Entity\FieldConfig; use Drupal\KernelTests\KernelTestBase; use Drupal\media\Entity\Media; @@ -57,6 +59,7 @@ protected function setUp() { 'label' => $id, 'handler' => 'test', 'new_revision' => FALSE, + 'auto_create_source_field' => TRUE, ]); $this->testBundle->save(); } @@ -76,7 +79,9 @@ public function testMediaBundleCreation() { $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.'); + // Source field is not set on the handler, but it should never be created + // automatically when a config is being imported. + $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.'); } @@ -87,6 +92,7 @@ public function testMediaEntityCreation() { $media = Media::create([ 'bundle' => $this->testBundle->id(), 'name' => 'Unnamed', + 'field_media_test' => 'Nation of sheep, ruled by wolves, owned by pigs.', ]); $media->save(); @@ -95,6 +101,7 @@ public function testMediaEntityCreation() { $this->assertInstanceOf(MediaInterface::class, Media::load($media->id()), 'The new media entity has not been created in the database.'); $this->assertEquals($this->testBundle->id(), $media->bundle(), 'The media was not created with the correct type.'); $this->assertEquals('Unnamed', $media->label(), 'The media was not created with the correct name.'); + $this->assertEquals('Nation of sheep, ruled by wolves, owned by pigs.', $media->bundle->entity->getHandler()->getSourceValue($media)->getValue() , 'Handler returns correct source value.'); // Test the creation of a media without user-defined label and check if a // default name is provided. @@ -119,10 +126,12 @@ public function testProgrammaticBundleManipulation() { $this->assertEquals('field_media_test', $field->getName()); $this->assertFalse($field->isNew()); - // Saving with a non-existent source field should create it. + // Saving with a non-existent source field should create it if the related + // flag is set. $this->testBundle->getHandler()->setConfiguration([ 'source_field' => 'field_magick', ]); + $this->testBundle->set('auto_create_source_field', TRUE); $this->testBundle->save(); $field = $this->testBundle->getHandler()->getSourceField($this->testBundle); $this->assertInstanceOf(FieldConfig::class, $field); @@ -131,16 +140,19 @@ public function testProgrammaticBundleManipulation() { // Trying to save without a source field should create a new, de-duped one. $this->testBundle->getHandler()->setConfiguration([]); + $this->testBundle->set('auto_create_source_field', TRUE); $this->testBundle->save(); $field = $this->testBundle->getHandler()->getSourceField($this->testBundle); $this->assertInstanceOf(FieldConfig::class, $field); $this->assertEquals('field_media_test_1', $field->getName()); $this->assertFalse($field->isNew()); - // Trying to reuse an existing field should, well, reuse the existing field. + // Trying to reuse an existing field should, well, reuse the existing field + // even if the auto create flag is set. $this->testBundle->getHandler()->setConfiguration([ 'source_field' => 'field_magick', ]); + $this->testBundle->set('auto_create_source_field', TRUE); $this->testBundle->save(); $field = $this->testBundle->getHandler()->getSourceField($this->testBundle); $this->assertInstanceOf(FieldConfig::class, $field); @@ -152,6 +164,42 @@ public function testProgrammaticBundleManipulation() { 'media.' . $this->testBundle->id() . '.field_media_generic_2', ]); $this->assertEmpty($duplicates); + + // If auto-create flag is not set fields shouldn't be created. + // ... if an imaginary field is set. + $this->testBundle->getHandler()->setConfiguration([ + 'source_field' => 'field_imaginary', + ]); + $this->testBundle->set('auto_create_source_field', FALSE); + $this->testBundle->save(); + $field = $this->container->get('entity_type.manager') + ->getStorage('field_config') + ->load('media.' . $this->testBundle->id() . '.field_imaginary'); + $field_storage = $this->container->get('entity_type.manager') + ->getStorage('field_storage_config') + ->load('media.field_imaginary'); + $this->assertNull($field, 'Field was not automatically created.'); + $this->assertNull($field_storage, 'Field was not automatically created.'); + + // ... if no field is set. + $this->testBundle->getHandler()->setConfiguration([]); + $this->testBundle->set('auto_create_source_field', FALSE); + $this->testBundle->save(); + $config = $this->testBundle->getHandler()->getConfiguration(); + $this->assertEquals('', $config['source_field'], 'Source field value was not automatically populated.'); + // Check what would the field be named like if it was created. + $proposed_field = $this->testBundle->getHandler()->getSourceField($this->testBundle); + $this->assertInstanceOf(FieldConfig::class, $proposed_field); + $this->assertEquals('field_media_test_2', $proposed_field->getName()); + $this->assertTrue($proposed_field->isNew()); + $field = $this->container->get('entity_type.manager') + ->getStorage('field_config') + ->load('media.' . $this->testBundle->id() . '.' . $proposed_field->getName()); + $field_storage = $this->container->get('entity_type.manager') + ->getStorage('field_storage_config') + ->load('media.' . $proposed_field->getName()); + $this->assertNull($field, 'Field was not automatically created.'); + $this->assertNull($field_storage, 'Field was not automatically created.'); } }