114 $now = Application::getInstance()->getConnection()->getSqlHelper()->getCurrentDateTimeFunction();
116 (
new IntegerField(
"ID", [
"primary" =>
true,
"autocomplete" =>
true])),
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"])),
123 (
new Reference(
"AUTHOR", \
Bitrix\
Main\UserTable::class, Join::on(
"this.AUTHOR_ID",
"ref.ID"))),
125 (
new DatetimeField(
"DATE_START", [
"default_value" =>
function(){
return new DateTime();},
"required" =>
true,
"validation" =>
function() {
128 [__CLASS__,
"validateActivityDate"]
131 (
new DatetimeField(
"DATE_END", [
"default_value" =>
function(){
135 },
"required" =>
true,
"validation" =>
function() {
138 [__CLASS__,
"validateActivityDate"]
145 (
new EnumField(
"DESCRIPTION_TYPE", [
"values" => [
"text",
"html"],
"default_value" =>
"text"])),
147 (
new Reference(
"IMAGE", FileTable::class, Join::on(
"this.IMAGE_ID",
"ref.ID"))),
151 (
new IntegerField(
"UNIQUE_TYPE", [
"default_value" => EventLimits::BY_IP|EventLimits::BY_USER_ID])),
152 (
new IntegerField(
"KEEP_IP_SEC", [
"default_value" => 604800])),
153 (
new IntegerField(
"OPTIONS", [
"default_value" => Option::ALLOW_REVOTE])),
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' ".
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"))),
175 public static function validateActivityDate($value, $primary, $row, $field)
180 $field, Loc::getMessage(
"VOTE_ERROR_DATE_VOTE_IS_EMPTY"), $field->getName()
193 $result = new \Bitrix\Main\ORM\EventResult();
194 if (($events =
GetModuleEvents(
"vote",
"onBeforeVoteAdd",
true)) && !empty($events))
198 foreach ($events as $ev)
202 $result->addError(
new EntityError(
"Error: ".serialize($ev),
"event"));
219 $id =
$event->getParameter(
"id");
220 $id = is_array($id) && array_key_exists(
"ID", $id) ? $id[
"ID"] : $id;
234 $result = new \Bitrix\Main\ORM\EventResult();
235 if (($events =
GetModuleEvents(
"vote",
"onBeforeVoteUpdate",
true)) && !empty($events))
239 $id =
$event->getParameter(
"id");
240 $id = is_array($id) && array_key_exists(
"ID", $id) ? $id[
"ID"] : $id;
241 foreach ($events as $ev)
263 $id =
$event->getParameter(
"id");
264 $id = is_array($id) && array_key_exists(
"ID", $id) ? $id[
"ID"] : $id;
282 if (isset(
$data[
"UNIQUE_TYPE"]) && (
289 foreach ([
"TIMESTAMP_X",
"DATE_START",
"DATE_END"] as
$key)
296 if (array_key_exists(
"IMAGE_ID",
$data))
298 if (
$str = \CFile::CheckImageFile(
$data[
"IMAGE_ID"]))
300 $result->addError(
new FieldError(static::getEntity()->getField(
"IMAGE_ID"),
$str));
305 $fields[
"IMAGE_ID"][
"MODULE_ID"] =
"vote";
306 if ($id =
$event->getParameter(
"id"))
308 $id = is_integer($id) ? $id : $id[
"ID"];
309 if ($id > 0 && ($vote = VoteTable::getById($id)->fetch()) && ($vote[
"IMAGE_ID"] > 0))
311 $fields[
"IMAGE_ID"][
"old_file"] = $vote[
"IMAGE_ID"];
314 if (\CFile::SaveForDB(
$fields,
"IMAGE_ID",
"") ===
false)
316 $result->unsetField(
"IMAGE_ID");
346 if (
$result instanceof AddResult)
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"]
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)
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"])
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))
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")
385 $result->addError(
new FieldError(
386 static::getEntity()->getField(
"DATE_START"),
387 Loc::getMessage(
"VOTE_ERROR_DATE_START_LATER_THAN_END")
390 else if (
$params[
"ACTIVE"] ==
"Y")
394 if ($channel[
"VOTE_SINGLE"] ==
"Y")
396 $dbRes = VoteTable::getList([
397 "select" => [
"ID",
"TITLE",
"DATE_START",
"DATE_END"],
398 "filter" => (is_null(
$params[
"ID"]) ? [] : [
400 "CHANNEL_ID" => $channel[
"ID"],
406 "<=DATE_START" =>
$params[
"DATE_START"],
407 ">=DATE_END" =>
$params[
"DATE_END"]
414 $field = static::getEntity()->getField(
"DATE_START");
415 $result->addError(
new FieldError(
417 Loc::getMessage(
"VOTE_ERROR_SAME_DATE_VOTE_IS_ALREADY_EXISTS", [
"#VOTE#" =>
$res[
"TITLE"].
" [".
$res[
"ID"].
"]"])
425 catch (\Exception $e)
445 $sql = intval($increment);
446 if ($increment ===
true)
448 else if ($increment ===
false)
450 $connection->queryExecute(
"UPDATE ".self::getTableName().
" SET COUNTER=".$sql.
" WHERE ID IN (".implode(
", ", $id).
")");
467 throw new \Bitrix\Main\ArgumentNullException(
"vote id");
468 parent::__construct(
$id);
473 $data = self::getData($this->
id);
476 $this->vote = array_diff_key(
$data,
array(
"QUESTIONS" =>
""));
477 foreach (
$data[
"QUESTIONS"] as $q)
479 $this->questions[$q[
"ID"]] = $q;
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"));
493 public static function getData($id)
495 if (!array_key_exists($id, self::$storage))
497 self::$storage[$id] =
null;
503 "Q_" =>
"QUESTION.*",
504 "A_" =>
"QUESTION.ANSWER",
507 "QUESTION.C_SORT" =>
"ASC",
508 "QUESTION.ID" =>
"ASC",
509 "QUESTION.ANSWER.C_SORT" =>
"ASC",
510 "QUESTION.ANSWER.ID" =>
"ASC",
517 if (($row =
$dbRes->fetch()) && $row)
522 if (mb_strpos(
$key,
"V_") === 0)
527 "QUESTIONS" =>
array());
528 if ($vote[
"IMAGE_ID"] > 0)
529 $images[$vote[
"IMAGE_ID"]] = &$vote[
"IMAGE"];
540 if (mb_strpos(
$key,
"A_") === 0)
543 if ($answer[
"IMAGE_ID"] > 0)
544 $images[$answer[
"IMAGE_ID"]] = &$answer[
"IMAGE"];
545 if ($answer[
"QUESTION_ID"] != $question[
"ID"])
551 if (mb_strpos(
$key,
"Q_") === 0)
552 $question[mb_substr(
$key, 2)] =
$val;
559 if ($question[
"IMAGE_ID"] > 0)
560 $images[$question[
"IMAGE_ID"]] = &$question[
"IMAGE"];
561 $vote[
"QUESTIONS"][$question[
"ID"]] = &$question;
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"]);
571 $answer[
"FIELD_NAME"] = $answer[
"MESSAGE_FIELD_NAME"];
575 $answer[
"FIELD_TYPE"] = $question[
"FIELD_TYPE"];
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;
581 }
while (($row =
$dbRes->fetch()) && $row);
584 if (
count($images) > 0)
586 $dbRes = \Bitrix\Main\FileTable::getList(
array(
"select" =>
array(
"*"),
"filter" =>
array(
"ID" => array_keys($images))));
594 foreach ($vote[
"QUESTIONS"] as $question)
596 $questionId = strval($question[
"ID"]);
599 foreach ($question[
"ANSWERS"] as $answer)
605 self::$storage[
$id] = $vote;
609 return self::$storage[
$id];
646 $questionsToRevise = [];
650 $vote = static::getData($voteId);
653 $questionsToRevise = (
$vote[
"QUESTIONS"] ?: []);
655 $questionsToSave = isset(
$data[
"QUESTIONS"]) && is_array(
$data[
"QUESTIONS"]) ?
$data[
"QUESTIONS"] : [];
656 unset(
$data[
"QUESTIONS"]);
657 VoteTable::checkFields(
$result, [
"ID" => $voteId],
$data);
662 foreach ($questionsToSave as
$key => $question)
664 if (($question[
"DEL"] ??
null) ==
"Y")
667 $question[
"ID"] = intval($question[
"ID"] ??
null);
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()));
675 $savedAnswers = ($question[
"ID"] > 0 ? $questionsToRevise[$question[
"ID"]][
"ANSWERS"] :
array());
676 $newAnswers =
array();
677 foreach ($question[
"ANSWERS"] as $keya => $answer)
679 $answer[
"ID"] = intval($answer[
"ID"] ??
null);
680 $answer[
"MESSAGE"] = trim($answer[
"MESSAGE"]);
681 if (($answer[
"DEL"] ??
null) !=
"Y" && $answer[
"MESSAGE"] !==
"")
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,
690 if (!array_key_exists($answer[
"ID"], $savedAnswers))
691 unset($answer[
"ID"]);
693 unset($savedAnswers[$answer[
"ID"]]);
694 $newAnswers[] = $answer;
697 $question[
"ANSWERS"] = $newAnswers;
699 if ($question[
"QUESTION"] ==
"" && empty($question[
"ANSWERS"]))
701 else if ($question[
"QUESTION"] ==
"")
705 else if (empty($question[
"ANSWERS"]))
707 $result->addError(
new Error(Loc::getMessage(
"VOTE_ANSWERS_EMPTY",
array(
"#QUESTION#" => HtmlFilter::encode($question[
"QUESTION"]))),
"QUESTION_".
$key));
711 foreach ($savedAnswers as $answer)
713 $question[
"ANSWERS"][] = $answer +
array(
"DEL" =>
"Y");
716 unset($questionsToRevise[$question[
"ID"]]);
723 foreach ($questionsToRevise as $question)
739 if (!($voteId > 0) && empty(
$data[
"QUESTIONS"]))
757 $vote = static::getData($voteId);
759 $vote = \Bitrix\Vote\VoteTable::getById($voteId)->fetch();
760 $vote += [
"QUESTIONS" => []];
763 foreach (
$data[
"QUESTIONS"] as $question)
765 $savedAnswers =
array();
766 if ($question[
"ID"] > 0 && array_key_exists($question[
"ID"],
$vote[
"QUESTIONS"]))
768 $savedAnswers =
$vote[
"QUESTIONS"][$question[
"ID"]][
"ANSWERS"];
769 unset(
$vote[
"QUESTIONS"][$question[
"ID"]]);
770 if (isset($question[
"DEL"]) && $question[
"DEL"] ===
"Y")
775 $question[
"C_SORT"] = (++$iQuestions) * 10;
780 $question[
"C_SORT"] = (++$iQuestions) * 10;
781 $question[
"VOTE_ID"] =
$vote[
"ID"];
783 if ($question[
"ID"] <= 0)
787 foreach ($question[
"ANSWERS"] as $answer)
789 if (!empty($answer[
"ID"]) && array_key_exists($answer[
"ID"], $savedAnswers))
791 unset($savedAnswers[$answer[
"ID"]]);
792 if ($answer[
"DEL"] ==
"Y")
797 $answer[
"C_SORT"] = (++$iAnswers)* 10;
802 $answer[
"QUESTION_ID"] = $question[
"ID"];
803 $answer[
"C_SORT"] = (++$iAnswers) * 10;
805 if ($answer[
"ID"] <= 0)
814 else if (!empty($savedAnswers))
816 while ($answer = array_pop($savedAnswers))
820 if ($iQuestions <= 0)
840 if (!empty(
$vote[
"URL"]))
842 if (defined(
"SITE_SERVER_NAME"))
844 $url = SITE_SERVER_NAME;
846 $url = (!empty(
$url) ?
$url : \COption::GetOptionString(
"main",
"server_name"));
849 $url = (\CMain::IsHTTPS() ?
"https" :
"http") .
"://" .
$url .
$vote[
"URL"];
855 if (
$event[
"VISIBLE"] ===
"Y" && $this->
getUser()->getParam(
"PERSONAL_GENDER") ===
"F")
861 "TO_USER_ID" =>
$vote[
"AUTHOR_ID"],
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,
873 : fn (?
string $languageId =
null) => Loc::getMessage(
874 "V_NOTIFY_MESSAGE" . $gender,
879 "NOTIFY_MESSAGE_OUT" => (!empty(
$url)
880 ? fn (?
string $languageId =
null) => Loc::getMessage(
881 "V_NOTIFY_MESSAGE_OUT_HREF" . $gender,
885 : fn (?
string $languageId =
null) => Loc::getMessage(
886 "V_NOTIFY_MESSAGE" . $gender,
892 \CIMNotify::Add(
$res);
898 $dbUser = \CUser::getById(
$vote[
"AUTHOR_ID"]);
899 if ($dbUser && ($u = $dbUser->Fetch()) && !empty($u[
"EMAIL"]))
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"],
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")
921 $eventFields[
"USER_NAME"] = (!!$eventFields[
"USER_NAME"] &&
$event[
"VISIBLE"] ==
"Y" ? $eventFields[
"USER_NAME"] : $eventFields[
"LOGIN"]);
924 foreach ($this[
"QUESTIONS"] as $question)
926 if (array_key_exists($question[
"ID"],
$event[
"BALLOT"]))
929 foreach ($question[
"ANSWERS"] as $answer)
931 if (array_key_exists($answer[
"ID"],
$event[
"BALLOT"][$question[
"ID"]][
"ANSWERS"]))
934 $event[
"BALLOT"][$question[
"ID"]][
"ANSWERS"][$answer[
"ID"]][
"MESSAGE"] !==
"")
936 $text[$question[
"ID"]][] =
$event[
"BALLOT"][$question[
"ID"]][
"ANSWERS"][$answer[
"ID"]][
"MESSAGE"];
940 $text[$question[
"ID"]][] = $answer[
"MESSAGE"];
944 if (!empty(
$text[$question[
"ID"]]))
946 $text[$question[
"ID"]] =
" - " . $question[
"QUESTION"] .
"\n - " . implode(
", ",
$text[$question[
"ID"]]);
950 $text[$question[
"ID"]] =
" - " . $question[
"QUESTION"] .
"\n - ...\n";
954 $eventFields[
"VOTE_STATISTIC"] =
"\n" . implode(
"\n\n",
$text);
956 \CEvent::Send(
"VOTE_FOR", $arrSites, $eventFields,
"N");
969 foreach ($this->questions as &$qs)
970 foreach ($qs[
"ANSWERS"] as &$as)
971 $as[
"STAT"] =
array();
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",
985 "filter" =>
array(
"VOTE_ID" => $this->
id,
"VALID" =>
"Y"),
987 "USER.USER.LAST_NAME" =>
"ASC",
988 "USER.USER.NAME" =>
"ASC",
989 "USER.USER.LOGIN" =>
"ASC"
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"]))
997 $stat = &$this->questions[
$res[
"Q_QUESTION_ID"]][
"ANSWERS"][
$res[
"A_ANSWER_ID"]][
"STAT"];
1002 "MESSAGE" =>
$res[
"A_MESSAGE"]
1005 $res[
"V_VISIBLE"] ==
"Y" &&
$res[
"U_ID"] > 0)
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"],
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",
1033 "filter" =>
array(
"VOTE_ID" => $this->
id,
"VALID" =>
"Y"),
1035 "USER.USER.LAST_NAME" =>
"ASC",
1036 "USER.USER.NAME" =>
"ASC",
1037 "USER.USER.LOGIN" =>
"ASC"
1046 "ID" =>
$res[
"V_ID"],
1047 "DATE" =>
$res[
"V_DATE_VOTE"],
1049 $res[
"V_VISIBLE"] ==
"Y" ?
"Y" :
"N"),
1051 "USER" => [
"ID" => 0]
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"],
1066 if (!array_key_exists(
$res[
"Q_QUESTION_ID"], $ballot))
1068 $ballot[
$res[
"Q_QUESTION_ID"]] = [];
1070 $ballot[
$res[
"Q_QUESTION_ID"]][
$res[
"A_ANSWER_ID"]] = trim(
$res[
"A_MESSAGE"]);
1079 if ($this->channel ===
null)
1081 $this->channel =
array();
1083 while ((
$res = $db->fetch()) &&
$res)
1085 if ($this->vote[
"CHANNEL_ID"] ==
$res[
"ID"])
1087 $this->channel =
$res;
1092 return $this->channel;
1101 return $this->vote[
$key] ??
null;
1111 if (array_key_exists(
$id, $this->questions))
1112 return $this->questions[
$id];
1120 return $this->questions;
1129 VoteTable::update($this->
id, [
"DATE_END" => (
new DateTime())->add(
"1Y")]);
1139 VoteTable::update($this->
id, [
"DATE_END" =>
new DateTime()]);
1148 public static function delete(
$id)
1151 return \CVote::Delete(
$id);
1161 unset($VOTE_CACHE[
"VOTE"][$this->
id]);
1162 unset(self::$storage[$this->
id]);
1163 unset(self::$canVoteStorage[$this->
id]);
1169 private function clearVotingCache()
1172 unset($VOTE_CACHE[
"VOTE_CACHE_VOTING"][$this->
id]);
1173 unset(self::$canVoteStorage[$this->
id]);
1184 $nameTemplate = Context::getCurrent()->getCulture()->getFormatName();
1188 while(ob_get_clean());
1189 header(
"Content-Transfer-Encoding: binary");
1192 $table1 = [
"body" => []];
1194 "head" => [Loc::getMessage(
"V_EXPORT_DATE"), Loc::getMessage(
"V_EXPORT_NAME")],
1198 foreach ($statistic as
$event)
1200 $user = Loc::getMessage(
"VOTE_GUEST");
1201 if (
$event[
"VISIBLE"] !==
"Y")
1203 $user = Loc::getMessage(
"VOTE_ANONYMOUSLY");
1205 else if (
$event[
"USER"][
"ID"] > 0)
1207 $user = \CUser::formatName($nameTemplate,
$event[
"USER"],
true,
false);
1211 "DATE" =>
$event[
"DATE"]->toUserTime()->format($dateTemplate),
1215 foreach ($this->questions as $questionId => $question)
1217 $answerMessage = [];
1218 if (array_key_exists($questionId,
$event[
"BALLOT"]))
1220 foreach ($question[
"ANSWERS"] as $answerId => $answer)
1222 if (array_key_exists($answerId,
$event[
"BALLOT"][$questionId]))
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] <>
'')
1229 $stat[
$event[
"ID"]] = $row[
"USER"].
" (".
$event[
"BALLOT"][$questionId][$answerId].
")";
1230 $answerMessage[] =
$event[
"BALLOT"][$questionId][$answerId];
1234 $answerMessage[] = $answer[
"MESSAGE"];
1235 $stat[
$event[
"ID"]] = $row[
"USER"];
1240 $row[] = implode(
", ", $answerMessage);
1242 $table2[
"body"][] = array_values($row);
1244 foreach ($this->questions as $questionId => $question)
1246 $table1[
"body"][] = [$question[
"QUESTION"],
"",
"",
""];
1247 foreach ($question[
"ANSWERS"] as $answerId => $answer)
1249 $table1[
"body"][] = [
"", $answer[
"MESSAGE"], $answer[
"COUNTER"], (array_key_exists(
"STAT", $answer) ? implode(
", ", $answer[
"STAT"]) :
"")];
1251 $table2[
"head"][] = $question[
"QUESTION"];
1254 if (
$type ===
"csv")
1256 Header(
"Content-Type: ". MimeType::getByFileExtension(
"csv"));
1257 header(
"Content-Disposition: attachment;filename=vote".$this->
id.
".csv");
1259 $f = fopen(
"php://output",
"w");
1260 fputcsv(
$f, $table2[
"head"],
';');
1261 foreach ($table2[
"body"] as $row) {
1262 fputcsv(
$f, $row,
';');
1269 "GENERAL_INFO" => Loc::getMessage(
"V_EXPORT_GENERAL_INFO"),
1270 "STATISTIC" => Loc::getMessage(
"V_EXPORT_STATISTIC")
1272 if (
$type ===
"xls")
1275 foreach ($table1[
"body"] as $row)
1277 $bodyRows[] = implode(
"</Data></Cell><Cell ss:StyleID=\"bold\"><Data ss:Type=\"String\">", $row);
1279 $table1[
"body"] = implode(
"</Data></Cell></Row><Row><Cell><Data ss:Type=\"String\">", $bodyRows);
1281 $table2[
"head"] = implode(
"</Data></Cell><Cell ss:StyleID=\"bold\"><Data ss:Type=\"String\">", $table2[
"head"]);
1283 foreach ($table2[
"body"] as $row)
1285 $bodyRows[] = implode(
"</Data></Cell><Cell ss:StyleID=\"bold\"><Data ss:Type=\"String\">", $row);
1287 $table2[
"body"] = implode(
"</Data></Cell></Row><Row><Cell><Data ss:Type=\"String\">", $bodyRows);
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">
1295 <Style ss:ID=
"bold">
1299 <Worksheet ss:Name=
"{$mess["GENERAL_INFO
"]}">
1302 <Cell><
Data ss:
Type=
"String">{$table1[
"body"]}</
Data></Cell>
1306 <Worksheet ss:Name=
"{$mess["STATISTIC
"]}">
1309 <Cell ss:StyleID=
"bold"><
Data ss:
Type=
"String">{$table2[
"head"]}</
Data></Cell>
1312 <Cell><
Data ss:
Type=
"String">{$table2[
"body"]}</
Data></Cell>
1324 foreach ($table1[
"body"] as $row)
1326 $bodyRows[] = implode(
"</td><td>", $row);
1328 $table1[
"body"] = implode(
"</td></tr><tr><td>", $bodyRows);
1330 $table2[
"head"] = implode(
"</th><th>", $table2[
"head"]);
1332 foreach ($table2[
"body"] as $row)
1334 $bodyRows[] = implode(
"</td><td>", $row);
1336 $table2[
"body"] = implode(
"</td></tr><tr><td>", $bodyRows);
1339<meta
http-equiv=
"Content-type" content=
"text/html;charset={$LANG_CHARSET}" />
1343 <tr><td>{$table1[
"body"]}</td></tr>
1349 <thead><tr><th>{$table2[
"head"]}</th></tr></thead>
1350 <tbody><tr><td>{$table2[
"body"]}</td></tr></tbody>
1355 header(
"Content-Type: ". MimeType::getByFileExtension(
"xls"));
1356 header(
"Content-Disposition: attachment;filename=vote".$this->
id.
".xls");
1359 \CMain::finalActions();
1372 $questions = $this->getQuestions();
1373 $data = [
"EXTRAS" => [],
"BALLOT" => [],
"MESSAGE" => []];
1375 foreach ($questions as $question)
1378 foreach ($question[
"ANSWERS"] as $answer)
1383 $answer[
"FIELD_TYPE"] : $question[
"FIELD_TYPE"]);
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;
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;
1400 $fieldName = ($answer[
"FIELD_TYPE"] ==
AnswerTypes::TEXT ?
"vote_field_" :
"vote_memo_") . $answer[
"ID"];
1401 $value = trim(
$request[$fieldName]);
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;
1441 if ($this[
"LAMP"] ==
"red")
1445 $voteId = $this->getId();
1446 if (
$user->lock($voteId) !==
true)
1448 throw new AccessDeniedException(Loc::getMessage(
"VOTE_IS_OCCUPIED"));
1453 $this->errorCollection->clear();
1465 && ($eventIdsToDelete = array_column(
$result->getData(),
'ID'))
1466 && !empty($eventIdsToDelete)
1469 $this->deleteEvents($eventIdsToDelete,
$userId);
1476 $this->errorCollection->add(
$result->getErrors());
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"),
1493 || !($eventResult =
$event->add($eventFields,
$data))
1496 $this->errorCollection->add(
$event->getErrors());
1500 $this->vote[
"COUNTER"]++;
1501 foreach ($eventResult->get(
"BALLOT") as $questionId => $question)
1503 $this->questions[$questionId][
"COUNTER"]++;
1504 foreach ($question[
"ANSWERS"] as $answerId => $answerEventParams)
1506 $this->questions[$questionId][
"ANSWERS"][$answerId][
"COUNTER"]++;
1509 foreach ($this->questions as $questionId => $question)
1511 foreach ($question[
"ANSWERS"] as $answerId => $answerEventParams)
1513 if ($this->questions[$questionId][
"ANSWERS"][$answerId][
"COUNTER"] > 0)
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);
1522 $this->questions[$questionId][
"ANSWERS"][$answerId][
"~PERCENT"] = 0;
1523 $this->questions[$questionId][
"ANSWERS"][$answerId][
"PERCENT"] = 0;
1527 self::$statStorage[] = $voteId;
1528 $_SESSION[
"VOTE"][
"VOTES"][$voteId] = $eventResult->get(
"EVENT_ID");
1532 $event3 = $this[
"EVENT3"];
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;
1539 \CStatEvent::AddCurrent($this[
"EVENT1"], $this[
"EVENT2"], $event3);
1542 if ($this[
"NOTIFY"] !==
"N" && $this[
"AUTHOR_ID"] > 0 && $this[
"AUTHOR_ID"] !=
$userId)
1544 self::sendVotingMessage($eventResult->toArray(), $this, ($this[
"NOTIFY"] ==
"I" ?
"im" :
"mail"));
1555 $user->unlock($voteId);
1556 return $this->errorCollection->isEmpty();
1564 public function isVotedFor(
$userId)
1568 $canVoteResult = $this->canVote(
$user);
1569 if (!$canVoteResult->isSuccess())
1573 $canVoteResult->getErrorCollection()->rewind();
1574 $canVoteResult->getErrorCollection()->valid();
1575 $canVoteResult->getErrorCollection()->next()
1579 $error = $canVoteResult->getErrorCollection()->current();
1594 else if (parent::canRead(
$userId))
1598 "select" =>
array(
"*"),
1602 ">=PERMISSION.PERMISSION" => 1,
1603 "PERMISSION.GROUP_ID" =>
$groups
1608 "group" =>
array(
"ID")
1612 if (
$res[
"ID"] == $this->
get(
"CHANNEL_ID"))
1628 else if (parent::canRead(
$userId))
1632 "select" =>
array(
"*"),
1636 ">=PERMISSION.PERMISSION" => 4,
1637 "PERMISSION.GROUP_ID" =>
$groups
1642 "group" =>
array(
"ID")
1646 if (
$res[
"ID"] == $this->
get(
"CHANNEL_ID"))
1655 return $this->
canRead(
$userId) && $this->vote[
"LAMP"] ==
"green";
1666 public function canVote(
$user)
1669 $voteId = intval($vote[
"ID"]);
1674 if (!array_key_exists($voteId, self::$canVoteStorage))
1676 self::$canVoteStorage[$voteId] = [];
1678 if (array_key_exists(
$user->getId(), self::$canVoteStorage[$voteId]))
1680 return self::$canVoteStorage[$voteId][
$user->getId()];
1683 $uniqueType = intval($vote[
"UNIQUE_TYPE"]);
1688 $result = new \Bitrix\Main\Result();
1690 if ($uniqueType & \Bitrix\Vote\Vote\
EventLimits::BY_SESSION && is_array($_SESSION[
"VOTE"][
"VOTES"]) && array_key_exists($voteId, $_SESSION[
"VOTE"][
"VOTES"]))
1692 $filter[
"ID"] = $_SESSION[
"VOTE"][
"VOTES"][$voteId];
1703 $delay = intval($vote[
"KEEP_IP_SEC"]);
1705 "IP" => \Bitrix\Main\Context::getCurrent()->getRequest()->getRemoteAddress()] +
1707 ">=DATE_VOTE" => (new \Bitrix\Main\Type\DateTime())->add(
"-T".$delay.
"S")] : []));
1715 if (!
$user->getUser()->IsAuthorized())
1724 $us = \CUser::GetByID(
$user->getId())->fetch();
1738 if ($filterCard > 0)
1740 $dbRes = \Bitrix\Vote\EventTable::getList([
1743 "USER_COOKIE_ID" =>
"USER.COOKIE_ID",
1744 "USER_AUTH_USER_ID" =>
"USER.AUTH_USER_ID",
1747 "VOTE_ID" => $voteId,
1760 if (($filterCard & \Bitrix\Vote\Vote\
EventLimits::BY_IP) && (
$res[
"IP"] == \Bitrix\Main\Context::getCurrent()->getRequest()->getRemoteAddress()))
1762 if ($vote[
"KEEP_IP_SEC"] > 0)
1765 $res[
"DATE_VOTE"]->add(
"T".$vote[
"KEEP_IP_SEC"].
"S");
1779 if ($filterCard <= 0)
1783 self::$canVoteStorage[$voteId][
$user->getId()] =
$result;
1789 $canVoteResult = $this->canVote(
$user);
1790 $result = new \Bitrix\Main\Result();
1791 if ($canVoteResult->isSuccess() || (
1794 $canVoteResult->getErrorCollection()->count() == 1
1797 $result->setData($canVoteResult->getData());
1800 return $canVoteResult;
1805 $result = new \Bitrix\Main\Result();
1812 if ($this[
"AUTHOR_ID"] !=
$user->getId())
1816 $result->addError(
new Error(
"Access denied.",
"Hidden results"));
1818 else if ($this[
"LAMP"] ==
"green")
1820 $canVoteResult = $this->canVote(
$user);
1821 if ($canVoteResult->isSuccess())
1822 $result->addError(
new Error(
"Access denied.",
"Hidden results"));
1834 if ($offset ==
"QUESTIONS")
1836 return array_key_exists($offset, $this->vote);
1844 if (array_key_exists($offset, $this->vote))
1845 return $this->vote[$offset];
1846 else if ($offset ==
"QUESTIONS")
1847 return $this->questions;
1859 throw new \Bitrix\Main\NotSupportedException(
"Model provide ArrayAccess only for reading");
1869 throw new \Bitrix\Main\NotSupportedException(
"Model provide ArrayAccess only for reading");
1875 if (
$user->lock($this->getId()) !==
true)
1878 ->addError(
new Error(Loc::getMessage(
"VOTE_IS_OCCUPIED")))
1883 if (!$canRevoteResult->isSuccess())
1887 return $canRevoteResult;
1890 $eventIdsToDelete = array_column($canRevoteResult->getData(),
'ID');
1891 $this->deleteEvents($eventIdsToDelete,
$userId);
1895 return new \Bitrix\Main\Result();
1898 private function deleteEvents(
1899 array $eventIdsToDelete,
1908 if (empty($eventIdsToDelete))
1913 $dbRes = \Bitrix\Vote\EventTable::getList([
1916 "Q_" =>
"QUESTION.*",
1917 "A_" =>
"QUESTION.ANSWER.*"],
1919 "VOTE_ID" => $this->
id,
1920 "ID" => $eventIdsToDelete
1924 "QUESTION.ID" =>
"ASC",
1925 "QUESTION.ANSWER.ID" =>
"ASC"]
1931 \CIMNotify::DeleteByTag(
"VOTING|{$this->getId()}",
$userId);
1934 $lastQuestionId = 0;
1937 if ($lastEventId <
$res[
"V_ID"])
1939 $lastEventId =
$res[
"V_ID"];
1940 \Bitrix\Vote\Event::deleteEvent(intval(
$res[
"V_ID"]));
1941 $this->vote[
"COUNTER"] = max($this->vote[
"COUNTER"] - 1, 0);
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"]))
1946 if ($lastQuestionId <
$res[
"Q_ID"])
1948 $lastQuestionId =
$res[
"Q_ID"];
1949 $this->questions[
$res[
"Q_QUESTION_ID"]][
"COUNTER"] =
1950 max($this->questions[
$res[
"Q_QUESTION_ID"]][
"COUNTER"] - 1, 0)
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,
1960 $questionCounter = (int)($this->questions[$questionId][
"COUNTER"] ?? 0);
1961 foreach ($this->questions[$questionId][
"ANSWERS"] as $answerId => $answer)
1963 $answerCounter = (int)($this->questions[$questionId][
"ANSWERS"][$answerId][
"COUNTER"] ?? 0);
1964 $percent = $answerCounter > 0 && $questionCounter > 0 ? $answerCounter * 100 / $questionCounter : 0;
1966 $this->questions[$questionId][
"ANSWERS"][$answerId][
"~PERCENT"] = $percent;
1967 $this->questions[$questionId][
"ANSWERS"][$answerId][
"PERCENT"] = round($percent, 2);
1972 $this->clearVotingCache();