diff --git a/composer.json b/composer.json index 69b51702..1ec26243 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "spryker/propel": "^3.45.0", "spryker/propel-orm": "^1.16.0", "spryker/symfony": "^3.1.0", + "spryker/transfer": "^3.39.0", "spryker/util-encoding": "^2.1.0" }, "require-dev": { @@ -28,8 +29,7 @@ "spryker/monolog": "*", "spryker/queue": "*", "spryker/silex": "^2.0.0", - "spryker/testify": "^3.58.0", - "spryker/transfer": "^3.39.0" + "spryker/testify": "^3.58.0" }, "suggest": { "spryker/console": "If you want to execute console commands", diff --git a/dependency.json b/dependency.json index 38f65ca2..3ceee424 100644 --- a/dependency.json +++ b/dependency.json @@ -1,4 +1,7 @@ { + "include": { + "spryker/transfer": "Provides transfer objects definition with `::get*OrFail()` functionality." + }, "include-dev": { "codeception/module-asserts": "Codeception module containing various assertions.", "phpunit/phpunit": "Need due to compatibility minimal version package with PHP 8." diff --git a/src/Spryker/Shared/EventBehavior/Transfer/event_behavior.transfer.xml b/src/Spryker/Shared/EventBehavior/Transfer/event_behavior.transfer.xml index 88db82b8..90472812 100644 --- a/src/Spryker/Shared/EventBehavior/Transfer/event_behavior.transfer.xml +++ b/src/Spryker/Shared/EventBehavior/Transfer/event_behavior.transfer.xml @@ -3,10 +3,23 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="spryker:transfer-01 http://static.spryker.com/transfer-01.xsd"> + + + + + + + + + + + + + diff --git a/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacade.php b/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacade.php index 59195554..c5ca6ed7 100644 --- a/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacade.php +++ b/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacade.php @@ -8,6 +8,8 @@ namespace Spryker\Zed\EventBehavior\Business; use Generated\Shared\Transfer\EventTriggerResponseTransfer; +use Generated\Shared\Transfer\HydrateEventsRequestTransfer; +use Generated\Shared\Transfer\HydrateEventsResponseTransfer; use Spryker\Zed\Kernel\Business\AbstractFacade; /** @@ -126,6 +128,20 @@ public function getEventTransfersAdditionalValues(array $eventTransfers, string return $this->getFactory()->createEventEntityTransferFilter()->getEventTransfersAdditionalValues($eventTransfers, $columnName); } + /** + * {@inheritDoc} + * + * @api + * + * @param \Generated\Shared\Transfer\HydrateEventsRequestTransfer $hydrateEventsRequestTransfer + * + * @return \Generated\Shared\Transfer\HydrateEventsResponseTransfer + */ + public function hydrateEventDataTransfer(HydrateEventsRequestTransfer $hydrateEventsRequestTransfer): HydrateEventsResponseTransfer + { + return $this->getFactory()->createEventEntityTransferFilter()->hydrateEventDataTransfer($hydrateEventsRequestTransfer); + } + /** * {@inheritDoc} * diff --git a/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacadeInterface.php b/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacadeInterface.php index 5e6b65e2..c9300da7 100644 --- a/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacadeInterface.php +++ b/src/Spryker/Zed/EventBehavior/Business/EventBehaviorFacadeInterface.php @@ -8,6 +8,8 @@ namespace Spryker\Zed\EventBehavior\Business; use Generated\Shared\Transfer\EventTriggerResponseTransfer; +use Generated\Shared\Transfer\HydrateEventsRequestTransfer; +use Generated\Shared\Transfer\HydrateEventsResponseTransfer; interface EventBehaviorFacadeInterface { @@ -101,7 +103,7 @@ public function getEventTransfersOriginalValues(array $eventTransfers, string $c /** * Specification: - * - Returns field value of the specficed column in eventTransfers. + * - Returns field value of the specified column in eventTransfers. * * @api * @@ -112,6 +114,26 @@ public function getEventTransfersOriginalValues(array $eventTransfers, string $c */ public function getEventTransfersAdditionalValues(array $eventTransfers, string $columnName): array; + /** + * Specification: + * - Extracts timestamp information for event entities passed in the request. + * - Always returns a map of entity IDs to their respective timestamps. + * - Optionally extracts additional values with timestamps for: + * - Foreign key values if `foreignKeyName` is provided. + * - Additional values if `additionalValueName` is provided. + * - Response structure (in HydrateEventsResponseTransfer): + * - `idTimestampMap`: [id => timestamp] + * - `foreignKeyTimestampMap`: [foreignKeyValue => timestamp] (if requested) + * - `additionalValueTimestampMap`: [additionalValue => timestamp] (if requested) + * + * @api + * + * @param \Generated\Shared\Transfer\HydrateEventsRequestTransfer $hydrateEventsRequestTransfer + * + * @return \Generated\Shared\Transfer\HydrateEventsResponseTransfer + */ + public function hydrateEventDataTransfer(HydrateEventsRequestTransfer $hydrateEventsRequestTransfer): HydrateEventsResponseTransfer; + /** * Specification: * - Triggers events for specified resources. diff --git a/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilter.php b/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilter.php index a45661f4..1f094b8a 100644 --- a/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilter.php +++ b/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilter.php @@ -7,6 +7,10 @@ namespace Spryker\Zed\EventBehavior\Business\Model; +use Generated\Shared\Transfer\EventEntityTransfer; +use Generated\Shared\Transfer\HydrateEventsRequestTransfer; +use Generated\Shared\Transfer\HydrateEventsResponseTransfer; + class EventEntityTransferFilter implements EventEntityTransferFilterInterface { /** @@ -145,6 +149,93 @@ public function getEventTransfersAdditionalValues(array $eventTransfers, string return array_unique($additionalValues); } + /** + * @param \Generated\Shared\Transfer\HydrateEventsRequestTransfer $hydrateEventsRequestTransfer + * + * @return \Generated\Shared\Transfer\HydrateEventsResponseTransfer + */ + public function hydrateEventDataTransfer(HydrateEventsRequestTransfer $hydrateEventsRequestTransfer): HydrateEventsResponseTransfer + { + $hydrateEventsResponseTransfer = new HydrateEventsResponseTransfer(); + $eventEntityTransfers = $hydrateEventsRequestTransfer->getEventEntities()->getArrayCopy(); + + if (count($eventEntityTransfers) === 0) { + return $hydrateEventsResponseTransfer; + } + usort($eventEntityTransfers, fn (EventEntityTransfer $a, EventEntityTransfer $b) => $a->getTimestamp() <=> $b->getTimestamp()); + + $hydrateEventsResponseTransfer->setIdTimestampMap($this->getIdsTimestampMap($eventEntityTransfers)); + + if ($hydrateEventsRequestTransfer->getAdditionalValueName()) { + $hydrateEventsResponseTransfer->setAdditionalValueTimestampMap($this->getAdditionalValueTimestampMap($eventEntityTransfers, $hydrateEventsRequestTransfer->getAdditionalValueName())); + } + + if ($hydrateEventsRequestTransfer->getForeignKeyName()) { + $hydrateEventsResponseTransfer->setForeignKeyTimestampMap($this->getForeignKeyTimestampMap($eventEntityTransfers, $hydrateEventsRequestTransfer->getForeignKeyName())); + } + + return $hydrateEventsResponseTransfer; + } + + /** + * @param array<\Generated\Shared\Transfer\EventEntityTransfer> $eventTransfers + * + * @return array + */ + protected function getIdsTimestampMap(array $eventTransfers): array + { + $ids = []; + foreach ($eventTransfers as $eventTransfer) { + $ids[(int)$eventTransfer->getId()] = (int)$eventTransfer->getTimestamp(); + } + + return $ids; + } + + /** + * @param array<\Generated\Shared\Transfer\EventEntityTransfer> $eventTransfers + * @param string $columnName + * + * @return array + */ + protected function getAdditionalValueTimestampMap(array $eventTransfers, string $columnName): array + { + $additionalValues = []; + foreach ($eventTransfers as $eventTransfer) { + $additionalValuesOfEvent = $eventTransfer->getAdditionalValues(); + if (!isset($additionalValuesOfEvent[$columnName])) { + continue; + } + + $additionalValues[$additionalValuesOfEvent[$columnName]] = (int)$eventTransfer->getTimestamp(); + } + + return $additionalValues; + } + + /** + * @param array<\Generated\Shared\Transfer\EventEntityTransfer> $eventTransfers + * @param string $foreignKeyColumnName + * + * @return array + */ + protected function getForeignKeyTimestampMap(array $eventTransfers, string $foreignKeyColumnName): array + { + $foreignKeys = []; + foreach ($eventTransfers as $eventTransfer) { + if (!isset($eventTransfer->getForeignKeys()[$foreignKeyColumnName])) { + continue; + } + + $value = $eventTransfer->getForeignKeys()[$foreignKeyColumnName] ?? null; + if ($value !== null) { + $foreignKeys[(int)$value] = (int)$eventTransfer->getTimestamp(); + } + } + + return $foreignKeys; + } + /** * @param array $columns * @param array $modifiedColumns diff --git a/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilterInterface.php b/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilterInterface.php index dc8c3a02..ba6f3ed8 100644 --- a/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilterInterface.php +++ b/src/Spryker/Zed/EventBehavior/Business/Model/EventEntityTransferFilterInterface.php @@ -7,6 +7,9 @@ namespace Spryker\Zed\EventBehavior\Business\Model; +use Generated\Shared\Transfer\HydrateEventsRequestTransfer; +use Generated\Shared\Transfer\HydrateEventsResponseTransfer; + interface EventEntityTransferFilterInterface { /** @@ -55,4 +58,11 @@ public function getEventTransfersOriginalValues(array $eventTransfers, string $c * @return array */ public function getEventTransfersAdditionalValues(array $eventTransfers, string $columnName): array; + + /** + * @param \Generated\Shared\Transfer\HydrateEventsRequestTransfer $hydrateEventsRequestTransfer + * + * @return \Generated\Shared\Transfer\HydrateEventsResponseTransfer + */ + public function hydrateEventDataTransfer(HydrateEventsRequestTransfer $hydrateEventsRequestTransfer): HydrateEventsResponseTransfer; } diff --git a/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceQueryContainerManager.php b/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceQueryContainerManager.php index dc4302ab..615a6f22 100644 --- a/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceQueryContainerManager.php +++ b/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceQueryContainerManager.php @@ -118,7 +118,9 @@ protected function createEventResourceQueryContainerPluginIterator(EventResource protected function triggerBulk(EventResourceQueryContainerPluginInterface $plugin, array $ids): void { $eventEntityTransfers = array_map(function ($id) { - return (new EventEntityTransfer())->setId($id); + return (new EventEntityTransfer()) + ->setId($id) + ->setTimestamp(time()); }, $ids); $this->eventFacade->triggerBulk($plugin->getEventName(), $eventEntityTransfers); diff --git a/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceRepositoryManager.php b/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceRepositoryManager.php index 209f6e83..11b40baa 100644 --- a/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceRepositoryManager.php +++ b/src/Spryker/Zed/EventBehavior/Business/Model/EventResourceRepositoryManager.php @@ -204,7 +204,9 @@ protected function getIdColumnName($plugin): ?string protected function triggerBulk(EventResourcePluginInterface $plugin, array $ids): void { $eventEntityTransfers = array_map(function ($id) { - return (new EventEntityTransfer())->setId($id); + return (new EventEntityTransfer()) + ->setId($id) + ->setTimestamp(time()); }, $ids); $this->eventFacade->triggerBulk($plugin->getEventName(), $eventEntityTransfers); diff --git a/src/Spryker/Zed/EventBehavior/Business/Model/TriggerManager.php b/src/Spryker/Zed/EventBehavior/Business/Model/TriggerManager.php index e46e45a6..d3ea936d 100644 --- a/src/Spryker/Zed/EventBehavior/Business/Model/TriggerManager.php +++ b/src/Spryker/Zed/EventBehavior/Business/Model/TriggerManager.php @@ -285,6 +285,7 @@ protected function triggerEvents(array $events): int $eventEntityTransfer->setEvent($data[EventBehavior::EVENT_CHANGE_NAME]); $eventEntityTransfer->setName($data[EventBehavior::EVENT_CHANGE_ENTITY_NAME]); $eventEntityTransfer->setId($id); + $eventEntityTransfer->setTimestamp($event->getCreatedAt()?->getTimestamp()); $eventEntityTransfer->setForeignKeys($data[EventBehavior::EVENT_CHANGE_ENTITY_FOREIGN_KEYS]); if (isset($data[EventBehavior::EVENT_CHANGE_ENTITY_ORIGINAL_VALUES])) { $eventEntityTransfer->setOriginalValues($data[EventBehavior::EVENT_CHANGE_ENTITY_ORIGINAL_VALUES]); diff --git a/tests/SprykerTest/Zed/EventBehavior/Business/EventBehaviorFacadeTest.php b/tests/SprykerTest/Zed/EventBehavior/Business/EventBehaviorFacadeTest.php index e13e70ca..5625c095 100644 --- a/tests/SprykerTest/Zed/EventBehavior/Business/EventBehaviorFacadeTest.php +++ b/tests/SprykerTest/Zed/EventBehavior/Business/EventBehaviorFacadeTest.php @@ -11,6 +11,7 @@ use DateInterval; use DateTime; use Generated\Shared\Transfer\EventEntityTransfer; +use Generated\Shared\Transfer\HydrateEventsRequestTransfer; use Orm\Zed\EventBehavior\Persistence\SpyEventBehaviorEntityChange; use Orm\Zed\EventBehavior\Persistence\SpyEventBehaviorEntityChangeQuery; use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher; @@ -41,6 +42,11 @@ class EventBehaviorFacadeTest extends Unit */ protected const ID = 'id'; + /** + * @var string + */ + protected const TIMESTAMP = 'timestamp'; + /** * @var string */ @@ -217,6 +223,46 @@ public function testGetEventTransferIds(): void $this->assertEquals($eventTransferIds, [1, 2]); } + /** + * @return void + */ + public function testHydrateEventDataTransfer(): void + { + // Arrange + $hydrateEventsRequestTransfer = new HydrateEventsRequestTransfer(); + + $eventEntityTransfer = new EventEntityTransfer(); + $eventEntityTransfer->setId(1); + $eventEntityTransfer->setAdditionalValues(['property1' => 'value1']); + $eventEntityTransfer->setTimestamp(102); + $eventEntityTransfer->setAdditionalValues(['property2' => 'value3']); + $hydrateEventsRequestTransfer->addEventEntity($eventEntityTransfer); + + $eventEntityTransfer = new EventEntityTransfer(); + $eventEntityTransfer->setId(2); + $eventEntityTransfer->setForeignKeys(['foreignKey' => 7]); + $eventEntityTransfer->setTimestamp(102); + $eventEntityTransfer->setAdditionalValues(['property2' => 'value1']); + $hydrateEventsRequestTransfer->addEventEntity($eventEntityTransfer); + + $eventEntityTransfer = new EventEntityTransfer(); + $eventEntityTransfer->setId(1); + $eventEntityTransfer->setForeignKeys(['foreignKey' => 5]); + $eventEntityTransfer->setTimestamp(106); + $eventEntityTransfer->setAdditionalValues(['property1' => 'value1', 'property2' => 'value2']); + $hydrateEventsRequestTransfer->addEventEntity($eventEntityTransfer); + + $hydrateEventsRequestTransfer->setForeignKeyName('foreignKey'); + $hydrateEventsRequestTransfer->setAdditionalValueName('property2'); + + $hydrateEventsResponseTransfer = $this->tester->getFacade()->hydrateEventDataTransfer($hydrateEventsRequestTransfer); + + // Assert + $this->assertEquals($hydrateEventsResponseTransfer->getIdTimestampMap(), [1 => 106, 2 => 102]); + $this->assertEquals($hydrateEventsResponseTransfer->getForeignKeyTimestampMap(), [7 => 102, 5 => 106]); + $this->assertEquals($hydrateEventsResponseTransfer->getAdditionalValueTimestampMap(), ['value3' => 102, 'value1' => 102, 'value2' => 106]); + } + /** * @return void */ @@ -347,7 +393,7 @@ public function assertTriggeredEvent(string $eventName, TransferInterface $event $actualArray[EventBehavior::EVENT_CHANGE_ENTITY_ADDITIONAL_VALUES] = $actualArray[static::FIELD_ADDITIONAL_VALUES]; unset($actualArray[static::FIELD_ADDITIONAL_VALUES]); - $this->assertEquals($actualArray, $this->createEventData($actualArray[static::ID])); + $this->assertEquals($actualArray, $this->createEventData($actualArray[static::ID], $actualArray[static::TIMESTAMP])); } /** @@ -435,14 +481,16 @@ protected function createLostEntityChangeEvent(string $idEntity = '123'): void /** * @param string $idEntity + * @param int $timestamp * * @return array */ - protected function createEventData(string $idEntity = '123'): array + protected function createEventData(string $idEntity = '123', int $timestamp = 0): array { return [ EventBehavior::EVENT_CHANGE_ENTITY_NAME => 'name', EventBehavior::EVENT_CHANGE_ENTITY_ID => $idEntity, + EventEntityTransfer::TIMESTAMP => $timestamp, EventBehavior::EVENT_CHANGE_ENTITY_FOREIGN_KEYS => [1, 2, 3], EventBehavior::EVENT_CHANGE_NAME => 'test', EventBehavior::EVENT_CHANGE_ENTITY_MODIFIED_COLUMNS => [],