Skip to content

Initial product variation logging PoC #801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: 8.x-2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions modules/log/commerce_log.commerce_log_categories.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ commerce_cart:
commerce_order:
label: Order
entity_type: commerce_order

commerce_product:
label: Product
entity_type: commerce_product
13 changes: 13 additions & 0 deletions modules/log/commerce_log.commerce_log_templates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,16 @@ order_assigned:
category: commerce_order
label: 'Order assigned'
template: '<p>The order was assigned to {{ user }}.</p>'

variation_added:
category: commerce_product
label: 'Variation added'
template: '<p>Variation added</p><p>id: {{ id }}</p><p>sku: {{ sku }}</p><p>title: {{ label }}</p>'
variation_field_changed:
category: commerce_product
label: 'Variation changed'
template: '<p>Variation changed</p><p>id: {{ id }}</p><p>sku: {{ sku }}</p><p>changed fields: {{ changed_fields }}</p>'
variation_deleted:
category: commerce_product
label: 'Variation deleted'
template: '<p>Variation deleted</p><p>id: {{ id }}</p><p>sku: {{ sku }}</p>'
24 changes: 23 additions & 1 deletion modules/log/commerce_log.module
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

/**
* Implements hook_preprocess_commerce_order().
* Implements hook_preprocess_HOOK() for commerce_order.
*/
function commerce_log_preprocess_commerce_order(&$variables) {
/** @var \Drupal\commerce_order\Entity\OrderInterface $order */
Expand All @@ -20,3 +20,25 @@ function commerce_log_preprocess_commerce_order(&$variables) {
'#title' => t('Order activity'),
];
}

/**
* Implements hook_preprocess_HOOK() for commerce_product_form.
*/
function commerce_log_preprocess_commerce_product_form(&$variables) {
/** @var \Drupal\commerce_product\Entity\ProductInterface $product */
if ($product = \Drupal::service('current_route_match')->getParameter('commerce_product')) {
$variables['form']['actions']['activity'] = [
'#weight' => 100,
'title' => [
'#markup' => '<h3>' . t('Product activity') . '</h3>',
],
'log' => [
'#type' => 'view',
'#name' => 'commerce_activity',
'#display_id' => 'default',
'#arguments' => [$product->id(), 'commerce_product'],
'#weight' => 100,
],
];
}
}
7 changes: 7 additions & 0 deletions modules/log/src/CommerceLogServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Drupal\commerce_log;

use Drupal\commerce_log\EventSubscriber\ProductVariationEventSubscriber;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Symfony\Component\DependencyInjection\Reference;
Expand Down Expand Up @@ -29,6 +30,12 @@ public function register(ContainerBuilder $container) {
->addTag('event_subscriber')
->addArgument(new Reference('entity_type.manager'));
}
if (isset($modules['commerce_product'])) {
$container->register('commerce_log.product_variation_subscriber', ProductVariationEventSubscriber::class)
->addTag('event_subscriber')
->addArgument(new Reference('entity_type.manager'))
->addArgument(new Reference('event_dispatcher'));
}
}

}
19 changes: 19 additions & 0 deletions modules/log/src/Event/LogEvents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Drupal\commerce_log\Event;

/**
* Defines events for the log module.
*/
final class LogEvents {

/**
* Name of the event fired to filter the changed fields used in the log diff.
*
* @Event
*
* @see \Drupal\commerce_log\Event\ProductVariationChangedFieldsFilterEvent
*/
const PRODUCT_VARIATION_CHANGED_FIELDS_FILTER = 'commerce_log.product_variation.changed_fields_filter';

}
47 changes: 47 additions & 0 deletions modules/log/src/Event/ProductVariationChangedFieldsFilterEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Drupal\commerce_log\Event;

use Symfony\Component\EventDispatcher\Event;

class ProductVariationChangedFieldsFilterEvent extends Event {

/**
* The removed order items.
*
* @var \Drupal\commerce_order\Entity\OrderItemInterface[]
*/
protected $fields;

/**
* Constructs a new ProductVariationChangedFieldsFilterEvent.
*
* @param array $fields
* The fields.
*/
public function __construct(array $fields) {
$this->fields = $fields;
}

/**
* Gets the fields.
*
* @return array
* The fields.
*/
public function getFields() {
return $this->fields;
}

/**
* Sets the fields.
*
* @return \Drupal\commerce_log\Event\ProductVariationChangedFieldsFilterEvent
* The product variation changed field filter event.
*/
public function setFields(array $fields) {
$this->fields = $fields;
return $this;
}

}
129 changes: 129 additions & 0 deletions modules/log/src/EventSubscriber/ProductVariationEventSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

namespace Drupal\commerce_log\EventSubscriber;

use Drupal\commerce_log\Event\LogEvents;
use Drupal\commerce_log\Event\ProductVariationChangedFieldsFilterEvent;
use Drupal\commerce_product\Entity\ProductVariationInterface;
use Drupal\commerce_product\Event\ProductEvents;
use Drupal\commerce_product\Event\ProductVariationEvent;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ProductVariationEventSubscriber implements EventSubscriberInterface {

/**
* The log storage.
*
* @var \Drupal\commerce_log\LogStorageInterface
*/
protected $logStorage;

/**
* The dispatcher service.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;

/**
* Constructs a new ProductVariationEventSubscriber object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
* The event dispatcher.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager, EventDispatcherInterface $eventDispatcher) {
$this->logStorage = $entityTypeManager->getStorage('commerce_log');
$this->eventDispatcher = $eventDispatcher;
}

/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events = [
ProductEvents::PRODUCT_VARIATION_PRESAVE => ['onVariationPresave', -100],
ProductEvents::PRODUCT_VARIATION_PREDELETE => ['onVariationPredelete', -100],
];
return $events;
}

/**
* Creates a log before saving a product variation.
*
* @param \Drupal\commerce_product\Event\ProductVariationEvent $event
* The variation event.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function onVariationPresave(ProductVariationEvent $event) {
if ($product = $event->getProductVariation()->getProduct()) {
$variation = $event->getProductVariation();
$original = $variation->original;
// If there isn't a related product yet, then it is a new variation.
if (!$original->getProduct()) {
$this->logStorage->generate($product, 'variation_added', [
'id' => $event->getProductVariation()->id(),
'sku' => $event->getProductVariation()->getSku(),
'label' => $event->getProductVariation()->label(),
])->save();
}
elseif ($changedValues = $this->getChangedFields($original, $variation)) {
$this->logStorage->generate($product, 'variation_field_changed', [
'id' => $event->getProductVariation()->id(),
'sku' => $event->getProductVariation()->getSku(),
'changed_fields' => json_encode($changedValues, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT),
])->save();
}
}
}

/**
* Creates a log when a product variation is deleted.
*
* @param \Drupal\commerce_product\Event\ProductVariationEvent $event
* The variation event.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function onVariationPredelete(ProductVariationEvent $event) {
$this->logStorage->generate($event->getProductVariation()->getProduct(), 'variation_deleted', [
'id' => $event->getProductVariation()->id(),
'sku' => $event->getProductVariation()->getSku(),
])->save();
}

/**
* Determine the changed fields and their values.
*
* @param \Drupal\commerce_product\Entity\ProductVariationInterface $original
* The original product variation.
* @param \Drupal\commerce_product\Entity\ProductVariationInterface $new
* The new product variation.
*
* @return array
* A list of changed values
*/
protected function getChangedFields(ProductVariationInterface $original, ProductVariationInterface $new) {
$changedFields = new ProductVariationChangedFieldsFilterEvent(['price', 'sku', 'status', 'title']);
$this->eventDispatcher->dispatch(LogEvents::PRODUCT_VARIATION_CHANGED_FIELDS_FILTER, $changedFields);
$changedValues = [];
foreach ($changedFields->getFields() as $field) {
$newValue = $new->{$field}->getValue();
$originalValue = $original->{$field}->getValue();
if ($newValue != $originalValue) {
$changedValues[$field] = [
'Original value' => $originalValue,
'New value' => $newValue,
];
}
}
return $changedValues;
}

}
4 changes: 2 additions & 2 deletions modules/log/tests/src/Kernel/OrderIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public function testPlaceValidateFulfillLogs() {

$logs = $this->logStorage->loadMultipleByEntity($this->order);
$this->assertEquals(2, count($logs));
$log = $logs[2];
$log = array_pop($logs);
$build = $this->logViewBuilder->view($log);
$this->render($build);

Expand All @@ -180,7 +180,7 @@ public function testPlaceValidateFulfillLogs() {

$logs = $this->logStorage->loadMultipleByEntity($this->order);
$this->assertEquals(3, count($logs));
$log = $logs[3];
$log = array_pop($logs);
$build = $this->logViewBuilder->view($log);
$this->render($build);

Expand Down