From 64198480a62c3dd8c8bac7d4749bfaf5b8980461 Mon Sep 17 00:00:00 2001
From: astanley <alanjarlathstanley@gmail.com>
Date: Thu, 27 Mar 2025 18:16:46 -0300
Subject: [PATCH] initial commit

---
 caption_linker.info.yml           |   7 ++
 caption_linker.module             |   6 ++
 src/Plugin/Action/LinkCaption.php | 107 ++++++++++++++++++++++++++++++
 3 files changed, 120 insertions(+)
 create mode 100644 caption_linker.info.yml
 create mode 100644 caption_linker.module
 create mode 100644 src/Plugin/Action/LinkCaption.php

diff --git a/caption_linker.info.yml b/caption_linker.info.yml
new file mode 100644
index 0000000..2bf0c28
--- /dev/null
+++ b/caption_linker.info.yml
@@ -0,0 +1,7 @@
+name: 'Caption Linker'
+type: module
+description: 'Links Ableplayer media to audio and video media'
+package: Custom
+core_version_requirement: ^10 || ^11
+dependencies:
+  - islandora:islandora
diff --git a/caption_linker.module b/caption_linker.module
new file mode 100644
index 0000000..493aebb
--- /dev/null
+++ b/caption_linker.module
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Primary module hooks for Caption Linker module.
+ */
diff --git a/src/Plugin/Action/LinkCaption.php b/src/Plugin/Action/LinkCaption.php
new file mode 100644
index 0000000..18a385c
--- /dev/null
+++ b/src/Plugin/Action/LinkCaption.php
@@ -0,0 +1,107 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\caption_linker\Plugin\Action;
+
+use Drupal\Core\Action\ActionBase;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Logger\LoggerChannelInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\islandora\IslandoraUtils;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a Link Caption action.
+ *
+ * @Action(
+ *   id = "caption_linker_link_caption",
+ *   label = @Translation("Link Caption"),
+ *   type = "node",
+ *   category = @Translation("Custom"),
+ * )
+ *
+ * @DCG
+ * For updating entity fields consider extending FieldUpdateActionBase.
+ * @see \Drupal\Core\Field\FieldUpdateActionBase
+ *
+ * @DCG
+ * In order to set up the action through admin interface the plugin has to be
+ * configurable.
+ * @see https://www.drupal.org/project/drupal/issues/2815301
+ * @see https://www.drupal.org/project/drupal/issues/2815297
+ *
+ * @DCG
+ * The whole action API is subject of change.
+ * @see https://www.drupal.org/project/drupal/issues/2011038
+ */
+final class LinkCaption extends ActionBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(
+    array $configuration,
+    $plugin_id,
+    $plugin_definition,
+    private readonly EntityTypeManagerInterface $entityTypeManager,
+    private readonly IslandoraUtils $islandoraUtils,
+    private readonly LoggerChannelInterface $loggerChannelIslandora,
+  ) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
+    return new self(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('islandora.utils'),
+      $container->get('logger.channel.islandora'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($object, ?AccountInterface $account = NULL, $return_as_object = FALSE) {
+    /** @var \Drupal\node\NodeInterface $object */
+    $access = $object->access('update', $account, TRUE)
+      ->andIf($object->status->access('edit', $account, TRUE));
+
+    return $return_as_object ? $access : $access->isAllowed();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute(ContentEntityInterface $entity = NULL): void {
+    $transcript_media = $this->getMediaByUri('http://pcdm.org/use#Transcript');
+    $host_media = $this->getMediaByUri('http://pcdm.org/use#ServiceFile')
+        ?? $this->getMediaByUri('http://pcdm.org/use#OriginalFile');
+
+    if ($transcript_media && $host_media
+        && $transcript_media->bundle() === 'able_player_caption'
+        && $host_media->hasField('field_ableplayer_media_caption')
+        && $host_media->get('field_ableplayer_media_caption')->isEmpty()) {
+
+      $host_media->set('field_ableplayer_media_caption', ['target_id' => $transcript_media->id()]);
+      $host_media->save();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMediaByUri($entity, $uri) {
+    $term = $this->islandoraUtils->getTermForUri($uri);
+    return $this->islandoraUtils->getMediaWithTerm($entity, $term);
+  }
+
+}