diff --git a/modules/opd_podcast/opd_podcast.module b/modules/opd_podcast/opd_podcast.module index 3c9c53a9b..e1d1f2a6d 100644 --- a/modules/opd_podcast/opd_podcast.module +++ b/modules/opd_podcast/opd_podcast.module @@ -2,7 +2,10 @@ declare(strict_types=1); +use Drupal\Core\Render\BubbleableMetadata; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\node\NodeInterface; +use Drupal\taxonomy\TermInterface; /** * @param array> $links @@ -23,3 +26,66 @@ function opd_podcast_node_links_alter(array &$links, NodeInterface $entity, arra $links['#attributes']['class'][] = 'm-0'; $links['#attributes']['class'][] = 'p-0'; } + +/** + * Implements hook_token_info(). + * + * @return array{tokens: array, types: array} + */ +function opd_podcast_token_info(): array { + $tokens = []; + + $type = [ + 'description' => t('Tokens related to podcasts.'), + 'name' => t('Podcasts'), + ]; + + $tokens['guest-names'] = [ + 'description' => t('The names of the guests on a podcast episode.'), + 'name' => t('Guest names'), + ]; + + return [ + 'tokens' => [ + 'opd-podcast' => $tokens, + ], + 'types' => [ + 'opd-podcast' => $type, + ], + ]; +} + +/** + * Implements hook_tokens(). + * + * @param array $tokens + * @param array $data + * @param array $options + * + * @return array + */ +function opd_podcast_tokens(string $type, array $tokens, array $data, array $options, BubbleableMetadata $bubbleableMetadata) : array { + $replacements = []; + + if ($type === 'opd-podcast') { + foreach ($tokens as $name => $original) { + switch ($name) { + case 'guest-names': + $node = $data['node'] ?? NULL; + assert($node instanceof NodeInterface); + assert($node->hasField('field_podcast_guests')); + + $guests = $node->get('field_podcast_guests')->referencedEntities(); + assert(is_array($guests)); + assert(!is_null($guests[0])); + assert($guests[0] instanceof TermInterface); + + $replacements[$original] = $guests[0]->label(); + break; + } + } + } + + return $replacements; +} + diff --git a/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/field.field.node.podcast_episode.field_podcast_guests.yml b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/field.field.node.podcast_episode.field_podcast_guests.yml new file mode 100644 index 000000000..07edab907 --- /dev/null +++ b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/field.field.node.podcast_episode.field_podcast_guests.yml @@ -0,0 +1,28 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_podcast_guests + - node.type.podcast_episode + - taxonomy.vocabulary.podcast_guest +id: node.podcast_episode.field_podcast_guests +field_name: field_podcast_guests +entity_type: node +bundle: podcast_episode +label: Guests +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:taxonomy_term' + handler_settings: + target_bundles: + podcast_guest: podcast_guest + sort: + field: name + direction: asc + auto_create: true + auto_create_bundle: '' +field_type: entity_reference diff --git a/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/field.storage.node.field_podcast_guests.yml b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/field.storage.node.field_podcast_guests.yml new file mode 100644 index 000000000..c2d56a5c1 --- /dev/null +++ b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/field.storage.node.field_podcast_guests.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - node + - taxonomy +id: node.field_podcast_guests +field_name: field_podcast_guests +entity_type: node +type: entity_reference +settings: + target_type: taxonomy_term +module: core +locked: false +cardinality: -1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/node.type.podcast_episode.yml b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/node.type.podcast_episode.yml new file mode 100644 index 000000000..93b198cff --- /dev/null +++ b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/node.type.podcast_episode.yml @@ -0,0 +1,11 @@ +langcode: en +status: true +dependencies: { } +third_party_settings: { } +name: 'Podcast episode' +type: podcast_episode +description: null +help: null +new_revision: true +preview_mode: 1 +display_submitted: true diff --git a/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/taxonomy.vocabulary.podcast_guest.yml b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/taxonomy.vocabulary.podcast_guest.yml new file mode 100644 index 000000000..609cdd81d --- /dev/null +++ b/modules/opd_podcast/tests/modules/opd_podcast_test/config/install/taxonomy.vocabulary.podcast_guest.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +name: 'Podcast guest' +vid: podcast_guest +description: null +weight: 0 +new_revision: false diff --git a/modules/opd_podcast/tests/modules/opd_podcast_test/opd_podcast_test.info.yml b/modules/opd_podcast/tests/modules/opd_podcast_test/opd_podcast_test.info.yml new file mode 100644 index 000000000..18841d3ef --- /dev/null +++ b/modules/opd_podcast/tests/modules/opd_podcast_test/opd_podcast_test.info.yml @@ -0,0 +1,8 @@ +name: Podcast Test +description: A test module for podcasts. +core_version_requirement: ^11 +type: module +package: oliverdavies.uk +hidden: true +dependencies: + - drupal:node diff --git a/modules/opd_podcast/tests/src/Kernel/PodcastTokenTest.php b/modules/opd_podcast/tests/src/Kernel/PodcastTokenTest.php new file mode 100644 index 000000000..fb22790b1 --- /dev/null +++ b/modules/opd_podcast/tests/src/Kernel/PodcastTokenTest.php @@ -0,0 +1,75 @@ +createPodcastNode( + guestNames: $guestNames, + ); + + $this->assertToken( + data: ['node' => $node], + expected: $expected, + token: 'guest-names', + type: 'opd-podcast', + ); + } + + public function podcastNodeProvider(): \Generator { + return [ + yield 'Single guest' => [['Matt Glaman'], 'Matt Glaman'], + ]; + } + + /** + * @param array $guestNames + * + * @return list + */ + private function createGuestTerms(array $guestNames): array { + return array_map( + array: $guestNames, + callback: fn (string $guestName): TermInterface => Term::create([ + 'name' => $guestName, + 'vid' => 'podcast_guest', + ]), + ); + } + + /** + * @param non-empty-string[] $guestNames + */ + private function createPodcastNode(array $guestNames): NodeInterface { + return $this->createNode([ + 'field_podcast_guests' => $this->createGuestTerms($guestNames), + 'title' => '::title::', + 'type' => 'podcast_episode', + ]); + } +}