'table table-striped'); protected $_columns = array(); protected $_templatePath = array(); protected $_primaryKey = array(); protected $_restParams = array(); /** * @var Qs_Paginator */ protected $_paginator; protected $_paginatorUrl; protected $_paginatorBaseUrl; protected $_isDisabledLimit = false; /** * @var Zend_Db_Select */ protected $_listSelect; /** * @var array */ protected $_list; protected $_listTemplate = 'list.tpl'; /** * @var Zend_Config */ protected $_config; protected $_configName; protected $_scriptOptions = array( /** Structure: array('name' => array('constructor' => string, 'options' => array), ...) */ 'handlers' => array() ); protected $_actionToolbar = false; protected $_actionToolbarOptions = array( 'controllerAction' => null, /** * Structure: * simple: array('name' => 'title') * extended: array('name' => array('title' => string, 'attribs' => array, * 'confirmation' => String, 'confirmationCallback' => Callback compatible with qs.call)) */ 'actions' => array(), 'attribs' => array( 'class' => 'list_action_toolbar' ), ); protected $_hasRowPreview = false; protected $_rowPreviewTemplate = 'row-preview.tpl'; protected $_rowPreviewOptions = array( 'controllerAction' => 'rowPreview', 'handlerClass' => null, 'caching' => false, ); public $defaultOrderBy; public $orderBy; public $idItem; public function __construct($options) { $this->setOptions($options); $this->_init(); } protected function _init() { $this->_initColumns(); return $this; } public function __get($key) { if ('_' == $key[0]) { throw new Qs_ViewController_Exception(sprintf('Cannot retrieve value for protected/private property "%s"', $key)); } if ('paginator' == $key) { return $this->_getPaginator(); } if (!isset($this->$key)) { return null; } return $this->$key; } public function __set($key, $value) { $this->setOption($key, $value); } public function setOptions($options) { if (isset($options['options'])) { unset($options['options']); } foreach ($options as $key => $value) { $method = 'set' . ucfirst($key); if (method_exists($this, $method)) { $this->$method($value); } else { $this->setOption($key, $value); } } return $this; } public function setOption($name, $value) { $name = (string) $name; if ('_' == $name[0]) { throw new Qs_ViewController_Exception(sprintf('Invalid attribute "%s"; must not contain a leading underscore', $name)); } if (null === $value) { unset($this->$name); } else { $this->$name = $value; } return $this; } protected function _initColumns() { return $this; } public function setDefaultIpp($ipp) { $this->_defaultIpp = $ipp; return $this; } public function getDefaultIpp() { return $this->_defaultIpp; } public function getAttribs() { if (!array_key_exists('id', $this->_attribs)) { $this->_attribs['id'] = $this->getAttrib('id'); } return $this->_attribs; } public function setAttribs(array $attribs) { $this->_attribs = $attribs; return $this; } public function setAttrib($name, $value) { $this->_attribs[$name] = $value; return $this; } public function getAttrib($name) { if (!array_key_exists($name, $this->_attribs)) { if ('id' === $name) { $this->_attribs[$name] = str_replace(array('_', '\\'), '-', strtolower(get_class($this))) . (($this->idItem) ? '-' . $this->idItem : ''); return $this->_attribs[$name]; } return null; } return $this->_attribs[$name]; } public function getOptions() { $options = get_object_vars($this); foreach ($options as $key => &$value) { if ('_' == substr($key, 0, 1)) { unset($options[$key]); continue; } $method = 'get' . ucfirst($key); if (method_exists($this, $method)) { $value = $this->$method(); } } return $options; } public function setSeoPaginator($flag = true) { $this->_seoPaginator = (bool) $flag; } public function addUrlVariables(array $variables) { $this->_urlVariables = array_unique(array_merge($this->_urlVariables, $variables)); return $this; } public function getUrlVariableValues(array $variableNames = null) { $result = array(); if (null === $variableNames) { $variableNames = $this->_urlVariables; } foreach ($variableNames as $name) { if (null !== ($value = Qs_Request::getGetValue($name))){ $result[$name] = $value; } } if (empty($result['ipp'])) { $result['ipp'] = $this->_getIpp(); } return $result; } protected function _getPaginator() { if (null === $this->_paginator) { $this->_paginator = Qs_Paginator::factory($this->getListSelect()); } return $this->_paginator; } public function getOrderBy() { $order = ''; if (null === $this->orderBy) { $orderBy = isset($_GET['orderBy']) ? $_GET['orderBy'] : $this->defaultOrderBy; $orderByParams = explode(' ', $orderBy); if (count($orderByParams) >= 2) { list($field, $order) = $orderByParams; } elseif (count($orderByParams) == 1) { $field = current($orderByParams); $order = ''; } $validField = false; if (!empty($field)) { foreach ($this->_columns as $column) { if (isset($column['orderBy']) && $field == $column['orderBy']) { $validField = true; break; } } } if (!$validField && ($this->defaultOrderBy != $orderBy || !$this->defaultOrderBy)) { $field = ''; foreach ($this->_columns as $column) { if (isset($column['orderBy'])) { $field = $column['orderBy']; break; } } } if (!empty($field)) { if ('DESC' != $order) { $order = ''; } else { $order = 'DESC'; } $this->orderBy = trim("{$field} {$order}"); } else if (!empty($this->defaultOrderBy)) { $this->orderBy = $this->defaultOrderBy; } else { $this->orderBy = false; } } return $this->orderBy; } public function setPageNumber($number) { $this->_pageNumber = (int) $number; } public function getPageNumber() { if (null === $this->_pageNumber) { $restParamsCount = count($this->_restParams); if ($this->_seoPaginator && $restParamsCount > 1 && 'page' == $this->_restParams[$restParamsCount - 2] && is_numeric($this->_restParams[$restParamsCount - 1]) ) { $this->_pageNumber = $this->_restParams[$restParamsCount - 1]; } else { $this->_pageNumber = (int) Qs_Request::getGetValue('page', 1); } } return $this->_pageNumber; } public function setIpp($ipp) { $this->_ipp = $ipp; return $this; } protected function _getCookieIpp() { if (!$this->_changeableIpp) { return null; } return Qs_Request::getCookieValue($this->_getIppCookieName()); } protected function _getIppCookieName() { return 'paginator-ipp-' . constant('CURRENT_PAGE'); } protected function _getIpp() { if ($this->isDisabledLimit()) { $this->_ipp = false; } if (null === $this->_ipp) { $cookieIpp = null; if (null === ($this->_ipp = Qs_Request::getGetValue('ipp'))) { if (null === ($this->_ipp = $this->_getCookieIpp())) { $this->_ipp = $this->_defaultIpp; } else { $cookieIpp = (int) $this->_ipp; } } $this->_ipp = (int) $this->_ipp; if (!in_array($this->_ipp, $this->_ippList)) { $this->_ippList[] = $this->_ipp; sort($this->_ippList); } if ($this->_changeableIpp && $cookieIpp !== $this->_ipp) { // refresh cookie value that expires in 90 days setcookie($this->_getIppCookieName(), $this->_ipp, time() + 7776000, parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)); } } return $this->_ipp; } public function setChangeableIpp($flag) { $this->_changeableIpp = (bool) $flag; return $this; } public function getChangeableIpp() { return $this->_changeableIpp; } public function setIppList(array $list) { $this->_ippList = $list; return $this; } public function getIppList() { return $this->_ippList; } public function isDisabledLimit() { return $this->_isDisabledLimit; } public function setIsDisabledLimit($flag = true) { $this->_isDisabledLimit = (bool) $flag; return $this; } public function getLimitPage() { if ($this->isDisabledLimit()) { $this->_limitPage = false; } if (null === $this->_limitPage) { $this->_limitPage = array($this->getPageNumber(), $this->_getIpp()); } return $this->_limitPage; } public function clearColumns() { $this->_columns = array(); return $this; } public function setColumns($columns) { $this->clearColumns(); $this->addColumns($columns); return $this; } public function addColumns($columns) { if ($columns instanceof Zend_Config) { /** @var $columns Zend_Config */ $columns = $columns->toArray(); } if (!is_array($columns) || empty($columns)) { throw new Qs_ViewController_Exception('Invalid columns'); } foreach ($columns as $column) { if (!isset($column['type'])) { throw new Qs_ViewController_Exception('Undefined column type'); } if (!isset($column['name'])) { throw new Qs_ViewController_Exception('Undefined column name'); } $this->addColumn($column['type'], $column['name'], $column); } return $this; } public function addColumn($type, $name, $options = array()) { $this->_columns[$name] = $this->_createColumn($type, $name, $options); return $this; } protected function _createColumn($type, $name, $options = array()) { if ($options instanceof Zend_Config) { $options = $options->toArray(); } $this->_initColumnAttribs($type, $name, $options); $prepareMethod = '_prepare' . ucfirst($type) . 'Column'; if (method_exists($this, $prepareMethod)) { $this->$prepareMethod($options); } else { $this->_prepareColumn($type, $name, $options); } if (!array_key_exists('params', $options)) { $options['params'] = array($name); } if (!array_key_exists('title', $options)) { $options['title'] = ucfirst(preg_replace('/([a-z])([A-Z])/', '$1 $2', $name)); } if (!isset($options['template'])) { $options['template'] = $type . '.tpl'; } if ('.' === dirname($options['template'])) { $options['template'] = $this->getTemplate('cells/' . $options['template']); } $options['type'] = $type; return $options; } public function removeColumn($name) { if (isset($this->_columns[$name])) { unset($this->_columns[$name]); } return $this; } protected function _prepareNoColumn(&$options) { if (!array_key_exists('title', $options)) { $options['title'] = '#'; } return $this; } protected function _prepareOptionsColumn(&$options) { if (!isset($options['actions'])) { $options['actions'] = array('edit' => array(), 'delete' => array()); } elseif (is_string($options['actions'])) { $actions = preg_split('/; ?/', $options['actions']); $options['actions'] = array_combine($actions, array_fill(0, count($actions), array())); } elseif(is_array($options['actions']) && !Qs_Array::isAssoc($options['actions'])) { $options['actions'] = array_combine($options['actions'], array_fill(0, count($options['actions']), array())); } foreach ($options['actions'] as $action => &$actionOptions) { if (!isset($actionOptions['link'])) { $actionOptions['link'] = Qs_Request::url(array('action' => $action)); } if (!isset($actionOptions['title'])) { $actionOptions['title'] = ucfirst(preg_replace('/([a-z])([A-Z])/', '$1 $2', $action)); } if (!isset($actionOptions['linkTitle'])) { $actionOptions['linkTitle'] = $actionOptions['title'] . ' this ' . $this->getConfig('itemName'); } } if (!isset($options['params'])) { $options['params'] = $this->_primaryKey; } $defaultAttribs = array( 'class' => 'grid_options' ); if (!isset($options['attribs'])) { $options['attribs'] = array(); } $options['attribs'] = array_merge($defaultAttribs, $options['attribs']); return $this; } protected function _addClassName(&$class, $newClass, $placement = 'append') { $parts = preg_split('/\s+/', $class); $parts = array_filter($parts, 'trim'); if (in_array($newClass, $parts)) { return false; } if ('append' == $placement) { $parts[] = $newClass; } else { array_unshift($parts, $newClass); } $class = implode(' ', $parts); return true; } protected function _initColumnAttribs($type, $name, &$options) { if (!array_key_exists('attribs', $options)) { $options['attribs'] = array(); } if (!array_key_exists('class', $options['attribs'])) { $options['attribs']['class'] = ''; } $typeClass = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $name)); $this->_addClassName($options['attribs']['class'], 'cell_' . $typeClass, 'prepend'); $this->_addClassName($options['attribs']['class'], 'grid_' . strtolower($type)); return $this; } protected function _prepareColumn($type, $name, &$options) { switch ($type) { case 'link_enum': if (!isset($options['key'])) { $options['key'] = $this->_primaryKey; } if (!isset($options['url'])) { $options['url'] = Qs_Request::url(array('action' => 'changeOption')) . '&'; } if (!isset($options['values'])) { $options['values'] = array('y' => 'Yes', 'n' => 'No'); } break; default: break; } return $this; } public function setSortLink($link) { $this->_sortLink = $link; } public function getSortLink() { if (null === $this->_sortLink) { $this->_sortLink = Qs_Constant::get('BASE_URL_LANGUAGE') . '/' . Qs_Constant::get('CURRENT_PAGE') . '?'; $variableNames = array_merge($this->_urlVariables, array('page')); $queryParams = $this->getUrlVariableValues($variableNames); unset($queryParams['orderBy']); if (!empty($queryParams)) { $this->_sortLink .= http_build_query($queryParams) . '&'; } } return $this->_sortLink; } public function setPaginatorUrl($url) { $this->_paginatorUrl = $url; return $this; } public function getPaginatorBaseUrl() { if (null === $this->_paginatorBaseUrl) { $this->_paginatorBaseUrl = Qs_Constant::get('BASE_URL_LANGUAGE') . '/' . Qs_Constant::get('CURRENT_PAGE_FINAL'); if ($this->_seoPaginator && !empty($this->_restParams)) { $restParamsCount = count($this->_restParams); if ($restParamsCount > 1 && 'page' == $this->_restParams[$restParamsCount - 2] && is_numeric($this->_restParams[$restParamsCount - 1]) ) { $restParams = array_slice($this->_restParams, 0, -2); } else { $restParams = $this->_restParams; } array_walk( $restParams, function ($value, $key) use (&$restParams) { $restParams[$key] = rawurlencode($value); } ); $this->_paginatorBaseUrl .= '/' . implode('/', $restParams); } } return $this->_paginatorBaseUrl; } public function setPaginatorBaseUrl($url) { $this->_paginatorBaseUrl = $url; return $this; } public function getPaginatorUrl() { if (null === $this->_paginatorUrl) { $queryParams = $this->getUrlVariableValues(); unset($queryParams['page']); $queryString = http_build_query($queryParams); if ($this->_seoPaginator) { $this->_paginatorUrl = $this->getPaginatorBaseUrl() . '/' . static::$_seoPaginatorPagePlaceholder; if (!empty($queryString)) { $this->_paginatorUrl .= '?' . $queryString; } } else { $this->_paginatorUrl = Qs_Constant::get('BASE_URL_LANGUAGE') . '/' . Qs_Constant::get('CURRENT_PAGE') . '?'; if (!empty($queryString)) { $this->_paginatorUrl .= $queryString . '&'; } $this->_paginatorUrl .= 'page=' . static::$_paginatorPagePlaceholder; } } return $this->_paginatorUrl; } public function getPaginatorPagePlaceholder() { return Qs_ViewController_List::$_paginatorPagePlaceholder; } public function getColumn($name) { return Qs_Array::get($this->_columns, $name); } public function getColumns() { return $this->_columns; } public function setList(array $list) { $this->_list = $list; return $this; } public function getList() { return $this->_list; } public function toArray() { $item = $this->getOptions(); $item['config'] = $this->getConfig()->toArray(); $item['attribs'] = $this->getAttribs(); $item['sortLink'] = $this->getSortLink(); $item['list'] = $this->getList(); $item['primary'] = $this->getPrimaryKey(); $item['tpl'] = $this->getTemplate($this->_listTemplate); $scriptOptions = $this->getScriptOptions(); $specialColumnsCount = 0; if ($this->_actionToolbar) { $specialColumnsCount += 1; $item['actionToolbar'] = $this->getActionToolbarOptions(); $colName = '_actionToolbar'; if (empty($this->_columns[$colName])) { $columnOptions = $this->_createColumn('checkbox', $colName, array('title' => '')); $this->_columns = array($colName => $columnOptions) + $this->_columns; } $this->_actionToolbarOptions['cellClasses'] = explode(' ', $this->_columns[$colName]['attribs']['class']); $scriptOptions['handlers']['actionToolbar'] = array( 'constructor' => 'Qs_ViewController_List_ActionToolbar', 'options' => $this->getActionToolbarOptions(), ); } if ($this->_hasRowPreview) { $specialColumnsCount += 1; $item['hasRowPreview'] = $this->_hasRowPreview; $scriptOptions['handlers']['rowPreview'] = array( 'constructor' => 'Qs_ViewController_List_RowPreview', 'options' => $this->getRowPreviewOptions(), ); } if ($scriptOptions && $scriptOptions['handlers']) { $item['script'] = array(array('js/lib/list.js')); $item['initObject'] = array(array('Qs_ViewController_List', array($scriptOptions))); } $item['columns'] = $this->getColumns(); $item['columnCount'] = ($item['columns']) ? count($item['columns']) + $specialColumnsCount : 0; $item['renderPrimaryKey'] = ($this->_actionToolbar || $this->_hasRowPreview); if (!$this->isDisabledLimit()) { $this->_getPaginator()->setCurrentPageNumber($this->getPageNumber()) ->setItemCountPerPage($this->_getIpp()) ->setCurrentItems($item['list']); $item['paginator'] = get_object_vars($this->_getPaginator()->getPages()); $item['paginator']['url'] = $this->getPaginatorUrl(); $item['paginator']['pagePlaceholder'] = Qs_ViewController_List::$_paginatorPagePlaceholder; $item['paginator']['ipp'] = $this->_getIpp(); $item['paginator']['changeableIpp'] = $this->getChangeableIpp(); $item['paginator']['ippList'] = $this->getIppList(); if ($item['paginator']['last'] < $this->getPageNumber() && ($item['paginator']['pageCount'] != 0 || $this->getPageNumber() > 1) ) { $redirectUrl = str_replace($this->getPaginatorPagePlaceholder(), 1, $this->getPaginatorUrl()); Qs_Http::redirect($redirectUrl, 307); } } return $item; } /** * @param $listSelect * @return Qs_ViewController_List */ public function setListSelect(Zend_Db_Select $listSelect) { $this->_listSelect = $listSelect; return $this; } /** * @return \Zend_Db_Select */ public function getListSelect() { return $this->_listSelect; } public function getSelectOptions() { $options = array(); if (false !== ($orderBy = $this->getOrderBy())) { $options['order'] = $orderBy; } if (false !== ($limitPage = $this->getLimitPage())) { $options['limitPage'] = $this->getLimitPage(); } return $options; } public function setRestParams(array $restParams) { $this->_restParams = $restParams; return $this; } public function getRestParams() { return $this->_restParams; } public function setTemplatePath(array $templatePath) { $this->_templatePath = $templatePath; return $this; } public function setPrimaryKey($primaryKey) { $this->_primaryKey = $primaryKey; return $this; } public function getPrimaryKey() { return $this->_primaryKey; } public function getTemplate($template) { return Qs_SiteMap::getTemplate($template, $this->_templatePath); } /** * @param null $field * @param null $default * @return mixed */ public function getConfig($field = null, $default = null) { if (null === $this->_config) { if (null === $this->_configName) { $this->_config = Qs_Config::getByInstance($this); } else { $this->_config = Qs_Config::get($this->_configName, Qs_Config::APP_TYPE); } } if (null === $field) { return $this->_config; } return $this->_config->get($field, $default); } public function setPreviewRowOption($name, $value) { $this->_rowPreviewOptions[$name] = $value; return $this; } public function getRowPreviewOptions() { return $this->_rowPreviewOptions; } public function setActionToolbarOption($name, $value) { $this->_actionToolbarOptions[$name] = $value; return $this; } public function getActionToolbarOptions() { if (!isset($this->_actionToolbarOptions['attribs']['id'])) { $id = str_replace(array('_', '\\'), '-', strtolower(get_class($this))) . '-toolbar-' . $this->idItem; $this->_actionToolbarOptions['attribs']['id'] = $id; } return $this->_actionToolbarOptions; } public function setScriptOption($name, $value) { $this->_scriptOptions[$name] = $value; return $this; } public function getScriptOptions() { if (!isset($this->_scriptOptions['primary'])) { $this->_scriptOptions['primary'] = $this->getPrimaryKey(); } if (!isset($this->_scriptOptions['idItem']) && isset($this->idItem)) { $this->_scriptOptions['idItem'] = $this->idItem; } if (!isset($this->_scriptOptions['listId'])) { $this->_scriptOptions['listId'] = $this->getAttrib('id'); } if (!isset($this->_scriptOptions['url'])) { $this->_scriptOptions['url'] = Qs_Request::url(); } return $this->_scriptOptions; } public function renderRowPreview(array $row) { /** @var $doc Qs_Doc */ $doc = Zend_Registry::get('doc'); $tpl = $this->getTemplate($this->_rowPreviewTemplate); $doc->assign('item', new Qs_Doc_Item($row)); return $doc->fetchTemplate($tpl); } public function setListTemplate($listTemplate) { $this->_listTemplate = $listTemplate; return $this; } public function getListTemplate() { return $this->_listTemplate; } }