Try a different way of naming and grouping classes.
This commit is contained in:
Oliver Davies 2025-06-12 02:10:08 +01:00
parent 52c1b33711
commit 6b6b362a49
15 changed files with 111 additions and 59 deletions

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
use Drupal\Core\Render\BubbleableMetadata; use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\opd_daily_emails\Repository\DailyEmailNodeRepository; use Drupal\opd_daily_emails\DailyEmailNodeRepository;
/** /**
* Implements hook_token_info(). * Implements hook_token_info().

View file

@ -1,3 +1,3 @@
services: services:
Drupal\opd_daily_emails\Repository\DailyEmailNodeRepository: Drupal\opd_daily_emails\DailyEmailNodeRepository:
autowire: true autowire: true

View file

@ -2,11 +2,10 @@
declare(strict_types=1); declare(strict_types=1);
namespace Drupal\opd_daily_emails\Repository; namespace Drupal\opd_daily_emails;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
use Drupal\opd_daily_emails\Collection\DailyEmailCollection;
final class DailyEmailNodeRepository implements DailyEmailRepositoryInterface { final class DailyEmailNodeRepository implements DailyEmailRepositoryInterface {
@ -15,7 +14,7 @@ final class DailyEmailNodeRepository implements DailyEmailRepositoryInterface {
) { ) {
} }
public function getAll(): DailyEmailCollection { public function getAll(): DailyEmails {
$nodeStorage = $this->entityTypeManager $nodeStorage = $this->entityTypeManager
->getStorage('node'); ->getStorage('node');
@ -31,7 +30,7 @@ final class DailyEmailNodeRepository implements DailyEmailRepositoryInterface {
/** @var NodeInterface[] */ /** @var NodeInterface[] */
$nodes = $nodeStorage->loadMultiple($nodeIds); $nodes = $nodeStorage->loadMultiple($nodeIds);
return new DailyEmailCollection($nodes); return DailyEmails::new($nodes);
} }
} }

View file

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Drupal\opd_daily_emails;
interface DailyEmailRepositoryInterface {
public function getAll(): DailyEmails;
}

View file

@ -2,16 +2,16 @@
declare(strict_types=1); declare(strict_types=1);
namespace Drupal\opd_daily_emails\Collection; namespace Drupal\opd_daily_emails;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
final class DailyEmailCollection implements \Countable { final class DailyEmails implements \Countable {
/** /**
* @param array<positive-int, NodeInterface> $emails * @param array<positive-int, NodeInterface> $emails
*/ */
public function __construct( private function __construct(
private array $emails, private array $emails,
) { ) {
} }
@ -24,4 +24,8 @@ final class DailyEmailCollection implements \Countable {
return array_values($this->emails)[0]; return array_values($this->emails)[0];
} }
public static function new(array $emails): self {
return new self($emails);
}
} }

View file

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Drupal\opd_daily_emails\Repository;
use Drupal\opd_daily_emails\Collection\DailyEmailCollection;
interface DailyEmailRepositoryInterface {
public function getAll(): DailyEmailCollection;
}

View file

@ -2,14 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
namespace Drupal\Tests\opd_daily_emails\Kernel\Repository; namespace Drupal\Tests\opd_daily_emails\Kernel;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\node\Traits\NodeCreationTrait; use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\opd_daily_emails\Traits\DailyEmailTestTrait; use Drupal\Tests\opd_daily_emails\Traits\DailyEmailTestTrait;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
use Drupal\opd_daily_emails\Repository\DailyEmailNodeRepository; use Drupal\opd_daily_emails\DailyEmailNodeRepository;
use Drupal\opd_daily_emails\Repository\DailyEmailRepositoryInterface; use Drupal\opd_daily_emails\DailyEmailRepositoryInterface;
final class DailyEmailNodeRepositoryTest extends EntityKernelTestBase { final class DailyEmailNodeRepositoryTest extends EntityKernelTestBase {

View file

@ -5,8 +5,7 @@ declare(strict_types=1);
use Drupal\Core\Render\BubbleableMetadata; use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
use Drupal\opd_podcast\Entity\PodcastEpisode; use Drupal\opd_podcast\PodcastEpisode;
use Drupal\taxonomy\TermInterface;
/** /**
* Implements hook_entity_bundle_info_alter(). * Implements hook_entity_bundle_info_alter().
@ -86,20 +85,7 @@ function opd_podcast_tokens(string $type, array $tokens, array $data, array $opt
$node = $data['node'] ?? NULL; $node = $data['node'] ?? NULL;
assert($node instanceof PodcastEpisode); assert($node instanceof PodcastEpisode);
$guests = $node->getGuests(); $replacements[$original] = strval($node->getGuests());
assert(is_array($guests));
assert(!is_null($guests[0]));
assert($guests[0] instanceof TermInterface);
// TODO: allow for more than two guests.
if (count($guests) === 2) {
assert($guests[1] instanceof TermInterface);
$replacements[$original] = sprintf('%s %s %s', $guests[0]->label(), t('and'), $guests[1]->label());
break;
}
$replacements[$original] = $guests[0]->label();
break; break;
} }
} }

View file

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace Drupal\opd_podcast\Entity; namespace Drupal\opd_podcast;
use Drupal\node\Entity\Node; use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
@ -11,8 +11,8 @@ final class PodcastEpisode extends Node implements NodeInterface {
public const NODE_TYPE = 'podcast_episode'; public const NODE_TYPE = 'podcast_episode';
public function getGuests(): array { public function getGuests(): PodcastGuests {
return $this->get('field_podcast_guests')->referencedEntities(); return PodcastGuests::new($this->get('field_podcast_guests')->referencedEntities());
} }
} }

View file

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace Drupal\opd_podcast;
use Drupal\taxonomy\TermInterface;
/**
* @implements \IteratorAggregate<TermInterface>
*/
final class PodcastGuests implements \ArrayAccess, \Countable, \IteratorAggregate, \Stringable {
/**
* @param TermInterface[] $guests
*/
private function __construct(private array $guests) {
}
public function count(): int {
return count($this->guests);
}
public function getIterator(): \Traversable {
return new \ArrayIterator($this->guests);
}
public function offsetExists(mixed $offset): bool {
return isset($this->guests[$offset]);
}
public function offsetGet(mixed $offset): mixed {
return $this->guests[$offset];
}
public function offsetSet(mixed $offset, mixed $value): void {
$this->guests[$offset] = $value;
}
public function offsetUnset(mixed $offset): void {
unset($this->guests[$offset]);
}
public function __toString(): string {
// TODO: allow for more than two guests.
if (count($this->guests) === 2) {
assert($this->guests[1] instanceof TermInterface);
return sprintf('%s %s %s', $this->guests[0]->label(), t('and'), $this->guests[1]->label());
}
return strval($this->guests[0]->label());
}
/**
* @param TermInterface[] $guests
*/
public static function new(array $guests): self {
return new self($guests);
}
}

View file

@ -2,8 +2,8 @@
declare(strict_types=1); declare(strict_types=1);
use Drupal\opd_presentations\Entity\Event; use Drupal\opd_presentations\Event;
use Drupal\opd_presentations\Entity\Presentation; use Drupal\opd_presentations\Presentation;
/** /**
* Implements hook_entity_bundle_info_alter(). * Implements hook_entity_bundle_info_alter().

View file

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace Drupal\opd_presentations\Entity; namespace Drupal\opd_presentations;
use Drupal\paragraphs\Entity\Paragraph; use Drupal\paragraphs\Entity\Paragraph;
use Drupal\paragraphs\ParagraphInterface; use Drupal\paragraphs\ParagraphInterface;

View file

@ -2,19 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace Drupal\opd_presentations\Collection; namespace Drupal\opd_presentations;
use Drupal\opd_presentations\Entity\Event;
/** /**
* @implements \IteratorAggregate<Event> * @implements \IteratorAggregate<Event>
*/ */
readonly final class EventCollection implements \IteratorAggregate { readonly final class Events implements \IteratorAggregate {
/** /**
* @param Event[] $events * @param Event[] $events
*/ */
public function __construct(private array $events) { private function __construct(private array $events) {
} }
public function first(): Event { public function first(): Event {
@ -25,4 +23,11 @@ readonly final class EventCollection implements \IteratorAggregate {
return new \ArrayIterator($this->events); return new \ArrayIterator($this->events);
} }
/**
* @param Event[] $events
*/
public static function new(array $events): self {
return new self($events);
}
} }

View file

@ -2,24 +2,22 @@
declare(strict_types=1); declare(strict_types=1);
namespace Drupal\opd_presentations\Entity; namespace Drupal\opd_presentations;
use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\node\Entity\Node; use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
use Drupal\opd_presentations\Collection\EventCollection;
use Drupal\opd_presentations\Entity\Event;
final class Presentation extends Node implements NodeInterface { final class Presentation extends Node implements NodeInterface {
public const NODE_TYPE = 'presentation'; public const NODE_TYPE = 'presentation';
public function getPastEvents(): EventCollection { public function getPastEvents(): Events {
$events = $this->get('field_events')->referencedEntities(); $events = $this->get('field_events')->referencedEntities();
$today = (new DrupalDateTime('today'))->format('U'); $today = (new DrupalDateTime('today'))->format('U');
return new EventCollection(array_filter( return Events::new(array_filter(
array: $events, array: $events,
callback: fn (Event $event): bool => $event->getEventDate() < $today, callback: fn (Event $event): bool => $event->getEventDate() < $today,
)); ));

View file

@ -7,8 +7,8 @@ namespace Drupal\Tests\opd_presentations\Traits;
use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Tests\node\Traits\NodeCreationTrait; use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\ctools\Testing\EntityCreationTrait; use Drupal\ctools\Testing\EntityCreationTrait;
use Drupal\opd_presentations\Entity\Event; use Drupal\opd_presentations\Event;
use Drupal\opd_presentations\Entity\Presentation; use Drupal\opd_presentations\Presentation;
trait PresentationCreationTrait { trait PresentationCreationTrait {