diff -u b/src/Entity/MediaBundle.php b/src/Entity/MediaBundle.php --- b/src/Entity/MediaBundle.php +++ b/src/Entity/MediaBundle.php @@ -7,8 +7,10 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityWithPluginCollectionInterface; use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection; +use Drupal\field\FieldStorageConfigInterface; use Drupal\media_entity\MediaBundleInterface; use Drupal\media_entity\MediaInterface; +use Drupal\media_entity\SourceFieldInterface; /** * Defines the Media bundle configuration entity. @@ -249,8 +251,50 @@ parent::postSave($storage, $update); if (!$update) { - // Inform the plugin that this bundle has just been created. - $this->getType()->onBundleSave($this->id()); + $type_plugin = $this->getType(); + + if ($type_plugin instanceof SourceFieldInterface) { + $field = $type_plugin->getSourceField($this); + + $storage = $field->getFieldStorageDefinition(); + if ($storage instanceof FieldStorageConfigInterface) { + $storage->save(); + } + + if ($field->isNew()) { + $entity_type = $field->getTargetEntityTypeId(); + $bundle = $field->getTargetBundle(); + + $plugin_definition = \Drupal::service('plugin.manager.field.field_type') + ->getDefinition($field->getType()); + + if ($field->isDisplayConfigurable('form')) { + $widget = \Drupal::service('plugin.manager.field.widget') + ->createInstance($plugin_definition['default_widget']) + ->getConfiguration(); + + entity_get_form_display($entity_type, $bundle, 'default') + ->setComponent($field->getName(), [ + 'type' => $widget->getPluginId(), + 'settings' => $widget->getConfiguration(), + ]) + ->save(); + } + if ($field->isDisplayConfigurable('view')) { + $formatter = \Drupal::service('plugin.manager.field.formatter') + ->createInstance($plugin_definition['default_formatter']); + + entity_get_display($entity_type, $bundle, 'default') + ->setComponent($field->getName(), [ + 'type' => $formatter->getPluginId(), + 'settings' => $formatter->getConfiguration(), + ]) + ->save(); + } + } + + $field->save(); + } } } diff -u b/src/MediaTypeBase.php b/src/MediaTypeBase.php --- b/src/MediaTypeBase.php +++ b/src/MediaTypeBase.php @@ -7,6 +7,7 @@ use Drupal\Core\Config\Config; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; @@ -15,7 +16,7 @@ /** * Base implementation of media type plugin. */ -abstract class MediaTypeBase extends PluginBase implements MediaTypeInterface, ContainerFactoryPluginInterface { +abstract class MediaTypeBase extends PluginBase implements MediaTypeInterface, SourceFieldInterface, ContainerFactoryPluginInterface { use StringTranslationTrait; /** @@ -105,7 +106,9 @@ * {@inheritdoc} */ public function defaultConfiguration() { - return []; + return [ + 'source_field' => NULL, + ]; } /** @@ -138,7 +141,31 @@ * {@inheritdoc} */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { - return []; + $options = []; + + /** @var \Drupal\media_entity\MediaBundleInterface $bundle */ + $bundle = $form_state->getFormObject()->getEntity(); + foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) { + $allowed_type = in_array($field->getType(), $this->pluginDefinition['allowed_field_types']); + $is_base_field = $field->getFieldStorageDefinition()->isBaseField(); + if ($allowed_type && !$is_base_field) { + $options[$field_name] = $field->getLabel(); + } + } + + // Select the source field. Only show it when the bundle is not new, so + // there will potentially be fields to select. + $form['source_field'] = [ + '#type' => 'select', + '#title' => $this->t('Field with source information.'), + '#default_value' => $this->configuration['source_field'], + '#empty_option' => $this->t('- create -'), + '#empty_value' => NULL, + '#options' => $options, + '#disabled' => empty($options), + ]; + + return $form; } /** @@ -162,5 +189,50 @@ * {@inheritdoc} */ - public function onBundleSave($bundle_name) {} + public function getSourceField(MediaBundleInterface $bundle) { + $id = 'media.' . $bundle->id() . '.' . $this->configuration['source_field']; + + return $this->entityTypeManager + ->getStorage('field_config') + ->load($id) + ?: + $this->createSourceField($bundle); + } + + /** + * Creates the source field definition for a bundle. + * + * @param \Drupal\media_entity\MediaBundleInterface $bundle + * The bundle. + * + * @return \Drupal\field\FieldConfigInterface + * The unsaved field definition. The field storage definition, if new, + * should not be saved either. + */ + abstract protected function createSourceField(MediaBundleInterface $bundle); + + /** + * Determine a free field name to use as the default field. + * + * @return string + * An appropriate field name that was determined to be available. + */ + protected function getSourceFieldName() { + $base_id = 'media.field_media_' . $this->getPluginId(); + $tries = 0; + $storage = $this->entityTypeManager->getStorage('field_storage_config'); + + // Iterate at least once, until no field with the generated ID is found. + do { + $id = $base_id; + // If we've tried before, increment and append suffix. + if ($tries) { + $id .= '_' . ++$tries; + } + $field = $storage->load($id); + } + while ($field); + + return $id; + } } diff -u b/src/MediaTypeInterface.php b/src/MediaTypeInterface.php --- b/src/MediaTypeInterface.php +++ b/src/MediaTypeInterface.php @@ -87,10 +87,2 @@ - /** - * Take actions when saving a bundle. - * - * @param string $bundle_name - * The machine-name of the bundle saved. - */ - public function onBundleSave($bundle_name); - } reverted: --- b/src/MediaTypeSourceFieldTrait.php +++ /dev/null @@ -1,233 +0,0 @@ -sourceFieldInfo(); - $options = []; - - $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) { - $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(); - } - } - - // Add a checkbox to allow the field being created automatically on save. - // Only include it when the bundle is new, so we can use its presence to - // know we can safely override the source field configuration. - if ($bundle->isNew()) { - $form['create_source_field'] = [ - '#type' => 'checkbox', - '#title' => $this->t('Create a source field automatically when saving this form.'), - '#description' => $this->t('If checked, a default field will be created and used as a source field. If you uncheck the field, you will need to create a field and revisit this form later to select it.'), - '#default_value' => TRUE, - ]; - } - - // Select the source field. Only show it when the bundle is not new, so - // there will potentially be fields to select. - $form['source_field'] = [ - '#type' => 'select', - '#title' => $this->t('Field with source information'), - '#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; - } - - /** - * {@inheritdoc} - */ - 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); - } - } - - /** - * {@inheritdoc} - */ - protected function createDefaultSourceField($bundle_name) { - $source_field_info = $this->sourceFieldInfo(); - - 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.'); - } - - $field_name = $this->defaultSourceFieldName; - - $storage = FieldStorageConfig::create([ - 'field_name' => $field_name, - 'entity_type' => 'media', - 'type' => $source_field_info['default_type'], - ]); - $storage->save(); - - // Create the field instance. - FieldConfig::create([ - 'entity_type' => 'media', - 'field_name' => $field_name, - 'label' => $source_field_info['default_label'], - 'required' => TRUE, - 'bundle' => $bundle_name, - ])->save(); - - // Make the field visible on the form display. - /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */ - $form_display = EntityFormDisplay::create([ - 'targetEntityType' => 'media', - 'bundle' => $bundle_name, - 'mode' => 'default', - 'status' => TRUE, - ]); - $form_display->setComponent($field_name, [ - 'type' => $source_field_info['default_widget'], - ])->save(); - - // Make the field visible on the media entity itself. - /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */ - $display = EntityViewDisplay::create([ - 'targetEntityType' => 'media', - 'bundle' => $bundle_name, - 'mode' => 'default', - 'status' => TRUE, - ]); - $display->setComponent($field_name, [ - 'type' => $source_field_info['default_formatter'], - ])->save(); - } - - /** - * Determine a free field name to use as the default field. - * - * @return string - * An appropriate field name that was determined to be available. - */ - protected function determineDefaultSourceFieldName() { - // Determine a unique field name. - if (isset($this->defaultSourceFieldName)) { - return $this->defaultSourceFieldName; - } - - $base_field_name = 'field_media_' . $this->getPluginId(); - $field_name_candidate = $base_field_name; - $postfix = ''; - while (FieldStorageConfig::loadByName('media', $field_name_candidate)) { - if (empty($postfix)) { - $postfix = 1; - } - else { - $postfix++; - } - - $field_name_candidate = $base_field_name . '_' . $postfix; - } - - $this->defaultSourceFieldName = $field_name_candidate; - - return $this->defaultSourceFieldName; - } - - /** - * {@inheritdoc} - */ - public function setConfiguration(array $configuration) { - // Take out the create_source_field key when present so it doesn't end up - // in the configuration. Record it was set so we can later decide to - // actually create the field. Determine the field name here so it correctly - // is entered into the configuration. - if (isset($configuration['create_source_field'])) { - $create_source_field = $configuration['create_source_field']; - unset($configuration['create_source_field']); - - if ($create_source_field) { - $configuration['source_field'] = $this->determineDefaultSourceFieldName(); - } - } - - parent::setConfiguration($configuration); - } - -} only in patch2: unchanged: --- a/src/Annotation/MediaType.php +++ b/src/Annotation/MediaType.php @@ -40,4 +40,11 @@ class MediaType extends Plugin { */ public $description = ''; + /** + * The field types that can be used as a source field for this type. + * + * @var string[] + */ + public $allowed_field_types = []; + } only in patch2: unchanged: --- a/src/Plugin/MediaEntity/Type/Generic.php +++ b/src/Plugin/MediaEntity/Type/Generic.php @@ -3,6 +3,7 @@ namespace Drupal\media_entity\Plugin\MediaEntity\Type; use Drupal\Core\Form\FormStateInterface; +use Drupal\media_entity\MediaBundleInterface; use Drupal\media_entity\MediaInterface; use Drupal\media_entity\MediaTypeBase; @@ -50,4 +51,27 @@ class Generic extends MediaTypeBase { return $form; } + /** + * {@inheritdoc} + */ + protected function createSourceField(MediaBundleInterface $bundle) { + $field_storage = $this->entityTypeManager + ->getStorage('field_storage_config') + ->create([ + 'entity_type' => 'media', + 'field_name' => $this->getSourceFieldName(), + // Strings are harmless, inoffensive puppies: a good choice for a + // generic media type. + 'type' => 'string', + ]); + + /** @var \Drupal\field\FieldConfigInterface $field */ + return $this->entityTypeManager + ->getStorage('field_config') + ->create([ + 'field_storage' => $field_storage, + 'bundle' => $bundle->id(), + ]); + } + } only in patch2: unchanged: --- /dev/null +++ b/src/SourceFieldInterface.php @@ -0,0 +1,20 @@ +