Rename custom module directories
- Rename `opdavies_blog` to `blog`. - Rename `opdavies_blog_test` to `blog_test`. - Rename `opdavies_talks` to `talks`. - Rename `opdavies_talks_test` to `talks_test`. The files within the directories haven't changed, so there is no breaking change caused by renaming the directories. Please enter the commit message for your changes. Lines starting
This commit is contained in:
parent
d7d5a6c8a3
commit
cbe60209e6
59 changed files with 0 additions and 0 deletions
|
@ -0,0 +1,6 @@
|
|||
opdavies_blog.settings:
|
||||
type: config_object
|
||||
label: 'Blog module configuration'
|
||||
mapping:
|
||||
zapier_post_tweet_url:
|
||||
type: string
|
11
web/modules/custom/blog/drush.services.yml
Normal file
11
web/modules/custom/blog/drush.services.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
services:
|
||||
Drupal\opdavies_blog\Command\ExportBodyValuesForThemePurgingCommand:
|
||||
arguments: ['@database']
|
||||
autowire: true
|
||||
tags:
|
||||
- { name: drush.command }
|
||||
|
||||
Drupal\opdavies_blog\Command\FormatTagNamesCommand:
|
||||
autowire: true
|
||||
tags:
|
||||
- { name: drush.command }
|
20
web/modules/custom/blog/hooks/entity_type/build.inc
Normal file
20
web/modules/custom/blog/hooks/entity_type/build.inc
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Entity type build hooks.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Drupal\discoverable_entity_bundle_classes\Storage\Node\NodeStorage;
|
||||
|
||||
/**
|
||||
* Implements hook_entity_type_build().
|
||||
*/
|
||||
function opdavies_blog_entity_type_build(array &$entityTypes): void {
|
||||
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entityTypes */
|
||||
if (isset($entityTypes['node'])) {
|
||||
$entityTypes['node']->setStorageClass(NodeStorage::class);
|
||||
}
|
||||
}
|
28
web/modules/custom/blog/hooks/node_links/alter.inc
Normal file
28
web/modules/custom/blog/hooks/node_links/alter.inc
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Node links alter hooks.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_node_links_alter().
|
||||
*/
|
||||
function opdavies_blog_node_links_alter(array &$links, NodeInterface $node): void {
|
||||
if (!method_exists($node, 'getExternalLink')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($link = $node->getExternalLink()) {
|
||||
$links['node']['#links']['node-readmore']['url'] = Url::fromUri($link['uri']);
|
||||
$links['node']['#links']['node-readmore']['title'] = t('Read more<span class="visually-hidden"> about @title</span> (<span class="visually-hidden">on </span>@domain)', [
|
||||
'@domain' => $link['title'],
|
||||
'@title' => $node->label(),
|
||||
]);
|
||||
}
|
||||
}
|
18
web/modules/custom/blog/hooks/preprocess/block.inc
Normal file
18
web/modules/custom/blog/hooks/preprocess/block.inc
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Block preprocess hooks.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Implements hook_preprocess_HOOK().
|
||||
*/
|
||||
function opdavies_blog_preprocess_block(array &$variables): void {
|
||||
// Add the 'markup' class to blocks.
|
||||
if (in_array($variables['plugin_id'], ['views_block:featured_blog_posts-block_1'])) {
|
||||
$variables['attributes']['class'][] = 'markup';
|
||||
}
|
||||
}
|
21
web/modules/custom/blog/hooks/preprocess/node.inc
Normal file
21
web/modules/custom/blog/hooks/preprocess/node.inc
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Node preprocess functions.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Implements hook_preprocess_HOOK().
|
||||
*/
|
||||
function opdavies_blog_preprocess_node(array &$variables): void {
|
||||
if (!method_exists($variables['node'], 'getExternalLink')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($link = $variables['node']->getExternalLink()) {
|
||||
$variables['url'] = $link['uri'];
|
||||
}
|
||||
}
|
9
web/modules/custom/blog/opdavies_blog.info.yml
Normal file
9
web/modules/custom/blog/opdavies_blog.info.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
name: Oliver Davies blog
|
||||
type: module
|
||||
core_version_requirement: ^8 || ^9
|
||||
package: Custom
|
||||
dependencies:
|
||||
- drupal:node
|
||||
- discoverable_entity_bundle_classes:discoverable_entity_bundle_classes
|
||||
- hook_event_dispatcher:hook_event_dispatcher
|
||||
- paragraphs:paragraphs
|
17
web/modules/custom/blog/opdavies_blog.install
Normal file
17
web/modules/custom/blog/opdavies_blog.install
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Drupal\opdavies_blog\Repository\PostRepository;
|
||||
|
||||
/**
|
||||
* Mark existing blog posts as sent to social media.
|
||||
*/
|
||||
function opdavies_blog_update_8001(): void {
|
||||
$posts = \Drupal::service(PostRepository::class)->getAll();
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$post->set('field_sent_to_social_media', TRUE);
|
||||
$post->save();
|
||||
}
|
||||
}
|
18
web/modules/custom/blog/opdavies_blog.module
Normal file
18
web/modules/custom/blog/opdavies_blog.module
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Custom module.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
$finder = Finder::create()
|
||||
->in(__DIR__ . DIRECTORY_SEPARATOR . 'hooks')
|
||||
->name('/.[php|inc]$/');
|
||||
|
||||
foreach ($finder as $file) {
|
||||
include $file->getPathname();
|
||||
}
|
12
web/modules/custom/blog/opdavies_blog.services.yml
Normal file
12
web/modules/custom/blog/opdavies_blog.services.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
services:
|
||||
Drupal\opdavies_blog\EventSubscriber\PushBlogPostToSocialMedia:
|
||||
autowire: true
|
||||
tags:
|
||||
- { name: event_subscriber }
|
||||
|
||||
Drupal\opdavies_blog\EventSubscriber\ReorderBlogTags:
|
||||
tags:
|
||||
- { name: event_subscriber }
|
||||
|
||||
Drupal\opdavies_blog\Repository\PostRepository:
|
||||
autowire: true
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Command;
|
||||
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final class ExportBodyValuesForThemePurgingCommand {
|
||||
|
||||
private static array $tableNames = [
|
||||
'block_content__body',
|
||||
'node__body',
|
||||
];
|
||||
|
||||
private string $filename = 'body-field-values.txt';
|
||||
|
||||
private Connection $database;
|
||||
|
||||
public function __construct(Connection $database) {
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drush command to export body field values into a file.
|
||||
*
|
||||
* @command opdavies:export-body-values-for-theme-purging
|
||||
*/
|
||||
public function handle(): void {
|
||||
$values = Collection::make(self::$tableNames)
|
||||
->flatMap(fn(string $tableName) => $this->getValuesFromTable($tableName))
|
||||
->implode(PHP_EOL);
|
||||
|
||||
file_put_contents($this->getFilePath(), $values);
|
||||
}
|
||||
|
||||
private function getFilePath(): string {
|
||||
return drupal_get_path('theme', 'opdavies') . DIRECTORY_SEPARATOR . $this->filename;
|
||||
}
|
||||
|
||||
private function getValuesFromTable(string $tableName): array {
|
||||
return $this->database->select($tableName)
|
||||
->fields($tableName, ['body_value'])
|
||||
->execute()
|
||||
->fetchCol();
|
||||
}
|
||||
|
||||
}
|
138
web/modules/custom/blog/src/Command/FormatTagNamesCommand.php
Normal file
138
web/modules/custom/blog/src/Command/FormatTagNamesCommand.php
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Command;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drush\Commands\DrushCommands;
|
||||
|
||||
final class FormatTagNamesCommand extends DrushCommands {
|
||||
|
||||
/**
|
||||
* A lookup table for new name overrides.
|
||||
*
|
||||
* @var array
|
||||
* An associative array, keyed by the original tag name. The value is either
|
||||
* an overridden tag name or FALSE if the tag name is not to be changed.
|
||||
*/
|
||||
private static $tagNames = [
|
||||
'accessible-bristol' => 'Accessible Bristol',
|
||||
'admin:hover' => FALSE,
|
||||
'aria' => 'ARIA',
|
||||
'cck' => 'CCK',
|
||||
'centos' => 'CentOS',
|
||||
'css' => 'CSS',
|
||||
'dcbristol' => FALSE,
|
||||
'ddev' => 'DDEV',
|
||||
'drupal-association' => 'Drupal Association',
|
||||
'drupal-bristol' => 'Drupal Bristol',
|
||||
'drupal-commerce' => 'Drupal Commerce',
|
||||
'drupal-planet' => 'Drupal Planet',
|
||||
'drupal-vm' => 'Drupal VM',
|
||||
'drupal-vm-generator' => 'Drupal VM Generator',
|
||||
'drupalcamp' => 'DrupalCamp',
|
||||
'drupalcamp-bristol' => 'DrupalCamp Bristol',
|
||||
'drupalcamp-london' => 'DrupalCamp London',
|
||||
'drupalcamp-north' => 'DrupalCamp North',
|
||||
'drupalcon' => 'DrupalCon',
|
||||
'entity-api' => 'Entity API',
|
||||
'fancy-slide' => 'Fancy Slide',
|
||||
'field-collection' => 'Field Collection',
|
||||
'filefield' => 'FileField',
|
||||
'form-api' => 'Form API',
|
||||
'git-flow' => 'Git Flow',
|
||||
'github' => 'GitHub',
|
||||
'github-actions' => 'GitHub Actions',
|
||||
'illuminate-collections' => 'Illuminate Collections',
|
||||
'image-caption' => 'Image Caption',
|
||||
'imagecache' => 'ImageCache',
|
||||
'imagefield' => 'ImageField',
|
||||
'imagefield-import' => 'ImageField Import',
|
||||
'javascript' => 'JavaScript',
|
||||
'laravel-collections' => 'Laravel Collections',
|
||||
'laravel-mix' => 'Laravel Mix',
|
||||
'linux-journal' => 'Linux Journal',
|
||||
'mac-os-x' => 'macOS',
|
||||
'mamp' => 'MAMP',
|
||||
'mod_rewrite' => FALSE,
|
||||
'npm' => FALSE,
|
||||
'oliverdavies.co.uk' => FALSE,
|
||||
'php' => 'PHP',
|
||||
'php-south-wales' => 'PHP South Wales',
|
||||
'phpstorm' => 'PhpStorm',
|
||||
'phpsw' => 'PHPSW',
|
||||
'phpunit' => 'PHPUnit',
|
||||
'postcss' => 'PostCSS',
|
||||
'psr' => 'PSR',
|
||||
'regular-expression' => 'Regular expressions',
|
||||
'sequel-pro' => 'Sequel Pro',
|
||||
'settings.php' => FALSE,
|
||||
'sql' => 'SQL',
|
||||
'ssh' => 'SSH',
|
||||
'sublime-text' => 'Sublime Text',
|
||||
'svn' => 'SVN',
|
||||
'swdug' => 'SWDUG',
|
||||
'symfonylive' => 'SymfonyLive',
|
||||
'tailwind-css' => 'Tailwind CSS',
|
||||
'tdd' => 'TDD',
|
||||
'test-driven-drupal' => 'Test Driven Drupal',
|
||||
'views-attach' => 'Views Attach',
|
||||
'virtualbox' => 'VirtualBox',
|
||||
'vuejs' => 'VueJS',
|
||||
'virtualhostx' => 'VirtualHostX',
|
||||
];
|
||||
|
||||
/**
|
||||
* The taxonomy term storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
private $termStorage;
|
||||
|
||||
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
|
||||
parent::__construct();
|
||||
|
||||
$this->termStorage = $entityTypeManager->getStorage('taxonomy_term');
|
||||
}
|
||||
|
||||
/**
|
||||
* Drush command for updating legacy tag names.
|
||||
*
|
||||
* @command opdavies:update-tag-names
|
||||
*/
|
||||
public function updateTagNames(): void {
|
||||
foreach ($this->getTags() as $tag) {
|
||||
$name = $tag->label();
|
||||
$newName = $this->getNewTagName($name);
|
||||
|
||||
if ($newName === NULL) {
|
||||
$this->writeln(sprintf('Skipping %s.', $name));
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->writeln(sprintf('Updating %s to %s.', $name, $newName));
|
||||
$tag->name = $newName;
|
||||
$tag->save();
|
||||
}
|
||||
}
|
||||
|
||||
private function getTags(): array {
|
||||
return $this->termStorage->loadByProperties([
|
||||
'vid' => 'tags',
|
||||
]);
|
||||
}
|
||||
|
||||
private function getNewTagName(string $tagName): ?string {
|
||||
if (!array_key_exists($tagName, static::$tagNames)) {
|
||||
return str_replace('-', ' ', ucfirst($tagName));
|
||||
}
|
||||
|
||||
if (static::$tagNames[$tagName] === FALSE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return static::$tagNames[$tagName];
|
||||
}
|
||||
|
||||
}
|
83
web/modules/custom/blog/src/Entity/Node/Post.php
Normal file
83
web/modules/custom/blog/src/Entity/Node/Post.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\Entity\Node;
|
||||
|
||||
use Drupal\discoverable_entity_bundle_classes\ContentEntityBundleInterface;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Defines an blog post node class.
|
||||
*
|
||||
* @ContentEntityBundleClass(
|
||||
* label = @Translation("Blog post"),
|
||||
* entity_type = "node",
|
||||
* bundle = "post"
|
||||
* );
|
||||
*/
|
||||
class Post extends Node implements ContentEntityBundleInterface {
|
||||
|
||||
public function getExternalLink(): ?array {
|
||||
return ($link = $this->get('field_external_link')->get(0))
|
||||
? $link->getValue()
|
||||
: NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Term[]
|
||||
*/
|
||||
public function getTags(): Collection {
|
||||
return new Collection($this->get('field_tags')->referencedEntities());
|
||||
}
|
||||
|
||||
public function hasBeenSentToSocialMedia(): bool {
|
||||
return (bool) $this->get('field_sent_to_social_media')->getString();
|
||||
}
|
||||
|
||||
public function hasTweet(): bool {
|
||||
return (bool) $this->get('field_has_tweet')->getString();
|
||||
}
|
||||
|
||||
public function isExternalPost(): bool {
|
||||
return (bool) $this->getExternalLink();
|
||||
}
|
||||
|
||||
public function setTags(array $tags): void {
|
||||
$this->set('field_tags', $tags);
|
||||
}
|
||||
|
||||
public function toTweet(): string {
|
||||
$parts = [
|
||||
$this->label(),
|
||||
$this->url('canonical', ['absolute' => TRUE]),
|
||||
$this->convertTermsToHashtags(),
|
||||
];
|
||||
|
||||
return implode(PHP_EOL . PHP_EOL, $parts);
|
||||
}
|
||||
|
||||
private function convertTermsToHashtags(): string {
|
||||
return $this->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('');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Config\ImmutableConfig;
|
||||
use Drupal\hook_event_dispatcher\Event\Entity\BaseEntityEvent;
|
||||
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
final class PushBlogPostToSocialMedia implements EventSubscriberInterface {
|
||||
|
||||
private ClientInterface $client;
|
||||
|
||||
private ImmutableConfig $config;
|
||||
|
||||
public function __construct(
|
||||
ConfigFactoryInterface $configFactory,
|
||||
Client $client
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->config = $configFactory->get('opdavies_blog.settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
return [
|
||||
HookEventDispatcherInterface::ENTITY_INSERT => 'onEntityUpdate',
|
||||
HookEventDispatcherInterface::ENTITY_UPDATE => 'onEntityUpdate',
|
||||
];
|
||||
}
|
||||
|
||||
public function onEntityUpdate(BaseEntityEvent $event): void {
|
||||
$entity = $event->getEntity();
|
||||
|
||||
if ($entity->getEntityTypeId() != 'node') {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Post $entity */
|
||||
if ($entity->bundle() != 'post') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$entity->isPublished()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this post has already been sent to social media, do not send it again.
|
||||
if ($entity->hasBeenSentToSocialMedia()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity->isExternalPost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$url = $this->config->get('zapier_post_tweet_url')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->client->post($url, [
|
||||
'form_params' => [
|
||||
'message' => $entity->toTweet(),
|
||||
],
|
||||
]);
|
||||
|
||||
$entity->set('field_sent_to_social_media', TRUE);
|
||||
$entity->save();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog\EventSubscriber;
|
||||
|
||||
use Drupal\hook_event_dispatcher\Event\Entity\BaseEntityEvent;
|
||||
use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
final class ReorderBlogTags implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
return [
|
||||
HookEventDispatcherInterface::ENTITY_PRE_SAVE => 'onEntityPreSave',
|
||||
];
|
||||
}
|
||||
|
||||
public function onEntityPresave(BaseEntityEvent $event): void {
|
||||
$entity = $event->getEntity();
|
||||
|
||||
if ($entity->getEntityTypeId() != 'node') {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Post $entity */
|
||||
if ($entity->bundle() != 'post') {
|
||||
return;
|
||||
}
|
||||
|
||||
$sortedTags = $entity->getTags()
|
||||
->sortBy(fn(TermInterface $tag) => $tag->label());
|
||||
|
||||
$entity->setTags($sortedTags->toArray());
|
||||
}
|
||||
|
||||
}
|
27
web/modules/custom/blog/src/Repository/PostRepository.php
Normal file
27
web/modules/custom/blog/src/Repository/PostRepository.php
Normal file
|
@ -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,22 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_external_link
|
||||
- node.type.post
|
||||
module:
|
||||
- link
|
||||
id: node.post.field_external_link
|
||||
field_name: field_external_link
|
||||
entity_type: node
|
||||
bundle: post
|
||||
label: 'External link'
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
link_type: 16
|
||||
title: 2
|
||||
field_type: link
|
|
@ -0,0 +1,22 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_has_tweet
|
||||
- node.type.post
|
||||
id: node.post.field_has_tweet
|
||||
field_name: field_has_tweet
|
||||
entity_type: node
|
||||
bundle: post
|
||||
label: 'Has tweet'
|
||||
description: 'Check to include Twitter''s widget.js script for this page.'
|
||||
required: false
|
||||
translatable: false
|
||||
default_value:
|
||||
-
|
||||
value: 0
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
on_label: 'Yes'
|
||||
off_label: 'No'
|
||||
field_type: boolean
|
|
@ -0,0 +1,22 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_sent_to_social_media
|
||||
- node.type.post
|
||||
id: node.post.field_sent_to_social_media
|
||||
field_name: field_sent_to_social_media
|
||||
entity_type: node
|
||||
bundle: post
|
||||
label: 'Sent to social media'
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value:
|
||||
-
|
||||
value: 0
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
on_label: 'On'
|
||||
off_label: 'Off'
|
||||
field_type: boolean
|
|
@ -0,0 +1,28 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_tags
|
||||
- node.type.post
|
||||
- taxonomy.vocabulary.tags
|
||||
id: node.post.field_tags
|
||||
field_name: field_tags
|
||||
entity_type: node
|
||||
bundle: post
|
||||
label: Tags
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:taxonomy_term'
|
||||
handler_settings:
|
||||
target_bundles:
|
||||
tags: tags
|
||||
sort:
|
||||
field: name
|
||||
direction: asc
|
||||
auto_create: true
|
||||
auto_create_bundle: ''
|
||||
field_type: entity_reference
|
|
@ -0,0 +1,18 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- link
|
||||
- node
|
||||
id: node.field_external_link
|
||||
field_name: field_external_link
|
||||
entity_type: node
|
||||
type: link
|
||||
settings: { }
|
||||
module: link
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
|
@ -0,0 +1,17 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
id: node.field_has_tweet
|
||||
field_name: field_has_tweet
|
||||
entity_type: node
|
||||
type: boolean
|
||||
settings: { }
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
|
@ -0,0 +1,17 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
id: node.field_sent_to_social_media
|
||||
field_name: field_sent_to_social_media
|
||||
entity_type: node
|
||||
type: boolean
|
||||
settings: { }
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
|
@ -0,0 +1,19 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- taxonomy
|
||||
id: node.field_tags
|
||||
field_name: field_tags
|
||||
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
|
|
@ -0,0 +1,11 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
third_party_settings: { }
|
||||
name: 'Blog post'
|
||||
type: post
|
||||
description: 'A single blog post.'
|
||||
help: ''
|
||||
new_revision: true
|
||||
preview_mode: 1
|
||||
display_submitted: true
|
|
@ -0,0 +1,7 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
name: Tags
|
||||
vid: tags
|
||||
description: 'Tags for categorising blog posts.'
|
||||
weight: 0
|
|
@ -0,0 +1,4 @@
|
|||
name: Oliver Davies Posts Test
|
||||
type: module
|
||||
core_version_requirement: ^8 || ^9
|
||||
hidden: true
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\opdavies_blog_test\Factory;
|
||||
|
||||
use Assert\Assert;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
final class PostFactory {
|
||||
|
||||
private Collection $tags;
|
||||
|
||||
private string $title = 'This is a test blog post';
|
||||
|
||||
public function __construct() {
|
||||
$this->tags = new Collection();
|
||||
}
|
||||
|
||||
public function create(array $overrides = []): Post {
|
||||
$this->tags->each(function (TermInterface $tag): void {
|
||||
Assert::that($tag->bundle())->same('tags');
|
||||
});
|
||||
|
||||
$values = [
|
||||
'field_tags' => $this->tags->toArray(),
|
||||
'title' => $this->title,
|
||||
'type' => 'post',
|
||||
];
|
||||
|
||||
/** @var Post $post */
|
||||
$post = Node::create($values + $overrides);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function setTitle(string $title): self {
|
||||
Assert::that($title)->notEmpty();
|
||||
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withTags(array $tags): self {
|
||||
foreach ($tags as $tag) {
|
||||
Assert::that($tag)->notEmpty()->string();
|
||||
|
||||
$this->tags->push(
|
||||
Term::create(['vid' => 'tags', 'name' => $tag])
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\custom\Kernel\Entity\Node;
|
||||
|
||||
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
|
||||
use Drupal\opdavies_blog_test\Factory\PostFactory;
|
||||
|
||||
final class PostTest extends EntityKernelTestBase {
|
||||
|
||||
public static $modules = [
|
||||
// Core.
|
||||
'node',
|
||||
'link',
|
||||
'taxonomy',
|
||||
|
||||
// Contrib.
|
||||
'discoverable_entity_bundle_classes',
|
||||
|
||||
// Custom.
|
||||
'opdavies_blog',
|
||||
'opdavies_blog_test',
|
||||
];
|
||||
|
||||
/** @test */
|
||||
public function it_can_determine_if_a_post_contains_a_tweet(): void {
|
||||
$post = (new PostFactory())->create();
|
||||
$post->save();
|
||||
|
||||
$this->assertFalse($post->hasTweet());
|
||||
|
||||
$post = (new PostFactory())->create(['field_has_tweet' => TRUE]);
|
||||
$post->save();
|
||||
|
||||
$this->assertTrue($post->hasTweet());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_converts_a_post_to_a_tweet(): void {
|
||||
$post = (new PostFactory())
|
||||
->setTitle('Creating a custom PHPUnit command for DDEV')
|
||||
->withTags(['Automated testing', 'DDEV', 'Drupal', 'Drupal 8', 'PHP'])
|
||||
->create();
|
||||
|
||||
$post->save();
|
||||
|
||||
$expected = <<<EOF
|
||||
Creating a custom PHPUnit command for DDEV
|
||||
|
||||
http://localhost/node/1
|
||||
|
||||
#AutomatedTesting #DDEV #Drupal #Drupal8 #PHP
|
||||
EOF;
|
||||
|
||||
$this->assertSame($expected, $post->toTweet());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function certain_terms_are_not_added_as_hashtags(): void {
|
||||
$post = (new PostFactory())
|
||||
->setTitle('Drupal Planet should not be added as a hashtag')
|
||||
->withTags(['Drupal', 'Drupal Planet', 'PHP'])
|
||||
->create();
|
||||
|
||||
$post->save();
|
||||
|
||||
$expected = <<<EOF
|
||||
Drupal Planet should not be added as a hashtag
|
||||
|
||||
http://localhost/node/1
|
||||
|
||||
#Drupal #PHP
|
||||
EOF;
|
||||
|
||||
$this->assertSame($expected, $post->toTweet());
|
||||
}
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
|
||||
$this->installConfig(['opdavies_blog_test']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\opdavies_blog\Kernel;
|
||||
|
||||
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\opdavies_blog\Entity\Node\Post;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Drupal\taxonomy\VocabularyInterface;
|
||||
use Drupal\Tests\node\Traits\NodeCreationTrait;
|
||||
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
|
||||
|
||||
final class ReorderBlogTagsTest extends EntityKernelTestBase {
|
||||
|
||||
use NodeCreationTrait;
|
||||
use TaxonomyTestTrait;
|
||||
|
||||
public static $modules = [
|
||||
// Core.
|
||||
'node',
|
||||
'taxonomy',
|
||||
'link',
|
||||
|
||||
// Contrib.
|
||||
'discoverable_entity_bundle_classes',
|
||||
'hook_event_dispatcher',
|
||||
|
||||
// Custom.
|
||||
'opdavies_blog_test',
|
||||
'opdavies_blog',
|
||||
];
|
||||
|
||||
/** @test */
|
||||
public function it_reorders_tags_on_blog_posts_to_be_arranged_alphabetically(): void {
|
||||
/** @var VocabularyInterface $vocabulary */
|
||||
$vocabulary = Vocabulary::load('tags');
|
||||
|
||||
$this->createTerm($vocabulary, ['name' => 'Drupal']); // 1
|
||||
$this->createTerm($vocabulary, ['name' => 'PHP']); // 2
|
||||
$this->createTerm($vocabulary, ['name' => 'Symfony']); // 3
|
||||
|
||||
$post = $this->createNode([
|
||||
'field_tags' => [3, 1, 2],
|
||||
'type' => 'post',
|
||||
]);
|
||||
|
||||
/** @var Post $post */
|
||||
$post = Node::load($post->id());
|
||||
|
||||
$this->assertSame(
|
||||
['Drupal', 'PHP', 'Symfony'],
|
||||
$post->getTags()
|
||||
->map(fn(TermInterface $tag) => $tag->label())
|
||||
->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig([
|
||||
'filter',
|
||||
'opdavies_blog_test',
|
||||
]);
|
||||
|
||||
$this->installEntitySchema('taxonomy_vocabulary');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue