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

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.     /**
  23.      * @var Connection
  24.      */
  25.     private $db;
  26.     public function __construct(Connection $db)
  27.     {
  28.         $this->db $db;
  29.     }
  30.     public static function getSubscribedEvents(): array
  31.     {
  32.         return [
  33.             ProductEvents::PRODUCT_WRITTEN_EVENT => 'productWritten',
  34.             WarehouseDefinition::ENTITY_WRITTEN_EVENT => 'warehouseWritten',
  35.         ];
  36.     }
  37.     public function productWritten(EntityWrittenEvent $entityWrittenEvent): void
  38.     {
  39.         $this->ensureProductWarehouseStockForProductsExist(
  40.             $this->getNewlyCreatedEntityIds($entityWrittenEvent),
  41.         );
  42.     }
  43.     public function warehouseWritten(EntityWrittenEvent $entityWrittenEvent): void
  44.     {
  45.         $this->ensureProductWarehouseStocksExist(
  46.             'warehouse.id',
  47.             $this->getNewlyCreatedEntityIds($entityWrittenEvent),
  48.         );
  49.     }
  50.     public function ensureProductWarehouseStockForProductsExist(array $productIds): void
  51.     {
  52.         $this->ensureProductWarehouseStocksExist('product.id'$productIds);
  53.     }
  54.     private function ensureProductWarehouseStocksExist(string $idFieldName, array $ids): void
  55.     {
  56.         if (count($ids) === 0) {
  57.             return;
  58.         }
  59.         // This query is a potential deadlock candidate and this is why it is wrapped in a retryable transaction
  60.         RetryableTransaction::retryable($this->db, fn() => $this->db->executeStatement(
  61.             'INSERT INTO pickware_erp_warehouse_stock (
  62.                 id,
  63.                 product_id,
  64.                 product_version_id,
  65.                 quantity,
  66.                 warehouse_id,
  67.                 created_at
  68.             ) SELECT
  69.                 ' SqlUuid::UUID_V4_GENERATION ',
  70.                 product.id,
  71.                 product.version_id,
  72.                 0,
  73.                 warehouse.id,
  74.                 NOW(3)
  75.             FROM product
  76.             CROSS JOIN pickware_erp_warehouse warehouse
  77.             WHERE ' $idFieldName ' IN (:ids) AND product.version_id = :liveVersionId
  78.             ON DUPLICATE KEY UPDATE pickware_erp_warehouse_stock.id = pickware_erp_warehouse_stock.id',
  79.             [
  80.                 'ids' => array_map('hex2bin'$ids),
  81.                 'liveVersionId' => hex2bin(Defaults::LIVE_VERSION),
  82.             ],
  83.             [
  84.                 'ids' => Connection::PARAM_STR_ARRAY,
  85.             ],
  86.         ));
  87.     }
  88.     private function getNewlyCreatedEntityIds(EntityWrittenEvent $entityWrittenEvent): array
  89.     {
  90.         if ($entityWrittenEvent->getContext()->getVersionId() !== Defaults::LIVE_VERSION) {
  91.             return [];
  92.         }
  93.         $ids = [];
  94.         foreach ($entityWrittenEvent->getWriteResults() as $writeResult) {
  95.             // $writeResult->getExistence() can be null, but we have no idea why and also not what this means.
  96.             $existence $writeResult->getExistence();
  97.             if (($existence === null && $writeResult->getOperation() === EntityWriteResult::OPERATION_INSERT)
  98.                 || ($existence !== null && !$existence->exists())
  99.             ) {
  100.                 $ids[] = $writeResult->getPrimaryKey();
  101.             }
  102.         }
  103.         return $ids;
  104.     }
  105. }