custom/plugins/PickwareErpStarter/src/Stock/WarehouseStockInitializer.php line 41

Open in your IDE?
  1. <?php
  2. /*
  3.  * Copyright (c) Pickware GmbH. All rights reserved.
  4.  * This file is part of software that is released under a proprietary license.
  5.  * You must not copy, modify, distribute, make publicly available, or execute
  6.  * its contents or parts thereof without express permission by the copyright
  7.  * holder, unless otherwise permitted by law.
  8.  */
  9. declare(strict_types=1);
  10. namespace Pickware\PickwareErpStarter\Stock;
  11. use Doctrine\DBAL\Connection;
  12. use Pickware\DalBundle\RetryableTransaction;
  13. use Pickware\DalBundle\Sql\SqlUuid;
  14. use Pickware\PickwareErpStarter\Warehouse\Model\WarehouseDefinition;
  15. use Shopware\Core\Content\Product\ProductEvents;
  16. use Shopware\Core\Defaults;
  17. use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. class WarehouseStockInitializer implements EventSubscriberInterface
  21. {
  22.     private Connection $db;
  23.     public function __construct(Connection $db)
  24.     {
  25.         $this->db $db;
  26.     }
  27.     public static function getSubscribedEvents(): array
  28.     {
  29.         return [
  30.             ProductEvents::PRODUCT_WRITTEN_EVENT => 'productWritten',
  31.             WarehouseDefinition::ENTITY_WRITTEN_EVENT => 'warehouseWritten',
  32.         ];
  33.     }
  34.     public function productWritten(EntityWrittenEvent $entityWrittenEvent): void
  35.     {
  36.         $this->ensureProductWarehouseStockForProductsExist(
  37.             $this->getNewlyCreatedEntityIds($entityWrittenEvent),
  38.         );
  39.     }
  40.     public function warehouseWritten(EntityWrittenEvent $entityWrittenEvent): void
  41.     {
  42.         $this->ensureProductWarehouseStocksExist(
  43.             'warehouse.id',
  44.             $this->getNewlyCreatedEntityIds($entityWrittenEvent),
  45.         );
  46.     }
  47.     public function ensureProductWarehouseStockForProductsExist(array $productIds): void
  48.     {
  49.         $this->ensureProductWarehouseStocksExist('product.id'$productIds);
  50.     }
  51.     private function ensureProductWarehouseStocksExist(string $idFieldName, array $ids): void
  52.     {
  53.         if (count($ids) === 0) {
  54.             return;
  55.         }
  56.         // This query is a potential deadlock candidate and this is why it is wrapped in a retryable transaction
  57.         RetryableTransaction::retryable($this->db, fn() => $this->db->executeStatement(
  58.             'INSERT INTO pickware_erp_warehouse_stock (
  59.                 id,
  60.                 product_id,
  61.                 product_version_id,
  62.                 quantity,
  63.                 warehouse_id,
  64.                 created_at
  65.             ) SELECT
  66.                 ' SqlUuid::UUID_V4_GENERATION ',
  67.                 product.id,
  68.                 product.version_id,
  69.                 0,
  70.                 warehouse.id,
  71.                 NOW(3)
  72.             FROM product
  73.             CROSS JOIN pickware_erp_warehouse warehouse
  74.             WHERE ' $idFieldName ' IN (:ids) AND product.version_id = :liveVersionId
  75.             ON DUPLICATE KEY UPDATE pickware_erp_warehouse_stock.id = pickware_erp_warehouse_stock.id',
  76.             [
  77.                 'ids' => array_map('hex2bin'$ids),
  78.                 'liveVersionId' => hex2bin(Defaults::LIVE_VERSION),
  79.             ],
  80.             [
  81.                 'ids' => Connection::PARAM_STR_ARRAY,
  82.             ],
  83.         ));
  84.     }
  85.     public function ensureProductWarehouseStocksExistsForAllProducts(): void
  86.     {
  87.         $this->db->executeStatement(
  88.             'INSERT INTO pickware_erp_warehouse_stock (
  89.                 id,
  90.                 product_id,
  91.                 product_version_id,
  92.                 quantity,
  93.                 warehouse_id,
  94.                 created_at
  95.             ) SELECT
  96.                 ' SqlUuid::UUID_V4_GENERATION ',
  97.                 product.id,
  98.                 product.version_id,
  99.                 0,
  100.                 warehouse.id,
  101.                 NOW(3)
  102.             FROM product
  103.             CROSS JOIN pickware_erp_warehouse warehouse
  104.             WHERE product.version_id = :liveVersionId
  105.             ON DUPLICATE KEY UPDATE pickware_erp_warehouse_stock.id = pickware_erp_warehouse_stock.id',
  106.             ['liveVersionId' => hex2bin(Defaults::LIVE_VERSION)],
  107.         );
  108.     }
  109.     private function getNewlyCreatedEntityIds(EntityWrittenEvent $entityWrittenEvent): array
  110.     {
  111.         if ($entityWrittenEvent->getContext()->getVersionId() !== Defaults::LIVE_VERSION) {
  112.             return [];
  113.         }
  114.         $ids = [];
  115.         foreach ($entityWrittenEvent->getWriteResults() as $writeResult) {
  116.             // $writeResult->getExistence() can be null, but we have no idea why and also not what this means.
  117.             $existence $writeResult->getExistence();
  118.             if (($existence === null && $writeResult->getOperation() === EntityWriteResult::OPERATION_INSERT)
  119.                 || ($existence !== null && !$existence->exists())
  120.             ) {
  121.                 $ids[] = $writeResult->getPrimaryKey();
  122.             }
  123.         }
  124.         return $ids;
  125.     }
  126. }