Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
numerator.php
1<?
2
4
5use Bitrix\Main\Entity\ExpressionField;
6use Bitrix\Main\Entity\Query;
17
18Loc::loadMessages(__FILE__);
19
26{
27 private $template;
28 private $type;
29 private $name;
31 private $generators = [];
32 private $code;
33 private $id;
34
35 const NUMERATOR_DEFAULT_TYPE = 'DEFAULT';
38 static protected $numberGeneratorFactory;
39
43 public static function create()
44 {
45 return new static();
46 }
47
48 private function __construct()
49 {
50 }
51
55 protected static function getNumberGeneratorFactory()
56 {
57 if (static::$numberGeneratorFactory === null)
58 {
59 static::$numberGeneratorFactory = new NumberGeneratorFactory();
60 }
61 return static::$numberGeneratorFactory;
62 }
63
72 public static function getSettingsFields($numeratorType)
73 {
74 $numeratorsAmount = static::getNextNumeratorNumber($numeratorType);
75 $settings = ['settingsFields' => [], 'settingsWords' => [],];
76 $settings['settingsFields'][static::getType()] = [
77 [
78 'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_NUMERATOR_NAME_TITLE'),
79 'settingName' => 'name',
80 'type' => 'string',
81 'default' => Loc::getMessage('NUMERATOR_DEFAULT_NUMERATOR_NAME', ['#NUMBER#' => $numeratorsAmount]),
82 ],
83 [
84 'settingName' => 'template',
85 'type' => 'string',
86 'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_NUMERATOR_TEMPLATE_TITLE'),
87 ],
88 ];
89 $allGeneratorsClasses = static::getNumberGeneratorFactory()->getClasses();
90 foreach ($allGeneratorsClasses as $class)
91 {
93 $isAvailableForAll = $class::getAvailableForType() == static::NUMERATOR_DEFAULT_TYPE;
94 if ($isAvailableForAll || $class::getAvailableForType() == $numeratorType)
95 {
96 if (in_array(UserConfigurable::class, class_implements($class)))
97 {
98 $settings['settingsFields'][$class::getType()] = $class::getSettingsFields();
99 }
100 $settings['settingsWords'][$class::getType()] = $class::getTemplateWordsSettings();
101 }
102 }
103 $settings['settingsWords'] = array_merge_recursive($settings['settingsWords'], static::getUserDefinedTemplateWords($numeratorType));
104
105 return $settings;
106 }
107
112 protected static function getUserDefinedTemplateWords($numeratorType)
113 {
114 $settingsWords = [];
115 $event = new Event('main', 'onBuildNumeratorTemplateWordsList', ['numeratorType' => $numeratorType]);
116 $event->send();
117
118 if ($event->getResults())
119 {
120 $count = 0;
121 foreach ($event->getResults() as $eventResult)
122 {
123 $eventParameters = $eventResult->getParameters();
124 if (isset($eventParameters['CODE']) && isset($eventParameters['NAME']))
125 {
126 $settingsWords["UserDefinedVirtualGenerator" . $count++] = [
128 => $eventParameters['NAME'],
129 ];
130 }
131 else
132 {
133 foreach ($eventParameters as $parameters)
134 {
135 if (isset($parameters['CODE']) && isset($parameters['NAME']))
136 {
137 $settingsWords["UserDefinedVirtualGenerator" . $count++] = [
139 => $parameters['NAME'],
140 ];
141 }
142 }
143 }
144 }
145 }
146 return $settingsWords;
147 }
148
157 public static function getListByType($type = null, $sort = null)
158 {
159 if (is_null($type))
160 {
161 $type = static::NUMERATOR_DEFAULT_TYPE;
162 }
163 return NumeratorTable::getNumeratorList($type, $sort);
164 }
165
174 public static function getOneByType($type = null)
175 {
176 if (is_null($type))
177 {
178 $type = static::NUMERATOR_DEFAULT_TYPE;
179 }
180 $numeratorSettings = static::getListByType($type);
181 if ($numeratorSettings && isset($numeratorSettings[0]))
182 {
183 return $numeratorSettings[0];
184 }
185 return null;
186 }
187
193 public static function getTemplateWordsForType($isAvailableByType = null)
194 {
195 if (is_null($isAvailableByType))
196 {
197 $isAvailableByType = static::NUMERATOR_DEFAULT_TYPE;
198 }
199 $settings = [];
200 $allGeneratorsClasses = static::getNumberGeneratorFactory()->getClasses();
201 foreach ($allGeneratorsClasses as $class)
202 {
204 $isAllTypesNeeded = $isAvailableByType === static::NUMERATOR_ALL_GENERATORS_TYPE;
205 $isAvailableByDefault = $class::getAvailableForType() == static::NUMERATOR_DEFAULT_TYPE;
206 if ($isAllTypesNeeded || $isAvailableByDefault || $class::getAvailableForType() == $isAvailableByType)
207 {
208 $settings = array_merge($settings, [$class::getType() => $class::getTemplateWordsForParse()]);
209 }
210 }
211 return $settings;
212 }
213
217 private function setNumberHashForGenerators($hash)
218 {
219 foreach ($this->generators as $index => $generator)
220 {
221 if ($generator instanceof Sequenceable)
222 {
223 $generator->setNumberHash($hash);
224 }
225 }
226 }
227
238 public function getNext($hash = null)
239 {
240 $this->setNumberHashForGenerators($hash);
241 $nextNumber = $this->template;
242 foreach ($this->generators as $index => $generator)
243 {
245 $nextNumber = $generator->parseTemplate($nextNumber);
246 }
247
248 return $nextNumber;
249 }
250
254 private function setDynamicConfigForGenerators($dynamicConfig)
255 {
256 if ($dynamicConfig !== null)
257 {
258 foreach ($this->generators as $generator)
259 {
260 if ($generator instanceof DynamicConfigurable)
261 {
262 $generator->setDynamicConfig($dynamicConfig);
263 }
264 }
265 }
266 }
267
278 public static function update($numId, $config)
279 {
280 $numerator = static::create();
281 $config[static::getType()]['idFromDb'] = $numId;
282 $result = $numerator->setNumeratorConfig($config);
283 if ($result->isSuccess())
284 {
285 $result = $numerator->setGeneratorsConfig($config);
286 if ($result->isSuccess())
287 {
288 return $numerator->save();
289 }
290 }
291 return $result;
292 }
293
300 public function setHash($hashable)
301 {
302 if ($hashable instanceof Hashable)
303 {
304 $this->setNumberHashForGenerators($hashable->getHash());
305 }
306 }
307
312 public function setDynamicConfig($dynamicConfig)
313 {
314 $this->setDynamicConfigForGenerators($dynamicConfig);
315 }
316
324 public function save()
325 {
326 $settingsToStore = $this->getSettings();
327 $result = NumeratorTable::saveNumerator($this->id, [
328 'CODE' => $this->code,
329 'NAME' => $this->name,
330 'TEMPLATE' => $this->template,
331 'TYPE' => $this->type ? $this->type : static::NUMERATOR_DEFAULT_TYPE,
332 'SETTINGS' => $settingsToStore,
333 ]);
334 if ($result->isSuccess())
335 {
336 $this->id = $result->getId();
337 }
338
339 return $result;
340 }
341
345 private function getSettings()
346 {
347 $settingsToStore = [];
348 foreach ($this->generators as $numberGenerator)
349 {
350 if ($numberGenerator instanceof UserConfigurable)
351 {
353 $settingsToStore = array_merge($settingsToStore, [$this->getTypeOfGenerator($numberGenerator) => $numberGenerator->getConfig(),]);
354 }
355 }
356 return $settingsToStore;
357 }
358
369 public static function load($numeratorId, $source = null)
370 {
371 if ($config = NumeratorTable::loadSettings($numeratorId))
372 {
373 $numerator = new static();
374 $result = $numerator->setConfig($config);
375 if (($result->isSuccess()))
376 {
377 $numerator->setDynamicConfig($source);
378 $numerator->setHash($source);
379 return $numerator;
380 }
381 }
382 return null;
383 }
384
390 public static function loadByCode($code, $source = null)
391 {
392 $id = NumeratorTable::getIdByCode($code);
393 if ($id === null)
394 {
395 return null;
396 }
397
398 return self::load($id, $source);
399 }
400
406 public static function delete($id)
407 {
408 if (!$id)
409 {
410 return (new Result())->addError(new Error('Numerator id is required'));
411 }
412 $result = NumeratorTable::delete((int)$id);
413 if ($result->isSuccess())
414 {
415 NumeratorSequenceTable::deleteByNumeratorId($id);
416 }
417 return $result;
418 }
419
424 public function previewNextNumber($hash = null)
425 {
426 $this->setNumberHashForGenerators($hash);
427 $nextNumber = $this->template;
428 foreach ($this->generators as $index => $generator)
429 {
431 $nextNumber = $generator->parseTemplateForPreview($nextNumber);
432 }
433
434 return $nextNumber;
435 }
436
444 public function previewNextSequentialNumber($hash = null)
445 {
446 $this->setNumberHashForGenerators($hash);
447 foreach ($this->generators as $generator)
448 {
449 if ($generator instanceof Sequenceable)
450 {
451 return $generator->getNextNumber($this->id);
452 }
453 }
454 return null;
455 }
456
460 public function hasSequentialNumber()
461 {
462 foreach ($this->generators as $generator)
463 {
464 if ($generator instanceof Sequenceable)
465 {
466 return true;
467 }
468 }
469 return false;
470 }
471
480 public function setNextSequentialNumber($nextNumber, $whereNumber = null, $hash = null)
481 {
482 $this->setNumberHashForGenerators($hash);
483 foreach ($this->generators as $generator)
484 {
485 if ($generator instanceof Sequenceable)
486 {
487 return $generator->setNextNumber($this->id, $nextNumber, $whereNumber);
488 }
489 }
490 return (new Result())->addError(new Error(Loc::getMessage('NUMERATOR_SET_SEQUENTIAL_IS_IMPOSSIBLE')));
491 }
492
496 public function getConfig()
497 {
498 $selfConfig = [
499 static::getType() => [
500 'name' => $this->name,
501 'template' => $this->template,
502 'id' => $this->id,
503 'code' => $this->code,
504 'type' => $this->type,
505 ],
506 ];
507 $generatorConfigs = [];
508 foreach ($this->generators as $generator)
509 {
510 if ($generator instanceof UserConfigurable)
511 {
512 $generatorConfigs[$this->getTypeOfGenerator($generator)] = $generator->getConfig();
513 }
514 }
515 return $selfConfig + $generatorConfigs;
516 }
517
523 public function setConfig($config)
524 {
525 $result = $this->setNumeratorConfig($config);
526 if (!$result->isSuccess())
527 {
528 return $result;
529 };
530
531 return $this->setGeneratorsConfig($config);
532 }
533
538 private function setNumeratorConfig($config)
539 {
540 $result = $this->validate($config);
541 if (!$result->isSuccess())
542 {
543 return $result;
544 };
545 $this->type = trim($config[static::getType()]['type']);
546 $this->setTemplate($config[static::getType()]['template']);
547 $this->name = trim($config[static::getType()]['name']);
548 if (isset($config[static::getType()]['idFromDb']))
549 {
550 $this->id = $config[static::getType()]['idFromDb'];
551 }
552 if (array_key_exists('code', $config[static::getType()]))
553 {
554 $code = $config[static::getType()]['code'];
555 if (is_string($code))
556 {
557 $code = trim($code);
558 }
559
560 $this->code = (is_string($code) && !empty($code)) ? $code : null;
561 }
562 return $result;
563 }
564
565 private function createGenerators()
566 {
567 $generatorTypesToCreate = $this->getGeneratorTypesByTemplate();
568 if ($this->type === static::NUMERATOR_ALL_GENERATORS_TYPE)
569 {
570 return $this->createGeneratorsOfTypes($generatorTypesToCreate);
571 }
572
573 $factory = static::getNumberGeneratorFactory();
574 $typesForCurrentNumerator = [];
575 foreach ($generatorTypesToCreate as $index => $generatorType)
576 {
577 $generatorClass = $factory->getClassByType($generatorType);
578 if ($generatorClass::getAvailableForType() === $this->type
579 || $generatorClass::getAvailableForType() === static::NUMERATOR_DEFAULT_TYPE
580 )
581 {
582 $typesForCurrentNumerator[] = $generatorType;
583 }
584 }
585
586 return $this->createGeneratorsOfTypes($typesForCurrentNumerator);
587 }
588
594 private function setGeneratorsConfig($config)
595 {
596 $generators = $this->createGenerators();
597 foreach ($generators as $index => $generator)
598 {
599 $this->addGenerator($generator);
600 }
601 $result = $this->validateGeneratorsConfig($config);
602
603 if ($result->isSuccess())
604 {
605 foreach ($this->generators as $generator)
606 {
607 if ($generator instanceof UserConfigurable)
608 {
610 $generator->setConfig($config[$this->getTypeOfGenerator($generator)] ?? null);
611 }
612 }
613 };
614
615 return $result;
616 }
617
621 public static function getType()
622 {
623 return str_replace('\\', '_', static::class);
624 }
625
629 protected function setTemplate($template)
630 {
631 $this->template = str_replace(["\r\n", "\n"], '', trim($template));
632 }
633
638 private function getTypeToTemplateWords()
639 {
640 $result = [];
641 $typesToClasses = static::getNumberGeneratorFactory()->getTypeToClassMap();
642 foreach ($typesToClasses as $type => $class)
643 {
645 $result[$type] = $class::getTemplateWordsForParse();
646 }
647 return $result;
648 }
649
654 private function getGeneratorTypesByTemplate()
655 {
656 $generatorTypes = [];
657 foreach ($this->getTypeToTemplateWords() as $type => $words)
658 {
659 foreach ($words as $word)
660 {
661 if (mb_stripos($this->template, $word) !== false)
662 {
663 $generatorTypes[$type] = 1;
664 }
665 }
666 }
667
668 return array_keys($generatorTypes);
669 }
670
675 private function createGeneratorsOfTypes($generatorTypesToCreate)
676 {
677 $generators = [];
678 foreach ($generatorTypesToCreate as $key => $type)
679 {
680 if ($generator = static::getNumberGeneratorFactory()->createGeneratorByType($type))
681 {
682 $generators[] = $generator;
683 }
684 }
685
686 return $generators;
687 }
688
693 private function validate($numeratorConfig)
694 {
695 $result = new Result();
696 if (!isset($numeratorConfig[static::getType()]))
697 {
698 $result->addError(new Error('Numerator config is required'));
699 }
700 $numeratorBaseConfig = $numeratorConfig[static::getType()];
701
702 if (isset($numeratorBaseConfig['code']))
703 {
704 if (is_string($numeratorBaseConfig['code']) && !empty($numeratorBaseConfig['code']))
705 {
706 $idWithSameCode = NumeratorTable::getIdByCode($numeratorBaseConfig['code']);
707 if ($idWithSameCode !== null)
708 {
709 $id = (int)($numeratorBaseConfig['idFromDb'] ?? null);
710 if ($id <= 0 || $idWithSameCode !== $id)
711 {
712 $result->addError(new Error('Another numerator with same code already exists'));
713 }
714 }
715 }
716 elseif (is_string($numeratorBaseConfig['code']))
717 {
718 $result->addError(new Error('Numerator code should be a non-empty string, if it is provided'));
719 }
720 else
721 {
722 $result->addError(new Error('Numerator code should be a string'));
723 }
724 }
725 if (!(isset($numeratorBaseConfig['name']) && $numeratorBaseConfig['name']))
726 {
727 $result->addError(new Error(Loc::getMessage('NUMERATOR_VALIDATE_NAME_IS_REQUIRED')));
728 }
729 $resultTemplate = $this->validateTemplate($numeratorBaseConfig['template']);
730 if ($resultTemplate->getErrors())
731 {
732 $result->addErrors($resultTemplate->getErrors());
733 }
734
735 return $result;
736 }
737
742 private function validateTemplate($template)
743 {
744 if (!($template && $template != ''))
745 {
746 return (new Result())->addError(new Error(Loc::getMessage('NUMERATOR_VALIDATE_TEMPLATE_IS_REQUIRED')));
747 }
748 return new Result();
749 }
750
758 private static function getNextNumeratorNumber($isAvailableForType)
759 {
760 $query = new Query(NumeratorTable::getEntity());
761 $query->addSelect(new ExpressionField('COUNT', 'COUNT(*)'));
762 $query->where('TYPE', $isAvailableForType);
763 $result = $query->exec()->fetch();
764 return $result ? $result['COUNT'] + 1 : 1;
765 }
766
771 private function validateGeneratorsConfig($config)
772 {
773 $result = new Result();
774 foreach ($this->generators as $generator)
775 {
776 if ($generator instanceof UserConfigurable)
777 {
778 $generatorResult = ($generator->validateConfig($config));
779 if ($generatorResult->getErrors())
780 {
781 $result->addErrors($generatorResult->getErrors());
782 }
783 }
784 }
785
786 return $result;
787 }
788
792 private function addGenerator($generator)
793 {
794 $this->generators[] = $generator;
795 }
796
801 private function getTypeOfGenerator($generator)
802 {
804 $generatorClass = get_class($generator);
805 return $generatorClass::getType();
806 }
807
808 public function getId()
809 {
810 return $this->id;
811 }
812}
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static saveNumerator($numeratorId, $numeratorFields)
setNextSequentialNumber($nextNumber, $whereNumber=null, $hash=null)
static getOneByType($type=null)
static getUserDefinedTemplateWords($numeratorType)
static update($numId, $config)
static getListByType($type=null, $sort=null)
static loadByCode($code, $source=null)
static load($numeratorId, $source=null)