Grido@master
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  • Download

Namespaces

  • Grido
    • Components
      • Actions
      • Columns
      • Filters
    • DataSources
    • PropertyAccessors
    • Translations

Classes

  • Grido\Translations\FileTranslator
  1 <?php
  2 
  3 /**
  4  * This file is part of the Grido (https://github.com/o5/grido)
  5  *
  6  * Copyright (c) 2014 Petr Bugyík (http://petr.bugyik.cz)
  7  *
  8  * For the full copyright and license information, please view
  9  * the file LICENSE.md that was distributed with this source code.
 10  */
 11 
 12 namespace Grido\Components\Columns;
 13 
 14 /**
 15  * An inline editable column.
 16  *
 17  * @package     Grido
 18  * @subpackage  Components\Columns
 19  * @author      Jakub Kopřiva <kopriva.jakub@gmail.com>
 20  * @author      Petr Bugyík
 21  *
 22  * @property \Nette\Forms\IControl $editableControl
 23  * @property callback $editableCallback
 24  * @property callback $editableValueCallback
 25  * @property callback $editableRowCallback
 26  */
 27 abstract class Editable extends Column
 28 {
 29     /** @var bool */
 30     protected $editable = FALSE;
 31 
 32     /** @var bool */
 33     protected $editableDisabled = FALSE;
 34 
 35     /** @var \Nette\Forms\IControl Custom control for inline editing */
 36     protected $editableControl;
 37 
 38     /** @var callback for custom handling with edited data; function($id, $newValue, $oldValue, Editable $column) {} */
 39     protected $editableCallback;
 40 
 41     /** @var callback for custom value; function($row, Columns\Editable $column) {} */
 42     protected $editableValueCallback;
 43 
 44     /** @var callback for getting row; function($row, Columns\Editable $column) {} */
 45     protected $editableRowCallback;
 46 
 47     /**
 48      * Sets column as editable.
 49      * @param callback $callback function($id, $newValue, $oldValue, Columns\Editable $column) {}
 50      * @param \Nette\Forms\IControl $control
 51      * @return Editable
 52      */
 53     public function setEditable($callback = NULL, \Nette\Forms\IControl $control = NULL)
 54     {
 55         $this->editable = TRUE;
 56         $this->setClientSideOptions();
 57 
 58         $callback && $this->setEditableCallback($callback);
 59         $control && $this->setEditableControl($control);
 60 
 61         return $this;
 62     }
 63 
 64     /**
 65      * Sets control for inline editation.
 66      * @param \Nette\Forms\IControl $control
 67      * @return Editable
 68      */
 69     public function setEditableControl(\Nette\Forms\IControl $control)
 70     {
 71         $this->isEditable() ?: $this->setEditable();
 72         $this->editableControl = $control;
 73 
 74         return $this;
 75     }
 76 
 77     /**
 78      * Sets editable callback.
 79      * @param callback $callback function($id, $newValue, $oldValue, Columns\Editable $column) {}
 80      * @return Editable
 81      */
 82     public function setEditableCallback($callback)
 83     {
 84         $this->isEditable() ?: $this->setEditable();
 85         $this->editableCallback = $callback;
 86 
 87         return $this;
 88     }
 89 
 90     /**
 91      * Sets editable value callback.
 92      * @param callback $callback for custom value; function($row, Columns\Editable $column) {}
 93      * @return Editable
 94      */
 95     public function setEditableValueCallback($callback)
 96     {
 97         $this->isEditable() ?: $this->setEditable();
 98         $this->editableValueCallback = $callback;
 99 
100         return $this;
101     }
102 
103     /**
104      * Sets editable row callback - it's required when used editable collumn with customRenderCallback
105      * @param callback $callback for getting row; function($id, Columns\Editable $column) {}
106      * @return Editable
107      */
108     public function setEditableRowCallback($callback)
109     {
110         $this->isEditable() ?: $this->setEditable();
111         $this->editableRowCallback = $callback;
112 
113         return $this;
114     }
115 
116     /**
117      * @return Editable
118      */
119     public function disableEditable()
120     {
121         $this->editable = FALSE;
122         $this->editableDisabled = TRUE;
123 
124         return $this;
125     }
126 
127     protected function setClientSideOptions()
128     {
129         $options = $this->grid->getClientSideOptions();
130         if (!isset($options['editable'])) { //only once
131             $this->grid->setClientSideOptions(array('editable' => TRUE));
132             $this->grid->onRender[] = function(\Grido\Grid $grid)
133             {
134                 foreach ($grid->getComponent(Column::ID)->getComponents() as $column) {
135                     if (!$column instanceof Editable || !$column->isEditable()) {
136                         continue;
137                     }
138 
139                     $colDb = $column->getColumn();
140                     $colName = $column->getName();
141                     $isMissing = function ($method) use ($grid) {
142                         return $grid->model instanceof \Grido\DataSources\Model
143                             ? !method_exists($grid->model->dataSource, $method)
144                             : TRUE;
145                     };
146 
147                     if (($column->editableCallback === NULL && (!is_string($colDb) || strpos($colDb, '.'))) ||
148                         ($column->editableCallback === NULL && $isMissing('update'))
149                     ) {
150                         $msg = "Column '$colName' has error: You must define callback via setEditableCallback().";
151                         throw new \Exception($msg);
152                     }
153 
154                     if ($column->editableRowCallback === NULL && $column->customRender && $isMissing('getRow')) {
155                         $msg = "Column '$colName' has error: You must define callback via setEditableRowCallback().";
156                         throw new \Exception($msg);
157                     }
158                 }
159             };
160         }
161     }
162 
163     /**********************************************************************************************/
164 
165     /**
166      * Returns header cell prototype (<th> html tag).
167      * @return \Nette\Utils\Html
168      */
169     public function getHeaderPrototype()
170     {
171         $th = parent::getHeaderPrototype();
172 
173         if ($this->isEditable()) {
174             $th->data['grido-editable-handler'] = $this->link('editable!');
175             $th->data['grido-editableControl-handler'] = $this->link('editableControl!');
176         }
177 
178         return $th;
179     }
180 
181     /**
182      * Returns cell prototype (<td> html tag).
183      * @param mixed $row
184      * @return \Nette\Utils\Html
185      */
186     public function getCellPrototype($row = NULL)
187     {
188         $td = parent::getCellPrototype($row);
189 
190         if ($this->isEditable() && $row !== NULL) {
191             $td->data['grido-editable-value'] = $this->editableValueCallback === NULL
192                 ? parent::getValue($row)
193                 : callback($this->editableValueCallback)->invokeArgs(array($row, $this));
194         }
195 
196         return $td;
197     }
198 
199     /**
200      * Returns control for editation.
201      * @returns \Nette\Forms\Controls\TextInput
202      */
203     public function getEditableControl()
204     {
205         if ($this->editableControl === NULL) {
206             $this->editableControl = new \Nette\Forms\Controls\TextInput;
207             $this->editableControl->controlPrototype->class[] = 'form-control';
208         }
209 
210         return $this->editableControl;
211     }
212 
213     /**
214      * @return callback
215      * @internal
216      */
217     public function getEditableCallback()
218     {
219         return $this->editableCallback;
220     }
221 
222     /**
223      * @return callback
224      * @internal
225      */
226     public function getEditableValueCallback()
227     {
228         return $this->editableValueCallback;
229     }
230 
231     /**
232      * @return callback
233      * @internal
234      */
235     public function getEditableRowCallback()
236     {
237         return $this->editableRowCallback;
238     }
239 
240     /**
241      * @return bool
242      * @internal
243      */
244     public function isEditable()
245     {
246         return $this->editable;
247     }
248 
249     /**
250      * @return bool
251      * @internal
252      */
253     public function isEditableDisabled()
254     {
255         return $this->editableDisabled;
256     }
257 
258     /**********************************************************************************************/
259 
260     /**
261      * @internal
262      */
263     public function handleEditable($id, $newValue, $oldValue)
264     {
265         $this->grid->onRegistered($this->grid);
266 
267         if (!$this->presenter->isAjax() || !$this->isEditable()) {
268             $this->presenter->terminate();
269         }
270 
271         $success = $this->editableCallback
272             ? callback($this->editableCallback)->invokeArgs(array($id, $newValue, $oldValue, $this))
273             : $this->grid->model->update($id, array($this->getColumn() => $newValue), $this->grid->primaryKey);
274 
275         if (is_callable($this->customRender)) {
276             $row = $this->editableRowCallback
277                 ? callback($this->editableRowCallback)->invokeArgs(array($id, $this))
278                 : $this->grid->model->getRow($id, $this->grid->primaryKey);
279             $html = callback($this->customRender)->invokeArgs(array($row));
280         } else {
281             $html = $this->formatValue($newValue);
282         }
283 
284         $payload = array('updated' => (bool) $success, 'html' => (string) $html);
285         $response = new \Nette\Application\Responses\JsonResponse($payload);
286         $this->presenter->sendResponse($response);
287     }
288 
289     /**
290      * @internal
291      */
292     public function handleEditableControl($value)
293     {
294         $this->grid->onRegistered($this->grid);
295 
296         if (!$this->presenter->isAjax() || !$this->isEditable()) {
297             $this->presenter->terminate();
298         }
299 
300         $control = $this->getEditableControl()->setValue($value);
301         $this->getForm()->addComponent($control, 'edit' . $this->getName());
302 
303         $response = new \Nette\Application\Responses\TextResponse($control->getControl()->render());
304         $this->presenter->sendResponse($response);
305     }
306 }
307 
Grido@master API documentation generated by ApiGen