10 private $arErrorsList = [];
12 private static $weekHolidays;
13 private static $yearHolidays;
14 private static $startWorkDay;
15 private static $endWorkDay;
16 private static $yearWorkdays;
19 private $arPriority = [
20 '(' => 0,
')' => 1,
';' => 2,
'=' => 3,
'<' => 3,
'>' => 3,
21 '<=' => 3,
'>=' => 3,
'<>' => 3,
'&' => 4,
'+' => 5,
'-' => 5,
22 '*' => 6,
'/' => 6,
'^' => 7,
'%' => 8,
'-m' => 9,
'+m' => 9,
23 ' ' => 10,
':' => 11,
'f' => 12,
27 private $arAvailableFunctions = [
28 'abs' => [
'args' =>
true,
'func' =>
'FunctionAbs'],
29 'and' => [
'args' =>
true,
'func' =>
'FunctionAnd'],
30 'date' => [
'args' =>
true,
'func' =>
'FunctionDate'],
31 'dateadd' => [
'args' =>
true,
'func' =>
'FunctionDateAdd'],
32 'datediff' => [
'args' =>
true,
'func' =>
'FunctionDateDiff'],
33 'false' => [
'args' =>
false,
'func' =>
'FunctionFalse'],
34 'if' => [
'args' =>
true,
'func' =>
'FunctionIf'],
35 'intval' => [
'args' =>
true,
'func' =>
'FunctionIntval'],
36 'floatval' => [
'args' =>
true,
'func' =>
'FunctionFloatval'],
37 'numberformat' => [
'args' =>
true,
'func' =>
'FunctionNumberFormat'],
38 'min' => [
'args' =>
true,
'func' =>
'FunctionMin'],
39 'max' => [
'args' =>
true,
'func' =>
'FunctionMax'],
40 'rand' => [
'args' =>
true,
'func' =>
'FunctionRand'],
41 'round' => [
'args' =>
true,
'func' =>
'FunctionRound'],
42 'ceil' => [
'args' =>
true,
'func' =>
'FunctionCeil'],
43 'floor' => [
'args' =>
true,
'func' =>
'FunctionFloor'],
44 'not' => [
'args' =>
true,
'func' =>
'FunctionNot'],
45 'or' => [
'args' =>
true,
'func' =>
'FunctionOr'],
46 'substr' => [
'args' =>
true,
'func' =>
'FunctionSubstr'],
47 'strpos' => [
'args' =>
true,
'func' =>
'FunctionStrpos'],
48 'strlen' => [
'args' =>
true,
'func' =>
'FunctionStrlen'],
49 'implode' => [
'args' =>
true,
'func' =>
'FunctionImplode'],
50 'explode' => [
'args' =>
true,
'func' =>
'FunctionExplode'],
51 'randstring' => [
'args' =>
true,
'func' =>
'FunctionRandString'],
52 'true' => [
'args' =>
false,
'func' =>
'FunctionTrue'],
53 'convert' => [
'args' =>
true,
'func' =>
'FunctionConvert'],
54 'merge' => [
'args' =>
true,
'func' =>
'FunctionMerge'],
55 'addworkdays' => [
'args' =>
true,
'func' =>
'FunctionAddWorkDays'],
56 'workdateadd' => [
'args' =>
true,
'func' =>
'FunctionWorkDateAdd'],
57 'isworkday' => [
'args' =>
true,
'func' =>
'FunctionIsWorkDay'],
58 'isworktime' => [
'args' =>
true,
'func' =>
'FunctionIsWorkTime'],
59 'urlencode' => [
'args' =>
true,
'func' =>
'FunctionUrlencode'],
60 'touserdate' => [
'args' =>
true,
'func' =>
'FunctionToUserDate'],
61 'getuserdateoffset' => [
'args' =>
true,
'func' =>
'FunctionGetUserDateOffset'],
62 'strtolower' => [
'args' =>
true,
'func' =>
'FunctionStrtolower'],
63 'strtoupper' => [
'args' =>
true,
'func' =>
'FunctionStrtoupper'],
64 'ucwords' => [
'args' =>
true,
'func' =>
'FunctionUcwords'],
65 'ucfirst' => [
'args' =>
true,
'func' =>
'FunctionUcfirst'],
66 'strtotime' => [
'args' =>
true,
'func' =>
'FunctionStrtotime'],
67 'locdate' => [
'args' =>
true,
'func' =>
'FunctionLocDate'],
68 'shuffle' => [
'args' =>
true,
'func' =>
'FunctionShuffle'],
69 'firstvalue'=> [
'args' =>
true,
'func' =>
'FunctionFirstValue'],
70 'swirl' => [
'args' =>
true,
'func' =>
'FunctionSwirl'],
71 'getdocumenturl' => [
'args' =>
true,
'func' =>
'FunctionGetDocumentUrl'],
72 'trim' => [
'args' =>
true,
'func' =>
'functionTrim'],
76 private $arAvailableErrors = [
77 0 =>
'Incorrect variable name - "#STR#"',
79 2 =>
'Syntax error "#STR#"',
80 3 =>
'Unknown function "#STR#"',
81 4 =>
'Unmatched closing bracket ")"',
82 5 =>
'Unmatched opening bracket "("',
83 6 =>
'Division by zero',
84 7 =>
'Incorrect order of operands',
85 8 =>
'Incorrect arguments of function "#STR#"',
94 $this->activity = $activity;
97 private function getVariableValue($variable)
99 $variable = trim($variable);
103 return $this->activity->ParseValue($variable);
106 private function setError($errnum, $errstr =
'')
108 $this->arErrorsList[] = [$errnum, str_replace(
'#STR#', $errstr, $this->arAvailableErrors[$errnum])];
113 return $this->arErrorsList;
122 private function getPolishNotation(
$text)
125 if (mb_substr(
$text, 0, 1) ===
'=')
127 if (mb_strpos(
$text,
'{{=') === 0 && mb_substr(
$text, -2) ==
'}}')
139 $arPolishNotation = $arStack = [];
144 \s*,\s* | # Combine ranges of variables
145 \s*;\s* | # Combine ranges of variables
152 \s*&\s* | # String concatenation
153 \s*\+\s* | # Addition or unary plus
157 \s*\^\s* | # Exponentiation
159 \s*[\d\.]+\s* | # Numbers
160 \s*\'[^\']*\'\s* | # String constants in apostrophes
161 \s*"[^"]*"\s* | # String constants in quotes
162 (\s*\w+\s*\(\s*) | # Function names
163 \s*'.CBPActivity::ValueInternalPattern.
'\s* | # Variables
164 (?<error>.+) # Any erroneous substring
166 while (preg_match($preg,
$text, $match))
168 if (isset($match[
'error']))
170 $this->SetError(2, $match[
'error']);
174 $str = trim($match[0]);
178 if (isset($match[1]) && $match[1])
183 if (isset($this->arAvailableFunctions[
$name]))
187 array_unshift($arStack, [
$name, $this->arPriority[
'f']]);
191 while ($this->arPriority[
'f'] <= $arStack[0][1])
193 $op = array_shift($arStack);
194 $arPolishNotation[] = [$op[0], self::Operation];
198 array_unshift($arStack, [
$name, $this->arPriority[
'f']]);
203 $this->SetError(3,
$name);
211 if ($prev ==
'' || in_array($prev, [
'(',
';',
'=',
'<=',
'>=',
'<>',
'<',
'>',
'&',
'+',
'-',
'*',
'/',
'^']))
219 array_unshift($arStack, [
'(', $this->arPriority[
'(']]);
222 while ($op = array_shift($arStack))
226 $arPolishNotation[] = [$op[0], self::Operation];
234 case ';' :
case '=' :
case '<=':
case '>=':
235 case '<>':
case '<' :
case '>' :
case '&' :
236 case '+' :
case '-' :
case '+m':
case '-m':
237 case '*' :
case '/' :
case '^' :
case '%' :
240 array_unshift($arStack, [
$str, $this->arPriority[
$str]]);
243 while ($this->arPriority[
$str] <= $arStack[0][1])
245 $op = array_shift($arStack);
246 $arPolishNotation[] = [$op[0], self::Operation];
250 array_unshift($arStack, [
$str, $this->arPriority[
$str]]);
253 if (mb_substr(
$str, 0, 1) ==
'0' || (
int)
$str)
255 $arPolishNotation[] = [(float)
$str, self::Constant];
258 if (mb_substr(
$str, 0, 1) ==
'"' || mb_substr(
$str, 0, 1) ==
"'")
260 $arPolishNotation[] = [mb_substr(
$str, 1, -1), self::Constant];
263 $arPolishNotation[] = [
$str, self::Variable];
265 $text = mb_substr(
$text, mb_strlen($match[0]));
267 while ($op = array_shift($arStack))
274 $arPolishNotation[] = [$op[0], self::Operation];
276 return $arPolishNotation;
281 if (!$arPolishNotation = $this->GetPolishNotation(
$text))
285 foreach ($arPolishNotation as $item)
290 array_unshift($stack, $item[0]);
293 array_unshift($stack, $this->GetVariableValue($item[0]));
295 case self::Operation:
299 $arg2 = array_shift($stack);
300 $arg1 = array_shift($stack);
301 if (!is_array($arg1) || !isset($arg1[0]))
304 array_unshift($stack, $arg1);
307 $arg2 = array_shift($stack);
308 $arg1 = array_shift($stack);
309 array_unshift($stack, $arg1 == $arg2);
312 $arg2 = array_shift($stack);
313 $arg1 = array_shift($stack);
314 array_unshift($stack, $arg1 <= $arg2);
317 $arg2 = array_shift($stack);
318 $arg1 = array_shift($stack);
319 array_unshift($stack, $arg1 >= $arg2);
322 $arg2 = array_shift($stack);
323 $arg1 = array_shift($stack);
324 array_unshift($stack, $arg1 != $arg2);
327 $arg2 = array_shift($stack);
328 $arg1 = array_shift($stack);
329 array_unshift($stack, $arg1 < $arg2);
332 $arg2 = array_shift($stack);
333 $arg1 = array_shift($stack);
334 array_unshift($stack, $arg1 > $arg2);
337 $arg2 = (string) array_shift($stack);
338 $arg1 = (string) array_shift($stack);
339 array_unshift($stack, $arg1 . $arg2);
342 $arg2 = (float) array_shift($stack);
343 $arg1 = (float) array_shift($stack);
344 array_unshift($stack, $arg1 + $arg2);
347 $arg2 = (float) array_shift($stack);
348 $arg1 = (float) array_shift($stack);
349 array_unshift($stack, $arg1 - $arg2);
352 $arg = (float) array_shift($stack);
353 array_unshift($stack, $arg);
356 $arg = (float) array_shift($stack);
357 array_unshift($stack, (-$arg));
360 $arg2 = (float) array_shift($stack);
361 $arg1 = (float) array_shift($stack);
362 array_unshift($stack, $arg1 * $arg2);
365 $arg2 = (float) array_shift($stack);
366 $arg1 = (float) array_shift($stack);
372 array_unshift($stack, $arg1 / $arg2);
375 $arg2 = (float) array_shift($stack);
376 $arg1 = (float) array_shift($stack);
377 array_unshift($stack, pow($arg1, $arg2));
380 $arg = (float) array_shift($stack);
381 array_unshift($stack, $arg / 100);
384 $func = $this->arAvailableFunctions[$item[0]][
'func'];
385 if ($this->arAvailableFunctions[$item[0]][
'args'])
387 $arg = array_shift($stack);
388 $val = $this->$func($arg);
392 $val = $this->$func();
397 $this->SetError(8, $item[0]);
400 array_unshift($stack,
$val);
404 if (
count($stack) > 1)
409 return array_shift($stack);
412 private function arrgsToArray($args)
414 if (!is_array($args))
418 foreach ($args as $arg)
426 foreach ($this->ArrgsToArray($arg) as
$val)
436 private function functionAbs($num)
438 return abs((
float) $num);
441 private function functionRound($args)
443 $ar = $this->ArrgsToArray($args);
444 $val = (float)array_shift(
$ar);
450 private function functionCeil($num)
452 return ceil((
double)$num);
455 private function functionFloor($num)
457 return floor((
double)$num);
460 private function functionMin($args)
462 if (!is_array($args))
463 return (
float) $args;
465 foreach ($args as &$arg)
468 $args = $this->ArrgsToArray($args);
470 return $args ? min($args) :
false;
473 private function functionMax($args)
475 if (!is_array($args))
476 return (
float) $args;
478 foreach ($args as &$arg)
481 $args = $this->ArrgsToArray($args);
483 return $args ? max($args) :
false;
486 private function functionRand($args)
488 $ar = $this->ArrgsToArray($args);
489 $min = (int)array_shift(
$ar);
493 $max = mt_getrandmax();
496 return mt_rand($min,
$max);
499 private function functionIntval($num)
504 private function functionFloatval($num)
506 return floatval($num);
511 private function functionTrue()
516 private function functionFalse()
521 private function functionIf($args)
523 if (!is_array($args))
526 $expression = (boolean) array_shift($args);
527 $ifTrue = array_shift($args);
528 $ifFalse = array_shift($args);
529 return $expression ? $ifTrue : $ifFalse;
532 private function functionNot($arg)
534 return !((boolean) $arg);
537 private function functionAnd($args)
539 if (!is_array($args))
540 return (
boolean) $args;
542 $args = $this->ArrgsToArray($args);
544 foreach ($args as $arg)
552 private function functionOr($args)
554 if (!is_array($args))
555 return (
boolean) $args;
557 $args = $this->ArrgsToArray($args);
558 foreach ($args as $arg)
569 private function functionDateAdd($args)
571 if (!is_array($args))
576 $ar = $this->ArrgsToArray($args);
577 $date = array_shift(
$ar);
578 $offset = $this->getDateTimeOffset($date);
579 $interval = array_shift(
$ar);
581 if (($date = $this->makeTimestamp($date)) ===
false)
586 if (empty($interval))
593 $interval = trim($interval);
595 if (mb_substr($interval, 0, 1) ===
"-")
597 $interval = mb_substr($interval, 1);
601 static $arMap = [
"y" =>
"YYYY",
"year" =>
"YYYY",
"years" =>
"YYYY",
602 "m" =>
"MM",
"month" =>
"MM",
"months" =>
"MM",
603 "d" =>
"DD",
"day" =>
"DD",
"days" =>
"DD",
604 "h" =>
"HH",
"hour" =>
"HH",
"hours" =>
"HH",
605 "i" =>
"MI",
"min" =>
"MI",
"minute" =>
"MI",
"minutes" =>
"MI",
606 "s" =>
"SS",
"sec" =>
"SS",
"second" =>
"SS",
"seconds" =>
"SS",
610 while (preg_match(
'/\s*([\d]+)\s*([a-z]+)\s*/i', $interval, $match))
612 $match2 = mb_strtolower($match[2]);
613 if (array_key_exists($match2, $arMap))
615 $arInterval[$arMap[$match2]] = ($bMinus ? -intval($match[1]) : intval($match[1]));
618 $p = mb_strpos($interval, $match[0]);
619 $interval = mb_substr($interval,
$p + mb_strlen($match[0]));
628 return new Bizproc\BaseType\Value\DateTime($newDate, $offset);
631 private function functionWorkDateAdd($args)
633 if (!is_array($args))
636 $ar = $this->ArrgsToArray($args);
637 $date = array_shift(
$ar);
638 $offset = $this->getDateTimeOffset($date);
639 $paramInterval = array_shift(
$ar);
644 $date = $this->FunctionToUserDate([
$user, $date]);
645 $offset = $this->getDateTimeOffset($date);
648 if (($date = $this->makeTimestamp($date,
true)) ===
false)
651 if (empty($paramInterval) || !CModule::IncludeModule(
'calendar'))
654 $paramInterval = trim($paramInterval);
656 if (mb_substr($paramInterval, 0, 1) ===
"-")
658 $paramInterval = mb_substr($paramInterval, 1);
662 $workDayInterval = $this->getWorkDayInterval();
663 $intervalMap = [
"d" => $workDayInterval,
"day" => $workDayInterval,
"days" => $workDayInterval,
664 "h" => 3600,
"hour" => 3600,
"hours" => 3600,
665 "i" => 60,
"min" => 60,
"minute" => 60,
"minutes" => 60,
669 while (preg_match(
'/\s*([\d]+)\s*([a-z]+)\s*/i', $paramInterval, $match))
671 $match2 = mb_strtolower($match[2]);
672 if (array_key_exists($match2, $intervalMap))
673 $interval += intval($match[1]) * $intervalMap[$match2];
675 $p = mb_strpos($paramInterval, $match[0]);
676 $paramInterval = mb_substr($paramInterval,
$p + mb_strlen($match[0]));
679 if (date(
'H:i:s', $date) ===
'00:00:00')
682 $date += $this->getCalendarWorkTime()[0];
685 $date = $this->getNearestWorkTime($date, $multiplier);
688 $days = (int) floor($interval / $workDayInterval);
689 $hours = $interval % $workDayInterval;
691 $remainTimestamp = $this->getWorkDayRemainTimestamp($date, $multiplier);
694 $date = $this->addWorkDay($date, $days * $multiplier);
696 if (
$hours > $remainTimestamp)
698 $date += $multiplier < 0 ? -$remainTimestamp -60 : $remainTimestamp + 60;
699 $date = $this->getNearestWorkTime($date, $multiplier) + ((
$hours - $remainTimestamp) * $multiplier);
702 $date += $multiplier *
$hours;
707 return new Bizproc\BaseType\Value\DateTime($date, $offset);
710 private function functionAddWorkDays($args)
712 if (!is_array($args))
715 $ar = $this->ArrgsToArray($args);
716 $date = array_shift(
$ar);
717 $offset = $this->getDateTimeOffset($date);
718 $days = (int) array_shift(
$ar);
720 if (($date = $this->makeTimestamp($date)) ===
false)
723 if ($days === 0 || !CModule::IncludeModule(
'calendar'))
726 $date = $this->addWorkDay($date, $days);
728 return new Bizproc\BaseType\Value\DateTime($date, $offset);
731 private function functionIsWorkDay($args)
733 if (!CModule::IncludeModule(
'calendar'))
736 if (!is_array($args))
739 $ar = $this->ArrgsToArray($args);
740 $date = array_shift(
$ar);
745 $date = $this->FunctionToUserDate([
$user, $date]);
748 if (($date = $this->makeTimestamp($date,
true)) ===
false)
751 return !$this->isHoliday($date);
754 private function functionIsWorkTime($args)
756 if (!CModule::IncludeModule(
'calendar'))
759 if (!is_array($args))
762 $ar = $this->ArrgsToArray($args);
763 $date = array_shift(
$ar);
768 $date = $this->FunctionToUserDate([
$user, $date]);
771 if (($date = $this->makeTimestamp($date,
true)) ===
false)
774 return !$this->isHoliday($date) && $this->isWorkTime($date);
777 private function functionDateDiff($args)
779 if (!is_array($args))
782 $ar = $this->ArrgsToArray($args);
783 $date1 = array_shift(
$ar);
784 $date2 = array_shift(
$ar);
785 $format = array_shift(
$ar);
787 if ($date1 ==
null || $date2 ==
null)
790 $date1Formatted = $this->getDateTimeObject($date1);
791 $date2Formatted = $this->getDateTimeObject($date2);
792 if ($date1Formatted ===
false || $date2Formatted ===
false)
797 $interval = $date1Formatted->diff($date2Formatted);
799 return $interval ===
false ? null : $interval->format($format);
802 private function functionDate($args)
804 $ar = $this->ArrgsToArray($args);
805 $format = array_shift(
$ar);
806 $date = array_shift(
$ar);
808 if (!$format || !is_string($format))
813 $ts = $date ? $this->makeTimestamp($date,
true) : time();
820 return date($format, $ts);
823 private function functionToUserDate($args)
825 if (!is_array($args))
830 $ar = $this->ArrgsToArray($args);
832 $date = array_shift(
$ar);
843 elseif (($date = $this->makeTimestamp($date)) ===
false)
848 $userId = CBPHelper::ExtractUsers(
$user, $this->activity->GetDocumentId(),
true);
851 return new Bizproc\BaseType\Value\DateTime($date, $offset);
854 private function functionGetUserDateOffset($args)
856 if (!is_array($args))
861 $ar = $this->ArrgsToArray($args);
869 $userId = CBPHelper::ExtractUsers(
$user, $this->activity->GetDocumentId(),
true);
879 private function functionStrtotime($args)
881 $ar = $this->ArrgsToArray($args);
882 $datetime = (string)array_shift(
$ar);
883 $baseDate = array_shift(
$ar);
885 $baseTimestamp = $baseDate ? $this->makeTimestamp($baseDate,
true) : time();
892 $timestamp = strtotime($datetime, (
int)$baseTimestamp);
894 if ($timestamp ===
false)
899 return new Bizproc\BaseType\Value\DateTime($timestamp);
902 private function functionLocDate($args)
904 $ar = $this->ArrgsToArray($args);
905 $format = array_shift(
$ar);
906 $date = array_shift(
$ar);
908 if (!$format || !is_string($format))
913 $reformFormat = $this->frameSymbolsInDateFormat($format);
914 $timestamp = $date ? $this->makeTimestamp($date,
true) : time();
921 $formattedDate = date($reformFormat, $timestamp);
923 if ($formattedDate ===
false)
928 return $this->replaceDateToLocDate($formattedDate, $reformFormat);
933 private function makeTimestamp($date, $appendOffset =
false)
941 if (is_string($date) && Bizproc\BaseType\Value\Date::isSerialized($date))
943 $date =
new Bizproc\BaseType\Value\Date($date);
946 if ($date instanceof Bizproc\BaseType\Value\Date)
948 return $date->getTimestamp() + ($appendOffset? $date->getOffset() : 0);
951 if (intval($date).
"!" === $date.
"!")
967 private function getWorkDayTimestamp($date)
969 return date(
'H', $date) * 3600 + date(
'i', $date) * 60;
972 private function getWorkDayRemainTimestamp($date, $multiplier = 1)
974 $dayTs = $this->getWorkDayTimestamp($date);
975 list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
976 return $multiplier < 0 ? $dayTs - $startSeconds :$endSeconds - $dayTs;
979 private function getWorkDayInterval()
981 list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
982 return $endSeconds - $startSeconds;
985 private function isHoliday($date)
987 [$yearWorkdays] = $this->getCalendarWorkdays();
988 [$weekHolidays, $yearHolidays] = $this->getCalendarHolidays();
990 $dayOfYear = date(
'j.n', $date);
991 if (in_array($dayOfYear, $yearWorkdays,
true))
996 $dayOfWeek = date(
'w', $date);
997 if (in_array($dayOfWeek, $weekHolidays))
1002 $dayOfYear = date(
'j.n', $date);
1003 if (in_array($dayOfYear, $yearHolidays,
true))
1011 private function isWorkTime($date)
1013 $dayTs = $this->getWorkDayTimestamp($date);
1014 list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
1015 return ($dayTs >= $startSeconds && $dayTs <= $endSeconds);
1018 private function getNearestWorkTime($date, $multiplier = 1)
1020 $reverse = $multiplier < 0;
1021 list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
1022 $dayTimeStamp = $this->getWorkDayTimestamp($date);
1024 if ($this->isHoliday($date))
1026 $date -= $dayTimeStamp;
1027 $date += $reverse? -86400 + $endSeconds : $startSeconds;
1028 $dayTimeStamp = $reverse? $endSeconds : $startSeconds;
1031 if (!$this->isWorkTime($date))
1033 $date -= $dayTimeStamp;
1035 if ($dayTimeStamp < $startSeconds)
1037 $date += $reverse? -86400 + $endSeconds : $startSeconds;
1041 $date += $reverse? $endSeconds : 86400 + $startSeconds;
1045 if ($this->isHoliday($date))
1046 $date = $this->addWorkDay($date, $reverse? -1 : 1);
1051 private function addWorkDay($date, $days)
1060 while ($days > 0 && $iterations < 1000)
1065 if ($this->isHoliday($date))
1073 private function getCalendarHolidays()
1075 if (static::$yearHolidays ===
null)
1078 $weekHolidays = [0, 6];
1081 if (isset($calendarSettings[
'week_holidays']))
1083 $weekDays = [
'SU' => 0,
'MO' => 1,
'TU' => 2,
'WE' => 3,
'TH' => 4,
'FR' => 5,
'SA' => 6];
1085 foreach ($calendarSettings[
'week_holidays'] as $day)
1086 $weekHolidays[] = $weekDays[$day];
1089 if (isset($calendarSettings[
'year_holidays']))
1091 foreach (explode(
',', $calendarSettings[
'year_holidays']) as $yearHoliday)
1093 $date = explode(
'.', trim($yearHoliday));
1094 if (
count($date) == 2 && $date[0] && $date[1])
1095 $yearHolidays[] = (int)$date[0] .
'.' . (
int)$date[1];
1098 static::$weekHolidays = $weekHolidays;
1099 static::$yearHolidays = $yearHolidays;
1102 return [static::$weekHolidays, static::$yearHolidays];
1105 private function getCalendarWorkTime()
1107 if (static::$startWorkDay ===
null)
1110 $endSeconds = 24 * 3600 - 1;
1113 if (!empty($calendarSettings[
'work_time_start']))
1115 $time = explode(
'.', $calendarSettings[
'work_time_start']);
1116 $startSeconds =
$time[0] * 3600;
1117 if (!empty(
$time[1]))
1118 $startSeconds +=
$time[1] * 60;
1121 if (!empty($calendarSettings[
'work_time_end']))
1123 $time = explode(
'.', $calendarSettings[
'work_time_end']);
1124 $endSeconds =
$time[0] * 3600;
1125 if (!empty(
$time[1]))
1126 $endSeconds +=
$time[1] * 60;
1128 static::$startWorkDay = $startSeconds;
1129 static::$endWorkDay = $endSeconds;
1131 return [static::$startWorkDay, static::$endWorkDay];
1134 private function getCalendarWorkdays()
1136 if (static::$yearWorkdays ===
null)
1141 $calendarYearWorkdays = $calendarSettings[
'year_workdays'] ??
'';
1143 foreach (explode(
',', $calendarYearWorkdays) as $yearWorkday)
1145 $date = explode(
'.', trim($yearWorkday));
1146 if (
count($date) === 2 && $date[0] && $date[1])
1148 $yearWorkdays[] = (int)$date[0] .
'.' . (
int)$date[1];
1152 static::$yearWorkdays = $yearWorkdays;
1155 return [static::$yearWorkdays];
1158 private function getDateTimeObject($date)
1160 if ($date instanceof Bizproc\BaseType\Value\Date)
1162 return (
new \DateTime())->setTimestamp($date->getTimestamp());
1165 $df = Main\Type\DateTime::getFormat();
1166 $df2 = Main\Type\Date::getFormat();
1167 $date1Formatted = \DateTime::createFromFormat($df, $date);
1168 if ($date1Formatted ===
false)
1170 $date1Formatted = \DateTime::createFromFormat($df2, $date);
1171 if ($date1Formatted)
1173 $date1Formatted->setTime(0, 0);
1176 return $date1Formatted;
1179 private function getDateTimeOffset($date)
1181 if ($date instanceof Bizproc\BaseType\Value\Date)
1183 return $date->getOffset();
1188 private function frameSymbolsInDateFormat($format)
1190 $complexSymbols = [
'j F',
'd F',
'jS F'];
1191 $symbols = [
'D',
'l',
'F',
'M',
'r'];
1194 foreach ($symbols as $symbol)
1196 $frameRule[$symbol] =
'#' . $symbol .
'#';
1197 $frameRule[
'\\' . $symbol] =
'\\' . $symbol;
1199 foreach ($complexSymbols as $symbol)
1201 $frameRule[$symbol] = substr($symbol, 0, -1) .
'#' . $symbol[-1] .
'_1#';
1202 $frameRule[
'\\' . $symbol] =
'\\' . substr($symbol, 0, -1) .
'#' . $symbol[-1] .
'#';
1205 return strtr($format, $frameRule);
1208 private function frameNamesInFormattedDateRFC2822($formattedDate)
1211 $pattern =
"/#(\w{3}), \d{2} (\w{3}) \d{4} \d{2}:\d{2}:\d{2} [+-]\d{4}#/";
1219 $reformMatch = str_replace(
1221 [
'#' . $day .
'#',
'#' . $month .
'#'],
1224 $reformMatch = substr($reformMatch, 1, -1);
1226 $formattedDate = str_replace($match, $reformMatch, $formattedDate);
1230 return $formattedDate;
1233 private function replaceDateToLocDate($formattedDate, $format)
1236 $dayNames = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'];
1252 if (strpos($format,
'#r#') !==
false)
1254 $formattedDate = $this->frameNamesInFormattedDateRFC2822($formattedDate);
1257 $replacementRule = [];
1258 foreach (array_merge($dayNames, $monthNames) as
$name)
1261 'BPCGCALC_LOCDATE_' . strtoupper(
$name)
1263 $shortName = substr(
$name, 0, $lenShortName);
1264 $replacementRule[
'#' . $shortName .
'#'] =
GetMessage(
1265 'BPCGCALC_LOCDATE_' . strtoupper($shortName) .
'_SHORT'
1268 foreach ($monthNames as $monthName)
1270 $replacementRule[
'#' . $monthName .
'_1' .
'#'] =
GetMessage(
1271 'BPCGCALC_LOCDATE_' . strtoupper($monthName) .
'_1'
1275 return strtr($formattedDate, $replacementRule);
1280 private function functionNumberFormat($args)
1282 $ar = $this->ArrgsToArray($args);
1283 $number = (float) array_shift(
$ar);
1284 $decimals = (int) (array_shift(
$ar) ?: 0);
1285 $decPoint = array_shift(
$ar);
1286 if ($decPoint ===
null)
1290 $decPoint = (string) $decPoint;
1292 $thousandsSeparator = array_shift(
$ar);
1293 if ($thousandsSeparator ===
null)
1295 $thousandsSeparator =
',';
1297 $thousandsSeparator = (string) $thousandsSeparator;
1299 return number_format($number, $decimals, $decPoint, $thousandsSeparator);
1302 private function functionRandString($args)
1304 $ar = $this->ArrgsToArray($args);
1305 $len = (int)array_shift(
$ar);
1307 return \randString($len);
1310 private function functionSubstr($args)
1312 if (!is_array($args))
1315 $ar = $this->ArrgsToArray($args);
1317 $pos = (int)array_shift(
$ar);
1318 $len = (int)array_shift(
$ar);
1320 if ((
$str ==
null) || (
$str ===
""))
1325 return mb_substr(
$str, $pos, $len);
1328 return mb_substr(
$str, $pos);
1331 private function functionStrpos($args)
1333 $ar = $this->ArrgsToArray($args);
1334 $haystack = (string)array_shift(
$ar);
1336 if (empty($haystack))
1341 $maxOffset = mb_strlen($haystack);
1342 $minOffset = -1 * $maxOffset;
1344 $needle = (string)array_shift(
$ar);
1345 $offset = max($minOffset, min($maxOffset, (
int)array_shift(
$ar)));
1347 return mb_strpos($haystack, $needle, $offset);
1350 private function functionStrlen($args)
1352 $ar = $this->ArrgsToArray($args);
1355 if (!is_scalar(
$str))
1361 return mb_strlen(
$str);
1364 private function functionImplode($args)
1367 $glue = (string)array_shift(
$ar);
1368 $pieces = \CBPHelper::MakeArrayFlat(array_shift(
$ar));
1375 return implode($glue, $pieces);
1378 private function functionExplode($args)
1381 $delimiter = array_shift(
$ar);
1389 if (is_array($delimiter))
1391 $delimiter = reset($delimiter);
1394 if (empty($delimiter) || !is_scalar(
$str) || !is_scalar($delimiter))
1400 return explode($delimiter,
$str);
1403 private function functionUrlencode($args)
1405 $ar = $this->ArrgsToArray($args);
1408 if (!is_scalar(
$str))
1412 $str = implode(
", ", CBPHelper::MakeArrayFlat(
$str));
1421 return urlencode(
$str);
1424 private function functionConvert($args)
1426 if (!is_array($args))
1429 $ar = $this->ArrgsToArray($args);
1432 $attr = array_shift(
$ar);
1435 if (
$type ===
'printableuserb24')
1439 $users = CBPHelper::StripUserPrefix(
$val);
1440 if (!is_array($users))
1446 if (
$ar = $db->GetNext())
1449 $attr = (!empty($attr) ?
'href="'.$attr.
'"' :
'href="#" onClick="return false;"');
1450 $result[] =
'<a class="feed-post-user-name" id="bp_'.$userId.
'_'.$ix.
'" '.$attr.
' bx-post-author-id="'.
$userId.
'" bx-post-author-gender="'.
$ar[
'PERSONAL_GENDER'].
'" bx-tooltip-user-id="'.
$userId.
'">'.
CUser::FormatName(CSite::GetNameFormat(
false),
$ar,
false).
'</a>';
1460 $users = CBPHelper::StripUserPrefix(
$val);
1461 if (!is_array($users))
1467 if (
$ar = $db->GetNext())
1482 private function functionStrtolower($args)
1484 $ar = $this->ArrgsToArray($args);
1487 if (!is_scalar(
$str))
1492 return mb_strtolower((
string)
$str);
1495 private function functionStrtoupper($args)
1497 $ar = $this->ArrgsToArray($args);
1500 if (!is_scalar(
$str))
1505 return mb_strtoupper((
string)
$str);
1508 private function functionUcwords($args)
1510 $ar = $this->ArrgsToArray($args);
1513 if (!is_scalar(
$str))
1518 return mb_convert_case((
string)
$str, MB_CASE_TITLE);
1521 private function functionUcfirst($args)
1523 $ar = $this->ArrgsToArray($args);
1526 if (!is_scalar(
$str))
1531 return $this->mb_ucfirst((
string)
$str);
1534 private function mb_ucfirst(
$str)
1536 $len = mb_strlen(
$str);
1537 $firstChar = mb_substr(
$str, 0, 1);
1538 $otherChars = mb_substr(
$str, 1, $len - 1);
1539 return mb_strtoupper($firstChar) . $otherChars;
1542 private function functionTrim($args)
1544 $array = $this->ArrgsToArray($args);
1551 foreach ($array as
$str)
1553 if (is_scalar(
$str) || (is_object(
$str) && method_exists(
$str,
'__toString')))
1568 private function functionMerge($args)
1570 if (!is_array($args))
1573 foreach ($args as &
$a)
1577 return call_user_func_array(
'array_merge', $args);
1580 private function functionShuffle($args)
1582 if (!is_array($args) || $args === [])
1587 $array = $this->ArrgsToArray($args);
1593 private function functionFirstValue($args)
1595 $ar = $this->ArrgsToArray($args);
1597 return $ar[0] ??
null;
1600 private function functionSwirl($args)
1602 $ar = $this->ArrgsToArray($args);
1605 return $ar[0] ??
null;
1608 return array_merge(array_slice(
$ar, 1), [
$ar[0]]);
1611 private function functionGetDocumentUrl($args)
1613 $ar = $this->ArrgsToArray($args);
1614 $format = array_shift(
$ar);
1615 $external = array_shift(
$ar);
1617 $url = $this->activity->workflow->getService(
'DocumentService')->GetDocumentAdminPage(
1618 $this->activity->getDocumentId()
1624 $url = Main\Engine\UrlManager::getInstance()->getHostUrl() .
$url;
1627 if ($format ===
'bb' || $format ===
'html')
1629 $name = $this->activity->workflow->getService(
'DocumentService')->getDocumentName(
1630 $this->activity->getDocumentId()
1634 if ($format ===
'bb')
1643 if ($format ===
'html')
1646 '<a href="%s" target="_blank">%s</a>',