Passed
Push — trunk ( 0c8c44...d7223d )
by Christian
18:03 queued 05:32
created

CustomerNewsletterSalesChannelsUpdater::delete()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 19
nc 4
nop 1
dl 0
loc 32
rs 9.6333
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Content\Newsletter\DataAbstractionLayer\Indexing;
4
5
use Doctrine\DBAL\Connection;
6
use Shopware\Core\Content\Newsletter\SalesChannel\NewsletterSubscribeRoute;
7
use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\RetryableQuery;
8
use Shopware\Core\Framework\Feature;
9
use Shopware\Core\Framework\Uuid\Uuid;
10
11
class CustomerNewsletterSalesChannelsUpdater
12
{
13
    private Connection $connection;
14
15
    /**
16
     * @internal
17
     */
18
    public function __construct(Connection $connection)
19
    {
20
        $this->connection = $connection;
21
    }
22
23
    /**
24
     * @param array<string> $ids
25
     */
26
    public function update(array $ids, bool $reverseUpdate = false): void
27
    {
28
        if (empty($ids)) {
29
            return;
30
        }
31
32
        $ids = array_unique($ids);
33
34
        $tableTemplate = <<<'SQL'
35
UPDATE `customer`, `newsletter_recipient` SET `customer`.`newsletter_sales_channel_ids` = (
36
    SELECT CONCAT(
37
        '{',
38
        GROUP_CONCAT(
39
            CONCAT(
40
                JSON_QUOTE(LOWER(HEX(`newsletter_recipient`.`id`))),
41
                ':',
42
                JSON_QUOTE(LOWER(HEX(`newsletter_recipient`.`sales_channel_id`)))
43
            )
44
        ),
45
        '}'
46
    )
47
    FROM `newsletter_recipient`
48
    WHERE `newsletter_recipient`.`email` = `customer`.`email`
49
    AND `newsletter_recipient`.`status` IN (:states)
50
)
51
WHERE `newsletter_recipient`.`email` = `customer`.`email`
52
AND #table#.`id` IN (:ids)
53
SQL;
54
55
        $resetTemplate = <<<'SQL'
56
UPDATE `customer`
57
LEFT JOIN `newsletter_recipient` ON `newsletter_recipient`.`email` = `customer`.`email`
58
SET `customer`.`newsletter_sales_channel_ids` = NULL
59
WHERE #table#.`id` IN (:ids)
60
SQL;
61
62
        $parameters = [
63
            'ids' => Uuid::fromHexToBytesList($ids),
64
            'states' => [NewsletterSubscribeRoute::STATUS_DIRECT, NewsletterSubscribeRoute::STATUS_OPT_IN],
65
        ];
66
67
        $replacement = [
68
            '#table#' => $reverseUpdate ? '`customer`' : '`newsletter_recipient`',
69
        ];
70
71
        $sql = str_replace(
72
            array_keys($replacement),
73
            array_values($replacement),
74
            $tableTemplate
75
        );
76
77
        $resetSql = str_replace(
78
            array_keys($replacement),
79
            array_values($replacement),
80
            $resetTemplate
81
        );
82
83
        RetryableQuery::retryable($this->connection, function () use ($resetSql, $parameters): void {
84
            $this->connection->executeUpdate(
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Connection::executeUpdate() has been deprecated: Use {@link executeStatement()} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

84
            /** @scrutinizer ignore-deprecated */ $this->connection->executeUpdate(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
85
                $resetSql,
86
                $parameters,
87
                ['ids' => Connection::PARAM_STR_ARRAY]
88
            );
89
        });
90
91
        RetryableQuery::retryable($this->connection, function () use ($sql, $parameters): void {
92
            $this->connection->executeUpdate(
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Connection::executeUpdate() has been deprecated: Use {@link executeStatement()} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

92
            /** @scrutinizer ignore-deprecated */ $this->connection->executeUpdate(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
93
                $sql,
94
                $parameters,
95
                ['ids' => Connection::PARAM_STR_ARRAY, 'states' => Connection::PARAM_STR_ARRAY]
96
            );
97
        });
98
    }
99
100
    /**
101
     * @param array<string> $ids
102
     */
103
    public function delete(array $ids): void
104
    {
105
        $sqlTemplate = <<<'SQL'
106
SELECT `customer`.`id`
107
FROM `customer`
108
WHERE #expressions#
109
SQL;
110
111
        $expressions = [];
112
        foreach ($ids as $id) {
113
            $expressions[] = 'JSON_EXTRACT(`customer`.`newsletter_sales_channel_ids`, \'$."' . $id . '"\') IS NOT NULL';
114
        }
115
116
        $replacement = [
117
            '#expressions#' => implode(' OR ', $expressions),
118
        ];
119
120
        $sql = str_replace(
121
            array_keys($replacement),
122
            array_values($replacement),
123
            $sqlTemplate
124
        );
125
126
        $customerIds = RetryableQuery::retryable($this->connection, function () use ($sql): array {
127
            return $this->connection->fetchFirstColumn($sql);
128
        });
129
130
        if (empty($customerIds)) {
131
            return;
132
        }
133
134
        $this->update(Uuid::fromBytesToHexList($customerIds), true);
135
    }
136
137
    /**
138
     * @deprecated tag:v6.5.0 - will be removed
139
     *
140
     * @param array<string> $ids
141
     */
142
    public function updateCustomerEmailRecipient(array $ids): void
143
    {
144
        Feature::triggerDeprecationOrThrow(
145
            'v6.5.0.0',
146
            Feature::deprecatedMethodMessage(__CLASS__, __METHOD__, 'v6.5.0.0')
147
        );
148
149
        $ids = array_unique($ids);
150
151
        $customers = $this->connection->fetchAllAssociative(
152
            'SELECT newsletter_sales_channel_ids, email FROM customer WHERE id IN (:ids)',
153
            ['ids' => Uuid::fromHexToBytesList($ids)],
154
            ['ids' => Connection::PARAM_STR_ARRAY]
155
        );
156
157
        $parameters = [];
158
159
        foreach ($customers as $customer) {
160
            if (!$customer['newsletter_sales_channel_ids']) {
161
                continue;
162
            }
163
164
            $parameters[] = [
165
                'newsletter_ids' => array_keys(
166
                    json_decode((string) $customer['newsletter_sales_channel_ids'], true)
167
                ),
168
                'email' => $customer['email'],
169
            ];
170
        }
171
172
        if (empty($parameters)) {
173
            return;
174
        }
175
176
        foreach ($parameters as $parameter) {
177
            RetryableQuery::retryable($this->connection, function () use ($parameter): void {
178
                $this->connection->executeUpdate(
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Connection::executeUpdate() has been deprecated: Use {@link executeStatement()} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

178
                /** @scrutinizer ignore-deprecated */ $this->connection->executeUpdate(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
179
                    'UPDATE newsletter_recipient SET email = (:email) WHERE id IN (:ids)',
180
                    ['ids' => Uuid::fromHexToBytesList($parameter['newsletter_ids']), 'email' => $parameter['email']],
181
                    ['ids' => Connection::PARAM_STR_ARRAY],
182
                );
183
            });
184
        }
185
    }
186
187
    /**
188
     * @param array<string> $ids
189
     */
190
    public function updateCustomersRecipient(array $ids): void
191
    {
192
        $ids = array_unique($ids);
193
194
        $customers = $this->connection->fetchAllAssociative(
195
            'SELECT newsletter_sales_channel_ids, email, first_name, last_name FROM customer WHERE id IN (:ids)',
196
            ['ids' => Uuid::fromHexToBytesList($ids)],
197
            ['ids' => Connection::PARAM_STR_ARRAY]
198
        );
199
200
        $parameters = [];
201
202
        foreach ($customers as $customer) {
203
            if (!$customer['newsletter_sales_channel_ids']) {
204
                continue;
205
            }
206
207
            $parameters[] = [
208
                'newsletter_ids' => array_keys(
209
                    json_decode((string) $customer['newsletter_sales_channel_ids'], true)
210
                ),
211
                'email' => $customer['email'],
212
                'first_name' => $customer['first_name'],
213
                'last_name' => $customer['last_name'],
214
            ];
215
        }
216
217
        if (empty($parameters)) {
218
            return;
219
        }
220
221
        foreach ($parameters as $parameter) {
222
            RetryableQuery::retryable($this->connection, function () use ($parameter): void {
223
                $this->connection->executeUpdate(
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\DBAL\Connection::executeUpdate() has been deprecated: Use {@link executeStatement()} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

223
                /** @scrutinizer ignore-deprecated */ $this->connection->executeUpdate(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
224
                    'UPDATE newsletter_recipient SET email = (:email), first_name = (:firstName), last_name = (:lastName) WHERE id IN (:ids)',
225
                    [
226
                        'ids' => Uuid::fromHexToBytesList($parameter['newsletter_ids']),
227
                        'email' => $parameter['email'],
228
                        'firstName' => $parameter['first_name'],
229
                        'lastName' => $parameter['last_name'],
230
                    ],
231
                    ['ids' => Connection::PARAM_STR_ARRAY],
232
                );
233
            });
234
        }
235
    }
236
}
237