Chris@0: entityTypeManager = $entity_type_manager; Chris@0: $this->entityFieldManager = $entity_field_manager; Chris@0: $this->fieldTypeManager = $field_type_manager; Chris@0: $this->configFactory = $config_factory; Chris@0: Chris@0: // Add the default configuration of the media source to the plugin. Chris@0: $this->setConfiguration($configuration); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { Chris@0: return new static( Chris@0: $configuration, Chris@0: $plugin_id, Chris@0: $plugin_definition, Chris@0: $container->get('entity_type.manager'), Chris@0: $container->get('entity_field.manager'), Chris@0: $container->get('plugin.manager.field.field_type'), Chris@0: $container->get('config.factory') Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function setConfiguration(array $configuration) { Chris@0: $this->configuration = NestedArray::mergeDeep( Chris@0: $this->defaultConfiguration(), Chris@0: $configuration Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getConfiguration() { Chris@0: return $this->configuration; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function defaultConfiguration() { Chris@0: return [ Chris@0: 'source_field' => '', Chris@0: ]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getMetadata(MediaInterface $media, $attribute_name) { Chris@0: switch ($attribute_name) { Chris@0: case 'default_name': Chris@0: return 'media:' . $media->bundle() . ':' . $media->uuid(); Chris@0: Chris@0: case 'thumbnail_uri': Chris@0: $default_thumbnail_filename = $this->pluginDefinition['default_thumbnail_filename']; Chris@0: return $this->configFactory->get('media.settings')->get('icon_base_uri') . '/' . $default_thumbnail_filename; Chris@0: } Chris@0: Chris@0: return NULL; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function calculateDependencies() { Chris@0: return []; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the source field options for the media type form. Chris@0: * Chris@0: * This returns all fields related to media entities, filtered by the allowed Chris@0: * field types in the media source annotation. Chris@0: * Chris@0: * @return string[] Chris@0: * A list of source field options for the media type form. Chris@0: */ Chris@0: protected function getSourceFieldOptions() { Chris@0: // If there are existing fields to choose from, allow the user to reuse one. Chris@0: $options = []; Chris@0: foreach ($this->entityFieldManager->getFieldStorageDefinitions('media') as $field_name => $field) { Chris@0: $allowed_type = in_array($field->getType(), $this->pluginDefinition['allowed_field_types'], TRUE); Chris@0: if ($allowed_type && !$field->isBaseField()) { Chris@0: $options[$field_name] = $field->getLabel(); Chris@0: } Chris@0: } Chris@0: return $options; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function buildConfigurationForm(array $form, FormStateInterface $form_state) { Chris@0: $options = $this->getSourceFieldOptions(); Chris@0: $form['source_field'] = [ Chris@0: '#type' => 'select', Chris@0: '#title' => $this->t('Field with source information'), Chris@0: '#default_value' => $this->configuration['source_field'], Chris@0: '#empty_option' => $this->t('- Create -'), Chris@0: '#options' => $options, Chris@0: '#description' => $this->t('Select the field that will store essential information about the media item. If "Create" is selected a new field will be automatically created.'), Chris@0: ]; Chris@0: Chris@0: if (!$options && $form_state->get('operation') === 'add') { Chris@0: $form['source_field']['#access'] = FALSE; Chris@0: $field_definition = $this->fieldTypeManager->getDefinition(reset($this->pluginDefinition['allowed_field_types'])); Chris@0: $form['source_field_message'] = [ Chris@0: '#markup' => $this->t('%field_type field will be automatically created on this type to store the essential information about the media item.', [ Chris@0: '%field_type' => $field_definition['label'], Chris@0: ]), Chris@0: ]; Chris@0: } Chris@0: elseif ($form_state->get('operation') === 'edit') { Chris@0: $form['source_field']['#access'] = FALSE; Chris@0: $fields = $this->entityFieldManager->getFieldDefinitions('media', $form_state->get('type')->id()); Chris@0: $form['source_field_message'] = [ Chris@0: '#markup' => $this->t('%field_name field is used to store the essential information about the media item.', [ Chris@0: '%field_name' => $fields[$this->configuration['source_field']]->getLabel(), Chris@0: ]), Chris@0: ]; Chris@0: } Chris@0: Chris@0: return $form; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { Chris@0: foreach (array_intersect_key($form_state->getValues(), $this->configuration) as $config_key => $config_value) { Chris@0: $this->configuration[$config_key] = $config_value; Chris@0: } Chris@0: Chris@0: // If no source field is explicitly set, create it now. Chris@0: if (empty($this->configuration['source_field'])) { Chris@0: $field_storage = $this->createSourceFieldStorage(); Chris@0: $field_storage->save(); Chris@0: $this->configuration['source_field'] = $field_storage->getName(); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates the source field storage definition. Chris@0: * Chris@0: * By default, the first field type listed in the plugin definition's Chris@0: * allowed_field_types array will be the generated field's type. Chris@0: * Chris@0: * @return \Drupal\field\FieldStorageConfigInterface Chris@0: * The unsaved field storage definition. Chris@0: */ Chris@0: protected function createSourceFieldStorage() { Chris@0: return $this->entityTypeManager Chris@0: ->getStorage('field_storage_config') Chris@0: ->create([ Chris@0: 'entity_type' => 'media', Chris@0: 'field_name' => $this->getSourceFieldName(), Chris@0: 'type' => reset($this->pluginDefinition['allowed_field_types']), Chris@0: ]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the source field storage definition. Chris@0: * Chris@0: * @return \Drupal\Core\Field\FieldStorageDefinitionInterface|null Chris@0: * The field storage definition or NULL if it doesn't exists. Chris@0: */ Chris@0: protected function getSourceFieldStorage() { Chris@0: // Nothing to do if no source field is configured yet. Chris@0: $field = $this->configuration['source_field']; Chris@0: if ($field) { Chris@0: // Even if we do know the name of the source field, there's no Chris@0: // guarantee that it exists. Chris@0: $fields = $this->entityFieldManager->getFieldStorageDefinitions('media'); Chris@0: return isset($fields[$field]) ? $fields[$field] : NULL; Chris@0: } Chris@0: return NULL; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getSourceFieldDefinition(MediaTypeInterface $type) { Chris@0: // Nothing to do if no source field is configured yet. Chris@0: $field = $this->configuration['source_field']; Chris@0: if ($field) { Chris@0: // Even if we do know the name of the source field, there is no Chris@0: // guarantee that it already exists. Chris@0: $fields = $this->entityFieldManager->getFieldDefinitions('media', $type->id()); Chris@0: return isset($fields[$field]) ? $fields[$field] : NULL; Chris@0: } Chris@0: return NULL; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function createSourceField(MediaTypeInterface $type) { Chris@0: $storage = $this->getSourceFieldStorage() ?: $this->createSourceFieldStorage(); Chris@0: return $this->entityTypeManager Chris@0: ->getStorage('field_config') Chris@0: ->create([ Chris@0: 'field_storage' => $storage, Chris@0: 'bundle' => $type->id(), Chris@0: 'label' => $this->pluginDefinition['label'], Chris@0: 'required' => TRUE, Chris@0: ]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determine the name of the source field. Chris@0: * Chris@0: * @return string Chris@0: * The source field name. If one is already stored in configuration, it is Chris@0: * returned. Otherwise, a new, unused one is generated. Chris@0: */ Chris@0: protected function getSourceFieldName() { Chris@17: // Some media sources are using a deriver, so their plugin IDs may contain Chris@17: // a separator (usually ':') which is not allowed in field names. Chris@17: $base_id = 'field_media_' . str_replace(static::DERIVATIVE_SEPARATOR, '_', $this->getPluginId()); Chris@0: $tries = 0; Chris@0: $storage = $this->entityTypeManager->getStorage('field_storage_config'); Chris@0: Chris@0: // Iterate at least once, until no field with the generated ID is found. Chris@0: do { Chris@0: $id = $base_id; Chris@0: // If we've tried before, increment and append the suffix. Chris@0: if ($tries) { Chris@0: $id .= '_' . $tries; Chris@0: } Chris@0: $field = $storage->load('media.' . $id); Chris@0: $tries++; Chris@0: } while ($field); Chris@0: Chris@0: return $id; Chris@0: } Chris@0: Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: public function getSourceFieldValue(MediaInterface $media) { Chris@14: $source_field = $this->configuration['source_field']; Chris@14: if (empty($source_field)) { Chris@14: throw new \RuntimeException('Source field for media source is not defined.'); Chris@14: } Chris@14: Chris@14: /** @var \Drupal\Core\Field\FieldItemInterface $field_item */ Chris@14: $field_item = $media->get($source_field)->first(); Chris@14: return $field_item->{$field_item->mainPropertyName()}; Chris@14: } Chris@14: Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: public function prepareViewDisplay(MediaTypeInterface $type, EntityViewDisplayInterface $display) { Chris@14: $display->setComponent($this->getSourceFieldDefinition($type)->getName()); Chris@14: } Chris@14: Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: public function prepareFormDisplay(MediaTypeInterface $type, EntityFormDisplayInterface $display) { Chris@14: // Make sure the source field is placed just after the "name" basefield. Chris@14: $name_component = $display->getComponent('name'); Chris@14: $source_field_weight = ($name_component && isset($name_component['weight'])) ? $name_component['weight'] + 5 : -50; Chris@14: $display->setComponent($this->getSourceFieldDefinition($type)->getName(), [ Chris@14: 'weight' => $source_field_weight, Chris@14: ]); Chris@14: } Chris@14: Chris@0: }