1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
vote.php
См. документацию.
1<?php
8namespace Bitrix\Vote;
9use \Bitrix\Main\AccessDeniedException;
10use Bitrix\Main\Context;
11use \Bitrix\Main\Entity;
12use Bitrix\Main\ErrorCollection;
13use \Bitrix\Main\ORM\Data\AddResult;
14use \Bitrix\Main\ORM\Data\Result;
15use \Bitrix\Main\Application;
16use \Bitrix\Main\Error;
17use \Bitrix\Main\Localization\Loc;
18use \Bitrix\Main\ArgumentException;
19use \Bitrix\Main\ORM\Data\UpdateResult;
20use \Bitrix\Main\ORM\Event;
21use \Bitrix\Main\ORM\Fields\DatetimeField;
22use \Bitrix\Main\ORM\Fields\ExpressionField;
23use \Bitrix\Main\ORM\Fields\TextField;
24use \Bitrix\Main\ORM\Fields\Validators\DateValidator;
25use \Bitrix\Main\ORM\Fields\IntegerField;
26use \Bitrix\Main\ORM\Fields\EnumField;
27use \Bitrix\Main\ORM\Fields\StringField;
28use \Bitrix\Main\ORM\Fields\BooleanField;
29use \Bitrix\Main\ORM\Fields\Relations\Reference;
30use \Bitrix\Main\ORM\Fields\FieldError;
31use \Bitrix\Main\ORM\EntityError;
32use \Bitrix\Main\ORM\Query\Join;
33use \Bitrix\Main\Text\HtmlFilter;
34use Bitrix\Main\Web\MimeType;
35use \Bitrix\Vote\Base\BaseObject;
36use \Bitrix\Vote\Vote\Option;
37use \Bitrix\Vote\Vote\EventLimits;
38use \Bitrix\Vote\Vote\Anonymity;
39use \Bitrix\Main\Type\DateTime;
40use \Bitrix\Main\FileTable;
41
42
43Loc::loadMessages(__FILE__);
44
94class VoteTable extends Entity\DataManager
95{
101 public static function getTableName()
102 {
103 return "b_vote";
104 }
105
112 public static function getMap()
113 {
114 $now = Application::getInstance()->getConnection()->getSqlHelper()->getCurrentDateTimeFunction();
115 return array(
116 (new IntegerField("ID", ["primary" => true, "autocomplete" => true])),
117 (new IntegerField("CHANNEL_ID", ["required" => true])),
118 (new IntegerField("C_SORT", ["default_value" => 100])),
119 (new BooleanField("ACTIVE", ["values" => ["N", "Y"], "default_value" => "Y"])),
120 (new IntegerField("ANONYMITY", ["default_value" => Anonymity::PUBLICLY])),
121 (new EnumField("NOTIFY", ["values" => ["N", "Y", "I"], "default_value" => "N"])),
122 (new IntegerField("AUTHOR_ID")),
123 (new Reference("AUTHOR", \Bitrix\Main\UserTable::class, Join::on("this.AUTHOR_ID", "ref.ID"))),
124 (new DatetimeField("TIMESTAMP_X", ["default_value" => function(){return new DateTime();}])),
125 (new DatetimeField("DATE_START", ["default_value" => function(){return new DateTime();}, "required" => true, "validation" => function() {
126 return [
127 new DateValidator,
128 [__CLASS__, "validateActivityDate"]
129 ];
130 }])),
131 (new DatetimeField("DATE_END", ["default_value" => function(){
132 $time = new DateTime();
133 $time->add("1D");
134 return $time;
135 }, "required" => true, "validation" => function() {
136 return [
137 new DateValidator,
138 [__CLASS__, "validateActivityDate"]
139 ];
140 }])),
141 (new StringField("URL", ["size" => 255])),
142 (new IntegerField("COUNTER")),
143 (new StringField("TITLE", ["size" => 255])),
144 (new TextField("DESCRIPTION")),
145 (new EnumField("DESCRIPTION_TYPE", ["values" => ["text", "html"], "default_value" => "text"])),
146 (new IntegerField("IMAGE_ID")),
147 (new Reference("IMAGE", FileTable::class, Join::on("this.IMAGE_ID", "ref.ID"))),
148 (new StringField("EVENT1", ["size" => 255])),
149 (new StringField("EVENT2", ["size" => 255])),
150 (new StringField("EVENT3", ["size" => 255])),
151 (new IntegerField("UNIQUE_TYPE", ["default_value" => EventLimits::BY_IP|EventLimits::BY_USER_ID])),
152 (new IntegerField("KEEP_IP_SEC", ["default_value" => 604800])), // one week
153 (new IntegerField("OPTIONS", ["default_value" => Option::ALLOW_REVOTE])),
154 (new IntegerField("STOP_EVENT_HANDLED")),
155 (new ExpressionField("LAMP",
156 "CASE ".
157 "WHEN (%s='Y' AND %s='Y' AND %s <= {$now} AND {$now} <= %s AND %s='Y') THEN 'yellow' ".
158 "WHEN (%s='Y' AND %s='Y' AND %s <= {$now} AND {$now} <= %s AND %s!='Y') THEN 'green' ".
159 "ELSE 'red' ".
160 "END",
161 ["CHANNEL.ACTIVE", "ACTIVE", "DATE_START", "DATE_END", "CHANNEL.VOTE_SINGLE",
162 "CHANNEL.ACTIVE", "ACTIVE", "DATE_START", "DATE_END", "CHANNEL.VOTE_SINGLE"])),
163 (new Reference("CHANNEL", ChannelTable::class, Join::on("this.CHANNEL_ID", "ref.ID"))),
164 (new Reference("QUESTION", QuestionTable::class, Join::on("this.ID", "ref.VOTE_ID"))),
165 (new Reference("USER", \Bitrix\Main\UserTable::class, Join::on("this.AUTHOR_ID", "ref.ID"))),
166 );
167 }
168
175 public static function validateActivityDate($value, $primary, $row, $field)
176 {
178 if (empty($value))
179 return new FieldError(
180 $field, Loc::getMessage("VOTE_ERROR_DATE_VOTE_IS_EMPTY"), $field->getName()
181 );
182
183 return true;
184 }
185
191 public static function onBeforeAdd(\Bitrix\Main\ORM\Event $event)
192 {
193 $result = new \Bitrix\Main\ORM\EventResult();
194 if (($events = GetModuleEvents("vote", "onBeforeVoteAdd", true)) && !empty($events))
195 {
197 $data = $event->getParameter("fields");
198 foreach ($events as $ev)
199 {
200 if (ExecuteModuleEventEx($ev, array(&$data)) === false)
201 {
202 $result->addError(new EntityError("Error: ".serialize($ev), "event"));
203 return $result;
204 }
205 }
206 if ($data != $event->getParameter("fields"))
207 {
208 $result->modifyFields($data);
209 }
210 }
211 return self::modifyData($event, $result);
212 }
217 public static function onAfterAdd(\Bitrix\Main\ORM\Event $event)
218 {
219 $id = $event->getParameter("id");
220 $id = is_array($id) && array_key_exists("ID", $id) ? $id["ID"] : $id;
221 $fields = $event->getParameter("fields");
222 /***************** Event onAfterVoteAdd ****************************/
223 foreach (GetModuleEvents("vote", "onAfterVoteAdd", true) as $event)
225 /***************** /Event ******************************************/
226 }
227
232 public static function onBeforeUpdate(\Bitrix\Main\ORM\Event $event)
233 {
234 $result = new \Bitrix\Main\ORM\EventResult();
235 if (($events = GetModuleEvents("vote", "onBeforeVoteUpdate", true)) && !empty($events))
236 {
238 $data = $event->getParameter("fields");
239 $id = $event->getParameter("id");
240 $id = is_array($id) && array_key_exists("ID", $id) ? $id["ID"] : $id;
241 foreach ($events as $ev)
242 {
243 if (ExecuteModuleEventEx($ev, array($id, &$data)) === false)
244 {
245 $result->addError(new EntityError("Error: ".serialize($ev), "event"));
246 return $result;
247 }
248 }
249 if ($data != $event->getParameter("fields"))
250 {
251 $result->modifyFields($data);
252 }
253 }
254 return self::modifyData($event, $result);
255 }
256
261 public static function onAfterUpdate(\Bitrix\Main\ORM\Event $event)
262 {
263 $id = $event->getParameter("id");
264 $id = is_array($id) && array_key_exists("ID", $id) ? $id["ID"] : $id;
265 $fields = $event->getParameter("fields");
266 /***************** Event onAfterVoteAdd ****************************/
267 foreach (GetModuleEvents("vote", "onAfterVoteUpdate", true) as $event)
269 /***************** /Event ******************************************/
270 }
271
277 private static function modifyData(\Bitrix\Main\ORM\Event $event, \Bitrix\Main\ORM\EventResult $result)
278 {
279 $data = array_merge($event->getParameter("fields"), $result->getModified());
280 $fields = [];
281
282 if (isset($data["UNIQUE_TYPE"]) && (
283 !($data["UNIQUE_TYPE"] & \Bitrix\Vote\Vote\EventLimits::BY_USER_AUTH) &&
284 ($data["UNIQUE_TYPE"] & \Bitrix\Vote\Vote\EventLimits::BY_USER_DATE_REGISTER ||
285 $data["UNIQUE_TYPE"] & \Bitrix\Vote\Vote\EventLimits::BY_USER_ID)
286 ))
287 $fields["UNIQUE_TYPE"] = $data["UNIQUE_TYPE"] | \Bitrix\Vote\Vote\EventLimits::BY_USER_AUTH;
288
289 foreach (["TIMESTAMP_X", "DATE_START", "DATE_END"] as $key)
290 {
291 if (isset($data[$key]) && !($data[$key] instanceof DateTime))
292 $fields[$key] = DateTime::createFromUserTime($data[$key]);
293 }
294
295 //region check image
296 if (array_key_exists("IMAGE_ID", $data))
297 {
298 if ($str = \CFile::CheckImageFile($data["IMAGE_ID"]))
299 {
300 $result->addError(new FieldError(static::getEntity()->getField("IMAGE_ID"), $str));
301 }
302 else
303 {
304 $fields["IMAGE_ID"] = $data["IMAGE_ID"];
305 $fields["IMAGE_ID"]["MODULE_ID"] = "vote";
306 if ($id = $event->getParameter("id"))
307 {
308 $id = is_integer($id) ? $id : $id["ID"];
309 if ($id > 0 && ($vote = VoteTable::getById($id)->fetch()) && ($vote["IMAGE_ID"] > 0))
310 {
311 $fields["IMAGE_ID"]["old_file"] = $vote["IMAGE_ID"];
312 }
313 }
314 if (\CFile::SaveForDB($fields, "IMAGE_ID", "") === false)
315 {
316 $result->unsetField("IMAGE_ID");
317 }
318 }
319 }
320 //endregion
321 if (!empty($fields))
322 {
323 $result->modifyFields(array_merge($result->getModified(), $fields));
324 }
325 return $result;
326 }
334 public static function checkFields(Result $result, $primary, array $data)
335 {
336 parent::checkFields($result, $primary, $data);
337 if ($result->isSuccess())
338 {
339 try
340 {
341 $vote = null;
342 //region check activity dates
345 $params = null;
346 if ($result instanceof AddResult)
347 {
348 $params = [
349 "ID" => null,
350 "ACTIVE" => (array_key_exists("ACTIVE", $data) ? $data["ACTIVE"] : "Y"),
351 "CHANNEL_ID" => $data["CHANNEL_ID"],
352 "DATE_START" => $data["DATE_START"],
353 "DATE_END" => $data["DATE_END"]
354 ];
355 }
356 else if (array_key_exists("CHANNEL_ID", $data) ||
357 array_key_exists("ACTIVE", $data) && $data["ACTIVE"] == "Y" ||
358 array_key_exists("DATE_START", $data) ||
359 array_key_exists("DATE_END", $data)
360 )
361 {
362 // if it is need to move to other channel or activate or change the dates
363 $vote = Vote::loadFromId($primary["ID"]);
364 $params = [
365 "ID" => $primary["ID"],
366 "ACTIVE" => (array_key_exists("ACTIVE", $data) ? $data["ACTIVE"] : $vote["ACTIVE"]),
367 "CHANNEL_ID" => (array_key_exists("CHANNEL_ID", $data) ? $data["CHANNEL_ID"] : $vote["CHANNEL_ID"]),
368 "DATE_START" => (array_key_exists("DATE_START", $data) ? $data["DATE_START"] : $vote["DATE_START"]),
369 "DATE_END" => (array_key_exists("DATE_END", $data) ? $data["DATE_END"] : $vote["DATE_END"])
370 ];
371 }
372 if (!is_null($params))
373 {
374 $params["DATE_START"] = static::getEntity()->getField("DATE_START")->cast($params["DATE_START"]);
375 $params["DATE_END"] = static::getEntity()->getField("DATE_END")->cast($params["DATE_END"]);
376 if (array_key_exists("DATE_END", $data))
377 $data["DATE_END"] = $params["DATE_END"];
378 if (!($params["DATE_START"] instanceof DateTime) || !($params["DATE_END"] instanceof DateTime))
379 $result->addError(new FieldError(
380 static::getEntity()->getField("DATE_START"),
381 Loc::getMessage("VOTE_ERROR_DATE_VOTE_IS_WRONG")
382 ));
383 else if ($params["DATE_START"]->getTimestamp() > $params["DATE_END"]->getTimeStamp())
384 {
385 $result->addError(new FieldError(
386 static::getEntity()->getField("DATE_START"),
387 Loc::getMessage("VOTE_ERROR_DATE_START_LATER_THAN_END")
388 ));
389 }
390 else if ($params["ACTIVE"] == "Y")
391 {
393 $channel = Channel::loadFromId($params["CHANNEL_ID"]);
394 if ($channel["VOTE_SINGLE"] == "Y")
395 {
396 $dbRes = VoteTable::getList([
397 "select" => ["ID", "TITLE", "DATE_START", "DATE_END"],
398 "filter" => (is_null($params["ID"]) ? [] : [
399 "!ID" => $params["ID"]]) + [
400 "CHANNEL_ID" => $channel["ID"],
401 [
402 "LOGIC" => "OR",
403 "><DATE_START" => [$params["DATE_START"], $params["DATE_END"]],
404 "><DATE_END" => [$params["DATE_START"], $params["DATE_END"]],
405 [
406 "<=DATE_START" => $params["DATE_START"],
407 ">=DATE_END" => $params["DATE_END"]
408 ]
409 ]
410 ]
411 ]);
412 if ($res = $dbRes->fetch())
413 {
414 $field = static::getEntity()->getField("DATE_START");
415 $result->addError(new FieldError(
416 $field,
417 Loc::getMessage("VOTE_ERROR_SAME_DATE_VOTE_IS_ALREADY_EXISTS", ["#VOTE#" => $res["TITLE"]." [".$res["ID"]."]"])
418 ));
419 }
420 }
421 }
422 }
423 //endregion
424 }
425 catch (\Exception $e)
426 {
427 $result->addError(new Error(
428 $e->getMessage()
429 ));
430 }
431 }
432 }
433
439 public static function setCounter(array $id, $increment = true)
440 {
441 if (empty($id))
442 return;
444
445 $sql = intval($increment);
446 if ($increment === true)
447 $sql = "COUNTER+1";
448 else if ($increment === false)
449 $sql = "COUNTER-1";
450 $connection->queryExecute("UPDATE ".self::getTableName()." SET COUNTER=".$sql." WHERE ID IN (".implode(", ", $id).")");
451 }
452}
453
454class Vote extends BaseObject implements \ArrayAccess
455{
456 protected $vote = array();
457 protected $questions = array();
458 protected $channel = null;
460 protected static $canVoteStorage = [];
461 public static $storage = array();
462 public static $statStorage = array();
463
464 public function __construct($id)
465 {
466 if (!($id > 0))
467 throw new \Bitrix\Main\ArgumentNullException("vote id");
468 parent::__construct($id);
469 }
470
471 public function init()
472 {
473 $data = self::getData($this->id);
474 if ($data === null)
475 throw new ArgumentException("Wrong vote id!");
476 $this->vote = array_diff_key($data, array("QUESTIONS" => ""));
477 foreach ($data["QUESTIONS"] as $q)
478 {
479 $this->questions[$q["ID"]] = $q;
480 }
482 $eventManager->addEventHandler("vote", "onAfterVoteQuestionAdd", array($this, "clearCache"));
483 $eventManager->addEventHandler("vote", "onAfterVoteQuestionUpdate", array($this, "clearCache"));
484 $eventManager->addEventHandler("vote", "onAfterVoteQuestionDelete", array($this, "clearCache"));
485 $eventManager->addEventHandler("vote", "onVoteQuestionActivate", array($this, "clearCache"));
486 $eventManager->addEventHandler("vote", "onVoteReset", array($this, "clearCache"));
487 }
488
493 public static function getData($id)
494 {
495 if (!array_key_exists($id, self::$storage))
496 {
497 self::$storage[$id] = null;
499 $dbRes = VoteTable::getList(array(
500 "select" => array(
501 "V_" => "*",
502 "V_LAMP" => "LAMP",
503 "Q_" => "QUESTION.*",
504 "A_" => "QUESTION.ANSWER",
505 ),
506 "order" => array(
507 "QUESTION.C_SORT" => "ASC",
508 "QUESTION.ID" => "ASC",
509 "QUESTION.ANSWER.C_SORT" => "ASC",
510 "QUESTION.ANSWER.ID" => "ASC",
511 ),
512 "filter" => array(
513 "ID" => $id
514 )
515 ));
516 // TODO Remake to a \Bitrix\Main\ORM\Objectify\Collection and its method ->fill()
517 if (($row = $dbRes->fetch()) && $row)
518 {
519 $images = array();
520 $vote = array();
521 foreach ($row as $key => $val)
522 if (mb_strpos($key, "V_") === 0)
523 $vote[mb_substr($key, 2)] = $val;
524 $vote += array(
525 "IMAGE" => null,
526 "FIELD_NAME" => \Bitrix\Vote\Event::getExtrasFieldName($vote["ID"], "#ENTITY_ID#"),
527 "QUESTIONS" => array());
528 if ($vote["IMAGE_ID"] > 0)
529 $images[$vote["IMAGE_ID"]] = &$vote["IMAGE"];
530 $question = [
531 'ID' => null,
532 'FIELD_TYPE' => \Bitrix\Vote\QuestionTypes::RADIO,
533 'COUNTER' => 0,
534 ];
535 do
536 {
537 $answer = array();
538 foreach ($row as $key => $val)
539 {
540 if (mb_strpos($key, "A_") === 0)
541 $answer[mb_substr($key, 2)] = $val;
542 }
543 if ($answer["IMAGE_ID"] > 0)
544 $images[$answer["IMAGE_ID"]] = &$answer["IMAGE"];
545 if ($answer["QUESTION_ID"] != $question["ID"])
546 {
547 unset($question);
548 $question = array();
549 foreach ($row as $key => $val)
550 {
551 if (mb_strpos($key, "Q_") === 0)
552 $question[mb_substr($key, 2)] = $val;
553 }
554 $question += array(
555 "IMAGE" => null,
556 "FIELD_NAME" => \Bitrix\Vote\Event::getFieldName($vote["ID"], $question["ID"]),
557 "ANSWERS" => array()
558 );
559 if ($question["IMAGE_ID"] > 0)
560 $images[$question["IMAGE_ID"]] = &$question["IMAGE"];
561 $vote["QUESTIONS"][$question["ID"]] = &$question;
562 }
563 $answer["FIELD_NAME"] = $answer["~FIELD_NAME"] = \Bitrix\Vote\Event::getFieldName($vote["ID"], $question["ID"]);
564 $answer["MESSAGE_FIELD_NAME"] = \Bitrix\Vote\Event::getMessageFieldName($vote["ID"], $question["ID"], $answer["ID"]);
565 if (
566 $answer["FIELD_TYPE"] == \Bitrix\Vote\AnswerTypes::TEXT ||
567 $answer["FIELD_TYPE"] == \Bitrix\Vote\AnswerTypes::TEXTAREA
568 )
569 {
570 if ($question["FIELD_TYPE"] == \Bitrix\Vote\QuestionTypes::COMPATIBILITY)
571 $answer["FIELD_NAME"] = $answer["MESSAGE_FIELD_NAME"];
572 }
573 else if ($question["FIELD_TYPE"] != \Bitrix\Vote\QuestionTypes::COMPATIBILITY)
574 {
575 $answer["FIELD_TYPE"] = $question["FIELD_TYPE"];
576 }
577 $answer["~PERCENT"] = ($question["COUNTER"] > 0 ? $answer["COUNTER"] * 100 / $question["COUNTER"] : 0);
578 $answer["PERCENT"] = round($answer["~PERCENT"], 2);
579 $question["ANSWERS"][$answer["ID"]] = &$answer;
580 unset($answer);
581 } while (($row = $dbRes->fetch()) && $row);
582 unset($question);
583 //region Getting images
584 if (count($images) > 0)
585 {
586 $dbRes = \Bitrix\Main\FileTable::getList(array("select" => array("*"), "filter" => array("ID" => array_keys($images))));
587 while ($res = $dbRes->fetch())
588 {
589 $images[$res["ID"]] = $res + array("SRC" => \CFile::GetFileSRC($res));
590 }
591 }
592 //endregion
593 //region Setting data into local storages
594 foreach ($vote["QUESTIONS"] as $question)
595 {
596 $questionId = strval($question["ID"]);
597 if (!array_key_exists($questionId, Question::$storage))
598 Question::$storage[$questionId] = $question;
599 foreach ($question["ANSWERS"] as $answer)
600 {
601 if (!array_key_exists($answer["ID"], Answer::$storage))
602 Answer::$storage[$answer["ID"]] = $answer;
603 }
604 }
605 self::$storage[$id] = $vote;
606 //endregion
607 }
608 }
609 return self::$storage[$id];
610 }
611
643 public static function checkData(array &$data, $voteId = 0)
644 {
645 $result = new AddResult();
646 $questionsToRevise = [];
647 if ($voteId > 0)
648 {
649 $result = new UpdateResult();
650 $vote = static::getData($voteId);
651 if (is_null($vote))
652 throw new ArgumentException(Loc::getMessage("VOTE_VOTE_NOT_FOUND", array("#ID#", $voteId)));
653 $questionsToRevise = ($vote["QUESTIONS"] ?: []);
654 }
655 $questionsToSave = isset($data["QUESTIONS"]) && is_array($data["QUESTIONS"]) ? $data["QUESTIONS"] : [];
656 unset($data["QUESTIONS"]);
657 VoteTable::checkFields($result, ["ID" => $voteId], $data);
658 if (!$result->isSuccess())
659 throw new ArgumentException(implode("", $result->getErrorMessages()));
660 /************** Check Data *****************************************/
661 $questions = array();
662 foreach ($questionsToSave as $key => $question)
663 {
664 if (($question["DEL"] ?? null) == "Y")
665 continue;
666
667 $question["ID"] = intval($question["ID"] ?? null);
668 $question = array(
669 "ID" => (array_key_exists($question["ID"], $questionsToRevise) ? $question["ID"] : null),
670 "QUESTION" => trim($question["QUESTION"]),
671 "QUESTION_TYPE" => trim($question["QUESTION_TYPE"]),
672 "FIELD_TYPE" => $question["FIELD_TYPE"],
673 "ANSWERS" => (is_array($question["ANSWERS"]) ? $question["ANSWERS"] : array()));
674
675 $savedAnswers = ($question["ID"] > 0 ? $questionsToRevise[$question["ID"]]["ANSWERS"] : array());
676 $newAnswers = array();
677 foreach ($question["ANSWERS"] as $keya => $answer)
678 {
679 $answer["ID"] = intval($answer["ID"] ?? null);
680 $answer["MESSAGE"] = trim($answer["MESSAGE"]);
681 if (($answer["DEL"] ?? null) != "Y" && $answer["MESSAGE"] !== "")
682 {
683 $answer = [
684 "ID" => $answer["ID"],
685 "MESSAGE" => $answer["MESSAGE"],
686 "MESSAGE_TYPE" => $answer["MESSAGE_TYPE"],
687 "FIELD_TYPE" => $answer["FIELD_TYPE"],
688 "REACTION" => $answer["REACTION"] ?? null,
689 ];
690 if (!array_key_exists($answer["ID"], $savedAnswers))
691 unset($answer["ID"]);
692 else
693 unset($savedAnswers[$answer["ID"]]);
694 $newAnswers[] = $answer;
695 }
696 }
697 $question["ANSWERS"] = $newAnswers;
698
699 if ($question["QUESTION"] == "" && empty($question["ANSWERS"]))
700 continue;
701 else if ($question["QUESTION"] == "")
702 {
703 $result->addError(new Error(Loc::getMessage("VOTE_QUESTION_EMPTY", array("#NUMBER#" => $key)), "QUESTION_".$key));
704 }
705 else if (empty($question["ANSWERS"]))
706 {
707 $result->addError(new Error(Loc::getMessage("VOTE_ANSWERS_EMPTY", array("#QUESTION#" => HtmlFilter::encode($question["QUESTION"]))), "QUESTION_".$key));
708 }
709 else
710 {
711 foreach ($savedAnswers as $answer)
712 {
713 $question["ANSWERS"][] = $answer + array("DEL" => "Y");
714 }
715 $questions[] = $question;
716 unset($questionsToRevise[$question["ID"]]);
717 }
718 }
719 if (!$result->isSuccess())
720 {
721 throw new ArgumentException(implode("", $result->getErrorMessages()));
722 }
723 foreach ($questionsToRevise as $question)
724 {
725 $questions[] = $question + array("DEL" => "Y");
726 }
727 $data += array("QUESTIONS" => $questions);
728 return true;
729 }
730
737 public static function saveData($voteId, array $data)
738 {
739 if (!($voteId > 0) && empty($data["QUESTIONS"]))
740 {
741 return 0;
742 }
743 if ($voteId)
744 {
745 $result = VoteTable::update($voteId, $data);
746 }
747 else
748 {
749 unset($data['ID']);
750 $result = VoteTable::add($data);
751 if ($result->isSuccess())
752 $voteId = $result->getId();
753 }
754 if (!$result->isSuccess())
755 throw new ArgumentException(implode("", $result->getErrorMessages()));
756 else if ($result instanceof UpdateResult)
757 $vote = static::getData($voteId);
758 else
759 $vote = \Bitrix\Vote\VoteTable::getById($voteId)->fetch();
760 $vote += ["QUESTIONS" => []];
761 /************** Check Data *****************************************/
762 $iQuestions = 0;
763 foreach ($data["QUESTIONS"] as $question)
764 {
765 $savedAnswers = array();
766 if ($question["ID"] > 0 && array_key_exists($question["ID"], $vote["QUESTIONS"]))
767 {
768 $savedAnswers = $vote["QUESTIONS"][$question["ID"]]["ANSWERS"];
769 unset($vote["QUESTIONS"][$question["ID"]]);
770 if (isset($question["DEL"]) && $question["DEL"] === "Y")
771 {
772 \CVoteQuestion::Delete($question["ID"]);
773 continue;
774 }
775 $question["C_SORT"] = (++$iQuestions) * 10;
776 \CVoteQuestion::Update($question["ID"], $question);
777 }
778 else
779 {
780 $question["C_SORT"] = (++$iQuestions) * 10;
781 $question["VOTE_ID"] = $vote["ID"];
782 $question["ID"] = \CVoteQuestion::Add($question);
783 if ($question["ID"] <= 0)
784 continue;
785 }
786 $iAnswers = 0;
787 foreach ($question["ANSWERS"] as $answer)
788 {
789 if (!empty($answer["ID"]) && array_key_exists($answer["ID"], $savedAnswers))
790 {
791 unset($savedAnswers[$answer["ID"]]);
792 if ($answer["DEL"] == "Y")
793 {
794 \CVoteAnswer::Delete($answer["ID"]);
795 continue;
796 }
797 $answer["C_SORT"] = (++$iAnswers)* 10;
798 \CVoteAnswer::Update($answer["ID"], $answer);
799 }
800 else
801 {
802 $answer["QUESTION_ID"] = $question["ID"];
803 $answer["C_SORT"] = (++$iAnswers) * 10;
804 $answer["ID"] = intval(\CVoteAnswer::Add($answer));
805 if ($answer["ID"] <= 0)
806 continue;
807 }
808 }
809 if ($iAnswers <= 0)
810 {
811 \CVoteQuestion::Delete($question["ID"]);
812 $iQuestions--;
813 }
814 else if (!empty($savedAnswers))
815 {
816 while ($answer = array_pop($savedAnswers))
817 \CVoteAnswer::Delete($answer["ID"]);
818 }
819 }
820 if ($iQuestions <= 0)
821 {
822 Vote::delete($vote["ID"]);
823 $vote["ID"] = 0;
824 }
825 return $vote["ID"];
826 }
827
835 public function sendVotingMessage(array $event, $vote, $type = "im")
836 {
837 if ($type == "im" && \Bitrix\Main\Loader::includeModule("im"))
838 {
839 $url = "";
840 if (!empty($vote["URL"]))
841 {
842 if (defined("SITE_SERVER_NAME"))
843 {
844 $url = SITE_SERVER_NAME;
845 }
846 $url = (!empty($url) ? $url : \COption::GetOptionString("main", "server_name"));
847 if (!empty($url))
848 {
849 $url = (\CMain::IsHTTPS() ? "https" : "http") . "://" . $url . $vote["URL"];
850 }
851 }
852
853 // send notification
854 $gender = "";
855 if ($event["VISIBLE"] === "Y" && $this->getUser()->getParam("PERSONAL_GENDER") === "F")
856 {
857 $gender = "_F";
858 }
859 $res = array(
860 "MESSAGE_TYPE" => IM_MESSAGE_SYSTEM,
861 "TO_USER_ID" => $vote["AUTHOR_ID"],
862 "FROM_USER_ID" => ( $event["VISIBLE"] === "Y" ? $this->getUser()->getId() : 0),
863 "NOTIFY_TYPE" => IM_NOTIFY_FROM,
864 "NOTIFY_MODULE" => "vote",
865 "NOTIFY_EVENT" => "voting",
866 "NOTIFY_TAG" => "VOTING|" . $vote["ID"],
867 "NOTIFY_MESSAGE" => (!empty($vote["URL"])
868 ? fn (?string $languageId = null) => Loc::getMessage(
869 "V_NOTIFY_MESSAGE_HREF" . $gender,
870 array("#VOTE_TITLE#" => $vote["TITLE"], "#VOTE_URL#" => $vote["URL"]),
871 $languageId
872 )
873 : fn (?string $languageId = null) => Loc::getMessage(
874 "V_NOTIFY_MESSAGE" . $gender,
875 array("#VOTE_TITLE#" => $vote["TITLE"]),
876 $languageId
877 )
878 ),
879 "NOTIFY_MESSAGE_OUT" => (!empty($url)
880 ? fn (?string $languageId = null) => Loc::getMessage(
881 "V_NOTIFY_MESSAGE_OUT_HREF" . $gender,
882 array("#VOTE_TITLE#" => $vote["TITLE"], "#VOTE_URL#" => $url),
883 $languageId
884 )
885 : fn (?string $languageId = null) => Loc::getMessage(
886 "V_NOTIFY_MESSAGE" . $gender,
887 array("#VOTE_TITLE#" => $vote["TITLE"]),
888 $languageId
889 )
890 )
891 );
892 \CIMNotify::Add($res);
893 }
894 else
895 {
896 $channel = $this->getChannel();
897 // send e-mail
898 $dbUser = \CUser::getById($vote["AUTHOR_ID"]);
899 if ($dbUser && ($u = $dbUser->Fetch()) && !empty($u["EMAIL"]))
900 {
901 $eventFields = array(
902 "EMAIL_TO" => $u["EMAIL"],
903 "VOTE_STATISTIC" => "",
904 "ID" => $event["EVENT_ID"],
905 "TIME" => GetTime(time(), "FULL"),
906 "VOTE_TITLE" => $vote["TITLE"],
907 "VOTE_DESCRIPTION" => $vote["DESCRIPTION"],
908 "VOTE_ID" => $vote["ID"],
909 "VOTE_COUNTER" => $vote["COUNTER"],
910 "URL" => $vote["URL"],
911 "CHANNEL" => $channel["TITLE"],
912 "CHANNEL_ID" => $channel["ID"],
913 "VOTER_ID" => $event["VOTE_USER_ID"],
914 "USER_NAME" => ($event["VISIBLE"] == "Y" ? $this->getUser()->getFullName() : "Hidden"),
915 "LOGIN" => ($event["VISIBLE"] == "Y" ? $this->getUser()->getLogin() : "hidden"),
916 "USER_ID" => ($event["VISIBLE"] == "Y" ? $this->getUser()->getID() : 0),
917 "STAT_GUEST_ID" => intval($_SESSION["SESS_GUEST_ID"]),
918 "SESSION_ID" => intval($_SESSION["SESS_SESSION_ID"]),
919 "IP" => \Bitrix\Main\Context::getCurrent()->getServer()->get("REMOTE_ADDR")
920 );
921 $eventFields["USER_NAME"] = (!!$eventFields["USER_NAME"] && $event["VISIBLE"] == "Y" ? $eventFields["USER_NAME"] : $eventFields["LOGIN"]);
922 // VOTE_STATISTIC
923 $text = array();
924 foreach ($this["QUESTIONS"] as $question)
925 {
926 if (array_key_exists($question["ID"], $event["BALLOT"]))
927 {
928 $text[$question["ID"]] = array();
929 foreach ($question["ANSWERS"] as $answer)
930 {
931 if (array_key_exists($answer["ID"], $event["BALLOT"][$question["ID"]]["ANSWERS"]))
932 {
933 if (($answer["FIELD_TYPE"] == \Bitrix\Vote\AnswerTypes::TEXT || $answer["FIELD_TYPE"] == \Bitrix\Vote\AnswerTypes::TEXTAREA) &&
934 $event["BALLOT"][$question["ID"]]["ANSWERS"][$answer["ID"]]["MESSAGE"] !== "")
935 {
936 $text[$question["ID"]][] = $event["BALLOT"][$question["ID"]]["ANSWERS"][$answer["ID"]]["MESSAGE"];
937 }
938 else
939 {
940 $text[$question["ID"]][] = $answer["MESSAGE"];
941 }
942 }
943 }
944 if (!empty($text[$question["ID"]]))
945 {
946 $text[$question["ID"]] = " - " . $question["QUESTION"] . "\n - " . implode(", ", $text[$question["ID"]]);
947 }
948 else
949 {
950 $text[$question["ID"]] = " - " . $question["QUESTION"] . "\n - ...\n";
951 }
952 }
953 }
954 $eventFields["VOTE_STATISTIC"] = "\n" . implode("\n\n", $text);
955 $arrSites = \CVoteChannel::GetSiteArray($channel["ID"]);
956 \CEvent::Send("VOTE_FOR", $arrSites, $eventFields, "N");
957 }
958 }
959
960 return true;
961 }
962
967 public function fillStatistic()
968 {
969 foreach ($this->questions as &$qs)
970 foreach ($qs["ANSWERS"] as &$as)
971 $as["STAT"] = array();
972
973 $dbRes = \Bitrix\Vote\EventTable::getList(array(
974 "select" => array(
975 "V_" => "*",
976 "Q_" => "QUESTION.*",
977 "A_" => "QUESTION.ANSWER.*",
978 "U_ID" => "USER.USER.ID",
979 "U_NAME" => "USER.USER.NAME",
980 "U_LAST_NAME" => "USER.USER.LAST_NAME",
981 "U_SECOND_NAME" => "USER.USER.SECOND_NAME",
982 "U_LOGIN" => "USER.USER.LOGIN",
983 "U_PERSONAL_PHOTO" => "USER.USER.PERSONAL_PHOTO",
984 ),
985 "filter" => array("VOTE_ID" => $this->id, "VALID" => "Y"),
986 "order" => array(
987 "USER.USER.LAST_NAME" => "ASC",
988 "USER.USER.NAME" => "ASC",
989 "USER.USER.LOGIN" => "ASC"
990 )
991 ));
992 while ($dbRes && ($res = $dbRes->fetch()))
993 {
994 if (array_key_exists($res["Q_QUESTION_ID"], $this->questions) &&
995 array_key_exists($res["A_ANSWER_ID"], $this->questions[$res["Q_QUESTION_ID"]]["ANSWERS"]))
996 {
997 $stat = &$this->questions[$res["Q_QUESTION_ID"]]["ANSWERS"][$res["A_ANSWER_ID"]]["STAT"];
998 $result = array(
999 "USER" => array(
1000 "ID" => 0,
1001 ),
1002 "MESSAGE" => $res["A_MESSAGE"]
1003 );
1004 if ($this["ANONYMITY"] !== \Bitrix\Vote\Vote\Anonymity::ANONYMOUSLY &&
1005 $res["V_VISIBLE"] == "Y" && $res["U_ID"] > 0)
1006 {
1007 $result["USER"] = array(
1008 "ID" => $res["U_ID"],
1009 "NAME" => $res["U_NAME"],
1010 "LAST_NAME" => $res["U_LAST_NAME"],
1011 "SECOND_NAME" => $res["U_SECOND_NAME"],
1012 "LOGIN" => $res["U_LOGIN"],
1013 "PERSONAL_PHOTO" => $res["U_PERSONAL_PHOTO"],
1014 );
1015 }
1016 $stat[$res["A_ID"]] = $result;
1017 }
1018 }
1019 }
1020
1021 public function getStatistic() {
1022 $dbRes = \Bitrix\Vote\EventTable::getList(array(
1023 "select" => array(
1024 "V_" => "*",
1025 "Q_" => "QUESTION.*",
1026 "A_" => "QUESTION.ANSWER.*",
1027 "U_ID" => "USER.USER.ID",
1028 "U_NAME" => "USER.USER.NAME",
1029 "U_LAST_NAME" => "USER.USER.LAST_NAME",
1030 "U_SECOND_NAME" => "USER.USER.SECOND_NAME",
1031 "U_PERSONAL_PHOTO" => "USER.USER.PERSONAL_PHOTO",
1032 ),
1033 "filter" => array("VOTE_ID" => $this->id, "VALID" => "Y"),
1034 "order" => array(
1035 "USER.USER.LAST_NAME" => "ASC",
1036 "USER.USER.NAME" => "ASC",
1037 "USER.USER.LOGIN" => "ASC"
1038 )
1039 ));
1040 $result = [];
1041 while ($dbRes && ($res = $dbRes->fetch()))
1042 {
1043 if (!array_key_exists($res["V_ID"], $result))
1044 {
1045 $result[$res["V_ID"]] = [
1046 "ID" => $res["V_ID"],
1047 "DATE" => $res["V_DATE_VOTE"],
1048 "VISIBLE" => ($this["ANONYMITY"] !== \Bitrix\Vote\Vote\Anonymity::ANONYMOUSLY &&
1049 $res["V_VISIBLE"] == "Y" ? "Y" : "N"),
1050 "BALLOT" => [],
1051 "USER" => ["ID" => 0]
1052 ];
1053 if ($result[$res["V_ID"]]["VISIBLE"] == "Y" && $res["U_ID"] > 0)
1054 {
1055 $result[$res["V_ID"]]["USER"] = array(
1056 "ID" => $res["U_ID"],
1057 "NAME" => $res["U_NAME"],
1058 "LAST_NAME" => $res["U_LAST_NAME"],
1059 "SECOND_NAME" => $res["U_SECOND_NAME"],
1060 "LOGIN" => $res["U_LOGIN"] ?? null,
1061 "PERSONAL_PHOTO" => $res["U_PERSONAL_PHOTO"],
1062 );
1063 }
1064 }
1065 $ballot = &$result[$res["V_ID"]]["BALLOT"];
1066 if (!array_key_exists($res["Q_QUESTION_ID"], $ballot))
1067 {
1068 $ballot[$res["Q_QUESTION_ID"]] = [];
1069 }
1070 $ballot[$res["Q_QUESTION_ID"]][$res["A_ANSWER_ID"]] = trim($res["A_MESSAGE"]);
1071 }
1072 return $result;
1073 }
1074
1077 public function getChannel()
1078 {
1079 if ($this->channel === null)
1080 {
1081 $this->channel = array();
1082 $db = Channel::getList(array());
1083 while (($res = $db->fetch()) && $res)
1084 {
1085 if ($this->vote["CHANNEL_ID"] == $res["ID"])
1086 {
1087 $this->channel = $res;
1088 break;
1089 }
1090 }
1091 }
1092 return $this->channel;
1093 }
1094
1099 public function get($key): mixed
1100 {
1101 return $this->vote[$key] ?? null;
1102 }
1103
1109 public function getQuestion(int $id)
1110 {
1111 if (array_key_exists($id, $this->questions))
1112 return $this->questions[$id];
1113 return null;
1114 }
1115
1118 public function getQuestions()
1119 {
1120 return $this->questions;
1121 }
1122
1127 public function resume()
1128 {
1129 VoteTable::update($this->id, ["DATE_END" => (new DateTime())->add("1Y")]);
1130 $this->clearCache();
1131 }
1132
1137 public function stop()
1138 {
1139 VoteTable::update($this->id, ["DATE_END" => new DateTime()]);
1140 $this->clearCache();
1141 }
1142
1148 public static function delete($id)
1149 {
1150 // @todo delete all attaches
1151 return \CVote::Delete($id);
1152 }
1153
1158 public function clearCache()
1159 {
1160 global $VOTE_CACHE;
1161 unset($VOTE_CACHE["VOTE"][$this->id]);
1162 unset(self::$storage[$this->id]);
1163 unset(self::$canVoteStorage[$this->id]);
1164 }
1165
1169 private function clearVotingCache()
1170 {
1171 global $VOTE_CACHE;
1172 unset($VOTE_CACHE["VOTE_CACHE_VOTING"][$this->id]);
1173 unset(self::$canVoteStorage[$this->id]);
1174 }
1175
1181 public function exportExcel($type = "html")
1182 {
1183 global $APPLICATION;
1184 $nameTemplate = Context::getCurrent()->getCulture()->getFormatName();
1185 $dateTemplate = \Bitrix\Main\Type\DateTime::getFormat();
1186
1187 $APPLICATION->restartBuffer();
1188 while(ob_get_clean());
1189 header("Content-Transfer-Encoding: binary");
1190
1191 $statistic = $this->getStatistic();
1192 $table1 = ["body" => []];
1193 $table2 = [
1194 "head" => [Loc::getMessage("V_EXPORT_DATE"), Loc::getMessage("V_EXPORT_NAME")],
1195 "body" => []
1196 ];
1197
1198 foreach ($statistic as $event)
1199 {
1200 $user = Loc::getMessage("VOTE_GUEST");
1201 if ($event["VISIBLE"] !== "Y")
1202 {
1203 $user = Loc::getMessage("VOTE_ANONYMOUSLY");
1204 }
1205 else if ($event["USER"]["ID"] > 0)
1206 {
1207 $user = \CUser::formatName($nameTemplate, $event["USER"], true, false);
1208 }
1209 /*@var \Bitrix\Main\Type\DateTime $event["DATE"] */
1210 $row = [
1211 "DATE" => $event["DATE"]->toUserTime()->format($dateTemplate),
1212 "USER" => $user
1213 ];
1214
1215 foreach ($this->questions as $questionId => $question)
1216 {
1217 $answerMessage = [];
1218 if (array_key_exists($questionId, $event["BALLOT"]))
1219 {
1220 foreach ($question["ANSWERS"] as $answerId => $answer)
1221 {
1222 if (array_key_exists($answerId, $event["BALLOT"][$questionId]))
1223 {
1224 if (!array_key_exists("STAT", $this->questions[$questionId]["ANSWERS"][$answerId]))
1225 $this->questions[$questionId]["ANSWERS"][$answerId]["STAT"] = [];
1226 $stat = &$this->questions[$questionId]["ANSWERS"][$answerId]["STAT"];
1227 if ($event["BALLOT"][$questionId][$answerId] <> '')
1228 {
1229 $stat[$event["ID"]] = $row["USER"]." (".$event["BALLOT"][$questionId][$answerId].")";
1230 $answerMessage[] = $event["BALLOT"][$questionId][$answerId];
1231 }
1232 else
1233 {
1234 $answerMessage[] = $answer["MESSAGE"];
1235 $stat[$event["ID"]] = $row["USER"];
1236 }
1237 }
1238 }
1239 }
1240 $row[] = implode(", ", $answerMessage);
1241 }
1242 $table2["body"][] = array_values($row);
1243 }
1244 foreach ($this->questions as $questionId => $question)
1245 {
1246 $table1["body"][] = [$question["QUESTION"], "", "", ""];
1247 foreach ($question["ANSWERS"] as $answerId => $answer)
1248 {
1249 $table1["body"][] = ["", $answer["MESSAGE"], $answer["COUNTER"], (array_key_exists("STAT", $answer) ? implode(", ", $answer["STAT"]) : "")];
1250 }
1251 $table2["head"][] = $question["QUESTION"];
1252 }
1253
1254 if ($type === "csv")
1255 {
1256 Header("Content-Type: ". MimeType::getByFileExtension("csv"));
1257 header("Content-Disposition: attachment;filename=vote".$this->id.".csv");
1258
1259 $f = fopen("php://output", "w");
1260 fputcsv($f, $table2["head"], ';');
1261 foreach ($table2["body"] as $row) {
1262 fputcsv($f, $row, ';');
1263 }
1264 fclose($f);
1265 }
1266 else
1267 {
1268 $mess = [
1269 "GENERAL_INFO" => Loc::getMessage("V_EXPORT_GENERAL_INFO"),
1270 "STATISTIC" => Loc::getMessage("V_EXPORT_STATISTIC")
1271 ];
1272 if ($type === "xls")
1273 {
1274 $bodyRows = [];
1275 foreach ($table1["body"] as $row)
1276 {
1277 $bodyRows[] = implode("</Data></Cell><Cell ss:StyleID=\"bold\"><Data ss:Type=\"String\">", $row);
1278 }
1279 $table1["body"] = implode("</Data></Cell></Row><Row><Cell><Data ss:Type=\"String\">", $bodyRows);
1280
1281 $table2["head"] = implode("</Data></Cell><Cell ss:StyleID=\"bold\"><Data ss:Type=\"String\">", $table2["head"]);
1282 $bodyRows = [];
1283 foreach ($table2["body"] as $row)
1284 {
1285 $bodyRows[] = implode("</Data></Cell><Cell ss:StyleID=\"bold\"><Data ss:Type=\"String\">", $row);
1286 }
1287 $table2["body"] = implode("</Data></Cell></Row><Row><Cell><Data ss:Type=\"String\">", $bodyRows);
1288 $LANG_CHARSET = LANG_CHARSET;
1289
1290 $res = <<<XML
1291<?xml version="1.0" charset="{$LANG_CHARSET}"?>
1292<?mso-application progid="Excel.Sheet"?>
1293<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
1294 <Styles>
1295 <Style ss:ID="bold">
1296 <Font ss:Bold="1"/>
1297 </Style>
1298 </Styles>
1299 <Worksheet ss:Name="{$mess["GENERAL_INFO"]}">
1300 <Table>
1301 <Row>
1302 <Cell><Data ss:Type="String">{$table1["body"]}</Data></Cell>
1303 </Row>
1304 </Table>
1305 </Worksheet>
1306 <Worksheet ss:Name="{$mess["STATISTIC"]}">
1307 <Table>
1308 <Row>
1309 <Cell ss:StyleID="bold"><Data ss:Type="String">{$table2["head"]}</Data></Cell>
1310 </Row>
1311 <Row>
1312 <Cell><Data ss:Type="String">{$table2["body"]}</Data></Cell>
1313 </Row>
1314 </Table>
1315 </Worksheet>
1316</Workbook>
1317XML;
1318 }
1319 else
1320 {
1321 $LANG_CHARSET = LANG_CHARSET;
1322
1323 $bodyRows = [];
1324 foreach ($table1["body"] as $row)
1325 {
1326 $bodyRows[] = implode("</td><td>", $row);
1327 }
1328 $table1["body"] = implode("</td></tr><tr><td>", $bodyRows);
1329
1330 $table2["head"] = implode("</th><th>", $table2["head"]);
1331 $bodyRows = [];
1332 foreach ($table2["body"] as $row)
1333 {
1334 $bodyRows[] = implode("</td><td>", $row);
1335 }
1336 $table2["body"] = implode("</td></tr><tr><td>", $bodyRows);
1337
1338 $res = <<<HTML
1339<meta http-equiv="Content-type" content="text/html;charset={$LANG_CHARSET}" />
1340<p>
1341<table border="1">
1342 <tbody>
1343 <tr><td>{$table1["body"]}</td></tr>
1344 </tbody>
1345</table>
1346</p>
1347<p>
1348<table border="1">
1349 <thead><tr><th>{$table2["head"]}</th></tr></thead>
1350 <tbody><tr><td>{$table2["body"]}</td></tr></tbody>
1351</table>
1352</p>
1353HTML;
1354 }
1355 header("Content-Type: ". MimeType::getByFileExtension("xls"));
1356 header("Content-Disposition: attachment;filename=vote".$this->id.".xls");
1357 echo $res;
1358 }
1359 \CMain::finalActions();
1360 die();
1361 }
1362
1363 private function getDataFromRequest(array $request)
1364 {
1366 if ($res !== null)
1367 {
1368 $data = $res;
1369 }
1370 else
1371 {
1372 $questions = $this->getQuestions();
1373 $data = ["EXTRAS" => [], "BALLOT" => [], "MESSAGE" => []];
1374
1375 foreach ($questions as $question)
1376 {
1377 $data["BALLOT"][$question["ID"]] = array();
1378 foreach ($question["ANSWERS"] as $answer)
1379 {
1380 $fieldType = (
1381 $question["FIELD_TYPE"] == \Bitrix\Vote\QuestionTypes::COMPATIBILITY ||
1382 $answer["FIELD_TYPE"] == AnswerTypes::TEXTAREA || $answer["FIELD_TYPE"] == AnswerTypes::TEXT ?
1383 $answer["FIELD_TYPE"] : $question["FIELD_TYPE"]);
1384
1385 switch ($fieldType)
1386 {
1387 case AnswerTypes::RADIO :
1389 $fieldName = ($fieldType == AnswerTypes::RADIO ? "vote_radio_" : "vote_dropdown_").$question["ID"];
1390 if ($request[$fieldName] == $answer["ID"])
1391 $data["BALLOT"][$question["ID"]][$answer["ID"]] = true;
1392 break;
1395 $fieldName = ($fieldType == AnswerTypes::CHECKBOX ? "vote_checkbox_" : "vote_multiselect_").$question["ID"];
1396 if (array_key_exists($fieldName, $request) && is_array($request[$fieldName]) && in_array($answer["ID"], $request[$fieldName]))
1397 $data["BALLOT"][$question["ID"]][$answer["ID"]] = true;
1398 break;
1399 default :
1400 $fieldName = ($answer["FIELD_TYPE"] == AnswerTypes::TEXT ? "vote_field_" : "vote_memo_") . $answer["ID"];
1401 $value = trim($request[$fieldName]);
1402 if ($value <> '')
1403 {
1404 if (!array_key_exists($question["ID"], $data["MESSAGE"]))
1405 $data["MESSAGE"][$question["ID"]] = [];
1406 $data["MESSAGE"][$question["ID"]][$answer["ID"]] = $value;
1407 $data["BALLOT"][$question["ID"]][$answer["ID"]] = true;
1408 }
1409 break;
1410 }
1411 }
1412 }
1413 }
1414 return $data;
1415 }
1434 public function voteFor(array $request, $params = [])
1435 {
1436 return $this->registerEvent($this->getDataFromRequest($request), $params, User::getCurrent());
1437 }
1438
1439 public function registerEvent(array $data, array $params, \Bitrix\Vote\User $user)
1440 {
1441 if ($this["LAMP"] == "red")
1442 {
1443 throw new AccessDeniedException(Loc::getMessage("VOTE_IS_NOT_ACTIVE"));
1444 }
1445 $voteId = $this->getId();
1446 if ($user->lock($voteId) !== true)
1447 {
1448 throw new AccessDeniedException(Loc::getMessage("VOTE_IS_OCCUPIED"));
1449 }
1450
1451 $userId = $user->getId();
1452
1453 $this->errorCollection->clear();
1454
1456 if (!isset($params["revote"]) || $params["revote"] != true)
1457 {
1458 $result = $this->canVote($user);
1459 }
1460 //region Delete event If It is possible
1461 else if (
1462 ($result = $this->canRevote($user))
1463 && $result->isSuccess()
1464 && !empty($result->getData())
1465 && ($eventIdsToDelete = array_column($result->getData(), 'ID'))
1466 && !empty($eventIdsToDelete)
1467 )
1468 {
1469 $this->deleteEvents($eventIdsToDelete, $userId);
1470 $result = $this->canVote($user);
1471 }
1472 //endregion
1473
1474 if (!$result->isSuccess())
1475 {
1476 $this->errorCollection->add($result->getErrors());
1477 }
1478 else
1479 {
1480 $event = new \Bitrix\Vote\Event($this);
1484 $eventFields = array(
1485 "VOTE_USER_ID" => $user->setVotedUserId(true),
1486 "DATE_VOTE" => (new DateTime()),
1487 "STAT_SESSION_ID" => $_SESSION["SESS_SESSION_ID"] ?? null,
1488 "IP" => \Bitrix\Main\Context::getCurrent()->getServer()->get("REMOTE_ADDR"),
1489 "VALID" => "Y",
1490 "VISIBLE" => ($this["ANONYMITY"] == \Bitrix\Vote\Vote\Anonymity::ANONYMOUSLY ? "N" : "Y") // can be replaced from $data array ["EXTRAS"]["HIDDEN"] = "Y"
1491 );
1492 if (!$event->check($data)
1493 || !($eventResult = $event->add($eventFields, $data))
1494 )
1495 {
1496 $this->errorCollection->add($event->getErrors());
1497 }
1498 else
1499 {
1500 $this->vote["COUNTER"]++;
1501 foreach ($eventResult->get("BALLOT") as $questionId => $question)
1502 {
1503 $this->questions[$questionId]["COUNTER"]++;
1504 foreach ($question["ANSWERS"] as $answerId => $answerEventParams)
1505 {
1506 $this->questions[$questionId]["ANSWERS"][$answerId]["COUNTER"]++;
1507 }
1508 }
1509 foreach ($this->questions as $questionId => $question)
1510 {
1511 foreach ($question["ANSWERS"] as $answerId => $answerEventParams)
1512 {
1513 if ($this->questions[$questionId]["ANSWERS"][$answerId]["COUNTER"] > 0)
1514 {
1515 $this->questions[$questionId]["ANSWERS"][$answerId]["~PERCENT"] =
1516 $this->questions[$questionId]["ANSWERS"][$answerId]["COUNTER"] * 100 /
1517 $this->questions[$questionId]["COUNTER"];
1518 $this->questions[$questionId]["ANSWERS"][$answerId]["PERCENT"] = round($this->questions[$questionId]["ANSWERS"][$answerId]["~PERCENT"], 2);
1519 }
1520 else
1521 {
1522 $this->questions[$questionId]["ANSWERS"][$answerId]["~PERCENT"] = 0;
1523 $this->questions[$questionId]["ANSWERS"][$answerId]["PERCENT"] = 0;
1524 }
1525 }
1526 }
1527 self::$statStorage[] = $voteId;
1528 $_SESSION["VOTE"]["VOTES"][$voteId] = $eventResult->get("EVENT_ID");
1529 // statistic module
1530 if (\Bitrix\Main\Loader::includeModule("statistic"))
1531 {
1532 $event3 = $this["EVENT3"];
1533 if (empty($event3))
1534 {
1535 $event3 = (\Bitrix\Main\Context::getCurrent()->getRequest()->isHttps() ? "https://" : "http://") .
1536 \Bitrix\Main\Context::getCurrent()->getServer()->getHttpHost() .
1537 "/bitrix/admin/vote_user_results.php?EVENT_ID=" . $eventResult->get("EVENT_ID") . "&lang=" . LANGUAGE_ID;
1538 }
1539 \CStatEvent::AddCurrent($this["EVENT1"], $this["EVENT2"], $event3);
1540 }
1541 // notification TODO replace this functional into other function
1542 if ($this["NOTIFY"] !== "N" && $this["AUTHOR_ID"] > 0 && $this["AUTHOR_ID"] != $userId)
1543 {
1544 self::sendVotingMessage($eventResult->toArray(), $this, ($this["NOTIFY"] == "I" ? "im" : "mail"));
1545 }
1546 $this->clearCache();
1547 /***************** Event onAfterVoting *****************************/
1548 foreach (GetModuleEvents("vote", "onAfterVoting", true) as $ev)
1549 {
1550 ExecuteModuleEventEx($ev, array($voteId, $eventResult->get("EVENT_ID"), $userId));
1551 }
1552 /***************** /Event ******************************************/
1553 }
1554 }
1555 $user->unlock($voteId);
1556 return $this->errorCollection->isEmpty();
1557 }
1558
1564 public function isVotedFor($userId)
1565 {
1566 $result = false;
1567 $user = ($userId instanceof User ? $userId : ($userId == $this->getUser()->getId() ? User::getCurrent() : User::loadFromId($userId)));
1568 $canVoteResult = $this->canVote($user);
1569 if (!$canVoteResult->isSuccess())
1570 {
1571 $result = 0;
1572 for (
1573 $canVoteResult->getErrorCollection()->rewind();
1574 $canVoteResult->getErrorCollection()->valid();
1575 $canVoteResult->getErrorCollection()->next()
1576 )
1577 {
1579 $error = $canVoteResult->getErrorCollection()->current();
1580 $result |= $error->getCode();
1581 }
1582 }
1583 return $result;
1584 }
1590 public function canRead($userId)
1591 {
1592 if (parent::canEdit($userId))
1593 return true;
1594 else if (parent::canRead($userId))
1595 {
1596 $groups = parent::loadUserGroups($userId);
1598 "select" => array("*"),
1599 "filter" => array(
1600 "ACTIVE" => "Y",
1601 "HIDDEN" => "N",
1602 ">=PERMISSION.PERMISSION" => 1,
1603 "PERMISSION.GROUP_ID" => $groups
1604 ),
1605 "order" => array(
1606 "TITLE" => "ASC"
1607 ),
1608 "group" => array("ID")
1609 ));
1610 while ($res = $dbRes->fetch())
1611 {
1612 if ($res["ID"] == $this->get("CHANNEL_ID"))
1613 return true;
1614 }
1615 }
1616 return false;
1617 }
1618
1624 public function canEdit($userId)
1625 {
1626 if (parent::canEdit($userId))
1627 return true;
1628 else if (parent::canRead($userId))
1629 {
1630 $groups = parent::loadUserGroups($userId);
1632 "select" => array("*"),
1633 "filter" => array(
1634 "ACTIVE" => "Y",
1635 "HIDDEN" => "N",
1636 ">=PERMISSION.PERMISSION" => 4,
1637 "PERMISSION.GROUP_ID" => $groups
1638 ),
1639 "order" => array(
1640 "TITLE" => "ASC"
1641 ),
1642 "group" => array("ID")
1643 ));
1644 while ($res = $dbRes->fetch())
1645 {
1646 if ($res["ID"] == $this->get("CHANNEL_ID"))
1647 return true;
1648 }
1649 }
1650 return false;
1651 }
1652
1653 public function canParticipate($userId)
1654 {
1655 return $this->canRead($userId) && $this->vote["LAMP"] == "green";
1656 }
1657
1666 public function canVote($user)
1667 {
1668 $vote = $this;
1669 $voteId = intval($vote["ID"]);
1670 if (!($user instanceof \Bitrix\Vote\User))
1671 {
1673 }
1674 if (!array_key_exists($voteId, self::$canVoteStorage))
1675 {
1676 self::$canVoteStorage[$voteId] = [];
1677 }
1678 if (array_key_exists($user->getId(), self::$canVoteStorage[$voteId]))
1679 {
1680 return self::$canVoteStorage[$voteId][$user->getId()];
1681 }
1682
1683 $uniqueType = intval($vote["UNIQUE_TYPE"]);
1684 $filterCard = 0;
1685
1686 $filter = ["LOGIC" => "OR"];
1687
1688 $result = new \Bitrix\Main\Result();
1689
1690 if ($uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_SESSION && is_array($_SESSION["VOTE"]["VOTES"]) && array_key_exists($voteId, $_SESSION["VOTE"]["VOTES"]))
1691 {
1692 $filter["ID"] = $_SESSION["VOTE"]["VOTES"][$voteId];
1694 $result->addError(new \Bitrix\Main\Error(Loc::getMessage("VOTE_ERROR_BY_SESSION"), \Bitrix\Vote\Vote\EventLimits::BY_SESSION));
1695 }
1696 if (($uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_COOKIE) && $user->getCookieId() > 0)
1697 {
1698 $filter["USER.COOKIE_ID"] = $user->getCookieId();
1700 }
1701 if ($uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_IP)
1702 {
1703 $delay = intval($vote["KEEP_IP_SEC"]);
1704 $filter[] = ([
1705 "IP" => \Bitrix\Main\Context::getCurrent()->getRequest()->getRemoteAddress()] +
1706 ($delay > 0 ? [
1707 ">=DATE_VOTE" => (new \Bitrix\Main\Type\DateTime())->add("-T".$delay."S")] : []));
1708 $filterCard |= \Bitrix\Vote\Vote\EventLimits::BY_IP;
1709 }
1710 if (
1711 $uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_USER_AUTH ||
1712 $uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_USER_DATE_REGISTER ||
1713 $uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_USER_ID)
1714 {
1715 if (!$user->getUser()->IsAuthorized())
1716 {
1718 $result->addError(new \Bitrix\Main\Error(Loc::getMessage("VOTE_ERROR_BY_USER_AUTH"), \Bitrix\Vote\Vote\EventLimits::BY_USER_AUTH));
1719 }
1720 else
1721 {
1722 if ($uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_USER_DATE_REGISTER)
1723 {
1724 $us = \CUser::GetByID($user->getId())->fetch();
1725 if (MakeTimeStamp($vote["DATE_START"]) < MakeTimeStamp($us["DATE_REGISTER"]))
1726 {
1727 $result->addError(new \Bitrix\Main\Error(Loc::getMessage("VOTE_ERROR_BY_USER_DATE_REGISTER"), \Bitrix\Vote\Vote\EventLimits::BY_USER_DATE_REGISTER));
1728 }
1729 }
1730 if ($uniqueType & \Bitrix\Vote\Vote\EventLimits::BY_USER_ID)
1731 {
1732 $filter["USER.AUTH_USER_ID"] = $user->getId();
1734 }
1735 }
1736 }
1737
1738 if ($filterCard > 0)
1739 {
1740 $dbRes = \Bitrix\Vote\EventTable::getList([
1741 "select" => [
1742 "*",
1743 "USER_COOKIE_ID" => "USER.COOKIE_ID",
1744 "USER_AUTH_USER_ID" => "USER.AUTH_USER_ID",
1745 ],
1746 "filter" => [
1747 "VOTE_ID" => $voteId,
1748 $filter
1749 ]
1750 ]);
1751 $data = $dbRes->fetchAll();
1752 $result->setData($data);
1753 foreach ($data as $res)
1754 {
1755 if (($filterCard & \Bitrix\Vote\Vote\EventLimits::BY_COOKIE) && $res["USER_COOKIE_ID"] == $user->getCookieId())
1756 {
1757 $result->addError(new \Bitrix\Main\Error(Loc::getMessage("VOTE_ERROR_BY_COOKIE"), \Bitrix\Vote\Vote\EventLimits::BY_COOKIE));
1759 }
1760 if (($filterCard & \Bitrix\Vote\Vote\EventLimits::BY_IP) && ($res["IP"] == \Bitrix\Main\Context::getCurrent()->getRequest()->getRemoteAddress()))
1761 {
1762 if ($vote["KEEP_IP_SEC"] > 0)
1763 {
1765 $res["DATE_VOTE"]->add("T".$vote["KEEP_IP_SEC"]."S");
1766 $result->addError(new \Bitrix\Main\Error(Loc::getMessage("VOTE_ERROR_BY_IP_2", ["#DATE#" => $res["DATE_VOTE"]->toString()]), \Bitrix\Vote\Vote\EventLimits::BY_IP));
1767 }
1768 else
1769 {
1770 $result->addError(new \Bitrix\Main\Error(Loc::getMessage("VOTE_ERROR_BY_IP"), \Bitrix\Vote\Vote\EventLimits::BY_IP));
1771 }
1772 $filterCard &= ~\Bitrix\Vote\Vote\EventLimits::BY_IP;
1773 }
1774 if (($filterCard & \Bitrix\Vote\Vote\EventLimits::BY_USER_ID) && ($res["USER_AUTH_USER_ID"] == $user->getId()))
1775 {
1776 $result->addError(new \Bitrix\Main\Error(Loc::getMessage("VOTE_ERROR_BY_USER_ID"), \Bitrix\Vote\Vote\EventLimits::BY_USER_ID));
1778 }
1779 if ($filterCard <= 0)
1780 break;
1781 }
1782 }
1783 self::$canVoteStorage[$voteId][$user->getId()] = $result;
1784 return $result;
1785 }
1786
1787 public function canRevote($user)
1788 {
1789 $canVoteResult = $this->canVote($user);
1790 $result = new \Bitrix\Main\Result();
1791 if ($canVoteResult->isSuccess() || (
1792 ($this["OPTIONS"] & Vote\Option::ALLOW_REVOTE) &&
1793 $canVoteResult->getErrorCollection()->getErrorByCode(\Bitrix\Vote\Vote\EventLimits::BY_USER_ID) &&
1794 $canVoteResult->getErrorCollection()->count() == 1
1795 ))
1796 {
1797 $result->setData($canVoteResult->getData());
1798 return $result;
1799 }
1800 return $canVoteResult;
1801 }
1802
1803 public function canReadResult($user)
1804 {
1805 $result = new \Bitrix\Main\Result();
1806
1807 if (!($user instanceof \Bitrix\Vote\User))
1808 {
1810 }
1811
1812 if ($this["AUTHOR_ID"] != $user->getId())
1813 {
1814 if ($this["OPTIONS"] & Vote\Option::HIDE_RESULT)
1815 {
1816 $result->addError(new Error("Access denied.", "Hidden results"));
1817 }
1818 else if ($this["LAMP"] == "green")
1819 {
1820 $canVoteResult = $this->canVote($user);
1821 if ($canVoteResult->isSuccess())
1822 $result->addError(new Error("Access denied.", "Hidden results"));
1823 }
1824 }
1825 return $result;
1826 }
1827
1832 public function offsetExists($offset)
1833 {
1834 if ($offset == "QUESTIONS")
1835 return true;
1836 return array_key_exists($offset, $this->vote);
1837 }
1838
1842 public function offsetGet($offset)
1843 {
1844 if (array_key_exists($offset, $this->vote))
1845 return $this->vote[$offset];
1846 else if ($offset == "QUESTIONS")
1847 return $this->questions;
1848 return null;
1849 }
1850
1857 public function offsetSet($offset, $value)
1858 {
1859 throw new \Bitrix\Main\NotSupportedException("Model provide ArrayAccess only for reading");
1860 }
1861
1867 public function offsetUnset($offset)
1868 {
1869 throw new \Bitrix\Main\NotSupportedException("Model provide ArrayAccess only for reading");
1870 }
1871
1872 public function recall(int $userId): \Bitrix\Main\Result
1873 {
1875 if ($user->lock($this->getId()) !== true)
1876 {
1877 return (new \Bitrix\Main\Result())
1878 ->addError(new Error(Loc::getMessage("VOTE_IS_OCCUPIED")))
1879 ;
1880 }
1881
1882 $canRevoteResult = $this->canRevote($userId);
1883 if (!$canRevoteResult->isSuccess())
1884 {
1885 $user->unlock($this->getId());
1886
1887 return $canRevoteResult;
1888 }
1889
1890 $eventIdsToDelete = array_column($canRevoteResult->getData(), 'ID');
1891 $this->deleteEvents($eventIdsToDelete, $userId);
1892
1893 $user->unlock($this->getId());
1894
1895 return new \Bitrix\Main\Result();
1896 }
1897
1898 private function deleteEvents(
1899 array $eventIdsToDelete,
1900 int $userId,
1901 ): void
1902 {
1903 if (!$this->id)
1904 {
1905 return;
1906 }
1907
1908 if (empty($eventIdsToDelete))
1909 {
1910 return;
1911 }
1912
1913 $dbRes = \Bitrix\Vote\EventTable::getList([
1914 "select" => [
1915 "V_" => "*",
1916 "Q_" => "QUESTION.*",
1917 "A_" => "QUESTION.ANSWER.*"],
1918 "filter" => [
1919 "VOTE_ID" => $this->id,
1920 "ID" => $eventIdsToDelete
1921 ],
1922 "order" => [
1923 "ID" => "ASC",
1924 "QUESTION.ID" => "ASC",
1925 "QUESTION.ANSWER.ID" => "ASC"]
1926 ]);
1927 if ($dbRes && ($res = $dbRes->fetch()))
1928 {
1929 if (\Bitrix\Main\Loader::includeModule("im"))
1930 {
1931 \CIMNotify::DeleteByTag("VOTING|{$this->getId()}", $userId);
1932 }
1933 $lastEventId = 0;
1934 $lastQuestionId = 0;
1935 do
1936 {
1937 if ($lastEventId < $res["V_ID"])
1938 {
1939 $lastEventId = $res["V_ID"];
1940 \Bitrix\Vote\Event::deleteEvent(intval($res["V_ID"]));
1941 $this->vote["COUNTER"] = max($this->vote["COUNTER"] - 1, 0);
1942 }
1943 if (array_key_exists($res["Q_QUESTION_ID"], $this->questions) &&
1944 array_key_exists($res["A_ANSWER_ID"], $this->questions[$res["Q_QUESTION_ID"]]["ANSWERS"]))
1945 {
1946 if ($lastQuestionId < $res["Q_ID"])
1947 {
1948 $lastQuestionId = $res["Q_ID"];
1949 $this->questions[$res["Q_QUESTION_ID"]]["COUNTER"] =
1950 max($this->questions[$res["Q_QUESTION_ID"]]["COUNTER"] - 1, 0)
1951 ;
1952 }
1953
1954 $questionId = $res["Q_QUESTION_ID"] ?? null;
1955 $answerId = $res["A_ANSWER_ID"] ?? null;
1956 $this->questions[$questionId]["ANSWERS"][$answerId]["COUNTER"] = max(
1957 $this->questions[$questionId]["ANSWERS"][$answerId]["COUNTER"] - 1,
1958 0);
1959
1960 $questionCounter = (int)($this->questions[$questionId]["COUNTER"] ?? 0);
1961 foreach ($this->questions[$questionId]["ANSWERS"] as $answerId => $answer)
1962 {
1963 $answerCounter = (int)($this->questions[$questionId]["ANSWERS"][$answerId]["COUNTER"] ?? 0);
1964 $percent = $answerCounter > 0 && $questionCounter > 0 ? $answerCounter * 100 / $questionCounter : 0;
1965
1966 $this->questions[$questionId]["ANSWERS"][$answerId]["~PERCENT"] = $percent;
1967 $this->questions[$questionId]["ANSWERS"][$answerId]["PERCENT"] = round($percent, 2);
1968 }
1969 }
1970 } while ($dbRes && ($res = $dbRes->fetch()));
1971 $this->clearCache();
1972 $this->clearVotingCache();
1973 }
1974 }
1975}
$connection
Определения actionsdefinitions.php:38
$type
Определения options.php:106
global $APPLICATION
Определения include.php:80
xml version
Определения yandex.php:67
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
Определения catalog_reindex.php:36
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static getInstance()
Определения application.php:98
Определения error.php:15
Определения event.php:5
static getInstance()
Определения eventmanager.php:31
static includeModule($moduleName)
Определения loader.php:67
static getFormat(Context\Culture $culture=null)
Определения date.php:264
static $storage
Определения answer.php:133
const CHECKBOX
Определения answertypes.php:16
const TEXT
Определения answertypes.php:19
const RADIO
Определения answertypes.php:15
const DROPDOWN
Определения answertypes.php:17
const TEXTAREA
Определения answertypes.php:20
const MULTISELECT
Определения answertypes.php:18
static loadFromId($id, $shouldBeNewIfIdIsNull=false)
Определения baseobject.php:141
static getList(array $parameters)
Определения channel.php:255
static getExtrasFieldName($id, $name)
Определения event.php:461
static getDataFromRequest($id, array $request)
Определения event.php:466
static getFieldName($id, $questionId)
Определения event.php:453
static $storage
Определения question.php:178
const COMPATIBILITY
Определения questiontypes.php:19
const RADIO
Определения questiontypes.php:15
Определения user.php:138
static getCurrent()
Определения user.php:312
const ANONYMOUSLY
Определения anonymity.php:17
const BY_USER_ID
Определения eventlimits.php:17
const BY_SESSION
Определения eventlimits.php:12
const BY_USER_DATE_REGISTER
Определения eventlimits.php:16
const BY_COOKIE
Определения eventlimits.php:13
const BY_USER_AUTH
Определения eventlimits.php:15
const HIDE_RESULT
Определения option.php:13
const ALLOW_REVOTE
Определения option.php:12
resume()
Определения vote.php:1127
getStatistic()
Определения vote.php:1021
canEdit($userId)
Определения vote.php:1624
exportExcel($type="html")
Определения vote.php:1181
__construct($id)
Определения vote.php:464
static $storage
Определения vote.php:461
offsetUnset($offset)
Определения vote.php:1867
offsetExists($offset)
Определения vote.php:1832
getChannel()
Определения vote.php:1077
sendVotingMessage(array $event, $vote, $type="im")
Определения vote.php:835
getQuestion(int $id)
Определения vote.php:1109
init()
Определения vote.php:471
static $canVoteStorage
Определения vote.php:460
$channel
Определения vote.php:458
static $statStorage
Определения vote.php:462
offsetGet($offset)
Определения vote.php:1842
stop()
Определения vote.php:1137
canRead($userId)
Определения vote.php:1590
canReadResult($user)
Определения vote.php:1803
$questions
Определения vote.php:457
$vote
Определения vote.php:456
fillStatistic()
Определения vote.php:967
static checkData(array &$data, $voteId=0)
Определения vote.php:643
getQuestions()
Определения vote.php:1118
clearCache()
Определения vote.php:1158
offsetSet($offset, $value)
Определения vote.php:1857
static saveData($voteId, array $data)
Определения vote.php:737
canParticipate($userId)
Определения vote.php:1653
canRevote($user)
Определения vote.php:1787
recall(int $userId)
Определения vote.php:1872
voteFor(array $request, $params=[])
Определения vote.php:1434
Определения vote.php:95
static onAfterAdd(\Bitrix\Main\ORM\Event $event)
Определения vote.php:217
static getMap()
Определения vote.php:112
static setCounter(array $id, $increment=true)
Определения vote.php:439
static onAfterUpdate(\Bitrix\Main\ORM\Event $event)
Определения vote.php:261
static getTableName()
Определения vote.php:101
static Add($arFields)
Определения answer.php:103
static Delete($ID, $QUESTION_ID=false, $VOTE_ID=false)
Определения answer.php:197
static Update($ID, $arFields)
Определения answer.php:151
static GetSiteArray($CHANNEL_ID)
Определения channel.php:329
static Update($ID, $arFields, $strUploadDir=false)
Определения question.php:155
static Add($arFields, $strUploadDir=false)
Определения question.php:108
static Delete($ID, $VOTE_ID=false)
Определения question.php:406
$str
Определения commerceml2.php:63
$f
Определения component_props.php:52
$data['IS_AVAILABLE']
Определения .description.php:13
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
<? if( $useEditor3):?>< tr class="heading">< td colspan="2"><? echo GetMessage("FILEMAN_OPTION_SPELL_SET");?></td ></tr ><? if(function_exists( 'pspell_config_create')):$use_pspell_checked=(COption::GetOptionString( $module_id, "use_pspell", "Y")=="Y") ? "checked" :"";?>< tr >< td valign="top">< label for="use_pspell"><?echo GetMessage("FILEMAN_OPTION_USE_PSPELL");?></label >< br >< a title="<?echo GetMessage("FILEMAN_OPTION_ADDISH_DICS_TITLE");?> http
Определения options.php:1473
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
$filter
Определения iblock_catalog_list.php:54
const IM_MESSAGE_SYSTEM
Определения include.php:21
const IM_NOTIFY_FROM
Определения include.php:37
const LANG_CHARSET
Определения include.php:65
$groups
Определения options.php:30
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
GetTime($timestamp, $type="SHORT", $site=false, $bSearchInSitesOnly=false)
Определения tools.php:1890
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
MakeTimeStamp($datetime, $format=false)
Определения tools.php:538
Определения aliases.php:105
Определения collection.php:2
$user
Определения mysql_to_pgsql.php:33
trait Error
Определения error.php:11
Определения anonymity.php:8
$time
Определения payment.php:61
$event
Определения prolog_after.php:141
if(empty($signedUserToken)) $key
Определения quickway.php:257
die
Определения quickway.php:367
$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
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$val
Определения options.php:1793
$eventManager
Определения include.php:412
$error
Определения subscription_card_product.php:20
$url
Определения iframe.php:7
$dbRes
Определения yandex_detail.php:168
$fields
Определения yandex_run.php:501