diff --git a/src/Entity/MediaBundle.php b/src/Entity/MediaBundle.php index d8ad3d7..1a9d5f8 100644 --- a/src/Entity/MediaBundle.php +++ b/src/Entity/MediaBundle.php @@ -250,7 +250,7 @@ class MediaBundle extends ConfigEntityBundleBase implements MediaBundleInterface if (!$update) { // Inform the plugin that this bundle has just been created. - $this->getType()->reactOnBundleCreated($this->id(), $this->getEntityTypeId()); + $this->getType()->onBundleSave($this->id()); } } diff --git a/src/MediaTypeBase.php b/src/MediaTypeBase.php index 87ef61b..b2da7e8 100644 --- a/src/MediaTypeBase.php +++ b/src/MediaTypeBase.php @@ -161,11 +161,6 @@ abstract class MediaTypeBase extends PluginBase implements MediaTypeInterface, C /** * {@inheritdoc} */ - public function reactOnBundleCreated($bundle_name, $entity_type_id) {} - - /** - * {@inheritdoc} - */ - public function createDefaultSourceField($bundle_name) {} + public function onBundleSave($bundle_name) {} } diff --git a/src/MediaTypeInterface.php b/src/MediaTypeInterface.php index 632dcec..09ca4c4 100644 --- a/src/MediaTypeInterface.php +++ b/src/MediaTypeInterface.php @@ -86,13 +86,11 @@ interface MediaTypeInterface extends PluginInspectionInterface, ConfigurablePlug public function getDefaultName(MediaInterface $media); /** - * Take actions on bundle creation. + * Take actions when saving a bundle. * * @param string $bundle_name - * The machine-name of the bundle created. - * @param string $entity_type_id - * The entity type id. + * The machine-name of the bundle saved. */ - public function reactOnBundleCreated($bundle_name, $entity_type_id); + public function onBundleSave($bundle_name); } diff --git a/src/MediaTypeDefaultFieldTrait.php b/src/MediaTypeSourceFieldTrait.php similarity index 64% rename from src/MediaTypeDefaultFieldTrait.php rename to src/MediaTypeSourceFieldTrait.php index 73452c2..e7094fe 100644 --- a/src/MediaTypeDefaultFieldTrait.php +++ b/src/MediaTypeSourceFieldTrait.php @@ -15,41 +15,44 @@ use Drupal\field\Entity\FieldStorageConfig; * Implements most of the behavior required for a single source field that may * be populated with a default field upon creation of a bundle. * - * You will need to add a source_field key to your configuration schema. + * You will need to add a source_field key to your configuration schema and + * annotate your class with the MediaTypeSourceField annotation. */ -trait MediaTypeDefaultFieldTrait { - use StringTranslationTrait; +trait MediaTypeSourceFieldTrait { protected $defaultSourceFieldName; /** - * Produce an array of allowed field types for the source field. + * Ensures the t() method is available. * - * @return array[string] - * An array containing field types that the media type allows as its source - * field. + * @see \Drupal\Core\StringTranslation\StringTranslationTrait */ - abstract public function allowedSourceFieldTypes(); + abstract protected function t($string, array $args = array(), array $options = array()); /** - * Return the default source field's type. - */ - abstract public function defaultSourceFieldType(); - - /** - * Return the default source field's label. - */ - abstract public function defaultSourceFieldLabel(); - - /** - * Return the default source field's formatter. - */ - abstract public function defaultSourceFieldFormatter(); - - /** - * Return the default source field's form widget. + * Provide information related to source field configuration. + * + * This includes information about a default field, a field that will be + * created automatically if the user does not disable the automatich creation. + * + * @return array[array] + * An array containing keys identifying information regarding the source + * field configuration: + * - allowed_types: array of strings specifying field types that are + * acceptable as source field types. + * - default_type: string identifying the default field type. + * - default_label: string that will be used for the label for the default + * field. + * - default_widget: string identifying the form widget for the default + * field. + * - default_formatter: string identifying the formatter to be used in the + * display. + * - field_storage_extra_config: (optional) array with extra keys to be + * passed to FieldStorageConfig::create(). + * - field_extra_config: (optional) array with extra keys to be passed to + * FieldConfig::create(). */ - abstract public function defaultSourceFieldWidget(); + abstract public function sourceFieldInfo(); /** * Produce a form fragment to configure the source field. @@ -62,15 +65,16 @@ trait MediaTypeDefaultFieldTrait { * @param \Drupal\Core\Form\FormStateInterface $form_state * @return array */ - protected function defaultFieldConfigurationForm(array $form, FormStateInterface $form_state) { - $options = ['' => $this->t('- None -')]; - $allowed_field_types = $this->allowedSourceFieldTypes(); + protected function sourceFieldConfigurationForm(array $form, FormStateInterface $form_state) { + $source_field_info = $this->sourceFieldInfo(); + + $allowed_field_types = $source_field_info['allowed_types']; /** @var \Drupal\media_entity\MediaBundleInterface $bundle */ $bundle = $form_state->getFormObject()->getEntity(); foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) { - if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition() - ->isBaseField() - ) { + $allowed_type = in_array($field->getType(), $allowed_field_types); + $is_base_field = $field->getFieldStorageDefinition()->isBaseField(); + if ($allowed_type && !$is_base_field) { $options[$field_name] = $field->getLabel(); } } @@ -89,13 +93,15 @@ trait MediaTypeDefaultFieldTrait { // Select the source field. Only show it when the bundle is not new, so // there will potentially be fields to select. - $form['source_field'] = array( + $form['source_field'] = [ '#type' => 'select', '#title' => $this->t('Field with source information'), - '#default_value' => $this->configuration['source_field'], + '#default_value' => isset($this->configuration['source_field']) ? $this->configuration['source_field'] : '', + '#empty_option' => $this->t('- None -'), + '#empty_value' => '', '#options' => $options, '#access' => !$bundle->isNew(), - ); + ]; return $form; @@ -104,7 +110,11 @@ trait MediaTypeDefaultFieldTrait { /** * {@inheritdoc} */ - public function reactOnBundleCreated($bundle_name, $entity_type_id) { + public function onBundleSave($bundle_name) { + // If we are creating a new bundle and the user elected to have the default + // field created, defaultSourceFieldName will have been set from + // setConfiguration() and determineDefaultSourceFieldName(). + // @see determineDefaultSourceFieldName() if (isset($this->defaultSourceFieldName)) { $this->createDefaultSourceField($bundle_name); } @@ -113,9 +123,10 @@ trait MediaTypeDefaultFieldTrait { /** * {@inheritdoc} */ - public function createDefaultSourceField($bundle_name) { + protected function createDefaultSourceField($bundle_name) { + $source_field_info = $this->sourceFieldInfo(); - if (!in_array($this->defaultSourceFieldType(), $this->allowedSourceFieldTypes())) { + if (!in_array($source_field_info['default_type'], $source_field_info['allowed_types'])) { throw new \LogicException('Default source field type is not within the allowed field types.'); } @@ -124,7 +135,7 @@ trait MediaTypeDefaultFieldTrait { $storage = FieldStorageConfig::create([ 'field_name' => $field_name, 'entity_type' => 'media', - 'type' => $this->defaultSourceFieldType(), + 'type' => $source_field_info['default_type'], ]); $storage->save(); @@ -132,7 +143,7 @@ trait MediaTypeDefaultFieldTrait { FieldConfig::create([ 'entity_type' => 'media', 'field_name' => $field_name, - 'label' => $this->defaultSourceFieldLabel(), + 'label' => $source_field_info['default_label'], 'required' => TRUE, 'bundle' => $bundle_name, ])->save(); @@ -146,7 +157,7 @@ trait MediaTypeDefaultFieldTrait { 'status' => TRUE, ]); $form_display->setComponent($field_name, [ - 'type' => $this->defaultSourceFieldWidget(), + 'type' => $source_field_info['default_widget'], ])->save(); // Make the field visible on the media entity itself. @@ -158,7 +169,7 @@ trait MediaTypeDefaultFieldTrait { 'status' => TRUE, ]); $display->setComponent($field_name, [ - 'type' => $this->defaultSourceFieldFormatter(), + 'type' => $source_field_info['default_formatter'], ])->save(); } @@ -188,7 +199,9 @@ trait MediaTypeDefaultFieldTrait { $field_name_candidate = $base_field_name . '_' . $postfix; } - return $this->defaultSourceFieldName = $field_name_candidate; + $this->defaultSourceFieldName = $field_name_candidate; + + return $this->defaultSourceFieldName; } /** diff --git a/tests/modules/media_entity_test_type/src/Plugin/MediaEntity/Type/TestType.php b/tests/modules/media_entity_test_type/src/Plugin/MediaEntity/Type/TestType.php index 5ba6800..bae89fe 100644 --- a/tests/modules/media_entity_test_type/src/Plugin/MediaEntity/Type/TestType.php +++ b/tests/modules/media_entity_test_type/src/Plugin/MediaEntity/Type/TestType.php @@ -7,7 +7,7 @@ use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Form\FormStateInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; -use Drupal\media_entity\MediaTypeDefaultFieldTrait; +use Drupal\media_entity\MediaTypeSourceFieldTrait; use Drupal\media_entity\Plugin\MediaEntity\Type\Generic; /** @@ -20,41 +20,19 @@ use Drupal\media_entity\Plugin\MediaEntity\Type\Generic; * ) */ class TestType extends Generic { - use MediaTypeDefaultFieldTrait; + use MediaTypeSourceFieldTrait; /** * {@inheritdoc} */ - public function allowedSourceFieldTypes() { - return ['string']; - } - - /** - * {@inheritdoc} - */ - public function defaultSourceFieldLabel() { - return $this->t('Test source'); - } - - /** - * {@inheritdoc} - */ - public function defaultSourceFieldType() { - return 'string'; - } - - /** - * {@inheritdoc} - */ - public function defaultSourceFieldWidget() { - return 'string_textfield'; - } - - /** - * {@inheritdoc} - */ - public function defaultSourceFieldFormatter() { - return 'string'; + public function sourceFieldInfo() { + return [ + 'allowed_types' => ['string'], + 'default_label' => $this->t('Test source'), + 'default_type' => 'string', + 'default_widget' => 'string_textfield', + 'default_formatter' => 'string', + ]; } /** @@ -73,7 +51,6 @@ class TestType extends Generic { public function defaultConfiguration() { return [ 'test_config_value' => 'This is default value.', - 'create_source_field' => TRUE, ]; } diff --git a/tests/src/FunctionalJavascript/BundleCreationTest.php b/tests/src/FunctionalJavascript/BundleCreationTest.php new file mode 100644 index 0000000..149a261 --- /dev/null +++ b/tests/src/FunctionalJavascript/BundleCreationTest.php @@ -0,0 +1,60 @@ +getSession()->getPage(); + + $this->drupalGet('admin/structure/media/add'); + + // Fill in a label to the bundle. + $page->fillField('label', 'Foo bundle'); + + // Select our test bundle type. + $this->assertSession()->fieldExists('Type provider'); + $this->assertSession()->optionExists('Type provider', 'test_type'); + $page->selectFieldOption('Type provider', 'test_type'); + $this->waitForAjaxToFinish(); +$this->saveHtmlOutput(); // @TODO Delete me before committing. + + // Make sure the checkbox for creating the source field is there and save. + $this->assertSession()->checkboxChecked('type_configuration[test_type][create_source_field]'); + $page->pressButton('Save media bundle'); +$this->saveHtmlOutput(); // @TODO Delete me before committing. + + // Check whether the source field was correctly created. + // @TODO Finish me. + $this->assertNotNull(FieldStorageConfig::loadByName('media', TestType::MEDIA_ENTITY_TEST_TYPE_DEFAULT_FIELD_NAME)); + } + +} diff --git a/tests/src/FunctionalJavascript/MediaEntityJavascriptTestBase.php b/tests/src/FunctionalJavascript/MediaEntityJavascriptTestBase.php index e52a064..8666d72 100644 --- a/tests/src/FunctionalJavascript/MediaEntityJavascriptTestBase.php +++ b/tests/src/FunctionalJavascript/MediaEntityJavascriptTestBase.php @@ -94,6 +94,13 @@ abstract class MediaEntityJavascriptTestBase extends JavascriptTestBase { } /** + * Waits for jQuery to become ready and animations to complete. + */ + protected function waitForAjaxToFinish() { + $this->assertSession()->assertWaitOnAjaxRequest(); + } + + /** * Waits and asserts that a given element is visible. * * @param string $selector @@ -108,4 +115,24 @@ abstract class MediaEntityJavascriptTestBase extends JavascriptTestBase { $this->assertJsCondition($condition, $timeout, $message); } + /** + * Debugger method to save additional HTML output. + * + * The base class will only save browser output when accessing page using + * ::drupalGet and providing a printer class to PHPUnit. This method + * is intended for developers to help debug browser test failures and capture + * more verbose output. + */ + protected function saveHtmlOutput() { + $out = $this->getSession()->getPage()->getContent(); + // Ensure that any changes to variables in the other thread are picked up. + $this->refreshVariables(); + if ($this->htmlOutputEnabled) { + $html_output = '
Ending URL: ' . $this->getSession()->getCurrentUrl(); + $html_output .= '
' . $out; + $html_output .= $this->getHtmlOutputHeaders(); + $this->htmlOutput($html_output); + } + } + }