1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
Utils.php
См. документацию.
1<?php
2
3namespace Bitrix\MessageService\Providers\Edna\WhatsApp;
4
5use Bitrix\Main\Application;
6use Bitrix\Main\Data\Cache;
7use Bitrix\Main\Error;
8use Bitrix\Main\Result;
9use Bitrix\MessageService\Internal\Entity\MessageTable;
10use Bitrix\MessageService\Internal\Entity\TemplateTable;
11use Bitrix\MessageService\Providers;
12use Bitrix\MessageService\Providers\Edna\EdnaUtils;
13
14class Utils extends EdnaUtils
15{
16 public const CACHE_KEY_TEMPLATES = 'whatsapp_templates_cache';
17 public const CACHE_DIR_TEMPLATES = '/messageservice/templates/';
18 protected const CACHE_TIME_TEMPLATES = 14400;
19
21 {
22 return new ExternalSender(
23 $this->optionManager->getOption(Providers\Constants\InternalOption::API_KEY),
25 $this->optionManager->getSocketTimeout(),
26 $this->optionManager->getStreamTimeout()
27 );
28 }
29
30 public function getMessageTemplates(string $subject = ''): Result
31 {
32 $result = new Result();
33
34 if ($this->optionManager->getOption('enable_templates_stub', 'N') === 'Y')
35 {
36 $templates = $this->removeUnsupportedTemplates($this->getMessageTemplatesStub());
37 return $result->setData($templates);
38 }
39
40 $subjectList = [$subject];
41 if ($subject === '')
42 {
43 $subjectList = $this->optionManager->getOption('sender_id', []);
44 }
45
46 $verifiedSubjectIdResult = $this->getVerifiedSubjectIdList($subjectList);
47 if (!$verifiedSubjectIdResult->isSuccess())
48 {
49 return $verifiedSubjectIdResult;
50 }
51
52 $verifiedSubjectIdList = $verifiedSubjectIdResult->getData();
53
54 $templates = [];
55
56 $cache = Cache::createInstance();
57 if ($cache->initCache(self::CACHE_TIME_TEMPLATES, self::CACHE_KEY_TEMPLATES, self::CACHE_DIR_TEMPLATES))
58 {
59 $templates = $cache->getVars();
60 }
61 elseif ($cache->startDataCache())
62 {
63 foreach ($verifiedSubjectIdList as $subjectId)
64 {
66 'subjectId' => $subjectId
67 ];
68
69 $templatesRequestResult =
70 $this->externalSender->callExternalMethod(Providers\Edna\Constants\Method::GET_TEMPLATES, $requestParams);
71
72 if ($templatesRequestResult->isSuccess())
73 {
74 $templates = array_merge($templates, $templatesRequestResult->getData());
75 }
76 }
77
78 $templates = $this->excludeOutdatedTemplates($templates);
79 $templates = $this->replaceNameToTitle($templates);
80
81 $cache->endDataCache($templates);
82 }
83
84 $checkErrors = $this->checkForErrors($templates);
85 if ($checkErrors->isSuccess())
86 {
87 $templates = $this->removeUnsupportedTemplates($templates);
88 $templates = $this->checkForPlaceholders($templates);
89 $result->setData($templates);
90 }
91 else
92 {
93 $result->addErrors($checkErrors->getErrors());
94 }
95
96 return $result;
97 }
98
99 public function prepareTemplateMessageText(array $message): string
100 {
101 $latestMessage = '';
102 if (isset($message['MESSAGE_HEADERS']['template']['header']['text']))
103 {
104 $latestMessage .= $message['MESSAGE_HEADERS']['template']['header']['text'] . '#BR#';
105 }
106
107 if (isset($message['MESSAGE_HEADERS']['template']['text']))
108 {
109 $latestMessage .= $message['MESSAGE_HEADERS']['template']['text'] . '#BR#';
110 }
111
112 if (isset($message['MESSAGE_HEADERS']['template']['footer']['text']))
113 {
114 $latestMessage .= $message['MESSAGE_HEADERS']['template']['footer']['text'];
115 }
116
117 return $latestMessage;
118 }
119
120 public function getSentTemplateMessage(string $from, string $to): string
121 {
122 $message = MessageTable::getList([
123 'select' => ['ID', 'MESSAGE_HEADERS'],
124 'filter' => [
125 '=SENDER_ID' => $this->providerId,
126 '=MESSAGE_FROM' => $from,
127 '=MESSAGE_TO' => '+' . $to,
128 ],
129 'limit' => 1,
130 'order' => ['ID' => 'DESC'],
131 ])->fetch();
132
133 if (!$message)
134 {
135 return '';
136 }
137
139 }
140
141 protected function getMessageTemplatesStub(): array
142 {
143 return [
144 [
145 'id' => 242,
146 'name' => 'only text',
147 'channelType' => 'whatsapp',
148 'language' => 'RU',
149 'content' => [
150 'attachment' => null,
151 'action' => null,
152 'caption' => null,
153 'header' => null,
154 'text' => "Hello! Welcome to our platform.",
155 'footer' => null,
156 'keyboard' => null,
157 ],
158 'category' => 'ACCOUNT_UPDATE',
160 'locked' => false,
161 'type' => 'OPERATOR',
162 'createdAt' => '2021-07-15T14:16:54.417024Z',
163 'updatedAt' => '2021-07-16T13:08:26.275414Z',
164 ],
165 [
166 'id' => 267,
167 'name' => 'text + header + footer',
168 'channelType' => 'whatsapp',
169 'language' => 'RU',
170 'content' => [
171 'attachment' => null,
172 'action' => null,
173 'caption' => null,
174 'header' => [
175 'text' => 'Greetings',
176 ],
177 'text' => 'Hello! Welcome to our platform.',
178 'footer' => [
179 'text' => 'Have a nice day',
180 ],
181 'keyboard' => null,
182 ],
183 'category' => 'ACCOUNT_UPDATE',
185 'locked' => false,
186 'type' => 'USER',
187 'createdAt' => '2021-07-20T09:21:42.444454Z',
188 'updatedAt' => '2021-07-20T09:21:42.444454Z',
189 ],
190 [
191 'id' => 268,
192 'name' => 'text + buttons',
193 'channelType' => 'whatsapp',
194 'language' => 'RU',
195 'content' => [
196 'attachment' => null,
197 'action' => null,
198 'caption' => null,
199 'header' => null,
200 'text' => "Hello! Welcome to our platform. Have you already tried it?",
201 'footer' => null,
202 'keyboard' => [
203 'rows' => [
204 [
205 'buttons' => [
206 [
207 'text' => 'Yes',
208 'buttonType' => "QUICK_REPLY",
209 'payload' => '1'
210 ],
211 [
212 'text' => 'No',
213 'buttonType' => "QUICK_REPLY",
214 'payload' => '2'
215 ],
216 ],
217 ],
218 ],
219 ],
220
221 ],
222 'category' => 'ACCOUNT_UPDATE',
224 'locked' => false,
225 'type' => 'USER',
226 'createdAt' => '2021-07-20T09:21:42.444454Z',
227 'updatedAt' => '2021-07-20T09:21:42.444454Z',
228 ],
229 [
230 'id' => 269,
231 'name' => 'text + button-link',
232 'channelType' => 'whatsapp',
233 'language' => 'RU',
234 'content' => [
235 'attachment' => null,
236 'action' => null,
237 'caption' => null,
238 'header' => null,
239 'text' => 'Hello! Welcome to our platform. Follow the link bellow to read manuals:',
240 'footer' => null,
241 'keyboard' => [
242 'rows' => [
243 [
244 'buttons' => [
245 [
246 'text' => 'Manual',
247 'buttonType' => "URL",
248 'url' => "https://docs.edna.io/"
249 ],
250 ],
251 ],
252 ],
253 ],
254 ],
255 'category' => 'ACCOUNT_UPDATE',
257 'locked' => false,
258 'type' => 'USER',
259 'createdAt' => '2021-07-20T09:21:42.444454Z',
260 'updatedAt' => '2021-07-20T09:21:42.444454Z',
261 ],
262 ];
263 }
264
265 private function getVerifiedSubjectIdList(array $subjectList): Result
266 {
267 $channelListResult = $this->getChannelList(Providers\Edna\Constants\ChannelType::WHATSAPP);
268 if (!$channelListResult->isSuccess())
269 {
270 return $channelListResult;
271 }
272
273 $filteredSubjectList = [];
274 foreach ($channelListResult->getData() as $channel)
275 {
276 if (isset($channel['subjectId']) && in_array($channel['subjectId'], $subjectList, true))
277 {
278 $filteredSubjectList[] = $channel['subjectId'];
279 }
280 }
281
282 $result = new Result();
283 if (empty($filteredSubjectList))
284 {
285 $result->addError(new Error('Verified subjects are missing'));
286
287 return $result;
288 }
289 $result->setData($filteredSubjectList);
290
291 return $result;
292 }
293
298 protected function checkApprovedStatus(array $template): bool
299 {
300 return isset($template['status']) && $template['status'] === Providers\Edna\Constants\TemplateStatus::APPROVED;
301 }
302
303 protected function checkForPlaceholders(array $templates): array
304 {
305 foreach ($templates as &$template)
306 {
307 $template['placeholders'] = [];
308
309 if (
310 !empty($template['content']['header']['text'])
311 && $this->hasPlaceholder($template['content']['header']['text'])
312 )
313 {
314 $template['placeholders']['header'] = $this->extractPlaceholders($template['content']['header']['text']);
315 }
316
317 if (
318 !empty($template['content']['text'])
319 && $this->hasPlaceholder($template['content']['text'])
320 )
321 {
322 $template['placeholders']['text'] = $this->extractPlaceholders($template['content']['text']);
323 }
324
325 if (
326 !empty($template['content']['footer']['text'])
327 && $this->hasPlaceholder($template['content']['footer']['text'])
328 )
329 {
330 $template['placeholders']['footer'] = $this->extractPlaceholders($template['content']['footer']['text']);
331 }
332 }
333
334 return $templates;
335 }
336
337 protected function hasPlaceholder(string $text): bool
338 {
339 return !empty($text) && preg_match("/{{[\d]+}}/", $text);
340 }
341
342 protected function extractPlaceholders(string $text): array
343 {
344 preg_match_all("/({{[\d]+}})/", $text, $matches);
345
346 return !empty($matches[0]) ? $matches[0] : [];
347 }
348
349 protected function checkForErrors(array $templates): Result
350 {
351 $checkResult = new Result();
352 foreach ($templates as $template)
353 {
354 if (!is_array($template))
355 {
356 $exception = new \Bitrix\Main\SystemException(
357 'Incorrect response from the Edna service: ' . var_export($templates, true)
358 );
359
360 \Bitrix\Main\Application::getInstance()->getExceptionHandler()->writeToLog($exception);
361
362 return $checkResult->addError(
363 new Error('Incorrect response from the Edna service.', 400, $templates)
364 );
365 }
366 }
367
368 return $checkResult;
369 }
370
371 protected function removeUnsupportedTemplates(array $templates): array
372 {
373 $filteredTemplates = [];
374 foreach ($templates as $template)
375 {
376 if (!is_array($template))
377 {
378 continue;
379 }
380
381 if (!$this->checkApprovedStatus($template))
382 {
383 continue;
384 }
385
386 $filteredTemplates[] = $template;
387 }
388
389 return $filteredTemplates;
390 }
391
392 protected function replaceNameToTitle(array $templates = []): array
393 {
394 $autoTemplates = TemplateTable::getList([
395 'filter' => ['=ACTIVE' => 'Y']
396 ])->fetchAll();
397
398 $titles = [];
399 foreach ($autoTemplates as $autoTemplate)
400 {
401 $titles[$autoTemplate['NAME']] = $autoTemplate['TITLE'];
402 }
403
404 foreach ($templates as $key => $template)
405 {
406 $templates[$key]['name'] = $titles[$template['name']] ?? $template['name'];
407 }
408
409 return $templates;
410 }
411
412 protected function excludeOutdatedTemplates(array $templates = []): array
413 {
414 $outdatedTemplatesResult = TemplateTable::getList([
415 'filter' => ['=ACTIVE' => 'N']
416 ])->fetchAll();
417
418 $outdatedTemplates = [];
419 foreach ($outdatedTemplatesResult as $outdatedTemplate)
420 {
421 $outdatedTemplates[$outdatedTemplate['NAME']] = true;
422 }
423
424 $activeTemplates = array_filter($templates, function ($template) use ($outdatedTemplates) {
425 return is_array($template) && isset($template['name']) && !isset($outdatedTemplates[$template['name']]);
426 });
427
428 return array_values($activeTemplates);
429 }
430
431 public function sendTemplate(string $name, string $text, array $examples = [], ?string $langCode = null): Result
432 {
433 if (is_null($langCode))
434 {
435 $langCode = Application::getInstance()->getContext()->getLanguage();
436 }
437
438 if (!$this->validateLanguage($langCode))
439 {
440 return (new Result)->addError(new Error('Unknown language code'));
441 }
442
443 $validateTemplateName = $this->validateTemplateName($name);
444 if (!$validateTemplateName->isSuccess())
445 {
446 return $validateTemplateName;
447 }
448
449 $validateTemplateText = $this->validateTemplateText($text);
450 if (!$validateTemplateText->isSuccess())
451 {
452 return $validateTemplateText;
453 }
454 $validateExamples = $this->validateExamples($text, $examples);
455 if (!$validateExamples->isSuccess())
456 {
457 return $validateExamples;
458 }
459
460 $subjectList = $this->optionManager->getOption('sender_id', []);
461 $verifiedSubjectIdResult = $this->getVerifiedSubjectIdList($subjectList);
462 if (!$verifiedSubjectIdResult->isSuccess())
463 {
464 return $verifiedSubjectIdResult;
465 }
466
467 $verifiedSubjectIdList = $verifiedSubjectIdResult->getData();
468
470 'messageMatcher' => [
471 'name' => $name,
472 'channelType' => $this->getChannelType(),
473 'language' => $langCode,
474 'category' => 'UTILITY',
475 'type' => 'OPERATOR',
476 'contentType' => 'TEXT',
477 'content' => [
478 'text' => $text,
479 'textExampleParams' => $examples
480 ]
481 ],
482 'subjectIds' => $verifiedSubjectIdList,
483 ];
484
485 return $this->externalSender->callExternalMethod(Providers\Edna\Constants\Method::SEND_TEMPLATE, $requestParams);
486 }
487
488 protected function getChannelType(): string
489 {
491 }
492
493 protected function validateTemplateText(string $text): Result
494 {
495 $result = new Result();
496
497 if (mb_strlen($text) > 1024)
498 {
499 return $result->addError(new Error('The maximum number of characters is 1024'));
500 }
501
502 if (!preg_match('/^(?!.* {4,}).*$/ui', $text))
503 {
504 return $result->addError(new Error('The text cannot contain newlines and 4 spaces in a row'));
505 }
506
507 return $result;
508 }
509
510 protected function validateExamples(string $text, array $examples): Result
511 {
512 $result = new Result();
513
514 $variables = [];
515 preg_match_all('/{{[0-9]+}}/ui', $text, $variables);
516 if (count($variables[0]) !== count($examples))
517 {
518 return $result->addError(new Error('The number of examples differs from the number of variables'));
519 }
520
521 return $result;
522 }
523
524 public static function cleanTemplatesCache(): void
525 {
526 $cache = Cache::createInstance();
527 $cache->clean(
530 );
531 }
532}
static getInstance()
Определения application.php:98
Определения error.php:15
static getList(array $parameters=array())
Определения datamanager.php:431
validateLanguage(string $langCode)
Определения EdnaUtils.php:266
validateTemplateName(string $name)
Определения EdnaUtils.php:293
getChannelList(string $imType)
Определения EdnaUtils.php:33
checkForPlaceholders(array $templates)
Определения Utils.php:303
checkForErrors(array $templates)
Определения Utils.php:349
getSentTemplateMessage(string $from, string $to)
Определения Utils.php:120
prepareTemplateMessageText(array $message)
Определения Utils.php:99
validateTemplateText(string $text)
Определения Utils.php:493
checkApprovedStatus(array $template)
Определения Utils.php:298
getMessageTemplates(string $subject='')
Определения Utils.php:30
excludeOutdatedTemplates(array $templates=[])
Определения Utils.php:412
sendTemplate(string $name, string $text, array $examples=[], ?string $langCode=null)
Определения Utils.php:431
replaceNameToTitle(array $templates=[])
Определения Utils.php:392
extractPlaceholders(string $text)
Определения Utils.php:342
removeUnsupportedTemplates(array $templates)
Определения Utils.php:371
validateExamples(string $text, array $examples)
Определения Utils.php:510
$template
Определения file_edit.php:49
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$requestParams
Определения urlrewrite.php:46
$name
Определения menu_edit.php:35
$message
Определения payment.php:8
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$text
Определения template_pdf.php:79
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$matches
Определения index.php:22