PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Util / DataInconsistency / DataInconsistencyRepository.php
mailpoet / lib / Util / DataInconsistency Last commit date
DataInconsistencyController.php 2 weeks ago DataInconsistencyRepository.php 2 weeks ago index.php 1 year ago
DataInconsistencyRepository.php
313 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Util\DataInconsistency;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Cron\Workers\SendingQueue\SendingQueue;
9 use MailPoet\Entities\CustomFieldEntity;
10 use MailPoet\Entities\NewsletterEntity;
11 use MailPoet\Entities\NewsletterLinkEntity;
12 use MailPoet\Entities\NewsletterPostEntity;
13 use MailPoet\Entities\ScheduledTaskEntity;
14 use MailPoet\Entities\ScheduledTaskSubscriberEntity;
15 use MailPoet\Entities\SegmentEntity;
16 use MailPoet\Entities\SendingQueueEntity;
17 use MailPoet\Entities\SubscriberCustomFieldEntity;
18 use MailPoet\Entities\SubscriberEntity;
19 use MailPoet\Entities\SubscriberSegmentEntity;
20 use MailPoet\Entities\SubscriberTagEntity;
21 use MailPoet\Entities\TagEntity;
22 use MailPoetVendor\Doctrine\DBAL\ArrayParameterType;
23 use MailPoetVendor\Doctrine\DBAL\ParameterType;
24 use MailPoetVendor\Doctrine\ORM\EntityManager;
25 use MailPoetVendor\Doctrine\ORM\Query;
26 use MailPoetVendor\Doctrine\ORM\QueryBuilder;
27
28 class DataInconsistencyRepository {
29 const DELETE_ROWS_LIMIT = 10000;
30
31 private EntityManager $entityManager;
32
33 public function __construct(
34 EntityManager $entityManager
35 ) {
36 $this->entityManager = $entityManager;
37 }
38
39 public function getOrphanedSendingTasksCount(): int {
40 $builder = $this->entityManager->createQueryBuilder()
41 ->select('count(st.id)');
42 return (int)$this->buildOrphanedSendingTasksQuery($builder)->getSingleScalarResult();
43 }
44
45 public function getOrphanedScheduledTasksSubscribersCount(): int {
46 $this->createOrphanedScheduledTaskSubscribersTemporaryTables();
47 $count = $this->getOrphanedScheduledTasksSubscribersCountFromTemporaryTables();
48 $this->dropOrphanedScheduledTaskSubscribersTemporaryTables();
49 return $count;
50 }
51
52 private function getOrphanedScheduledTasksSubscribersCountFromTemporaryTables(): int {
53 $connection = $this->entityManager->getConnection();
54 $stsTable = $this->entityManager->getClassMetadata(ScheduledTaskSubscriberEntity::class)->getTableName();
55 /** @var string $count */
56 $count = $connection->executeQuery("
57 SELECT COUNT(*) FROM $stsTable sts WHERE sts.task_id IN (SELECT task_id FROM orphaned_task_ids)
58 ")->fetchOne();
59 return intval($count);
60 }
61
62 public function getSendingQueuesWithoutNewsletterCount(): int {
63 $sqTable = $this->entityManager->getClassMetadata(SendingQueueEntity::class)->getTableName();
64 $newsletterTable = $this->entityManager->getClassMetadata(NewsletterEntity::class)->getTableName();
65 /** @var string $count */
66 $count = $this->entityManager->getConnection()->executeQuery("
67 SELECT count(*) FROM $sqTable sq
68 LEFT JOIN $newsletterTable n ON n.`id` = sq.`newsletter_id`
69 WHERE n.`id` IS NULL
70 ")->fetchOne();
71 return intval($count);
72 }
73
74 public function getOrphanedSubscriptionsCount(): int {
75 $subscriberTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
76 $segmentTable = $this->entityManager->getClassMetadata(SegmentEntity::class)->getTableName();
77 $subscriberSegmentTable = $this->entityManager->getClassMetadata(SubscriberSegmentEntity::class)->getTableName();
78 /** @var string $count */
79 $count = $this->entityManager->getConnection()->executeQuery("
80 SELECT count(distinct ss.`id`) FROM $subscriberSegmentTable ss
81 LEFT JOIN $segmentTable seg ON seg.`id` = ss.`segment_id`
82 LEFT JOIN $subscriberTable sub ON sub.`id` = ss.`subscriber_id`
83 WHERE seg.`id` IS NULL OR sub.`id` IS NULL
84 ")->fetchOne();
85 return intval($count);
86 }
87
88 public function getOrphanedSubscriberCustomFieldsCount(): int {
89 $subscriberTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
90 $customFieldTable = $this->entityManager->getClassMetadata(CustomFieldEntity::class)->getTableName();
91 $subscriberCustomFieldTable = $this->entityManager->getClassMetadata(SubscriberCustomFieldEntity::class)->getTableName();
92 /** @var string $count */
93 $count = $this->entityManager->getConnection()->executeQuery("
94 SELECT count(distinct scf.`id`) FROM $subscriberCustomFieldTable scf
95 LEFT JOIN $customFieldTable cf ON cf.`id` = scf.`custom_field_id`
96 LEFT JOIN $subscriberTable sub ON sub.`id` = scf.`subscriber_id`
97 WHERE cf.`id` IS NULL OR sub.`id` IS NULL
98 ")->fetchOne();
99 return intval($count);
100 }
101
102 public function getOrphanedSubscriberTagsCount(): int {
103 $subscriberTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
104 $tagTable = $this->entityManager->getClassMetadata(TagEntity::class)->getTableName();
105 $subscriberTagTable = $this->entityManager->getClassMetadata(SubscriberTagEntity::class)->getTableName();
106 /** @var string $count */
107 $count = $this->entityManager->getConnection()->executeQuery("
108 SELECT count(distinct st.`id`) FROM $subscriberTagTable st
109 LEFT JOIN $tagTable t ON t.`id` = st.`tag_id`
110 LEFT JOIN $subscriberTable sub ON sub.`id` = st.`subscriber_id`
111 WHERE t.`id` IS NULL OR sub.`id` IS NULL
112 ")->fetchOne();
113 return intval($count);
114 }
115
116 public function getOrphanedNewsletterLinksCount(): int {
117 $newsletterTable = $this->entityManager->getClassMetadata(NewsletterEntity::class)->getTableName();
118 $sendingQueueTable = $this->entityManager->getClassMetadata(SendingQueueEntity::class)->getTableName();
119 $newsletterLinkTable = $this->entityManager->getClassMetadata(NewsletterLinkEntity::class)->getTableName();
120 /** @var string $count */
121 $count = $this->entityManager->getConnection()->executeQuery("
122 SELECT count(distinct nl.`id`) FROM $newsletterLinkTable nl
123 LEFT JOIN $newsletterTable n ON n.`id` = nl.`newsletter_id`
124 LEFT JOIN $sendingQueueTable sq ON sq.`id` = nl.`queue_id`
125 WHERE n.`id` IS NULL OR sq.`id` IS NULL
126 ")->fetchOne();
127 return intval($count);
128 }
129
130 public function getOrphanedNewsletterPostsCount(): int {
131 $newsletterTable = $this->entityManager->getClassMetadata(NewsletterEntity::class)->getTableName();
132 $newsletterPostTable = $this->entityManager->getClassMetadata(NewsletterPostEntity::class)->getTableName();
133 /** @var string $count */
134 $count = $this->entityManager->getConnection()->executeQuery("
135 SELECT count(distinct np.`id`) FROM $newsletterPostTable np
136 LEFT JOIN $newsletterTable n ON n.`id` = np.`newsletter_id`
137 WHERE n.`id` IS NULL
138 ")->fetchOne();
139 return intval($count);
140 }
141
142 public function cleanupOrphanedSendingTasks(): int {
143 /** @var array<int, array{id: string}> $ids */
144 $ids = $this->buildOrphanedSendingTasksQuery(
145 $this->entityManager->createQueryBuilder()
146 ->select('st.id')
147 )->getResult();
148
149 if (!$ids) {
150 return 0;
151 }
152 $ids = array_column($ids, 'id');
153 // delete the orphaned tasks
154 $qb = $this->entityManager->createQueryBuilder();
155 $countDeletedTasks = $qb->delete(ScheduledTaskEntity::class, 'st')
156 ->where($qb->expr()->in('st.id', ':ids'))
157 ->setParameter('ids', $ids)
158 ->getQuery()
159 ->execute();
160
161 // delete the scheduled tasks subscribers
162 $stsTable = $this->entityManager->getClassMetadata(ScheduledTaskSubscriberEntity::class)->getTableName();
163 $this->entityManager->getConnection()->executeStatement(
164 "DELETE sts_top FROM $stsTable sts_top
165 JOIN (
166 SELECT sts.`task_id`, sts.`subscriber_id` FROM $stsTable sts
167 WHERE `task_id` IN (:ids)
168 LIMIT :limit
169 ) as to_delete ON sts_top.`task_id` = to_delete.`task_id` AND sts_top.`subscriber_id` = to_delete.`subscriber_id`",
170 ['limit' => self::DELETE_ROWS_LIMIT, 'ids' => $ids],
171 ['limit' => ParameterType::INTEGER, 'ids' => ArrayParameterType::INTEGER]
172 );
173
174
175 $qb = $this->entityManager->createQueryBuilder();
176 $qb->delete(ScheduledTaskSubscriberEntity::class, 'sts')
177 ->where($qb->expr()->in('sts.task', ':ids'))
178 ->setParameter('ids', $ids)
179 ->getQuery()
180 ->execute();
181
182 return $countDeletedTasks;
183 }
184
185 public function cleanupOrphanedScheduledTaskSubscribers(): int {
186 $stsTable = $this->entityManager->getClassMetadata(ScheduledTaskSubscriberEntity::class)->getTableName();
187 $deletedCount = 0;
188
189 $this->createOrphanedScheduledTaskSubscribersTemporaryTables();
190 do {
191 $deletedCount += (int)$this->entityManager->getConnection()->executeStatement(
192 "
193 DELETE sts_top FROM $stsTable sts_top
194 JOIN (
195 SELECT task_id, subscriber_id
196 FROM $stsTable
197 WHERE task_id IN (SELECT task_id FROM orphaned_task_ids)
198 LIMIT :limit
199 ) AS to_delete ON sts_top.task_id = to_delete.task_id AND sts_top.subscriber_id = to_delete.subscriber_id
200 ",
201 ['limit' => self::DELETE_ROWS_LIMIT],
202 ['limit' => ParameterType::INTEGER]
203 );
204 } while ($this->getOrphanedScheduledTasksSubscribersCountFromTemporaryTables() > 0);
205 $this->dropOrphanedScheduledTaskSubscribersTemporaryTables();
206 return $deletedCount;
207 }
208
209 public function cleanupSendingQueuesWithoutNewsletter(): int {
210 $sqTable = $this->entityManager->getClassMetadata(SendingQueueEntity::class)->getTableName();
211 $newsletterTable = $this->entityManager->getClassMetadata(NewsletterEntity::class)->getTableName();
212 $deletedQueuesCount = (int)$this->entityManager->getConnection()->executeStatement("
213 DELETE sq FROM $sqTable sq
214 LEFT JOIN $newsletterTable n ON n.`id` = sq.`newsletter_id`
215 WHERE n.`id` IS NULL
216 ");
217
218 $this->cleanupOrphanedSendingTasks();
219 return $deletedQueuesCount;
220 }
221
222 public function cleanupOrphanedSubscriptions(): int {
223 $subscriberTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
224 $segmentTable = $this->entityManager->getClassMetadata(SegmentEntity::class)->getTableName();
225 $subscriberSegmentTable = $this->entityManager->getClassMetadata(SubscriberSegmentEntity::class)->getTableName();
226 return (int)$this->entityManager->getConnection()->executeStatement("
227 DELETE ss FROM $subscriberSegmentTable ss
228 LEFT JOIN $segmentTable seg ON seg.`id` = ss.`segment_id`
229 LEFT JOIN $subscriberTable sub ON sub.`id` = ss.`subscriber_id`
230 WHERE seg.`id` IS NULL OR sub.`id` IS NULL
231 ");
232 }
233
234 public function cleanupOrphanedSubscriberCustomFields(): int {
235 $subscriberTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
236 $customFieldTable = $this->entityManager->getClassMetadata(CustomFieldEntity::class)->getTableName();
237 $subscriberCustomFieldTable = $this->entityManager->getClassMetadata(SubscriberCustomFieldEntity::class)->getTableName();
238 return (int)$this->entityManager->getConnection()->executeStatement("
239 DELETE scf FROM $subscriberCustomFieldTable scf
240 LEFT JOIN $customFieldTable cf ON cf.`id` = scf.`custom_field_id`
241 LEFT JOIN $subscriberTable sub ON sub.`id` = scf.`subscriber_id`
242 WHERE cf.`id` IS NULL OR sub.`id` IS NULL
243 ");
244 }
245
246 public function cleanupOrphanedSubscriberTags(): int {
247 $subscriberTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
248 $tagTable = $this->entityManager->getClassMetadata(TagEntity::class)->getTableName();
249 $subscriberTagTable = $this->entityManager->getClassMetadata(SubscriberTagEntity::class)->getTableName();
250 return (int)$this->entityManager->getConnection()->executeStatement("
251 DELETE st FROM $subscriberTagTable st
252 LEFT JOIN $tagTable t ON t.`id` = st.`tag_id`
253 LEFT JOIN $subscriberTable sub ON sub.`id` = st.`subscriber_id`
254 WHERE t.`id` IS NULL OR sub.`id` IS NULL
255 ");
256 }
257
258 public function cleanupOrphanedNewsletterLinks(): int {
259 $newsletterTable = $this->entityManager->getClassMetadata(NewsletterEntity::class)->getTableName();
260 $sendingQueueTable = $this->entityManager->getClassMetadata(SendingQueueEntity::class)->getTableName();
261 $newsletterLinkTable = $this->entityManager->getClassMetadata(NewsletterLinkEntity::class)->getTableName();
262 return (int)$this->entityManager->getConnection()->executeStatement("
263 DELETE nl FROM $newsletterLinkTable nl
264 LEFT JOIN $newsletterTable n ON n.`id` = nl.`newsletter_id`
265 LEFT JOIN $sendingQueueTable sq ON sq.`id` = nl.`queue_id`
266 WHERE n.`id` IS NULL OR sq.`id` IS NULL
267 ");
268 }
269
270 public function cleanupOrphanedNewsletterPosts(): int {
271 $newsletterTable = $this->entityManager->getClassMetadata(NewsletterEntity::class)->getTableName();
272 $newsletterPostTable = $this->entityManager->getClassMetadata(NewsletterPostEntity::class)->getTableName();
273 return (int)$this->entityManager->getConnection()->executeStatement("
274 DELETE np FROM $newsletterPostTable np
275 LEFT JOIN $newsletterTable n ON n.`id` = np.`newsletter_id`
276 WHERE n.`id` IS NULL
277 ");
278 }
279
280 private function buildOrphanedSendingTasksQuery(QueryBuilder $queryBuilder): Query {
281 return $queryBuilder
282 ->from(ScheduledTaskEntity::class, 'st')
283 ->leftJoin('st.sendingQueue', 'sq')
284 ->where('sq.id IS NULL')
285 ->andWhere('st.type = :type')
286 ->setParameter('type', SendingQueue::TASK_TYPE)
287 ->getQuery();
288 }
289
290 private function createOrphanedScheduledTaskSubscribersTemporaryTables(): void {
291 $connection = $this->entityManager->getConnection();
292 $stTable = $this->entityManager->getClassMetadata(ScheduledTaskEntity::class)->getTableName();
293 $stsTable = $this->entityManager->getClassMetadata(ScheduledTaskSubscriberEntity::class)->getTableName();
294
295 // 1. Get the DISTINCT task IDs so that the subsequent JOIN is more efficient.
296 $connection->executeStatement("
297 CREATE TEMPORARY TABLE IF NOT EXISTS task_ids
298 SELECT DISTINCT task_id FROM $stsTable
299 ");
300
301 // 2. Get the orphaned task IDs.
302 $connection->executeStatement("
303 CREATE TEMPORARY TABLE IF NOT EXISTS orphaned_task_ids
304 SELECT task_id FROM task_ids LEFT JOIN $stTable st ON st.id = task_ids.task_id WHERE st.id IS NULL
305 ");
306 }
307
308 private function dropOrphanedScheduledTaskSubscribersTemporaryTables(): void {
309 $this->entityManager->getConnection()->executeStatement("DROP TEMPORARY TABLE IF EXISTS task_ids");
310 $this->entityManager->getConnection()->executeStatement("DROP TEMPORARY TABLE IF EXISTS orphaned_task_ids");
311 }
312 }
313