null, ]; public function init() { $renderMode = $this->getRenderMode(); if (self::RENDER_MODE_FULL === $renderMode) { $this->_defaults['attendType'] = ($this->getAllowCurrentUser()) ? self::ATTEND_MYSELF : self::ATTEND_OTHER; $this->_initDFRelations(); $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 _initDFRelations() { $this->_dfRelations = [ [ 'node' => '[name="attendType"]' . ($this->getAllowCurrentUser() ? ':checked' : ''), 'group' => '[name="attendType"]', 'event' => 'change', 'rules' => [ [ 'value' => self::ATTEND_MYSELF, 'nodes' => ['#attendee-fieldset-current'], ], [ 'value' => self::ATTEND_MYSELF_OTHER, 'autoRebuildNodes' => true, 'nodes' => [ '#attendee-fieldset-current', 'fieldset[data-attendee]', '#addAttendee-label', '#addAttendee-element', ], ], [ 'value' => self::ATTEND_OTHER, 'autoRebuildNodes' => true, 'nodes' => [ 'fieldset[data-attendee]', '#addAttendee-label', '#addAttendee-element', ], ], ], ], ]; return $this; } /** * @param string $name element name * @return string element label id (e.g. foo-label) */ protected function _dfGetElementLabelId($name) { return null; } /** * @param string $name element name * @return string element container id (e.g. foo-element) */ protected function _dfGetElementContainerId($name) { return null; } protected function _initElements() { $this->_addAttendeesGroup(); $this->_addAddAttendeeButton(); return $this; } protected function _addAddAttendeeButton() { $this->addElement( 'button', 'addAttendee', [ 'label' => 'Add New Attendee', 'attribs' => [ 'data-action' => 'add', 'class' => 'btn', ], 'ignore' => true, 'escape' => false, ] ); return $this; } protected function _addAttendeeSubForm() { $defaults = (self::RENDER_MODE_FULL === $this->getRenderMode()) ? (array) Qs_Array::get($this->_defaults, 'attendee', []) : [$this->getAttendeeIndex() => []]; $attendeeForm = new AttendeeForm([ 'defaults' => $defaults, 'renderMode' => $this->getRenderMode(), 'maxAttendeeCount' => $this->getMaxAttendeeCount(), 'currentUserId' => $this->getCurrentUserId(), 'allowCurrentUser' => $this->getAllowCurrentUser(), 'allowMembers' => $this->getAllowMembers(), 'allowNonMembers' => $this->getAllowNonMembers(), 'userAutocompleteUrl' => $this->getUserAutocompleteUrl(), 'eventEntity' => $this->getEventEntity(), 'alaCarteItemsType' => $this->getAlaCarteItemsType(), 'workshopType' => $this->getWorkshopType(), ]); $this->addSubForm($attendeeForm, 'attendee'); return $this; } protected function _addAttendeesGroup() { if ($this->getAllowCurrentUser()) { $options = [ self::ATTEND_MYSELF => 'Myself Only', self::ATTEND_MYSELF_OTHER => 'Myself and Others', self::ATTEND_OTHER => 'Others (I\'m not attending)', ]; if (false == $this->getAllowNonMembers() && null == $this->getCurrentUserId()) { unset($options[self::ATTEND_MYSELF], $options[self::ATTEND_MYSELF_OTHER]); } $this->addElement( 'radio', 'attendType', [ 'label' => 'Who Will Attend?', 'separator' => '   ', 'multiOptions' => $options, 'required' => true, ] ); } else { $this->addElement('hidden', 'attendType', ['value' => self::ATTEND_OTHER]); } $this->_addAttendeeSubForm(); 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()]); $dynamicFormOptions = ['relations' => $this->dfConvertRelations()]; $doc->addInitFunction('$("#' . $this->getId() . '").dynamicForm', [$dynamicFormOptions]); } 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 = []; foreach ($attendees as $attendee) { if (!empty($attendee['firstName']) && !empty($attendee['lastName']) && ($name = $attendee['firstName'] . ' ' . $attendee['lastName']) && !in_array($name, $result) ) { $result[] = $name; } } return $result; } /** * Валідуєтсья наступне: * 1. дублювання аттенді в евенті * 2. дублювання аттенді в формі * @param array $data * @return array|bool * @throws \Exception */ public function validateData($data) { if ($this->hasErrors()) { return true; } $errors = []; $eventObj = $this->getEventObj(); $attendeeObj = $this->getAttendeeObj(); $data = $this->_filterData($data); $attendees = (array) $data['attendee']; // [email => id] pairs for entered attendees $formNames = $this->_fetchAttendeeNames($attendees); $nameToId = (array) $attendeeObj->getUsersIds($formNames); $formIds = array_filter(array_unique(Qs_Array::fetchColAll($attendees, 'id'))); $idToName = (array) $attendeeObj->getUsersNames($formIds); $registeredAttendees = (array) $this->getAttendeeObj()->getBoughtAttendees(); $registeredIds = array_filter(Qs_Array::fetchColAll($registeredAttendees, 'userId')); $registeredNames = array_unique(Qs_Array::fetchColAll($registeredAttendees, 'name')); $inCartAttendees = (array) $this->getAttendeeObj()->getInCartAttendees(); $inCartUserIds = array_filter(Qs_Array::fetchColAll($inCartAttendees, 'userId')); $inCartNames = array_unique(Qs_Array::fetchColAll($inCartAttendees, 'name')); $registrationLimit = (int) $eventObj->getData('registrationLimit'); $registeredCount = count($registeredAttendees) + count($inCartAttendees) + count($attendees); // registration limit validation if ($registrationLimit && $registrationLimit < $registeredCount) { $errors[] = 'Registration limit is exceeded by ' . ($registeredCount - $registrationLimit); } $signedIds = []; $signedNames = []; if ($this->getAllowCurrentUser() && ($currentId = $this->getCurrentUserId())) { if (isset($attendees['current']) && $attendees['current']['id'] != $currentId) { throw new Exception('Wrong params'); } } if (empty($attendees)) { $errors[] = 'No attendees to register'; } $alreadyRegisteredMsg = 'User has already been registered for this event'; $alreadyInCartMsg = 'User has already been added to the Shopping Cart'; $alreadyAddedMsg = 'User has already been added to this form'; $memberAddedAsNonMember = 'Registered member can not be signed in as a nonmember'; // user can be signed for event only once foreach ($attendees as $idx => $item) { $attendeeErrors = []; if (AttendeeForm::TYPE_MEMBER === $item['type']) { $userId = $item['id']; if (in_array($userId, $registeredIds)) { $attendeeErrors[] = $alreadyRegisteredMsg; } if (in_array($userId, $inCartUserIds)) { $attendeeErrors[] = $alreadyInCartMsg; } $userName = isset($idToName[$userId]) ? $idToName[$userId] : null; $callback = function ($value) use ($userName) { return 0 == strcasecmp($value, $userName); }; if ($userName && array_filter($registeredNames, $callback)) { if (empty($attendeeErrors) || !in_array($alreadyRegisteredMsg, $attendeeErrors)) { $attendeeErrors[] = $alreadyRegisteredMsg; } } if ($userName && array_filter($inCartNames, $callback)) { if (empty($attendeeErrors) || !in_array($alreadyInCartMsg, $attendeeErrors)) { $attendeeErrors[] = $alreadyInCartMsg; } } if (in_array($userId, $signedIds)) { $attendeeErrors[] = $alreadyAddedMsg; } else { $signedIds[] = $userId; } if ($attendeeErrors) { if ($item['mode'] == AttendeeItemForm::MODE_CURRENT_USER) { $errors['attendType'] = $attendeeErrors; } else { $errors['attendee'][$idx]['id'] = $attendeeErrors; } } } elseif ($item['firstName'] && $item['lastName']) { $userName = $item['firstName'] . ' ' . $item['lastName']; $userId = (isset($nameToId[$userName])) ? $nameToId[$userName] : null; if ($userId) { $errors['attendee'][$idx]['lastName'][] = $memberAddedAsNonMember; } $callback = function ($value) use ($userName) { return 0 == strcasecmp($value, $userName); }; if (array_filter($registeredNames, $callback)) { $errors['attendee'][$idx]['lastName'][] = $alreadyRegisteredMsg; } if (array_filter($inCartNames, $callback)) { $errors['attendee'][$idx]['lastName'][] = $alreadyInCartMsg; } $callback = function ($value) use ($userName) { return 0 == strcasecmp($value, $userName); }; $nameAdded = (bool) array_filter($signedNames, $callback); $idAdded = ($userId && in_array($userId, $signedIds)); if ($nameAdded || $idAdded) { $errors['attendee'][$idx]['lastName'][] = $alreadyAddedMsg; } if (!$nameAdded) { $signedNames[] = $userName; } if (!$idAdded) { $signedIds[] = $userId; } } } return ($errors) ? $errors : true; } 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'] : []; $attendType = $data['attendType']; $allowCurrent = (bool) $this->getAllowCurrentUser(); $allowMembers = (bool) $this->getAllowMembers(); $allowNonMembers = (bool) $this->getAllowNonMembers(); foreach ($attendees as $idx => $item) { $attendee = [ 'mode' => $item['mode'], 'type' => $item['type'], ]; if (AttendeeItemForm::MODE_CURRENT_USER === $item['mode']) { if (!$allowCurrent || self::ATTEND_OTHER === $attendType) { continue; } } else { // AttendeeItemForm::MODE_CHOOSE_TYPE if (self::ATTEND_MYSELF === $attendType) { continue; } } if (AttendeeForm::TYPE_MEMBER === $item['type']) { if (!$allowMembers) { continue; } $attendee['id'] = $item['id']; } else { // AttendeeForm::TYPE_NONMEMBER if (!$allowNonMembers) { continue; } } $attendee = array_merge($attendee, Qs_Array::map($item, $this->getConfigArray('attendeeFields'))); if (!empty($item['workshopId'])) { $map = Qs_Array::group($this->getEventEntity()->getWorkshops(), ['id'], []); $attendee['workshopTitle'] = Qs_Array::get($map, $item['workshopId'] . '[title]', ''); } $result['attendee'][$idx] = $attendee; } 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 setCurrentUserId($currentUserId) { $this->_currentUserId = $currentUserId; return $this; } public function getCurrentUserId() { return $this->_currentUserId; } 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; } }