Browse Source

Extracted logic to service

main
astanley 8 months ago
parent
commit
b73d0a8372
  1. 7
      caption_linker.services.yml
  2. 49
      src/Plugin/Action/LinkCaption.php
  3. 67
      src/Service/CaptionLinker.php
  4. 101
      tests/src/Unit/Service/CaptionLinkerTest.php

7
caption_linker.services.yml

@ -0,0 +1,7 @@
services:
caption_linker.caption_linker:
class: Drupal\caption_linker\Service\CaptionLinker
arguments:
- '@entity_type.manager'
- '@islandora.utils'
- '@logger.channel.islandora'

49
src/Plugin/Action/LinkCaption.php

@ -1,16 +1,13 @@
<?php
declare(strict_types=1);
namespace Drupal\caption_linker\Plugin\Action;
use Drupal\caption_linker\Service\CaptionLinker;
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;
/**
@ -22,20 +19,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* 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 {
@ -46,9 +29,7 @@ final class LinkCaption extends ActionBase implements ContainerFactoryPluginInte
array $configuration,
$plugin_id,
$plugin_definition,
private readonly EntityTypeManagerInterface $entityTypeManager,
private readonly IslandoraUtils $islandoraUtils,
private readonly LoggerChannelInterface $loggerChannelIslandora,
private readonly CaptionLinker $captionLinker,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
@ -61,9 +42,7 @@ final class LinkCaption extends ActionBase implements ContainerFactoryPluginInte
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('islandora.utils'),
$container->get('logger.channel.islandora'),
$container->get('caption_linker.caption_linker')
);
}
@ -74,7 +53,6 @@ final class LinkCaption extends ActionBase implements ContainerFactoryPluginInte
/** @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();
}
@ -82,26 +60,7 @@ final class LinkCaption extends ActionBase implements ContainerFactoryPluginInte
* {@inheritdoc}
*/
public function execute(ContentEntityInterface $entity = NULL): void {
$transcript_media = $this->getMediaByUri($entity, 'http://pcdm.org/use#Transcript');
$host_media = $this->getMediaByUri($entity, 'http://pcdm.org/use#ServiceFile')
?? $this->getMediaByUri($entity, '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);
$this->captionLinker->linkCaption($entity);
}
}

67
src/Service/CaptionLinker.php

@ -0,0 +1,67 @@
<?php
namespace Drupal\caption_linker\Service;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\islandora\IslandoraUtils;
/**
* Service to link transcript media items to host media items as captions.
*/
class CaptionLinker {
/**
* Constructs a new CaptionLinker service.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager service.
* @param \Drupal\islandora\IslandoraUtils $islandoraUtils
* The Islandora utils service.
* @param \Drupal\Core\Logger\LoggerChannelInterface $logger
* The logger for the Islandora channel.
*/
public function __construct(
protected readonly EntityTypeManagerInterface $entityTypeManager,
protected readonly IslandoraUtils $islandoraUtils,
protected readonly LoggerChannelInterface $logger
) {}
/**
* Links a transcript media item to a host media item as a caption.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The node entity to process.
*/
public function linkCaption(ContentEntityInterface $entity): void {
$transcript_media = $this->getMediaByUri($entity, 'http://pcdm.org/use#Transcript');
$host_media = $this->getMediaByUri($entity, 'http://pcdm.org/use#ServiceFile')
?? $this->getMediaByUri($entity, '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();
}
}
/**
* Gets a media item from an entity by its RDF use URI.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The node or media entity.
* @param string $uri
* The RDF use URI.
*
* @return \Drupal\media\MediaInterface|null
* The matching media item or NULL if not found.
*/
protected function getMediaByUri(ContentEntityInterface $entity, string $uri) {
$term = $this->islandoraUtils->getTermForUri($uri);
return $this->islandoraUtils->getMediaWithTerm($entity, $term);
}
}

101
tests/src/Unit/Service/CaptionLinkerTest.php

@ -0,0 +1,101 @@
<?php
namespace Drupal\Tests\caption_linker\Unit\Service;
use Drupal\caption_linker\Service\CaptionLinker;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\islandora\IslandoraUtils;
use Drupal\media\MediaInterface;
use Drupal\node\NodeInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\caption_linker\Service\CaptionLinker
* @group caption_linker
*/
class CaptionLinkerTest extends TestCase {
/**
* The service under test.
*/
protected CaptionLinker $captionLinker;
protected MockObject $islandoraUtils;
protected MockObject $entityTypeManager;
protected MockObject $logger;
protected function setUp(): void {
$this->islandoraUtils = $this->createMock(IslandoraUtils::class);
$this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
$this->logger = $this->createMock(LoggerChannelInterface::class);
$this->captionLinker = new CaptionLinker(
$this->entityTypeManager,
$this->islandoraUtils,
$this->logger
);
}
/**
* Tests linking the caption when all conditions are met.
*/
public function testLinkCaption(): void {
$node = $this->createMock(NodeInterface::class);
$transcript = $this->createMock(MediaInterface::class);
$host = $this->createMock(MediaInterface::class);
// Mock the Islandora methods.
$this->islandoraUtils->method('getTermForUri')->willReturn('mock_term');
$this->islandoraUtils->method('getMediaWithTerm')
->withConsecutive([$node, 'mock_term'], [$node, 'mock_term'], [$node, 'mock_term'])
->willReturnOnConsecutiveCalls($transcript, $host, null);
$transcript->method('bundle')->willReturn('able_player_caption');
// Field checks and save expectations.
$host->method('hasField')->with('field_ableplayer_media_caption')->willReturn(TRUE);
$host->method('get')->with('field_ableplayer_media_caption')->willReturn(
new class {
public function isEmpty() { return TRUE; }
}
);
$host->expects($this->once())->method('set')->with(
'field_ableplayer_media_caption',
['target_id' => $transcript->id()]
);
$host->expects($this->once())->method('save');
$transcript->method('id')->willReturn(42);
$this->captionLinker->linkCaption($node);
}
/**
* Tests that no linking occurs if caption field is not empty.
*/
public function testNoLinkIfFieldPopulated(): void {
$node = $this->createMock(NodeInterface::class);
$transcript = $this->createMock(MediaInterface::class);
$host = $this->createMock(MediaInterface::class);
$this->islandoraUtils->method('getTermForUri')->willReturn('mock_term');
$this->islandoraUtils->method('getMediaWithTerm')->willReturnOnConsecutiveCalls($transcript, $host);
$transcript->method('bundle')->willReturn('able_player_caption');
$host->method('hasField')->willReturn(TRUE);
$host->method('get')->willReturn(
new class {
public function isEmpty() { return FALSE; }
}
);
$host->expects($this->never())->method('set');
$host->expects($this->never())->method('save');
$this->captionLinker->linkCaption($node);
}
}
Loading…
Cancel
Save