PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.3 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 / API / MP / v1 / Segments.php
mailpoet / lib / API / MP / v1 Last commit date
API.php 3 months ago APIException.php 3 months ago CustomFields.php 2 months ago Segments.php 2 months ago Subscribers.php 2 months ago Tags.php 3 months ago index.php 3 years ago
Segments.php
213 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\API\MP\v1;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Entities\SegmentEntity;
9 use MailPoet\Form\FormsRepository;
10 use MailPoet\Newsletter\Segment\NewsletterSegmentRepository;
11 use MailPoet\Segments\SegmentsRepository;
12
13 class Segments {
14 private const DATE_FORMAT = 'Y-m-d H:i:s';
15
16 /** @var NewsletterSegmentRepository */
17 private $newsletterSegmentRepository;
18
19 /** @var FormsRepository */
20 private $formsRepository;
21
22 /** @var SegmentsRepository */
23 private $segmentsRepository;
24
25 public function __construct (
26 NewsletterSegmentRepository $newsletterSegmentRepository,
27 FormsRepository $formsRepository,
28 SegmentsRepository $segmentsRepository
29 ) {
30 $this->newsletterSegmentRepository = $newsletterSegmentRepository;
31 $this->formsRepository = $formsRepository;
32 $this->segmentsRepository = $segmentsRepository;
33 }
34
35 public function getAll(): array {
36 $segments = $this->segmentsRepository->findBy(['type' => SegmentEntity::TYPE_DEFAULT], ['id' => 'asc']);
37 $result = [];
38 foreach ($segments as $segment) {
39 $result[] = $this->buildItem($segment);
40 }
41 return $result;
42 }
43
44 public function addList(array $data): array {
45 $this->validateSegmentName($data);
46
47 try {
48 $name = isset($data['name']) ? sanitize_text_field($data['name']) : '';
49 $description = isset($data['description']) ? sanitize_textarea_field($data['description']) : '';
50 $segment = $this->segmentsRepository->createOrUpdate($name, $description);
51 } catch (\Exception $e) {
52 throw new APIException(
53 __('The list couldn’t be created in the database', 'mailpoet'),
54 APIException::FAILED_TO_SAVE_LIST
55 );
56 }
57
58 return $this->buildItem($segment);
59 }
60
61 public function updateList(array $data): array {
62 // firstly validation on list id
63 $this->validateSegmentId((string)($data['id'] ?? ''));
64
65 // secondly validation on list name
66 $this->validateSegmentName($data);
67
68 // update is supported only for default segment type
69 $this->validateSegmentType((string)$data['id']);
70
71 $name = isset($data['name']) ? sanitize_text_field($data['name']) : '';
72 $description = isset($data['description']) ? sanitize_textarea_field($data['description']) : '';
73
74 try {
75 $segment = $this->segmentsRepository->createOrUpdate(
76 $name,
77 $description,
78 SegmentEntity::TYPE_DEFAULT,
79 [],
80 (int)$data['id']
81 );
82 } catch (\Exception $e) {
83 throw new APIException(
84 __('The list couldn’t be updated in the database', 'mailpoet'),
85 APIException::FAILED_TO_UPDATE_LIST
86 );
87 }
88
89 return $this->buildItem($segment);
90 }
91
92 public function deleteList(string $listId): bool {
93 $this->validateSegmentId($listId);
94
95 // delete is supported only for default segment type
96 $this->validateSegmentType($listId);
97
98 $activelyUsedNewslettersSubjects = $this->newsletterSegmentRepository->getSubjectsOfActivelyUsedEmailsForSegments([$listId]);
99 if (isset($activelyUsedNewslettersSubjects[$listId])) {
100 throw new APIException(
101 str_replace(
102 '%1$s',
103 "'" . join("', '", $activelyUsedNewslettersSubjects[$listId]) . "'",
104 // translators: %1$s is a comma-separated list of emails for which the segment is used.
105 _x('List cannot be deleted because it’s used for %1$s email', 'Alert shown when trying to delete segment, which is assigned to any automatic emails.', 'mailpoet')
106 ),
107 APIException::LIST_USED_IN_EMAIL
108 );
109 }
110
111 $activelyUsedFormNames = $this->formsRepository->getNamesOfFormsForSegments();
112 if (isset($activelyUsedFormNames[$listId])) {
113 throw new APIException(
114 str_replace(
115 '%1$s',
116 "'" . join("', '", $activelyUsedFormNames[$listId]) . "'",
117 // translators: %1$s is a comma-separated list of forms for which the segment is used.
118 _nx(
119 'List cannot be deleted because it’s used for %1$s form',
120 'List cannot be deleted because it’s used for %1$s forms',
121 count($activelyUsedFormNames[$listId]),
122 'Alert shown when trying to delete segment, when it is assigned to a form.',
123 'mailpoet'
124 )
125 ),
126 APIException::LIST_USED_IN_FORM
127 );
128 }
129
130 try {
131 $this->segmentsRepository->bulkDelete([$listId]);
132 return true;
133 } catch (\Exception $e) {
134 throw new APIException(
135 __('The list couldn’t be deleted from the database', 'mailpoet'),
136 APIException::FAILED_TO_DELETE_LIST
137 );
138 }
139 }
140
141 private function validateSegmentId(string $segmentId): void {
142 if (empty($segmentId)) {
143 throw new APIException(
144 __('List id is required.', 'mailpoet'),
145 APIException::LIST_ID_REQUIRED
146 );
147 }
148
149 if (!$this->segmentsRepository->findOneById($segmentId)) {
150 throw new APIException(
151 __('The list does not exist.', 'mailpoet'),
152 APIException::LIST_NOT_EXISTS
153 );
154 }
155 }
156
157 /**
158 * Throws an exception when the segment's name is invalid.
159 * Validates against the sanitized name so whitespace-only inputs that
160 * collapse to empty after sanitize_text_field() are rejected up front
161 * instead of being silently saved as an empty list name.
162 * @return void
163 */
164 private function validateSegmentName(array $data): void {
165 $name = isset($data['name']) && is_string($data['name']) ? sanitize_text_field($data['name']) : '';
166 if ($name === '') {
167 throw new APIException(
168 __('List name is required.', 'mailpoet'),
169 APIException::LIST_NAME_REQUIRED
170 );
171 }
172
173 $segmentId = isset($data['id']) ? (int)$data['id'] : null;
174 if (!$this->segmentsRepository->isNameUnique($name, $segmentId)) {
175 throw new APIException(
176 __('This list already exists.', 'mailpoet'),
177 APIException::LIST_EXISTS
178 );
179 }
180 }
181
182 private function validateSegmentType(string $segmentId): void {
183 $segment = $this->segmentsRepository->findOneById($segmentId);
184 if ($segment && $segment->getType() !== SegmentEntity::TYPE_DEFAULT) {
185 throw new APIException(
186 str_replace(
187 '%1$s',
188 "'" . $segment->getType() . "'",
189 // translators: %1$s is an invalid segment type.
190 __('List of the type %1$s is not supported for this action.', 'mailpoet')
191 ),
192 APIException::LIST_TYPE_IS_NOT_SUPPORTED
193 );
194 }
195 }
196
197 /**
198 * @param SegmentEntity $segment
199 * @return array
200 */
201 private function buildItem(SegmentEntity $segment): array {
202 return [
203 'id' => (string)$segment->getId(), // (string) for BC
204 'name' => $segment->getName(),
205 'type' => $segment->getType(),
206 'description' => $segment->getDescription(),
207 'created_at' => ($createdAt = $segment->getCreatedAt()) ? $createdAt->format(self::DATE_FORMAT) : null,
208 'updated_at' => ($updatedAt = $segment->getUpdatedAt()) ? $updatedAt->format(self::DATE_FORMAT) : null,
209 'deleted_at' => ($deletedAt = $segment->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null,
210 ];
211 }
212 }
213