Skip to content
This repository has been archived by the owner on Feb 13, 2023. It is now read-only.

Commit

Permalink
bugfix(product) fix audit information generation for product (#1820)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrkreft authored Dec 28, 2021
1 parent 51770a2 commit 7a536d5
Show file tree
Hide file tree
Showing 37 changed files with 345 additions and 261 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## CHANGELOG FOR 1.1.x
#### 1.1.7
- bugfix [#1816](https://github.com/ergonode/backend/issues/1816) Fixed product audits (rprzedzik)

#### 1.1.6
- bugfix [#1776](https://github.com/ergonode/backend/issues/1776) Fixed not recalculating segment for product on completeness update (piotrkreft)

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"doctrine/doctrine-bundle": "^2.3",
"doctrine/migrations": "2.2.x",
"egulias/email-validator": "^2.1",
"ergonode/exporter-shopware-6": "dev-main",
"ergonode/exporter-shopware-6": "~1.0",
"ergonode/importer-magento-1": "^1.0",
"gesdinet/jwt-refresh-token-bundle": "^0.11.1|^0.12",
"guzzlehttp/guzzle": "^6.3",
Expand Down
16 changes: 7 additions & 9 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

115 changes: 115 additions & 0 deletions module/product/migrations/Version20211219110000.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php
/**
* Copyright © Bold Brand Commerce Sp. z o.o. All rights reserved.
* See LICENSE.txt for license details.
*/

declare(strict_types=1);

namespace Ergonode\Migration;

use Doctrine\DBAL\Schema\Schema;
use Ergonode\Product\Domain\Event\ProductValueChangedEvent;
use Ergonode\Product\Domain\Event\ProductValueAddedEvent;

/**
* Auto-generated Ergonode Migration Class:
*/
final class Version20211219110000 extends AbstractErgonodeMigration
{
/**
* @throws \Exception
*/
public function up(Schema $schema): void
{
$this->addSql('
CREATE TABLE IF NOT EXISTS audit (
id uuid NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
created_by UUID DEFAULT NULL,
edited_at TIMESTAMP WITH TIME ZONE NOT NULL,
edited_by UUID DEFAULT NULL,
PRIMARY KEY(id)
)
');

$this->updateAudit();
$eventId = $this->getEventId(ProductValueAddedEvent::class);
$this->removeEvents($eventId, 'esa_created_at');
$this->removeEvents($eventId, 'esa_created_by');
$this->removeEvents($eventId, 'esa_edited_at');
$this->removeEvents($eventId, 'esa_edited_by');
$eventId = $this->getEventId(ProductValueChangedEvent::class);
$this->removeEvents($eventId, 'esa_edited_at');
$this->removeEvents($eventId, 'esa_edited_by');

$this->removeValues('esa_created_at');
$this->removeValues('esa_created_by');
$this->removeValues('esa_edited_at');
$this->removeValues('esa_edited_by');

$this->addSql('ALTER TABLE product DROP column created_at');
$this->addSql('ALTER TABLE product DROP column updated_at');

$this->addSql('DELETE FROM event_store_snapshot WHERE aggregate_id in (SELECT id FROM product)');
}

private function getEventId(string $event): string
{
return $this->connection->executeQuery(
'SELECT id FROM event_store_event WHERE event_class = :class',
[
':class' => $event,
]
)->fetchOne();
}

private function removeEvents(string $eventId, string $code): void
{
$this->connection->executeQuery(
'DELETE FROM event_store WHERE event_id = ? and payload::TEXT ilike \'%'.$code.'%\'',
[$eventId]
);
}

private function removeValues(string $code): void
{
$attributeId = $this->connection->executeQuery(
'SELECT id FROM attribute WHERE code = :code',
[
':code' => $code,
]
)->fetchOne();

if ($attributeId) {
$this->addSql(
'DELETE FROM value_translation WHERE value_id IN
(SELECT value_id FROM product_value WHERE attribute_id = ?)',
[$attributeId]
);

$this->addSql(
'DELETE FROM product_value WHERE attribute_id = ?',
[$attributeId]
);
}
}

private function updateAudit(): void
{
$this->addSql('INSERT INTO audit (id, created_at, edited_at)
SELECT id, created_at, updated_at FROM product');

$this->addSql('UPDATE audit
SET created_by = t.recorded_by
FROM (SELECT aggregate_id, recorded_by FROM event_store
WHERE id IN (SELECT min(id) FROM event_store group by aggregate_id)) AS t
WHERE audit.id = t.aggregate_id');

$this->addSql('UPDATE audit
SET edited_by = t.recorded_by
FROM (SELECT aggregate_id, recorded_by FROM event_store
WHERE id IN (SELECT max(id) FROM event_store group by aggregate_id)) AS t
WHERE audit.id = t.aggregate_id');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/**
* Copyright © Bold Brand Commerce Sp. z o.o. All rights reserved.
* See LICENSE.txt for license details.
*/

declare(strict_types=1);

namespace Ergonode\Product\Application\Handler;

use Ergonode\SharedKernel\Domain\Aggregate\UserId;
use Ergonode\SharedKernel\Domain\User\UserInterface;
use Doctrine\DBAL\Connection;
use Symfony\Component\Security\Core\Security;

abstract class AbstractAuditEventHandler
{
protected Connection $connection;

protected Security $security;

public function __construct(Connection $connection, Security $security)
{
$this->connection = $connection;
$this->security = $security;
}

protected function getUser(): ?UserId
{
$user = $this->security->getUser();

if ($user instanceof UserInterface) {
return $user->getId();
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/**
* Copyright © Bold Brand Commerce Sp. z o.o. All rights reserved.
* See LICENSE.txt for license details.
*/

declare(strict_types=1);

namespace Ergonode\Product\Application\Handler;

use Ergonode\Product\Application\Event\ProductCreatedEvent;
use Doctrine\DBAL\Types\Types;

class AuditProductCreatedEventHandler extends AbstractAuditEventHandler
{
private const TABLE = 'audit';

public function __invoke(ProductCreatedEvent $event): void
{
$date = new \DateTime();
$user = $this->getUser();

$this->connection->insert(
self::TABLE,
[
'id' => $event->getProduct()->getId()->getValue(),
'created_at' => $date,
'edited_at' => $date,
'created_by' => $user,
'edited_by' => $user,
],
[
'created_at' => Types::DATETIMETZ_MUTABLE,
'edited_at' => Types::DATETIMETZ_MUTABLE,
],
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* Copyright © Bold Brand Commerce Sp. z o.o. All rights reserved.
* See LICENSE.txt for license details.
*/

declare(strict_types=1);

namespace Ergonode\Product\Application\Handler;

use Doctrine\DBAL\Connection;
use Ergonode\Product\Application\Event\ProductDeletedEvent;

class AuditProductDeletedEventHandler
{
private const TABLE = 'audit';

private Connection $connection;

public function __construct(Connection $connection)
{
$this->connection = $connection;
}

public function __invoke(ProductDeletedEvent $event): void
{
$this->connection->delete(
self::TABLE,
[
'id' => $event->getProduct()->getId()->getValue(),
]
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
/**
* Copyright © Bold Brand Commerce Sp. z o.o. All rights reserved.
* See LICENSE.txt for license details.
*/

declare(strict_types=1);

namespace Ergonode\Product\Application\Handler;

use Doctrine\DBAL\Types\Types;
use Ergonode\Product\Application\Event\ProductUpdatedEvent;

class AuditProductUpdatedEventHandler extends AbstractAuditEventHandler
{
private const TABLE = 'audit';

public function __invoke(ProductUpdatedEvent $event): void
{
$createdAt = new \DateTime();
$createdBy = $this->getUser();

$this->connection->update(
self::TABLE,
[
'edited_at' => $createdAt,
'edited_by' => $createdBy,
],
[
'id' => $event->getProduct()->getId()->getValue(),
],
[
'edited_at' => Types::DATETIMETZ_MUTABLE,
],
);
}
}
29 changes: 1 addition & 28 deletions module/product/src/Domain/Factory/ProductFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,19 @@

namespace Ergonode\Product\Domain\Factory;

use Ergonode\Core\Application\Security\Security;
use Ergonode\Product\Domain\Entity\AbstractProduct;
use Ergonode\Product\Domain\Entity\Attribute\CreatedAtSystemAttribute;
use Ergonode\Product\Domain\Entity\Attribute\CreatedBySystemAttribute;
use Ergonode\Product\Domain\ValueObject\Sku;
use Ergonode\Product\Infrastructure\Provider\ProductStrategyProvider;
use Ergonode\SharedKernel\Domain\Aggregate\ProductId;
use Ergonode\SharedKernel\Domain\Aggregate\TemplateId;
use Ergonode\Value\Domain\ValueObject\StringValue;

class ProductFactory implements ProductFactoryInterface
{
private ProductStrategyProvider $productProvider;

private Security $security;

public function __construct(ProductStrategyProvider $productProvider, Security $security)
public function __construct(ProductStrategyProvider $productProvider)
{
$this->productProvider = $productProvider;
$this->security = $security;
}

public function create(
Expand All @@ -39,26 +32,6 @@ public function create(
array $categories = [],
array $attributes = []
): AbstractProduct {
$attributes = $this->addAudit($attributes);

return $this->productProvider->provide($type)->build($id, $sku, $templateId, $categories, $attributes);
}

/**
* @param array $attributes
*
* @return array
*/
private function addAudit(array $attributes): array
{
$user = $this->security->getUser();
if ($user) {
$value = new StringValue(sprintf('%s %s', $user->getFirstName(), $user->getLastName()));
$attributes[CreatedBySystemAttribute::CODE] = $value;
}

$attributes[CreatedAtSystemAttribute::CODE] = new StringValue((new \DateTime())->format(\DateTime::W3C));

return $attributes;
}
}
Loading

0 comments on commit 7a536d5

Please sign in to comment.