Move all files to old/drupal/
This commit is contained in:
parent
8203e983d5
commit
7d76bf2968
468 changed files with 0 additions and 0 deletions
105
old/drupal/web/modules/custom/blog/src/Entity/Node/Post.php
Normal file
105
old/drupal/web/modules/custom/blog/src/Entity/Node/Post.php
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Entity\Node;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final class Post {
|
||||
|
||||
public const FIELD_EXTERNAL_LINK = 'field_external_link';
|
||||
public const FIELD_HAS_TWEET = 'field_has_tweet';
|
||||
public const FIELD_SEND_TO_SOCIAL_MEDIA = 'field_send_to_social_media';
|
||||
public const FIELD_SENT_TO_SOCIAL_MEDIA = 'field_sent_to_social_media';
|
||||
public const FIELD_TAGS = 'field_tags';
|
||||
|
||||
private NodeInterface $node;
|
||||
|
||||
public function __construct(EntityInterface $node) {
|
||||
$this->node = $node;
|
||||
}
|
||||
|
||||
public function bundle(): string {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
public function get(string $name): FieldItemListInterface {
|
||||
return $this->node->get($name);
|
||||
}
|
||||
|
||||
public function getExternalLink(): ?array {
|
||||
return ($link = $this->get(self::FIELD_EXTERNAL_LINK)->get(0))
|
||||
? $link->getValue()
|
||||
: NULL;
|
||||
}
|
||||
|
||||
public function getNode(): NodeInterface {
|
||||
|
||||
return $this->node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Term[]
|
||||
*/
|
||||
public function getTags(): Collection {
|
||||
return new Collection($this->get(self::FIELD_TAGS)->referencedEntities());
|
||||
}
|
||||
|
||||
public function hasBeenSentToSocialMedia(): bool {
|
||||
return (bool) $this->get(self::FIELD_SENT_TO_SOCIAL_MEDIA)->getString();
|
||||
}
|
||||
|
||||
public function hasTweet(): bool {
|
||||
return (bool) $this->get(self::FIELD_HAS_TWEET)->getString();
|
||||
}
|
||||
|
||||
public function id(): int {
|
||||
return (int) $this->node->id();
|
||||
}
|
||||
|
||||
public function isExternalPost(): bool {
|
||||
return (bool) $this->getExternalLink();
|
||||
}
|
||||
|
||||
public function label(): string {
|
||||
return $this->node->label();
|
||||
}
|
||||
|
||||
public function markAsSentToSocialMedia(): self {
|
||||
$this->set(self::FIELD_SENT_TO_SOCIAL_MEDIA, TRUE);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function save(): void {
|
||||
$this->node->save();
|
||||
}
|
||||
|
||||
public function set(string $name, $value): void {
|
||||
$this->node->set($name, $value);
|
||||
}
|
||||
|
||||
public function setTags(array $tags): void {
|
||||
$this->set(self::FIELD_TAGS, $tags);
|
||||
}
|
||||
|
||||
public function shouldSendToSocialMedia(): bool {
|
||||
return (bool) $this->get(self::FIELD_SEND_TO_SOCIAL_MEDIA)->getString();
|
||||
}
|
||||
|
||||
public function url(string $type, array $options = []): string {
|
||||
return $this->node->url($type, $options);
|
||||
}
|
||||
|
||||
public static function createFromNode(EntityInterface $node): self {
|
||||
// TODO: ensure that this is a node and a `post` type.
|
||||
return new self($node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Queue\QueueFactory;
|
||||
use Drupal\core_event_dispatcher\Event\Entity\AbstractEntityEvent;
|
||||
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
final class PushPostToSocialMediaOnceItIsPublished implements EventSubscriberInterface {
|
||||
|
||||
private QueueFactory $queueFactory;
|
||||
|
||||
public function __construct(QueueFactory $queueFactory) {
|
||||
$this->queueFactory = $queueFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
return [
|
||||
HookEventDispatcherInterface::ENTITY_INSERT => 'pushPost',
|
||||
HookEventDispatcherInterface::ENTITY_UPDATE => 'pushPost',
|
||||
];
|
||||
}
|
||||
|
||||
public function pushPost(AbstractEntityEvent $event): void {
|
||||
$entity = $event->getEntity();
|
||||
|
||||
if ($entity->getEntityTypeId() != 'node') {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Post $entity */
|
||||
if ($entity->bundle() != 'post') {
|
||||
return;
|
||||
}
|
||||
|
||||
$queue = $this->queueFactory->get('opdavies_blog.push_post_to_social_media');
|
||||
$queue->createQueue();
|
||||
|
||||
$queue->createItem([
|
||||
'post' => $entity,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\EventSubscriber;
|
||||
|
||||
use Drupal\core_event_dispatcher\Event\Entity\AbstractEntityEvent;
|
||||
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
final class SortTagsAlphabeticallyWhenPostIsSaved implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
return [
|
||||
HookEventDispatcherInterface::ENTITY_PRE_SAVE => 'sortTags',
|
||||
];
|
||||
}
|
||||
|
||||
public function sortTags(AbstractEntityEvent $event): void {
|
||||
$entity = $event->getEntity();
|
||||
|
||||
if ($entity->getEntityTypeId() != 'node') {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity->bundle() != 'post') {
|
||||
return;
|
||||
}
|
||||
|
||||
$post = Post::createFromNode($entity);
|
||||
|
||||
$sortedTags = $post->getTags()
|
||||
->sortBy(fn(TermInterface $tag) => $tag->label());
|
||||
|
||||
$post->setTags($sortedTags->toArray());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
final class OpdaviesBlogServiceProvider implements ServiceProviderInterface {
|
||||
|
||||
public function register(ContainerBuilder $container): void {
|
||||
foreach (['EventSubscriber', 'Repository', 'Service', 'UseCase'] as $directory) {
|
||||
$files = Finder::create()
|
||||
->in(__DIR__ . '/' . $directory)
|
||||
->files()
|
||||
->name('*.php');
|
||||
|
||||
foreach ($files as $file) {
|
||||
$class = 'Drupal\opdavies_blog\\' . $directory . '\\' .
|
||||
str_replace('/', '\\', substr($file->getRelativePathname(), 0, -4));
|
||||
|
||||
if ($container->hasDefinition($class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition = new Definition($class);
|
||||
$definition->setAutowired(TRUE);
|
||||
if ($directory == 'EventSubscriber') {
|
||||
$definition->addTag('event_subscriber');
|
||||
}
|
||||
$container->setDefinition($class, $definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\opdavies_blog\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Routing\CurrentRouteMatch;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\opdavies_blog\Repository\RelatedPostsRepository;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @Block(
|
||||
* id = "opdavies_blog_related_posts",
|
||||
* admin_label = @Translation("Related Posts"),
|
||||
* category = @Translation("Blog")
|
||||
* )
|
||||
*/
|
||||
class RelatedPostsBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
private CurrentRouteMatch $currentRouteMatch;
|
||||
|
||||
private RelatedPostsRepository $relatedPostsRepository;
|
||||
|
||||
public function __construct(
|
||||
array $configuration,
|
||||
string $pluginId,
|
||||
array $pluginDefinition,
|
||||
CurrentRouteMatch $currentRouteMatch,
|
||||
RelatedPostsRepository $relatedPostsRepository
|
||||
) {
|
||||
parent::__construct($configuration, $pluginId, $pluginDefinition);
|
||||
|
||||
$this->currentRouteMatch = $currentRouteMatch;
|
||||
$this->relatedPostsRepository = $relatedPostsRepository;
|
||||
}
|
||||
|
||||
public static function create(
|
||||
ContainerInterface $container,
|
||||
array $configuration,
|
||||
$pluginId,
|
||||
$pluginDefinition
|
||||
): self {
|
||||
return new self(
|
||||
$configuration,
|
||||
$pluginId,
|
||||
$pluginDefinition,
|
||||
$container->get('current_route_match'),
|
||||
$container->get(RelatedPostsRepository::class)
|
||||
);
|
||||
}
|
||||
|
||||
public function build(): array {
|
||||
$currentPost = $this->currentRouteMatch->getParameter('node');
|
||||
|
||||
/** @var Collection|Post[] $relatedPosts */
|
||||
$relatedPosts = $this->relatedPostsRepository->getFor($currentPost);
|
||||
|
||||
if ($relatedPosts->isEmpty()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$build['content'] = [
|
||||
'#items' => $relatedPosts
|
||||
->sortByDesc(fn(Post $post) => $post->getNode()->getCreatedTime())
|
||||
->map(fn(Post $post) => $this->generateLinkToPost($post))
|
||||
->slice(0, 3)
|
||||
->toArray(),
|
||||
'#theme' => 'item_list',
|
||||
];
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
public function getCacheMaxAge(): int {
|
||||
return 604800;
|
||||
}
|
||||
|
||||
public function getCacheContexts(): array {
|
||||
return Cache::mergeContexts(parent::getCacheContexts(), ['route']);
|
||||
}
|
||||
|
||||
public function getCacheTags(): array {
|
||||
/** @var Post $post */
|
||||
$post = $this->currentRouteMatch->getParameter('node');
|
||||
|
||||
return Cache::mergeTags(parent::getCacheTags(), ["node:{$post->id()}"]);
|
||||
}
|
||||
|
||||
private function generateLinkToPost(Post $post): Link {
|
||||
return Link::createFromRoute(
|
||||
$post->label(),
|
||||
'entity.node.canonical',
|
||||
['node' => $post->id()]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Plugin\QueueWorker;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Queue\QueueWorkerBase;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\opdavies_blog\Service\PostPusher\IftttPostPusher;
|
||||
use Drupal\opdavies_blog\Service\PostPusher\IntegromatPostPusher;
|
||||
use Drupal\opdavies_blog\Service\PostPusher\PostPusher;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @QueueWorker(
|
||||
* id = "opdavies_blog.push_post_to_social_media",
|
||||
* title = "Push a blog post to social media",
|
||||
* cron = {"time": 30}
|
||||
* )
|
||||
*/
|
||||
final class PostPusherQueueWorker extends QueueWorkerBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
private EntityStorageInterface $nodeStorage;
|
||||
|
||||
/**
|
||||
* @var array|PostPusher[]
|
||||
*/
|
||||
private array $postPushers;
|
||||
|
||||
public function __construct(
|
||||
array $configuration,
|
||||
string $pluginId,
|
||||
array $pluginDefinition,
|
||||
EntityStorageInterface $nodeStorage,
|
||||
array $postPushers
|
||||
) {
|
||||
parent::__construct($configuration, $pluginId, $pluginDefinition);
|
||||
|
||||
$this->nodeStorage = $nodeStorage;
|
||||
$this->postPushers = $postPushers;
|
||||
}
|
||||
|
||||
public static function create(
|
||||
ContainerInterface $container,
|
||||
array $configuration,
|
||||
$pluginId,
|
||||
$pluginDefinition
|
||||
) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$pluginId,
|
||||
$pluginDefinition,
|
||||
$container->get('entity_type.manager')->getStorage('node'),
|
||||
[
|
||||
$container->get(IftttPostPusher::class),
|
||||
$container->get(IntegromatPostPusher::class),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function processItem($data): void {
|
||||
/** @var Post $post */
|
||||
['post' => $post] = $data;
|
||||
|
||||
if (!$this->shouldBePushed($post)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$post->getNode()->isLatestRevision()) {
|
||||
$node = $this->nodeStorage->load($post->id());
|
||||
$post = Post::createFromNode($node);
|
||||
|
||||
if (!$this->shouldBePushed($post)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->postPushers as $pusher) {
|
||||
$pusher->push($post);
|
||||
}
|
||||
|
||||
$post->set(Post::FIELD_SENT_TO_SOCIAL_MEDIA, TRUE);
|
||||
$post->save();
|
||||
}
|
||||
|
||||
private function shouldBePushed(Post $post): bool {
|
||||
if ($post->isExternalPost()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!$post->getNode()->isPublished()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!$post->shouldSendToSocialMedia()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($post->hasBeenSentToSocialMedia()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Repository;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final class PostRepository {
|
||||
|
||||
private EntityStorageInterface $nodeStorage;
|
||||
|
||||
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
|
||||
$this->nodeStorage = $entityTypeManager->getStorage('node');
|
||||
}
|
||||
|
||||
public function getAll(): Collection {
|
||||
return new Collection(
|
||||
$this->nodeStorage->loadByProperties([
|
||||
'type' => 'post',
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Repository;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\Query\QueryInterface;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final class RelatedPostsRepository {
|
||||
|
||||
private EntityStorageInterface $nodeStorage;
|
||||
|
||||
public function __construct(
|
||||
EntityTypeManagerInterface $entityTypeManager
|
||||
) {
|
||||
$this->nodeStorage = $entityTypeManager->getStorage('node');
|
||||
}
|
||||
|
||||
public function getFor(Post $post): Collection {
|
||||
$tags = $post->get('field_tags')->referencedEntities();
|
||||
|
||||
if (!$tags) {
|
||||
return new Collection();
|
||||
}
|
||||
|
||||
$tagIds = (new Collection($tags))
|
||||
->map(fn(TermInterface $tag) => $tag->id())
|
||||
->values();
|
||||
|
||||
/** @var array $postIds */
|
||||
$postIds = $this->query($post, $tagIds)->execute();
|
||||
|
||||
$posts = $this->nodeStorage->loadMultiple($postIds);
|
||||
|
||||
return new Collection(array_values($posts));
|
||||
}
|
||||
|
||||
private function query(Post $post, Collection $tagIds): QueryInterface {
|
||||
$query = $this->nodeStorage->getQuery();
|
||||
|
||||
// Ensure that the current node ID is not returned as a related post.
|
||||
$query->condition('nid', $post->id(), '!=');
|
||||
|
||||
// Only return posts with the same tags.
|
||||
$query->condition('field_tags', $tagIds->toArray(), 'IN');
|
||||
|
||||
$query->condition('status', NodeInterface::PUBLISHED);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Service\PostPusher;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\opdavies_blog\UseCase\ConvertPostToTweet;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class IftttPostPusher extends WebhookPostPusher {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
private ConfigFactoryInterface $configFactory;
|
||||
|
||||
public function __construct(
|
||||
ConvertPostToTweet $convertPostToTweet,
|
||||
ClientInterface $client,
|
||||
ConfigFactoryInterface $configFactory
|
||||
) {
|
||||
$this->convertPostToTweet = $convertPostToTweet;
|
||||
$this->configFactory = $configFactory;
|
||||
|
||||
parent::__construct($convertPostToTweet, $client);
|
||||
}
|
||||
|
||||
public function push(Post $post): void {
|
||||
$url = $this->configFactory
|
||||
->get('opdavies_blog.settings')
|
||||
->get('post_tweet_webhook_url');
|
||||
|
||||
Assert::notNull($url, 'Cannot push the post if there is no URL.');
|
||||
|
||||
$this->client->post($url, [
|
||||
'form_params' => [
|
||||
'value1' => $this->t('Blogged: @text', ['@text' => ($this->convertPostToTweet)($post)])
|
||||
->render(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Service\PostPusher;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\opdavies_blog\UseCase\ConvertPostToTweet;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class IntegromatPostPusher extends WebhookPostPusher {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
private ConfigFactoryInterface $configFactory;
|
||||
|
||||
public function __construct(
|
||||
ConvertPostToTweet $convertPostToTweet,
|
||||
ClientInterface $client,
|
||||
ConfigFactoryInterface $configFactory
|
||||
) {
|
||||
$this->convertPostToTweet = $convertPostToTweet;
|
||||
$this->configFactory = $configFactory;
|
||||
|
||||
parent::__construct($convertPostToTweet, $client);
|
||||
}
|
||||
|
||||
public function push(Post $post): void {
|
||||
$url = $this->configFactory
|
||||
->get('opdavies_blog.settings')
|
||||
->get('integromat_webhook_url');
|
||||
|
||||
Assert::notNull($url, 'Cannot push the post if there is no URL.');
|
||||
|
||||
$this->client->post($url, [
|
||||
'form_params' => [
|
||||
'text' => $this->t('@text', ['@text' => ($this->convertPostToTweet)($post)])
|
||||
->render(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Service\PostPusher;
|
||||
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
|
||||
final class NullPostPusher implements PostPusher {
|
||||
|
||||
public function push(Post $post): void {}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Service\PostPusher;
|
||||
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
|
||||
interface PostPusher {
|
||||
|
||||
public function push(Post $post): void;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Service\PostPusher;
|
||||
|
||||
use Drupal\opdavies_blog\UseCase\ConvertPostToTweet;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
|
||||
abstract class WebhookPostPusher implements PostPusher {
|
||||
|
||||
protected ConvertPostToTweet $convertPostToTweet;
|
||||
|
||||
protected ClientInterface $client;
|
||||
|
||||
public function __construct(
|
||||
ConvertPostToTweet $convertPostToTweet,
|
||||
ClientInterface $client
|
||||
) {
|
||||
|
||||
$this->convertPostToTweet = $convertPostToTweet;
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\UseCase;
|
||||
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final class ConvertPostToTweet {
|
||||
|
||||
private Post $post;
|
||||
|
||||
public function __invoke(Post $post): string {
|
||||
$this->post = $post;
|
||||
|
||||
$parts = [
|
||||
$post->label(),
|
||||
$post->url('canonical', ['absolute' => TRUE]),
|
||||
$this->convertTermsToHashtags(),
|
||||
];
|
||||
|
||||
return implode(PHP_EOL . PHP_EOL, $parts);
|
||||
}
|
||||
|
||||
private function convertTermsToHashtags(): string {
|
||||
return $this->post
|
||||
->getTags()
|
||||
->filter(fn(Term $term) => !$this->tagsToRemove()
|
||||
->contains($term->label()))
|
||||
->map(fn(Term $term) => $this->convertTermToHashtag($term))
|
||||
->implode(' ');
|
||||
}
|
||||
|
||||
private function tagsToRemove(): Collection {
|
||||
// TODO: Move these values into configuration/settings.php.
|
||||
return new Collection([
|
||||
'Drupal Planet',
|
||||
]);
|
||||
}
|
||||
|
||||
private function convertTermToHashtag(Term $tag): string {
|
||||
return '#' . (new Collection(explode(' ', $tag->label())))
|
||||
->map(fn(string $word): string => ucfirst($word))
|
||||
->implode('');
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue