'add', 'delete' => 'delete', 'up' => 'up', 'down' => 'down', 'row' => 'row', ]; protected $_placement = 'APPEND'; protected $_tag = 'table'; protected $_tagRow = 'tr'; protected $_tagCell = 'td'; protected $_tagBody = 'tbody'; protected $_tagHead = 'thead'; protected $_tagHeaderCell = 'th'; protected $_tagFoot = 'tfoot'; protected $_view; protected $_elementName; protected $_options; protected $_columns; public function setOptions(array $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->_options[$key] = $value; } } return $this; } function __call($name, $args) { $prefix = substr($name, 0, 3); if (in_array($prefix, ['set', 'get']) && substr($name, -3) == 'Tag') { $property = '_tag' . substr($name, 3, -3); if (property_exists($this, $property)) { if ($prefix == 'get') { return $this->$property; } elseif ($prefix == 'set') { $this->$property = $args[0]; return $this; } } } $debugData = debug_backtrace(); echo "Fatal error: Call to undefined method " . get_class($this) . ": $name() in {$debugData[1]['file']} on line " . "{$debugData[1]['line']}"; exit; } public function getOptions() { if (null === $this->_options) { $this->_options = Qs_Array::exclude($this->getElement()->getAttribs(), 'helper'); } return $this->_options; } public function initRender() { $doc = Zend_Registry::get('doc'); $doc->addScript('js/lib/form-element-grid.js') ->addInitFunction('Qs_Form_Element_Grid.init', [$this->getElement()->getId(), $this->_getScriptOptions()]); return $this; } public function render($content) { $element = $this->getElement(); $this->_columns = $element->getColumns(); $this->_view = $element->getView(); if (null === $this->_view) { return $content; } if (empty($this->_columns)) { throw new Qs_Form_Decorator_Exception('Columns is not defined'); } $this->_elementName = $element->getFullyQualifiedName(); $values = $element->getValue(); $tag = $this->getTag(); $placement = $this->getPlacement(); $noAttribs = $this->getOption('noAttribs'); $separator = $this->getOption('separator'); $id = $element->getId(); $attribs = []; if (!$noAttribs) { $attribs = $this->getOptions(); } if (!isset($attribs['class'])) { $attribs['class'] = 'grid'; } $attribs['id'] = $id; $grid = $this->_getOpenTag($tag, $attribs) . $this->_renderColumns($values) . $this->_getCloseTag($tag); switch ($placement) { case self::APPEND: return $content . $separator . $grid; case self::PREPEND: return $grid . $separator . $content; } } protected function _getScriptOptions() { $options = [ 'columns' => $this->getElement()->getColumns(), 'name' => $this->getElement()->getFullyQualifiedName(), 'autoIncrement' => max(count($this->getElement()->getValue()), 1), 'sortable' => $this->getElement()->isSortable(), ]; if (!($itemName = $this->getOption('itemName'))) { $itemName = 'row'; } $options['itemName'] = $this->_getText($itemName); return $options; } protected function _renderScriptOptions() { $options = $this->_getScriptOptions(); return json_encode($options); } protected function _renderColumns($values = null) { $content = ''; $attribs = $this->getOption('rowAttribs'); $noHeader = $this->getOption('noHeader'); $tag = $this->getRowTag(); $headerCellTag = $this->getHeaderCellTag(); // Header if (!$noHeader) { $content .= $this->_getOpenTag($this->getHeadTag()); $content .= $this->_getOpenTag($tag, $attribs); foreach ($this->_columns as $name => $options) { $attribs = []; if (isset($options['attribs'])) { $attribs = $options['attribs']; } if (isset($options['title'])) { $content .= $this->_getOpenTag($headerCellTag, $attribs) . $options['title'] . $this->_getCloseTag($headerCellTag); } } $content .= $this->_getCloseTag($tag); $content .= $this->_getCloseTag($this->getHeadTag()); } $content .= $this->_renderFooter(); $content .= $this->_getOpenTag($this->getBodyTag()); if (empty($values)) { $values = [array_fill_keys(array_keys(Qs_Array::exclude($this->_columns, '_options')), '')]; } // Rows $index = 0; foreach ($values as $rowValues) { $content .= $this->_getOpenTag($tag, $attribs); foreach ($this->_columns as $name => $options) { $value = (array_key_exists($name, $rowValues)) ? $rowValues[$name] : null; $this->_prepareCellOptions($name, $value, $options); $name = str_replace('[]', '[' . $index . ']', $this->_elementName) . '[' . $name . ']'; $content .= $this->_renderCell($name, $options); } $content .= $this->_getCloseTag($tag); $index++; } $content .= $this->_getCloseTag($this->getBodyTag()); return $content; } protected function _prepareCellOptions($name, $value, &$options) { $options['value'] = (is_array($value)) ? $value['value'] : $value; $options['shortName'] = $name; if (is_array($value)) { if (isset($value['label'])) { $options['label'] = $value['label']; } } } protected function _getId($name) { $id = $name; if (substr($id, -2) == '[]') { $id = substr($id, 0, strlen($id) - 2); } if (strstr($id, ']')) { $id = trim($id, ']'); $id = str_replace('][', '-', $id); $id = str_replace('[', '-', $id); } return $id; } protected function _renderInput($type, $name, $value, $label, $attribs = [], $options = []) { if (!isset($attribs['class'])) { $attribs['class'] = $type; } $description = ''; if (isset($attribs['description'])) { $description = $attribs['description']; unset($attribs['description']); } $content = $this->_getOpenTag('span', ['id' => $this->_getId($name) . '-label']) . htmlspecialchars($label) . ' ' . $this->_getCloseTag('span') . $this->_view->{'form' . ucfirst($type)}($name, $value, $attribs, $options); if ($description) { $content .= $description; } return $content; } protected function _renderCell($name, array $options) { $id = $this->getElement()->getId(); $tag = $this->getCellTag(); $label = ''; $value = ''; $cellAttribs = ['class' => str_replace('-', '_', $id) . '_' . $options['shortName']]; $elementAttribs = []; foreach ($options as $optionName => $optionValue) { if (in_array($name, ['class', 'style', 'description'])) { $elementAttribs[$optionName] = $optionValue; } } extract($options); switch ($type) { case 'text': case 'hidden': $content = $this->_renderInput($type, $name, $value, $label, $elementAttribs); break; case 'options': $content = ''; if ($this->getElement()->isSortable()) { $content .= '' . $this->_getText('up') . ' | '; $content .= '' . $this->_getText('down') . ' | '; } $content .= '' . $this->_getText('delete') . ''; break; case 'select': $content = $this->_renderInput($type, $name, $value, $label, [], $multiOptions); break; default: $content = ''; } if ($tag) { $content = $this->_getOpenTag($tag, $cellAttribs) . $content . $this->_getCloseTag($tag); } return $content; } protected function _renderAddLink() { $id = $this->getElement()->getId(); $content = $this->_getOpenTag( 'a', [ 'id' => $id . '-add', 'onclick' => "return Qs_Form_Element_Grid.add('{$id}');", 'href' => '#', ] ); if (!($itemName = $this->getOption('itemName'))) { $itemName = 'row'; } $content .= $this->_getText('add') . ' ' . $itemName; $content .= $this->_getCloseTag('a'); return $content; } public function setText($field, $value) { $this->_texts[$field] = $value; } protected function _getText($text) { if (isset($this->_texts[$text])) { $text = $this->_texts[$text]; } if ($translator = $this->getElement()->getTranslator()) { return $translator->translate($text); } return $text; } protected function _renderElement($type, $arguments) { $helperName = 'form' . ucfirst($type); if ($helper = $this->_view->getHelper($helperName)) { return call_user_func_array([$helper, $helperName], $arguments); } throw new Qs_Form_Decorator_Exception('Unsupported element type: ' . $type); } protected function _renderFooterCells() { $content = ''; $colspan = count($this->_columns); foreach ($this->_columns as $name => $column) { if (isset($column['valueFrom'])) { if ($options = $this->getElement()->getSourceElement($column['valueFrom'])) { $content .= $this->_getOpenTag($this->getCellTag()) . $this->_renderElement($options['type'], $options['arguments']) . $this->_getCloseTag($this->getCellTag()); $colspan--; } } } $content .= $this->_getOpenTag($this->getCellTag(), ['colspan' => $colspan]) . $this->_renderAddLink() . $this->_getCloseTag($this->getCellTag()); return $content; } protected function _renderFooter() { $content = $this->_getOpenTag($this->getFootTag()) . $this->_getOpenTag($this->getRowTag()) . $this->_renderFooterCells() . $this->_getCloseTag($this->getRowTag()) . $this->_getCloseTag($this->getFootTag()); return $content; } }