vendor/shopware/core/Content/Rule/DataAbstractionLayer/RulePayloadUpdater.php line 87

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Rule\DataAbstractionLayer;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Content\Rule\DataAbstractionLayer\Indexing\ConditionTypeNotFound;
  5. use Shopware\Core\Framework\App\Event\AppScriptConditionEvents;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\FetchModeHelper;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\RetryableQuery;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  9. use Shopware\Core\Framework\Rule\Collector\RuleConditionRegistry;
  10. use Shopware\Core\Framework\Rule\Container\AndRule;
  11. use Shopware\Core\Framework\Rule\Container\ContainerInterface;
  12. use Shopware\Core\Framework\Rule\ScriptRule;
  13. use Shopware\Core\Framework\Uuid\Uuid;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. class RulePayloadUpdater implements EventSubscriberInterface
  16. {
  17.     private Connection $connection;
  18.     private RuleConditionRegistry $ruleConditionRegistry;
  19.     /**
  20.      * @internal
  21.      */
  22.     public function __construct(Connection $connectionRuleConditionRegistry $ruleConditionRegistry)
  23.     {
  24.         $this->connection $connection;
  25.         $this->ruleConditionRegistry $ruleConditionRegistry;
  26.     }
  27.     public static function getSubscribedEvents(): array
  28.     {
  29.         return [
  30.             AppScriptConditionEvents::APP_SCRIPT_CONDITION_WRITTEN_EVENT => 'updatePayloads',
  31.         ];
  32.     }
  33.     public function update(array $ids): array
  34.     {
  35.         $conditions $this->connection->fetchAll(
  36.             'SELECT LOWER(HEX(rc.rule_id)) as array_key, rc.*, rs.script, rs.identifier, rs.updated_at as lastModified
  37.             FROM rule_condition rc
  38.             LEFT JOIN app_script_condition rs ON rc.script_id = rs.id AND rs.active = 1
  39.             WHERE rc.rule_id IN (:ids)
  40.             ORDER BY rc.rule_id',
  41.             ['ids' => Uuid::fromHexToBytesList($ids)],
  42.             ['ids' => Connection::PARAM_STR_ARRAY]
  43.         );
  44.         $rules FetchModeHelper::group($conditions);
  45.         $update = new RetryableQuery(
  46.             $this->connection,
  47.             $this->connection->prepare('UPDATE `rule` SET payload = :payload, invalid = :invalid WHERE id = :id')
  48.         );
  49.         $updated = [];
  50.         foreach ($rules as $id => $rule) {
  51.             $invalid false;
  52.             $serialized null;
  53.             try {
  54.                 $nested $this->buildNested($rulenull);
  55.                 //ensure the root rule is an AndRule
  56.                 $nested = new AndRule($nested);
  57.                 $serialized serialize($nested);
  58.             } catch (ConditionTypeNotFound $exception) {
  59.                 $invalid true;
  60.             } finally {
  61.                 $update->execute([
  62.                     'id' => Uuid::fromHexToBytes($id),
  63.                     'payload' => $serialized,
  64.                     'invalid' => (int) $invalid,
  65.                 ]);
  66.             }
  67.             $updated[$id] = ['payload' => $serialized'invalid' => $invalid];
  68.         }
  69.         return $updated;
  70.     }
  71.     public function updatePayloads(EntityWrittenEvent $event): void
  72.     {
  73.         $ruleIds $this->connection->fetchFirstColumn(
  74.             'SELECT DISTINCT rc.rule_id
  75.                 FROM rule_condition rc
  76.                 INNER JOIN app_script_condition rs ON rc.script_id = rs.id
  77.                 WHERE rs.id IN (:ids)',
  78.             ['ids' => Uuid::fromHexToBytesList(array_values($event->getIds()))],
  79.             ['ids' => Connection::PARAM_STR_ARRAY]
  80.         );
  81.         if (empty($ruleIds)) {
  82.             return;
  83.         }
  84.         $this->update(Uuid::fromBytesToHexList($ruleIds));
  85.     }
  86.     private function buildNested(array $rules, ?string $parentId): array
  87.     {
  88.         $nested = [];
  89.         foreach ($rules as $rule) {
  90.             if ($rule['parent_id'] !== $parentId) {
  91.                 continue;
  92.             }
  93.             if (!$this->ruleConditionRegistry->has($rule['type'])) {
  94.                 throw new ConditionTypeNotFound($rule['type']);
  95.             }
  96.             $ruleClass $this->ruleConditionRegistry->getRuleClass($rule['type']);
  97.             $object = new $ruleClass();
  98.             if ($object instanceof ScriptRule) {
  99.                 $object->assign([
  100.                     'script' => $rule['script'] ?? '',
  101.                     'lastModified' => $rule['lastModified'] ? new \DateTimeImmutable($rule['lastModified']) : null,
  102.                     'identifier' => $rule['identifier'] ?? null,
  103.                     'values' => $rule['value'] ? json_decode($rule['value'], true) : [],
  104.                 ]);
  105.                 $nested[] = $object;
  106.                 continue;
  107.             }
  108.             if ($rule['value'] !== null) {
  109.                 $object->assign(json_decode($rule['value'], true));
  110.             }
  111.             if ($object instanceof ContainerInterface) {
  112.                 $children $this->buildNested($rules$rule['id']);
  113.                 foreach ($children as $child) {
  114.                     $object->addRule($child);
  115.                 }
  116.             }
  117.             $nested[] = $object;
  118.         }
  119.         return $nested;
  120.     }
  121. }