1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
Operator.php
См. документацию.
1<?php
2declare(strict_types=1);
3
4namespace Bitrix\Landing\Copilot\Data\Block;
5
6use Bitrix\Landing\Block;
7use Bitrix\Landing\Copilot\Data;
8use Bitrix\Landing;
9
16{
17 private const ZONES_WHERE_NEED_CHECK_RESPONSE = ['ru'];
18 private const DEFAULT_ASPECT_RATIO = '3by2';
19 private const DEFAULT_WIDTH = 720;
20
21 public static function getTitleStyleClass(): string
22 {
23 $titleStyleClasses = [
24 'u-heading-v2-0',
25 'u-heading-v2-3--bottom',
26 'u-heading-v2-8--bottom',
27 'u-heading-v2-3--top',
28 'u-heading-v2-8--top',
29 'u-heading-v2-13-2--left',
30 'u-heading-v2-13-2--right',
31 ];
32
33 return $titleStyleClasses[array_rand($titleStyleClasses)];
34 }
35
44 public static function checkBlocksAmount(Data\Site $siteData, array $json): bool
45 {
46 if (
47 !isset($json['blocks'])
48 || !is_array($json['blocks'])
49 )
50 {
51 return false;
52 }
53
54 $blocksData = $siteData->getBlocks();
55
56 $countBlocksFromResponse = count($json['blocks']);
57 $countBlocksForRequest = 0;
58 foreach ($blocksData as $blockData)
59 {
60 if (!$blockData->isSeparator() && !$blockData->isMenu())
61 {
62 $countBlocksForRequest++;
63 }
64 }
65
66 return $countBlocksFromResponse === $countBlocksForRequest;
67 }
68
74 public static function isNeedCheckDataFromResponse(): bool
75 {
77
78 return in_array($zone, self::ZONES_WHERE_NEED_CHECK_RESPONSE, true);
79 }
80
88 public static function prepareDataFromResponse(array $nodeDataFromResponse): array
89 {
90 $preparedData = [];
91 foreach ($nodeDataFromResponse as $dataItem)
92 {
93 if (is_string($dataItem))
94 {
95 $preparedData[] = self::replaceWordsForZone($dataItem);
96 }
97 if (is_array($dataItem))
98 {
99 $preparedData[] = $dataItem;
100 }
101 }
102
103 return $preparedData;
104 }
105
106
115 public static function getSizeDataImagesBySelector(string $selector, string $blockContent): array
116 {
117 $tagsWithClass = self::findTagsWithClass(substr($selector, 1), $blockContent);
118 $defaultImageLinks = self::findImageLinks($tagsWithClass);
119
120 return self::getSizeDataImages($defaultImageLinks);
121 }
122
130 public static function getDefaultSrc(array $dataImages): array
131 {
132 $defaultSrc = [
133 'src' => [],
134 'src2x' => [],
135 ];
136
137 $baseUrl = 'https://cdn.bitrix24.site/bitrix/images/landing/default/';
138
139 foreach ($dataImages as $dataImage)
140 {
141 if (!isset($dataImage['aspectRatio'], $dataImage['width']))
142 {
143 continue;
144 }
145
146 $aspectRatio = $dataImage['aspectRatio'];
147 $width = (int)$dataImage['width'];
148
149 $defaultSrc['src'][] = "{$baseUrl}{$aspectRatio}/{$width}.png";
150 $defaultSrc['src2x'][] = "{$baseUrl}{$aspectRatio}/" . ($width * 2) . '.png';
151 }
152
153 return $defaultSrc;
154 }
155
164 public static function extractNodeClasses(string $nodeCode, string $blockContent): string
165 {
166 if (str_starts_with($nodeCode, '.'))
167 {
168 $nodeCode = substr($nodeCode, 1);
169 }
170 $pattern = '/class="([^"]*' . $nodeCode . '(\s|")(?:|")[^"]*)"/';
171 if (preg_match($pattern, $blockContent, $matches))
172 {
173 return $matches[1];
174 }
175
176 return '';
177 }
178
186 public static function extractWrapperClasses(string $blockContent): string
187 {
188 if (preg_match('/class="([^"]*landing-block[^"]*)"/', $blockContent, $matches))
189 {
190 return $matches[1];
191 }
192
193 return '';
194 }
195
201 public static function getAllowedAspectRatios(): array
202 {
203 return [
204 '9by16' => 0.56,
205 '2by3' => 0.67,
206 '1by1' => 1,
207 '3by2' => 1.5,
208 '16by9' => 1.78,
209 ];
210 }
211
212 public static function isBlockAvailableForScenarioChangeBlock(int $blockId): bool
213 {
214 $blockInstance = new Block($blockId);
215 if ($blockInstance->getId() <= 0)
216 {
217 return false;
218 }
219
220 $blockManifest = $blockInstance->getManifest();
221 $blockContent = $blockInstance->getContent();
222
223 $notAllowedSections = [
224 'countdowns',
225 'separator',
226 'menu',
227 'sidebar',
228 'store',
229 'other',
230 'video',
231 ];
232 $blockSection = (array)($blockManifest['block']['section'] ?? null);
233 $sectionIntersect = array_intersect($notAllowedSections, $blockSection);
234 if (!empty($sectionIntersect))
235 {
236 return false;
237 }
238
239 $notAllowedNodeTypes = ['embed'];
240 $imageElements = 0;
241 foreach ($blockManifest['nodes'] as $node)
242 {
243 if (isset($node['type']) && in_array($node['type'], $notAllowedNodeTypes, true))
244 {
245 return false;
246 }
247
248 if (isset($node['type']) && $node['type'] === 'img')
249 {
250 $nodeCode = ltrim($node['code'], '.');
251 $imageElements += substr_count($blockContent, $nodeCode . ' ');
252 $imageElements += substr_count($blockContent, $nodeCode . '"');
253 }
254 }
255
256 if ($imageElements > 4)
257 {
258 return false;
259 }
260
261 if (self::hasNotAllowedTagInBlockContent($blockContent))
262 {
263 return false;
264 }
265
266 if ($blockInstance->getRepoId())
267 {
268 return false;
269 }
270
271 return true;
272 }
273
274 private static function hasNotAllowedTagInBlockContent(string $blockContent): bool
275 {
276 $notAllowedTags = ['table'];
277
278 foreach ($notAllowedTags as $tag)
279 {
280 if (preg_match('/<\s*' . preg_quote($tag, '/') . '\b/i', $blockContent))
281 {
282 return true;
283 }
284 }
285
286 return false;
287 }
288
296 private static function replaceWordsForZone(string $dataItem): string
297 {
298 $zone = Landing\Manager::getZone();
299
300 $replacementMap = [
301 'ru' => [
302 'fa-square-instagram' => 'fa-pinterest',
303 'fa-instagram' => 'fa-pinterest',
304 'fa-meta' => 'fa-vk',
305 'fa-square-facebook' => 'fa-vk',
306 'fa-facebook-messenger' => 'fa-vk',
307 'fa-facebook-f' => 'fa-vk',
308 'fa-facebook' => 'fa-vk',
309 'Instagram' => 'Pinterest',
310 'Facebook' => 'VK',
311 ],
312 ];
313
314 if (isset($replacementMap[$zone]))
315 {
316 foreach ($replacementMap[$zone] as $search => $replace)
317 {
318 $dataItem = preg_replace_callback(
319 '/' . preg_quote($search, '/') . '/i',
320 static function() use ($replace) {
321 return $replace;
322 },
323 $dataItem
324 );
325 }
326 }
327
328 return $dataItem;
329 }
330
339 private static function findTagsWithClass(string $class, string $contentBlock): array
340 {
341 $patternPart1 = '/<([a-z]+)\b[^>]*class=["][^"]*\b';
342 $patternPart2 = '\b(?:["\s][^"]*)?["][^>]*>/i';
343 $pattern = $patternPart1 . $class . $patternPart2;
344
345 preg_match_all($pattern, $contentBlock, $matches, PREG_SET_ORDER);
346
347 $tags = [];
348 foreach ($matches as $match)
349 {
350 $tags[] = $match[0];
351 }
352
353 return $tags;
354 }
355
363 private static function findImageLinks(array $tags): array
364 {
365 $links = [];
366
367 foreach ($tags as $tag)
368 {
369 $pattern = '/\b(?:https?:\/\/|www\.)\S+\.(?:jpg|jpeg|png)(?=\b|[^a-z0-9])/i';
370 if (preg_match($pattern, $tag, $match))
371 {
372 $links[] = $match[0];
373 }
374 else
375 {
376 $links[] = '';
377 }
378 }
379
380 return $links;
381 }
382
390 private static function getSizeDataImages(array $defaultImageLinks): array
391 {
392 $imagesData = [];
393
394 foreach ($defaultImageLinks as $defaultImageLink)
395 {
396 [$width, $height, $aspectRatio] = Images::getImageData($defaultImageLink);
397
398 $closestAspectRatioKey = self::getClosestAspectRatioKey($aspectRatio);
399
400 $closestWidth = self::getClosestWidth((int)$width, $closestAspectRatioKey);
401
402 $imagesData[] = [
403 'width' => $closestWidth, // value from default copilot image
404 'height' => $height, // todo: value from default url in block
405 'aspectRatio' => $closestAspectRatioKey, // value from default copilot image
406 ];
407 }
408
409 return $imagesData;
410 }
411
417 private static function getAllowedWidths(): array
418 {
419 return [
420 '9by16' => ['180', '270', '360', '450', '540', '720'],
421 '2by3' => ['240', '320', '360', '480', '600', '720', '880'],
422 '1by1' => ['180', '256', '512', '720', '1024', '1280', '1440', '1920'],
423 '3by2' => ['360', '480', '540', '720', '900', '1080', '1320', '1620', '1920'],
424 '16by9' => ['320', '450', '480', '640', '800', '960', '1280', '1440', '1600', '1920'],
425 ];
426 }
427
435 public static function getClosestAspectRatioKey(float $aspectRatio): ?string
436 {
437 $allowedAspectRatios = self::getAllowedAspectRatios();
438 $closestAspectRatioKey = null;
439 $closestAspectRatioDiff = PHP_FLOAT_MAX;
440
441 foreach ($allowedAspectRatios as $key => $value)
442 {
443 $diff = abs($aspectRatio - $value);
444 if ($diff < $closestAspectRatioDiff)
445 {
446 $closestAspectRatioDiff = $diff;
447 $closestAspectRatioKey = $key;
448 }
449 }
450
451 return $closestAspectRatioKey;
452 }
453
461 public static function getAvatarLinks(array $gendersData): array
462 {
463 $genderMaxValues = [
464 'male' => 50,
465 'female' => 52,
466 'unisex' => 18,
467 ];
468
469 $links = [];
470
471 foreach ($gendersData as $gender)
472 {
473 $gender = in_array($gender, ['male', 'female']) ? $gender : 'unisex';
474
475 if (!isset($usedRandInt[$gender]))
476 {
477 $usedRandInt[$gender] = [];
478 }
479
480 do
481 {
482 $randInt = rand(1, $genderMaxValues[$gender]);
483 }
484 while (in_array($randInt, $usedRandInt[$gender], true));
485
486 $usedRandInt[$gender][] = $randInt;
487
488 $links[] = 'https://cdn.bitrix24.site/bitrix/images/landing/default/' . $gender . '/' . $randInt . '.png';
489 }
490
491 return $links;
492 }
493
494 public static function getDefaultAspectRatio(): string
495 {
496 return self::DEFAULT_ASPECT_RATIO;
497 }
498
499 public static function getDefaultWidth(string $aspectRatio): int
500 {
501 $allowedWidths = self::getAllowedWidths();
502
503 if (!isset($allowedWidths[$aspectRatio]))
504 {
505 return self::DEFAULT_WIDTH;
506 }
507
508 $widths = $allowedWidths[$aspectRatio];
509 $middleIndex = (int)(count($widths) / 2);
510
511 return (int)$widths[$middleIndex];
512 }
513
514 public static function getDefaultAvatarLinks(array $gendersData): array
515 {
516 $defaultAvatarLink = 'https://cdn.bitrix24.site/bitrix/images/landing/default/1by1/512.png';
517 $defaultAvatarLink2x = 'https://cdn.bitrix24.site/bitrix/images/landing/default/1by1/1024.png';
518 $links = [];
519 $countLinks = count($gendersData);
520 for ($i = 0; $i < $countLinks; $i++)
521 {
522 $links[] = [
523 'src' => $defaultAvatarLink,
524 'src2x' => $defaultAvatarLink2x,
525 ];
526 }
527
528 return $links;
529 }
530
539 public static function getClosestWidth(int $width, ?string $closestAspectRatioKey): ?int
540 {
541 $allowedWidths = self::getAllowedWidths();
542
543 if ($closestAspectRatioKey === null)
544 {
545 return null;
546 }
547
548 $closest = $allowedWidths[$closestAspectRatioKey][0] ?? null;
549 $smallestDifference = abs($width - $closest);
550
551 foreach ($allowedWidths[$closestAspectRatioKey] as $allowedWidth)
552 {
553 $difference = abs($width - $allowedWidth);
554 if ($difference < $smallestDifference)
555 {
556 $smallestDifference = $difference;
557 $closest = $allowedWidth;
558 }
559 }
560
561 return (int)$closest;
562 }
563}
static isBlockAvailableForScenarioChangeBlock(int $blockId)
Определения Operator.php:212
static getClosestAspectRatioKey(float $aspectRatio)
Определения Operator.php:435
static getAllowedAspectRatios()
Определения Operator.php:201
static getClosestWidth(int $width, ?string $closestAspectRatioKey)
Определения Operator.php:539
static getDefaultAvatarLinks(array $gendersData)
Определения Operator.php:514
static getDefaultSrc(array $dataImages)
Определения Operator.php:130
static checkBlocksAmount(Data\Site $siteData, array $json)
Определения Operator.php:44
static getAvatarLinks(array $gendersData)
Определения Operator.php:461
static extractWrapperClasses(string $blockContent)
Определения Operator.php:186
static extractNodeClasses(string $nodeCode, string $blockContent)
Определения Operator.php:164
static isNeedCheckDataFromResponse()
Определения Operator.php:74
static getDefaultWidth(string $aspectRatio)
Определения Operator.php:499
static prepareDataFromResponse(array $nodeDataFromResponse)
Определения Operator.php:88
static getSizeDataImagesBySelector(string $selector, string $blockContent)
Определения Operator.php:115
static getZone()
Определения manager.php:930
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
Определения cookies.php:2
Определения aliases.php:105
if(empty($signedUserToken)) $key
Определения quickway.php:257
$i
Определения factura.php:643
</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
$width
Определения html.php:68
if(!Loader::includeModule('sale')) $pattern
Определения index.php:20
$matches
Определения index.php:22