* // Приклад 1. Опції беруться по урлу * // Примітки: * // - в даному прикладі встановлюється одна опція для того щоб в режимі редагування бачити в полі * // яке текстове значення відповідає хіддену. Задача по вибірці цього значення лягає на ViewController. * // - урл повинен віддавати JSON: [{value: 'value 1', title: 'title 1'}, ...] * $form->addElement('autocomplete', 'state', array('label' => 'State', 'required' => true)); * $form->state->setDataUrl($this->url(array('action' => 'autocompleteState'))); * if (null !== ($state = $this->_getData('state'))) { * if (null !== ($stateTitle = $this->_getDataObj()->tableDState->search($state, 'title'))) { * $form->state->setTitle($stateTitle); * } * } * * * * // Приклад 2. Опції задано одразу у форматі array('value' => 'title', ...) * $form->addElement('autocomplete', 'state', array('label' => 'State', 'required' => true)); * $form->state->setMultiOptions($this->_getDataObj()->getDState4Select()); * * * * // Приклад 3. Опції повертає колбек у форматі [{value: 'value 1', title: 'title 1'}, ...] * $form->addElement('autocomplete', 'state', array('label' => 'State', 'required' => true)); * $form->state->setDataCallback('getStates'); * * * Options that can be passed to script: 'autoFocus', 'delay', 'minLength', 'position'. * Callbacks: 'renderItem', 'search', 'open', 'focus', 'select', 'close', 'change'. */ class Qs_Form_Element_Autocomplete extends Zend_Form_Element_Multi { // sources priority dataUrl, dataCallback, dataArray, multiOptions protected $_dataUrl; protected $_dataCallback; protected $_dataArray; protected $_title; protected $_notFoundMessage = '"%value%" was not found in the haystack'; /** * Sets url for ajax requests, data should be returned in format: [{value: 'value 1', title: 'title 1'}, ...] * @param string $url * @return Qs_Form_Element_Autocomplete */ public function setDataUrl($url) { $this->_dataUrl = $url; $this->setRegisterInArrayValidator(false); return $this; } public function getDataUrl() { return $this->_dataUrl; } /** * Sets JavaScript callback for data requests. * Callback should return result in format [{value: 'value 1', title: 'title 1'}, ...] * @param string $callback * @return Qs_Form_Element_Autocomplete */ public function setDataCallback($callback) { $this->_dataCallback = $callback; $this->setRegisterInArrayValidator(false); return $this; } public function getDataCallback() { return $this->_dataCallback; } /** * Sets data for autocomplete. * Supported formats: * [[value: 'value 1', title: 'title 1', ...], ...] * [value => [title: 'title 1', ...], ...] * @throws Qs_Form_Element_Exception * @param array $data * @return Qs_Form_Element_Autocomplete */ public function setDataArray(array $data) { if (null !== $data && !is_array($data)) { throw new Qs_Form_Element_Exception('Parameter $data should be array but "' . gettype($data) . '" provided'); } $this->setRegisterInArrayValidator(false); $this->_dataArray = []; foreach ((array) $data as $value => $info) { if (!array_key_exists('title', $info)) { throw new Qs_Form_Element_Exception('Incorrect dataArray format, items should contain "title" field'); } if (!array_key_exists('value', $info)) { $info['value'] = $value; } $this->_dataArray[] = $info; } return $this; } public function getDataArray() { return $this->_dataArray; } public function getNotFoundMessage() { $translator = $this->getTranslator(); if (null !== $translator) { return $translator->translate($this->_notFoundMessage); } return $this->_notFoundMessage; } public function setNotFoundMessage($message) { $this->_notFoundMessage = $message; return $this; } public function loadDefaultDecorators() { if ($this->loadDefaultDecoratorsIsDisabled()) { return; } $decorators = $this->getDecorators(); if (empty($decorators)) { $this->addDecorator('JQuery_Autocomplete') ->addDecorator('Errors') ->addDecorator('Description', ['tag' => 'p', 'class' => 'description']) ->addDecorator('HtmlTag', ['tag' => 'dd', 'id' => $this->getName() . '-element']) ->addDecorator('Label', ['tag' => 'dt', 'disableFor' => true]); } } public function isValid($value, $context = null) { if ($this->_dataArray && !$this->_dataCallback && !$this->_dataUrl) { if (!$this->getValidator('InArray')) { $dataArray = $this->getDataArray(); $options = []; foreach ($dataArray as $info) { $options[] = $info['value']; } $this->addValidator('InArray', true, [$options]); } } $isValid = parent::isValid($value, $context); if (is_array($context)) { $display = Qs_Array::get($context, $this->getFullyQualifiedDisplayName()); $title = Qs_Array::get($context, $this->getFullyQualifiedTitleName()); if ($display != $title) { $this->_messages['isEmpty'] = str_replace('%value%', $display, $this->getNotFoundMessage()); $isValid = false; } } return $isValid; } public function getFullyQualifiedDisplayName() { return $this->_getSystemName($this->getFullyQualifiedName()); } public function getFullyQualifiedTitleName() { return $this->_getSystemName($this->getFullyQualifiedDisplayName()); } protected function _getSystemName($name) { if (false !== ($pos = strrpos($name, '['))) { $pos++; $_name = substr($name, 0, $pos) . '_' . substr($name, $pos); } else { $_name = '_' . $name; } return $_name; } public function getTitleId() { return $this->_getSystemId($this->getDisplayId()); } public function getDisplayId() { return $this->_getSystemId($this->getId()); } protected function _getSystemId($id) { if (false !== ($pos = strrpos($id, '-'))) { $pos++; $_id = substr($id, 0, $pos) . '_' . substr($id, $pos); } else { $_id = '_' . $id; } return $_id; } /** * Sets display title * @param string $title * @return Qs_Form_Element_Autocomplete */ public function setTitle($title) { $this->_title = (string) $title; return $this; } public function getTitle() { if (null === $this->_title) { $this->_title = $this->_initTitle(); } return $this->_title; } protected function _initTitle() { if (null === $this->_title) { if ($this->_dataUrl || $this->_dataCallback) { $this->_title = ''; } else if ($this->_getMultiOptions()) { $this->_title = $this->getMultiOption($this->_value); } else if ($this->_dataArray) { foreach ($this->_dataArray as $item) { if ($this->_value === $item['value']) { $this->_title = $item['title']; break; } } } } $this->_title = (null === $this->_title) ? '' : $this->_title; return $this->_title; } }