diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 4ecddd9..851e78d 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -73,6 +73,14 @@
+
+
+
+ GETTERS_AND_SETTERS
+ KEEP
+
+
+
\ No newline at end of file
diff --git a/bin/run-tests.sh b/bin/run-tests.sh
index d2ffa98..358ca47 100755
--- a/bin/run-tests.sh
+++ b/bin/run-tests.sh
@@ -9,10 +9,14 @@ symfony php vendor/bin/phpcs -n \
--exclude="Drupal.Commenting.ClassComment,Drupal.Commenting.FunctionComment" \
web/modules/custom
-# symfony php vendor/bin/phpcs -ns \
-# --standard="Drupal,DrupalPractice" \
-# --extensions="php,module,inc,install,test,profile,theme" \
-# --exclude="Drupal.Commenting.ClassComment,Drupal.Commenting.DocComment,Drupal.Commenting.FunctionComment,Drupal.NamingConventions.ValidFunctionName" \
-# web/modules/custom/**/tests
+symfony php vendor/bin/phpcs -n \
+ --standard="Drupal,DrupalPractice" \
+ --extensions="php,module,inc,install,test,profile,theme" \
+ --exclude="Drupal.Commenting.ClassComment,Drupal.Commenting.DocComment,Drupal.Commenting.FunctionComment,Drupal.NamingConventions.ValidFunctionName" \
+ web/modules/custom/**/tests
vendor/bin/phpstan analyze
+
+symfony php vendor/bin/phpunit \
+ -c web/core \
+ "$@"
diff --git a/composer.json b/composer.json
index eb8ee60..cf0d2ee 100644
--- a/composer.json
+++ b/composer.json
@@ -20,6 +20,7 @@
"drupal/config_ignore": "^2.2",
"drupal/core-composer-scaffold": "^8.8",
"drupal/core-recommended": "^8.8",
+ "drupal/hook_event_dispatcher": "^1.28",
"drupal/markdown": "^1.3",
"drupal/metatag": "^1.11",
"drupal/migrate_plus": "^5.0",
diff --git a/composer.lock b/composer.lock
index bc5b24c..60a52f6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "48b1c5f01bc8e5486f59462cb6b68de4",
+ "content-hash": "2800d415e7b235b84c6922ceaa045ed8",
"packages": [
{
"name": "asm89/stack-cors",
@@ -2177,6 +2177,108 @@
"source": "https://git.drupalcode.org/project/entity_reference_revisions"
}
},
+ {
+ "name": "drupal/hook_event_dispatcher",
+ "version": "1.28.0",
+ "source": {
+ "type": "git",
+ "url": "https://git.drupalcode.org/project/hook_event_dispatcher.git",
+ "reference": "8.x-1.28"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://ftp.drupal.org/files/projects/hook_event_dispatcher-8.x-1.28.zip",
+ "reference": "8.x-1.28",
+ "shasum": "a8e836015f27c87ad0584452cea3bfb02f0e4f2b"
+ },
+ "require": {
+ "drupal/core": "^8 || ^9"
+ },
+ "require-dev": {
+ "drupal/coder": "8.3.1",
+ "drupal/core": "^8.8",
+ "drupal/eck": "^1.0@alpha",
+ "drupal/paragraphs": "^1.10",
+ "drupal/webform": "*",
+ "mockery/mockery": "^1.3",
+ "php-parallel-lint/php-parallel-lint": "^1.0",
+ "phpmd/phpmd": "2.7.0",
+ "phpunit/phpunit": "^7",
+ "squizlabs/php_codesniffer": "^3.4"
+ },
+ "suggest": {
+ "drupal/paragraphs": "Enables the creation of paragraphs entities.",
+ "drupal/token": "Provides additional tokens not supported by core (most notably fields), as well as a UI for browsing tokens."
+ },
+ "type": "drupal-module",
+ "extra": {
+ "drupal": {
+ "version": "8.x-1.28",
+ "datestamp": "1588695401",
+ "security-coverage": {
+ "status": "covered",
+ "message": "Covered by Drupal's security advisory policy"
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Drupal\\hook_event_dispatcher\\": "src/",
+ "Drupal\\webform_event_dispatcher\\": "modules/webform_event_dispatcher/src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Drupal\\Tests\\hook_event_dispatcher\\": "tests/src/",
+ "Drupal\\Tests\\webform_event_dispatcher\\": "modules/webform_event_dispatcher/tests/src/",
+ "Drupal\\Tests\\": "vendor/drupal/core/tests/Drupal/Tests",
+ "Drupal\\TestTools\\": "vendor/drupal/core/tests/Drupal/TestTools",
+ "Drupal\\views\\": "vendor/drupal/core/modules/views/src/"
+ }
+ },
+ "notification-url": "https://packages.drupal.org/8/downloads",
+ "scripts": {
+ "test": [
+ "@phplint",
+ "@phpunit",
+ "@phpcs",
+ "@phpmd"
+ ],
+ "phplint": [
+ "vendor/bin/parallel-lint --exclude vendor/ --exclude .idea/ -e php,module,inc,install,profile,theme ."
+ ],
+ "phpunit": [
+ "vendor/bin/phpunit --configuration=phpunit.xml"
+ ],
+ "phpcs": [
+ "vendor/bin/phpcs --ignore=vendor/,.idea/ --standard=vendor/drupal/coder/coder_sniffer/Drupal/ruleset.xml --extensions=php,module,inc,install,profile,theme --report=full --warning-severity=0 ."
+ ],
+ "phpcbf": [
+ "vendor/bin/phpcbf --ignore=vendor/,.idea/ --standard=vendor/drupal/coder/coder_sniffer/Drupal/ruleset.xml --extensions=php,module,inc,install,profile,theme ."
+ ],
+ "phpmd": [
+ "vendor/bin/phpmd --exclude vendor/,.idea/ --suffixes php,module,inc,install,profile,theme . text phpmd.xml"
+ ]
+ },
+ "license": [
+ "GPL-2.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "pdenooijer",
+ "homepage": "https://www.drupal.org/user/3175437"
+ },
+ {
+ "name": "robin.ingelbrecht",
+ "homepage": "https://www.drupal.org/user/2339074"
+ }
+ ],
+ "description": "Dispatches events for several drupal core hooks.",
+ "homepage": "https://www.drupal.org/project/hook_event_dispatcher",
+ "support": {
+ "source": "https://git.drupalcode.org/project/hook_event_dispatcher"
+ }
+ },
{
"name": "drupal/markdown",
"version": "1.3.0",
diff --git a/config/default/core.extension.yml b/config/default/core.extension.yml
index 06c7d55..bc6331c 100644
--- a/config/default/core.extension.yml
+++ b/config/default/core.extension.yml
@@ -17,6 +17,7 @@ module:
field_ui: 0
file: 0
filter: 0
+ hook_event_dispatcher: 0
image: 0
link: 0
markdown: 0
diff --git a/phpstan.neon b/phpstan.neon
index 85d00f4..7aa084a 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -7,6 +7,9 @@ parameters:
- *Test.php
- *TestBase.php
checkMissingIterableValueType: false
+ ignoreErrors:
+ - '#Call to an undefined method Drupal\\Core\\Entity\\EntityInterface::get()#'
+ - '#Call to an undefined method Drupal\\Core\\Entity\\EntityInterface::set()#'
includes:
- vendor/mglaman/phpstan-drupal/extension.neon
- vendor/phpstan/phpstan-deprecation-rules/rules.neon
diff --git a/web/modules/custom/custom/custom.info.yml b/web/modules/custom/custom/custom.info.yml
index 82617ad..46f6f5a 100644
--- a/web/modules/custom/custom/custom.info.yml
+++ b/web/modules/custom/custom/custom.info.yml
@@ -3,3 +3,7 @@ type: module
core: 8.x
core_version_requirements: ^8 || ^9
package: Custom
+dependencies:
+ - drupal:node
+ - hook_event_dispatcher:hook_event_dispatcher
+ - paragraphs:paragraphs
diff --git a/web/modules/custom/custom/custom.services.yml b/web/modules/custom/custom/custom.services.yml
new file mode 100644
index 0000000..f55ff04
--- /dev/null
+++ b/web/modules/custom/custom/custom.services.yml
@@ -0,0 +1,4 @@
+services:
+ Drupal\custom\EventSubscriber\UpdateTalkCreatedDateOnSave:
+ tags:
+ - { name: event_subscriber }
diff --git a/web/modules/custom/custom/src/EventSubscriber/UpdateTalkCreatedDateOnSave.php b/web/modules/custom/custom/src/EventSubscriber/UpdateTalkCreatedDateOnSave.php
new file mode 100644
index 0000000..3dc01e9
--- /dev/null
+++ b/web/modules/custom/custom/src/EventSubscriber/UpdateTalkCreatedDateOnSave.php
@@ -0,0 +1,64 @@
+ 'entityInsertOrUpdate',
+ HookEventDispatcherInterface::ENTITY_UPDATE => 'entityInsertOrUpdate',
+ ];
+ }
+
+ public function entityInsertOrUpdate(BaseEntityEvent $event): void {
+ if ($event->getEntity()->getEntityTypeId() != 'node') {
+ return;
+ }
+
+ if ($event->getEntity()->bundle() != 'talk') {
+ return;
+ }
+
+ $this->updateCreatedDate($event->getEntity());
+ }
+
+ private function updateCreatedDate(EntityInterface $talk): void {
+ if (!$eventDate = $this->findLatestEventDate($talk)) {
+ return;
+ }
+
+ $talkDate = (new \DateTime($eventDate))->getTimestamp();
+
+ if ($talkDate == $talk->get('created')->getString()) {
+ return;
+ }
+
+ $talk->set('created', $talkDate);
+ }
+
+ /**
+ * Find the date for the latest event.
+ *
+ * @return string|null
+ */
+ private function findLatestEventDate(EntityInterface $talk) {
+ return Collection::make($talk->get('field_events')->referencedEntities())
+ ->map(fn(ParagraphInterface $event) => $event->get('field_date')
+ ->getString())
+ ->max();
+ }
+
+}
diff --git a/web/modules/custom/custom/src/Plugin/migrate/destination/OpdTalk.php b/web/modules/custom/custom/src/Plugin/migrate/destination/OpdTalk.php
index 01f4f8c..648d6e0 100644
--- a/web/modules/custom/custom/src/Plugin/migrate/destination/OpdTalk.php
+++ b/web/modules/custom/custom/src/Plugin/migrate/destination/OpdTalk.php
@@ -12,6 +12,8 @@ use Drupal\paragraphs\Entity\Paragraph;
use Illuminate\Support\Collection;
/**
+ * A migrate destination for a talk node.
+ *
* @MigrateDestination(
* id="opd_talk"
* )
diff --git a/web/modules/custom/custom/tests/modules/custom_test/config/install/field.field.node.talk.field_events.yml b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.field.node.talk.field_events.yml
new file mode 100644
index 0000000..7a027ef
--- /dev/null
+++ b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.field.node.talk.field_events.yml
@@ -0,0 +1,30 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.storage.node.field_events
+ - node.type.talk
+ - paragraphs.paragraphs_type.event
+ module:
+ - entity_reference_revisions
+id: node.talk.field_events
+field_name: field_events
+entity_type: node
+bundle: talk
+label: Events
+description: ''
+required: false
+translatable: false
+default_value: { }
+default_value_callback: ''
+settings:
+ handler: 'default:paragraph'
+ handler_settings:
+ negate: 0
+ target_bundles:
+ event: event
+ target_bundles_drag_drop:
+ event:
+ enabled: true
+ weight: 2
+field_type: entity_reference_revisions
diff --git a/web/modules/custom/custom/tests/modules/custom_test/config/install/field.field.paragraph.event.field_date.yml b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.field.paragraph.event.field_date.yml
new file mode 100644
index 0000000..0ba8a33
--- /dev/null
+++ b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.field.paragraph.event.field_date.yml
@@ -0,0 +1,20 @@
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.storage.paragraph.field_date
+ - paragraphs.paragraphs_type.event
+ module:
+ - datetime
+id: paragraph.event.field_date
+field_name: field_date
+entity_type: paragraph
+bundle: event
+label: Date
+description: ''
+required: true
+translatable: false
+default_value: { }
+default_value_callback: ''
+settings: { }
+field_type: datetime
diff --git a/web/modules/custom/custom/tests/modules/custom_test/config/install/field.storage.node.field_events.yml b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.storage.node.field_events.yml
new file mode 100644
index 0000000..1371e99
--- /dev/null
+++ b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.storage.node.field_events.yml
@@ -0,0 +1,20 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - entity_reference_revisions
+ - node
+ - paragraphs
+id: node.field_events
+field_name: field_events
+entity_type: node
+type: entity_reference_revisions
+settings:
+ target_type: paragraph
+module: entity_reference_revisions
+locked: false
+cardinality: -1
+translatable: true
+indexes: { }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/web/modules/custom/custom/tests/modules/custom_test/config/install/field.storage.paragraph.field_date.yml b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.storage.paragraph.field_date.yml
new file mode 100644
index 0000000..6087ad8
--- /dev/null
+++ b/web/modules/custom/custom/tests/modules/custom_test/config/install/field.storage.paragraph.field_date.yml
@@ -0,0 +1,19 @@
+langcode: en
+status: true
+dependencies:
+ module:
+ - datetime
+ - paragraphs
+id: paragraph.field_date
+field_name: field_date
+entity_type: paragraph
+type: datetime
+settings:
+ datetime_type: date
+module: datetime
+locked: false
+cardinality: 1
+translatable: true
+indexes: { }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/web/modules/custom/custom/tests/modules/custom_test/config/install/node.type.talk.yml b/web/modules/custom/custom/tests/modules/custom_test/config/install/node.type.talk.yml
new file mode 100644
index 0000000..813cea8
--- /dev/null
+++ b/web/modules/custom/custom/tests/modules/custom_test/config/install/node.type.talk.yml
@@ -0,0 +1,10 @@
+langcode: en
+status: true
+dependencies: { }
+name: Talk
+type: talk
+description: ''
+help: ''
+new_revision: true
+preview_mode: 1
+display_submitted: false
diff --git a/web/modules/custom/custom/tests/modules/custom_test/config/install/paragraphs.paragraphs_type.event.yml b/web/modules/custom/custom/tests/modules/custom_test/config/install/paragraphs.paragraphs_type.event.yml
new file mode 100644
index 0000000..9909b1e
--- /dev/null
+++ b/web/modules/custom/custom/tests/modules/custom_test/config/install/paragraphs.paragraphs_type.event.yml
@@ -0,0 +1,9 @@
+langcode: en
+status: true
+dependencies: { }
+id: event
+label: Event
+icon_uuid: null
+icon_default: null
+description: ''
+behavior_plugins: { }
diff --git a/web/modules/custom/custom/tests/modules/custom_test/custom_test.info.yml b/web/modules/custom/custom/tests/modules/custom_test/custom_test.info.yml
new file mode 100644
index 0000000..7353524
--- /dev/null
+++ b/web/modules/custom/custom/tests/modules/custom_test/custom_test.info.yml
@@ -0,0 +1,5 @@
+name: Custom Test
+type: module
+core: 8.x
+core_version_requirements: ^8 || ^9
+hidden: true
diff --git a/web/modules/custom/custom/tests/src/Kernel/UpdatesTalkCreatedDateTest.php b/web/modules/custom/custom/tests/src/Kernel/UpdatesTalkCreatedDateTest.php
new file mode 100644
index 0000000..5ceee42
--- /dev/null
+++ b/web/modules/custom/custom/tests/src/Kernel/UpdatesTalkCreatedDateTest.php
@@ -0,0 +1,100 @@
+modify('+1 week');
+ $eventDateToFormat = $eventDate->format(DateTimeItemInterface::DATE_STORAGE_FORMAT);
+ $eventDateToTimestamp = $eventDate->getTimestamp();
+
+ $talk = $this->createTalk($eventDateToFormat);
+
+ $this->assertEqual($eventDateToTimestamp, $talk->get('created')
+ ->getString());
+ }
+
+ public function testUpdatingNode() {
+ $talk = $this->createTalk();
+
+ $eventDate = (new \DateTime('today'))->modify('+1 week');
+ $eventDateToFormat = $eventDate->format(DateTimeItemInterface::DATE_STORAGE_FORMAT);
+ $eventDateToTimestamp = $eventDate->getTimestamp();
+
+ $event = $this->createEvent($eventDateToFormat);
+ $talk->set('field_events', [$event]);
+ $talk->save();
+
+ $this->assertEqual($eventDateToTimestamp, $talk->get('created')
+ ->getString());
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->installEntitySchema('paragraph');
+ $this->installSchema('node', ['node_access']);
+
+ $this->installConfig(['custom_test']);
+ }
+
+ private function createTalk(?string $eventDateToFormat = NULL): EntityInterface {
+ if ($eventDateToFormat) {
+ $event = $this->createEvent($eventDateToFormat);
+ }
+
+ $talk = Node::create([
+ 'title' => 'TDD - Test Driven Drupal',
+ 'type' => 'talk',
+ ]);
+
+ if (isset($event)) {
+ $talk->set('field_events', [$event]);
+ }
+
+ $talk->save();
+
+ return $talk;
+ }
+
+ private function createEvent(string $eventDateToFormat): ParagraphInterface {
+ $event = Paragraph::create([
+ 'field_date' => $eventDateToFormat,
+ 'type' => 'event',
+ ]);
+
+ $event->save();
+
+ return $event;
+ }
+
+}