getRenderMode(); if (self::RENDER_MODE_FULL === $renderMode) { $this->addFormRule([$this, 'validateData']); parent::init(); } elseif (self::RENDER_MODE_ATTENDEE === $renderMode) { $this->_initPaths(); $this->_addAttendeeSubForm(); } else { throw new Exception('Wrong option "renderMode"'); } return $this; } protected function _initElements() { $this->_addAttendeeSubForm(); $this->_addAddAttendeeButton(); return $this; } protected function _addAddAttendeeButton() { $this->addElement( 'button', 'addAttendee', [ 'label' => ' Add New Attendee', 'attribs' => [ 'data-action' => 'add', 'class' => 'btn btn-secondary' ], 'ignore' => true, 'escape' => false, ] ); return $this; } protected function _addAttendeeSubForm() { $defaults = (self::RENDER_MODE_FULL === $this->getRenderMode()) ? (array) $this->_getData('attendee') : [$this->getAttendeeIndex() => []]; $attendeeForm = new AttendeeForm([ 'adminMode' => $this->_adminMode, 'editMode' => $this->_editMode, 'event' => $this->getEventObj()->getData(), 'defaults' => $defaults, 'renderMode' => $this->getRenderMode(), 'maxAttendeeCount' => $this->getMaxAttendeeCount(), 'currentUserId' => $this->getCurrentUserId(), 'currentUserName' => $this->getCurrentUserName(), 'allowCurrentUser' => $this->getAllowCurrentUser(), 'allowMembers' => $this->getAllowMembers(), 'allowStatusChange' => $this->isAllowStatusChange(), 'allowNonMembers' => $this->getAllowNonMembers(), 'hasStatus' => $this->isHasStatus(), 'userAutocompleteUrl' => $this->getUserAutocompleteUrl(), ]); $this->addSubForm($attendeeForm, 'attendee'); return $this; } public function isAllowStatusChange() { return $this->_allowStatusChange; } public function setAllowStatusChange($allowStatusChange) { $this->_allowStatusChange = $allowStatusChange; return $this; } public function initRender() { if ($this->getInitializedRender()) { return $this; } $this->setAttrib('style', 'display: none'); return parent::initRender(); } protected function _addResources() { /** @var $doc \Qs_Doc */ $doc = Zend_Registry::get('doc'); // add scripts used by dynamically loaded form elements $doc->addScript('js/jquery-ui.js'); $doc->addScript('js/lib/form-element-autocomplete.js'); $doc->addScript('js/jquery.required.js'); $doc->addScript('js/app/event/form.js'); $doc->addScript('js/jquery.dynamicForm.js'); if (self::RENDER_MODE_FULL === $this->getRenderMode()) { $doc->addInitObject('app.event.Form', [$this->_getScriptOptions()]); } return $this; } protected function _getScriptOptions() { $options = [ 'requestUrl' => Qs_Request::getBaseUrl(), 'formId' => $this->getId(), ]; if (($attendeeForm = $this->getSubForm('attendee'))) { $options['attendeeNodeId'] = $this->getSubForm('attendee')->getId() . '-element'; $options['maxAttendeeCount'] = $this->getMaxAttendeeCount(); } return $options; } public function loadDefaultDecorators() { if (self::RENDER_MODE_ATTENDEE === $this->getRenderMode()) { if (false == $this->loadDefaultDecoratorsIsDisabled() && null == $this->getDecorators()) { $this->addDecorator('FormElements'); } } else { parent::loadDefaultDecorators(); } return $this; } protected function _fetchAttendeeNames(array $attendees) { $result = []; $typeRule = new TypeRule($this->getEventObj()->getData('type')); foreach ($attendees as $attendee) { if (!empty($attendee['firstName']) && !empty($attendee['lastName']) && ($name = $attendee['firstName'] . ' ' . $attendee['lastName']) && !in_array($name, $result) ) { $result[] = $name; } if ($typeRule->featureSpouse && !empty($attendee['spouseFirstName']) && !empty($attendee['spouseLastName']) && ($name = $attendee['spouseFirstName'] . ' ' . $attendee['spouseLastName']) && !in_array($name, $result) ) { $result[] = $name; } } return $result; } /** * Валідуєтсья наступне: * 1. дублювання аттенді в евенті * 2. дублювання аттенді в формі * @return array|bool * @throws \Exception */ public function validateData() { if ($this->hasErrors()) { return true; } $errors = []; $eventObj = $this->getEventObj(); $attendeeObj = $this->getAttendeeObj(); $typeRule = new TypeRule($eventObj->getData('type')); $data = $this->getValues(); $attendees = (array) $data['attendee']; $spouses = ($typeRule->featureSpouse) ? $this->_extractAttendeeSpouses($attendees) : []; if (empty($attendees)) { $errors[] = $this->_msgNoAttendees; return $errors; } // [name => id] pairs for nonmembers and spouses $formNames = $this->_fetchAttendeeNames($attendees); $nameToId = $this->_arrayToLower((array) $attendeeObj->getUsersIds($formNames)); $registeredAttendees = (array) $this->getAttendeeObj()->getRegisteredAttendees(); $registeredIds = array_filter(Qs_Array::fetchColAll($registeredAttendees, 'userId')); $registrationLimit = (int) $eventObj->getData('registrationLimit'); $registeredCount = count($registeredAttendees) + count($attendees) + count($spouses); // registration limit validation if ($registrationLimit && $registrationLimit < $registeredCount) { $errors[] = Qs_String::fill( $this->_msgLimitExceeded, ['count' => $registeredCount - $registrationLimit], '{}' ); } $signedIds = []; $signedNames = []; // user can be signed for event only once foreach ($attendees as $idx => $item) { $this->_validateAttendee( $idx, $item, $errors, $registeredIds, $nameToId, $signedIds, $signedNames ); } // validate spouse/partners (no attendee with same name on form or registered) if ($typeRule->featureSpouse) { foreach ($spouses as $idx => $userName) { $this->_validateSpouse($idx, $userName, $errors, $nameToId, $signedIds, $signedNames); } } return ($errors) ? $errors : true; } protected function _validateAttendee( $idx, $attendee, &$errors, $registeredIds, $nameToId, &$signedIds, &$signedNames ) { if (AttendeeForm::TYPE_MEMBER === $attendee['type']) { $userId = $attendee['id']; if (in_array($userId, $registeredIds)) { if ($attendee['attendType'] === AttendeeForm::ATTEND_MYSELF) { $errors['attendee'][$idx]['currentId'][] = $this->_msgAlreadyRegistered; } else { $errors['attendee'][$idx]['id'][] = $this->_msgAlreadyRegistered; } } if (in_array($userId, $signedIds)) { if ($attendee['attendType'] === AttendeeForm::ATTEND_MYSELF) { $errors['attendee'][$idx]['currentId'][] = $this->_msgAlreadyAdded; } else { $errors['attendee'][$idx]['id'][] = $this->_msgAlreadyAdded; } } else { $signedIds[] = $userId; } } elseif ($attendee['firstName'] && $attendee['lastName']) { $userName = strtolower($attendee['firstName'] . ' ' . $attendee['lastName']); $userId = (isset($nameToId[$userName])) ? $nameToId[$userName] : null; $nameAdded = in_array($userName, $signedNames); $idAdded = ($userId && in_array($userId, $signedIds)); if ($nameAdded || $idAdded) { $errors['attendee'][$idx]['lastName'][] = $this->_msgAlreadyAdded; } if (!$nameAdded) { $signedNames[] = $userName; } if (!$idAdded) { $signedIds[] = $userId; } } } protected function _validateSpouse($idx, $userName, &$errors, $nameToId, $signedIds, $signedNames) { $userName = strtolower($userName); $userId = (isset($nameToId[$userName])) ? $nameToId[$userName] : null; if ($userId) { $errors['attendee'][$idx]['spouseLastName'][] = $this->_msgMemberAddedAsSpouse; } $nameAdded = in_array($userName, $signedNames); $idAdded = ($userId && in_array($userId, $signedIds)); if ($nameAdded || $idAdded) { $errors['attendee'][$idx]['spouseLastName'][] = $this->_msgAlreadyAdded; } if (!$nameAdded) { $signedNames[] = $userName; } if (!$idAdded) { $signedIds[] = $userId; } } protected function _arrayToLower(array $list) { $result = []; foreach ($list as $key => $val) { $key = is_numeric($key) ? $key : strtolower($key); $val = is_numeric($val) ? $val : strtolower($val); $result[$key] = $val; } return $result; } /** * @param $attendees * * @return array [attendeeIdx => spouseName, ...] */ protected function _extractAttendeeSpouses(array $attendees) { $result = []; foreach ($attendees as $idx => $item) { if (isset($item['spouseEnabled']) && 'y' === $item['spouseEnabled']) { $result[$idx] = $item['spouseFirstName'] . ' ' . $item['spouseLastName']; } } return $result; } public function getValues($suppressArrayNotation = false) { $data = parent::getValues($suppressArrayNotation); return $this->_filterData($data); } /** * Unset values of unavailable elements * @param array $data Request or Form data * @return array */ protected function _filterData(array $data) { $result = $data; $result['attendee'] = []; $attendees = (isset($data['attendee'])) ? (array) $data['attendee'] : []; $allowCurrent = (bool) $this->getAllowCurrentUser(); $allowMembers = (bool) $this->getAllowMembers(); $allowNonMembers = (bool) $this->getAllowNonMembers(); foreach ($attendees as $idx => $item) { if ((!$allowCurrent && $item['currentId']) || (!$allowMembers && $item['type'] === AttendeeForm::TYPE_MEMBER) || (!$allowNonMembers && $item['type'] === AttendeeForm::TYPE_NONMEMBER) ) { continue; } $result['attendee'][$idx] = $item; } return $result; } public function setRenderMode($renderMode) { $this->_renderMode = $renderMode; return $this; } public function getRenderMode() { return $this->_renderMode; } public function setAttendeeIndex($attendeeIndex) { $this->_attendeeIndex = $attendeeIndex; return $this; } public function getAttendeeIndex() { if (null === $this->_attendeeIndex) { throw new Qs_Exception_EmptyPropertyException($this, '_attendeeIndex'); } return $this->_attendeeIndex; } public function setMaxAttendeeCount($maxAttendeeCount) { $this->_maxAttendeeCount = (int) $maxAttendeeCount; return $this; } public function getMaxAttendeeCount() { return $this->_maxAttendeeCount; } public function setAllowCurrentUser($allowCurrentUser) { $this->_allowCurrentUser = (bool) $allowCurrentUser; return $this; } public function getAllowCurrentUser() { return $this->_allowCurrentUser; } public function setAllowMembers($allowMembers) { $this->_allowMembers = (bool) $allowMembers; return $this; } public function getAllowMembers() { return $this->_allowMembers; } public function isHasStatus() { return $this->_hasStatus; } public function setHasStatus($hasStatus) { $this->_hasStatus = $hasStatus; return $this; } public function setCurrentUserId($currentUserId) { $this->_currentUserId = $currentUserId; return $this; } public function getCurrentUserId() { return $this->_currentUserId; } public function getCurrentUserName() { return $this->_currentUserName; } public function setCurrentUserName($currentUserName) { $this->_currentUserName = $currentUserName; return $this; } public function setAllowNonMembers($allowNonMembers) { $this->_allowNonMembers = (bool) $allowNonMembers; return $this; } public function getAllowNonMembers() { return $this->_allowNonMembers; } public function setUserAutocompleteUrl($userAutocompleteUrl) { $this->_userAutocompleteUrl = $userAutocompleteUrl; return $this; } public function getUserAutocompleteUrl() { return $this->_userAutocompleteUrl; } public function setEventObj(Obj $dataObj) { $this->_eventObj = $dataObj; return $this; } public function getEventObj() { if (null === $this->_eventObj) { throw new Qs_Exception_EmptyPropertyException($this, '_eventObj'); } return $this->_eventObj; } public function setAttendeeObj($attendeeObj) { $this->_attendeeObj = $attendeeObj; return $this; } public function getAttendeeObj() { if (null === $this->_attendeeObj) { throw new Qs_Exception_EmptyPropertyException($this, '_attendeeObj'); } return $this->_attendeeObj; } }