'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;
}
}