diff --git a/config/schema/media_entity_twitter.schema.yml b/config/schema/media_entity_twitter.schema.yml index 04c37e6..bfd40d8 100644 --- a/config/schema/media_entity_twitter.schema.yml +++ b/config/schema/media_entity_twitter.schema.yml @@ -13,6 +13,9 @@ media_entity.bundle.type.twitter: source_field: type: string label: 'Field with embed code/URL' + create_source_field: + type: boolean + label: 'Whether to automatically create a source field on bundle creation or not' use_twitter_api: type: boolean label: 'Whether to use twitter api or not' diff --git a/src/Plugin/MediaEntity/Type/Twitter.php b/src/Plugin/MediaEntity/Type/Twitter.php index ce93d30..97defcf 100644 --- a/src/Plugin/MediaEntity/Type/Twitter.php +++ b/src/Plugin/MediaEntity/Type/Twitter.php @@ -3,11 +3,15 @@ namespace Drupal\media_entity_twitter\Plugin\MediaEntity\Type; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\Render\RendererInterface; +use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\media_entity\MediaInterface; use Drupal\media_entity\MediaTypeBase; use Drupal\media_entity\MediaTypeException; @@ -26,6 +30,21 @@ use Symfony\Component\DependencyInjection\ContainerInterface; class Twitter extends MediaTypeBase { /** + * The name of the default source field on the media entity. + */ + const MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME = 'field_media_twitter'; + + /** + * The id of the widget to be used when creating the default source field. + */ + const MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_WIDGET = 'string_textfield'; + + /** + * The id of the formatter to be used when creating the default source field. + */ + const MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_FORMATTER = 'twitter_embed'; + + /** * Config factory service. * * @var \Drupal\Core\Config\ConfigFactoryInterface @@ -115,6 +134,7 @@ class Twitter extends MediaTypeBase { public function defaultConfiguration() { return [ 'use_twitter_api' => FALSE, + 'create_source_field' => TRUE, 'generate_thumbnails' => FALSE, ]; } @@ -135,7 +155,7 @@ class Twitter extends MediaTypeBase { 'image_local_uri' => $this->t('Gets URI of the locally saved image.'), 'content' => $this->t('This tweet content'), 'retweet_count' => $this->t('Retweet count for this tweet'), - 'profile_image_url_https' => $this->t('Link to profile image') + 'profile_image_url_https' => $this->t('Link to profile image'), ); } @@ -239,10 +259,21 @@ class Twitter extends MediaTypeBase { '#type' => 'select', '#title' => $this->t('Field with source information'), '#description' => $this->t('Field on media entity that stores Twitter embed code or URL. You can create a bundle without selecting a value for this dropdown initially. This dropdown can be populated after adding fields to the bundle.'), - '#default_value' => empty($this->configuration['source_field']) ? NULL : $this->configuration['source_field'], + '#default_value' => empty($this->configuration['source_field']) ? static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME : $this->configuration['source_field'], '#options' => $options, ); + // Add a checkbox to allow the field being created automatically on save. + if (empty($this->configuration['source_field'])) { + $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. You can change this setting later.'), + '#default_value' => $this->configuration['create_source_field'], + '#access' => $bundle->isNew(), + ]; + } + $form['use_twitter_api'] = array( '#type' => 'select', '#title' => $this->t('Whether to use Twitter api to fetch tweets or not.'), @@ -324,15 +355,13 @@ class Twitter extends MediaTypeBase { public function attachConstraints(MediaInterface $media) { parent::attachConstraints($media); - if (isset($this->configuration['source_field'])) { - $source_field_name = $this->configuration['source_field']; - if ($media->hasField($source_field_name)) { - foreach ($media->get($source_field_name) as &$embed_code) { - /** @var \Drupal\Core\TypedData\DataDefinitionInterface $typed_data */ - $typed_data = $embed_code->getDataDefinition(); - $typed_data->addConstraint('TweetEmbedCode'); - $typed_data->addConstraint('TweetVisible'); - } + $source_field_name = empty($this->configuration['source_field']) ? static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME : $this->configuration['source_field']; + if ($media->hasField($source_field_name)) { + foreach ($media->get($source_field_name) as &$embed_code) { + /** @var \Drupal\Core\TypedData\DataDefinitionInterface $typed_data */ + $typed_data = $embed_code->getDataDefinition(); + $typed_data->addConstraint('TweetEmbedCode'); + $typed_data->addConstraint('TweetVisible'); } } } @@ -433,14 +462,12 @@ class Twitter extends MediaTypeBase { protected function matchRegexp(MediaInterface $media) { $matches = array(); - if (isset($this->configuration['source_field'])) { - $source_field = $this->configuration['source_field']; - if ($media->hasField($source_field)) { - $property_name = $media->{$source_field}->first()->mainPropertyName(); - foreach (static::$validationRegexp as $pattern => $key) { - if (preg_match($pattern, $media->{$source_field}->{$property_name}, $matches)) { - return $matches; - } + $source_field_name = empty($this->configuration['source_field']) ? static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME : $this->configuration['source_field']; + if ($media->hasField($source_field_name)) { + $property_name = $media->{$source_field_name}->first()->mainPropertyName(); + foreach (static::$validationRegexp as $pattern => $key) { + if (preg_match($pattern, $media->{$source_field_name}->{$property_name}, $matches)) { + return $matches; } } } @@ -485,4 +512,64 @@ class Twitter extends MediaTypeBase { return parent::getDefaultName($media); } + /** + * {@inheritdoc} + */ + public function reactOnBundleCreated($bundle_name, $entity_type_id) { + if (!empty($this->configuration['create_source_field'])) { + $this->createDefaultSourceField($bundle_name); + } + } + + /** + * {@inheritdoc} + */ + public function createDefaultSourceField($bundle_name) { + + // Create / load the field storage. + if (!$storage = FieldStorageConfig::loadByName('media', static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME)) { + $storage = FieldStorageConfig::create([ + 'field_name' => static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME, + 'entity_type' => 'media', + 'type' => 'string', + ]); + $storage->save(); + } + + // Create the field instance. + FieldConfig::create([ + 'entity_type' => 'media', + 'field_name' => static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME, + 'label' => $this->t('Tweet URL'), + '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(static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME, [ + 'type' => static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_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(static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_NAME, [ + 'type' => static::MEDIA_ENTITY_TWITTER_DEFAULT_FIELD_FORMATTER, + ])->save(); + + // @TODO Evaluate if it's necessary to save the 'source_field' config value. + } + }