HCE Project DC service web UI  0.2
Hierarchical Cluster Engine DC service web UI
 All Classes Namespaces Files Functions Variables Pages
TbGroupGridView.php
Go to the documentation of this file.
1 <?php
13 Yii::import('booster.widgets.TbGridView');
14 
25 {
26 
27  const MERGE_SIMPLE = 'simple';
28  const MERGE_NESTED = 'nested';
29  const MERGE_FIRSTROW = 'firstrow';
30 
34  public $mergeColumns = array();
35 
40 
44  public $mergeCellCss = 'text-align: center; vertical-align: middle';
45 
49  public $extraRowColumns = array();
50 
55 
59  public $extraRowHtmlOptions = array();
60 
64  public $extraRowCssClass = 'extrarow';
65 
69  private $_changes;
70 
74  public function init()
75  {
76  parent::init();
77 
81  if (!empty($this->extraRowColumns)) {
82  foreach ($this->columns as $column) {
83  if ($column instanceof CDataColumn && in_array($column->name, $this->extraRowColumns)) {
84  $column->filterHtmlOptions = array('style' => 'display:none');
85  $column->filter = false;
86  }
87  }
88  }
92  if (isset($this->extraRowHtmlOptions['class']) && !empty($this->extraRowCssClass)) {
93  $this->extraRowHtmlOptions['class'] .= ' ' . $this->extraRowCssClass;
94  } else {
95  $this->extraRowHtmlOptions['class'] = $this->extraRowCssClass;
96  }
97  }
98 
102  public function registerClientScript()
103  {
104  $id=$this->getId();
105 
106  if($this->ajaxUpdate===false)
107  $ajaxUpdate=false;
108  else
109  $ajaxUpdate=array_unique(preg_split('/\s*,\s*/',$this->ajaxUpdate.','.$id,-1,PREG_SPLIT_NO_EMPTY));
110  $options=array(
111  'ajaxUpdate'=>$ajaxUpdate,
112  'ajaxVar'=>$this->ajaxVar,
113  'pagerClass'=>$this->pagerCssClass,
114  'loadingClass'=>$this->loadingCssClass,
115  'filterClass'=>$this->filterCssClass,
116  'tableClass'=>$this->itemsCssClass,
117  'selectableRows'=>$this->selectableRows,
118  'enableHistory'=>$this->enableHistory,
119  'updateSelector'=>$this->updateSelector,
120  'filterSelector'=>$this->filterSelector
121  );
122  if($this->ajaxUrl!==null)
123  $options['url']=CHtml::normalizeUrl($this->ajaxUrl);
124  if($this->ajaxType!==null)
125  $options['ajaxType']=strtoupper($this->ajaxType);
126  if($this->enablePagination)
127  $options['pageVar']=$this->dataProvider->getPagination()->pageVar;
128  foreach(array('beforeAjaxUpdate', 'afterAjaxUpdate', 'ajaxUpdateError', 'selectionChanged') as $event)
129  {
130  if($this->$event!==null)
131  {
132  if($this->$event instanceof CJavaScriptExpression)
133  $options[$event]=$this->$event;
134  else
135  $options[$event]=new CJavaScriptExpression($this->$event);
136  }
137  }
138 
139  $options=CJavaScript::encode($options);
140  $cs=Yii::app()->getClientScript();
141  $cs->registerCoreScript('jquery');
142  $cs->registerCoreScript('bbq');
143  if($this->enableHistory)
144  $cs->registerCoreScript('history');
145  // $cs->registerScriptFile($this->baseScriptUrl.'/jquery.yiigridview.js',CClientScript::POS_END);
146  $cs->registerPackage('group-grid-view');
147  $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiGroupGridView($options);");
148  }
149 
153  public function renderTableBody()
154  {
155  if (!empty($this->mergeColumns) || !empty($this->extraRowColumns)) {
156  $this->groupByColumns();
157  }
158 
160  }
161 
165  public function groupByColumns()
166  {
167  $data = $this->dataProvider->getData();
168  if (count($data) == 0) {
169  return;
170  }
171 
172  if (!is_array($this->mergeColumns)) {
173  $this->mergeColumns = array($this->mergeColumns);
174  }
175  if (!is_array($this->extraRowColumns)) {
176  $this->extraRowColumns = array($this->extraRowColumns);
177  }
178 
179  //store columns for group. Set object for existing columns in grid and string for attributes
180  $groupColumns = array_unique(array_merge($this->mergeColumns, $this->extraRowColumns));
181  foreach ($groupColumns as $key => $colName) {
182  foreach ($this->columns as $column) {
183  if (property_exists($column, 'name') && $column->name == $colName) {
184  $groupColumns[$key] = $column;
185  break;
186  }
187  }
188  }
189 
190 
191  //values for first row
192  $lastStored = $this->getRowValues($groupColumns, $data[0], 0);
193  foreach ($lastStored as $colName => $value) {
194  $lastStored[$colName] = array(
195  'value' => $value,
196  'count' => 1,
197  'index' => 0,
198  );
199  }
200 
201  //iterate data
202  $rowcount = count($data);
203  for ($i = 1; $i < $rowcount; $i++) {
204  //save row values in array
205  $current = $this->getRowValues($groupColumns, $data[$i], $i);
206 
207  //define is change occured. Need this extra foreach for correctly proceed extraRows
208  $changedColumns = array();
209  foreach ($current as $colName => $curValue) {
210  if ($curValue != $lastStored[$colName]['value']) {
211  $changedColumns[] = $colName;
212  }
213  }
214 
219  $saveChangeForAllColumns = (count(array_intersect($changedColumns, $this->extraRowColumns)) > 0);
220 
225  $changeOccurred = false;
226  foreach ($current as $colName => $curValue) {
227  //value changed
228  $valueChanged = ($curValue != $lastStored[$colName]['value']);
229  //change already occured in this loop and mergeType set to MERGETYPE_NESTED
230  $saveChange = $valueChanged || ($changeOccurred && $this->mergeType == self::MERGE_NESTED);
231 
232  if ($saveChangeForAllColumns || $saveChange) {
233  $changeOccurred = true;
234 
235  //store in class var
236  $prevIndex = $lastStored[$colName]['index'];
237  $this->_changes[$prevIndex]['columns'][$colName] = $lastStored[$colName];
238  if (!isset($this->_changes[$prevIndex]['count'])) {
239  $this->_changes[$prevIndex]['count'] = $lastStored[$colName]['count'];
240  }
241 
242  //update lastStored for particular column
243  $lastStored[$colName] = array(
244  'value' => $curValue,
245  'count' => 1,
246  'index' => $i,
247  );
248 
249  } else {
250  $lastStored[$colName]['count']++;
251  }
252  }
253  }
254 
255  //storing for last row
256  foreach ($lastStored as $colName => $v) {
257  $prevIndex = $v['index'];
258  $this->_changes[$prevIndex]['columns'][$colName] = $v;
259 
260  if (!isset($this->_changes[$prevIndex]['count'])) {
261  $this->_changes[$prevIndex]['count'] = $v['count'];
262  }
263  }
264  }
265 
271  public function renderTableRow($row)
272  {
273  $change = false;
274  if ($this->_changes && array_key_exists($row, $this->_changes)) {
275  $change = $this->_changes[$row];
276  //if change in extracolumns --> put extra row
277  $columnsInExtra = array_intersect(array_keys($change['columns']), $this->extraRowColumns);
278  if (count($columnsInExtra) > 0) {
279  $this->renderExtraRow($row, $change, $columnsInExtra);
280  }
281  }
282 
283  // original CGridView code
284  if ($this->rowCssClassExpression !== null) {
285  $data = $this->dataProvider->data[$row];
286  echo '<tr class="' . $this->evaluateExpression(
287  $this->rowCssClassExpression,
288  array('row' => $row, 'data' => $data)
289  ) . '">';
290  } else if (is_array($this->rowCssClass) && ($n = count($this->rowCssClass)) > 0) {
291  echo '<tr class="' . $this->rowCssClass[$row % $n] . '">';
292  } else {
293  echo '<tr>';
294  }
295 
296 
297  if (!$this->_changes) { //standart CGridview's render
298  foreach ($this->columns as $column) {
299  $column->renderDataCell($row);
300  }
301  } else { //for grouping
302  foreach ($this->columns as $column) {
303  $isGroupColumn = property_exists($column, 'name') && in_array($column->name, $this->mergeColumns);
304  if (!$isGroupColumn) {
305  $column->renderDataCell($row);
306  continue;
307  }
308 
309  $isChangedColumn = $change && array_key_exists($column->name, $change['columns']);
310 
311  //for rowspan show only changes (with rowspan)
312  switch ($this->mergeType) {
313  case self::MERGE_SIMPLE:
314  case self::MERGE_NESTED:
315  if ($isChangedColumn) {
316  $options = $column->htmlOptions;
317  $column->htmlOptions['rowspan'] = $change['columns'][$column->name]['count'];
318  $column->htmlOptions['class'] = 'merge';
319  $style = isset($column->htmlOptions['style']) ? $column->htmlOptions['style'] : '';
320  $column->htmlOptions['style'] = $style . ';' . $this->mergeCellCss;
321  $column->renderDataCell($row);
322  $column->htmlOptions = $options;
323  }
324  break;
325 
326  case self::MERGE_FIRSTROW:
327  if ($isChangedColumn) {
328  $column->renderDataCell($row);
329  } else {
330  echo '<td></td>';
331  }
332  break;
333  }
334 
335  }
336  }
337 
338  echo "</tr>\n";
339  }
340 
351  private function getRowValues($columns, $data, $rowIndex)
352  {
353  foreach ($columns as $column) {
354  if ($column instanceOf TbDataColumn) {
355  $result[$column->name] = $this->getDataCellContent($column, $data, $rowIndex);
356  } elseif (is_string($column)) {
357  if (is_array($data) && array_key_exists($column, $data)) {
358  $result[$column] = $data[$column];
359  } elseif ($data instanceOf CActiveRecord && $data->hasAttribute($column)) {
360  $result[$column] = $data->getAttribute($column);
361  } else {
362  throw new CException('Column or attribute "' . $column . '" not found!');
363  }
364  }
365  }
366  return isset($result) ? $result : false;
367  }
368 
376  private function renderExtraRow($beforeRow, $change, $columnsInExtra)
377  {
378  $data = $this->dataProvider->data[$beforeRow];
379  if ($this->extraRowExpression) { //user defined expression, use it!
380  $content = $this->evaluateExpression(
381  $this->extraRowExpression,
382  array('data' => $data, 'row' => $beforeRow, 'values' => $change['columns'])
383  );
384  } else { //generate value
385  $values = array();
386  foreach ($columnsInExtra as $c) {
387  $values[] = $change['columns'][$c]['value'];
388  }
389 
390  $content = '<strong>' . implode(' :: ', $values) . '</strong>';
391  }
392 
393  $colspan = count($this->columns);
394 
395  echo '<tr class="extrarow">';
396  $this->extraRowHtmlOptions['colspan'] = $colspan;
397  echo CHtml::openTag('td', $this->extraRowHtmlOptions);
398  echo $content;
399  echo CHtml::closeTag('td');
400  echo '</tr>';
401  }
402 
412  private function getDataCellContent($column, $data, $row)
413  {
414  if ($column->value !== null) {
415  $value = $column->evaluateExpression($column->value, array('data' => $data, 'row' => $row));
416  } else if ($column->name !== null) {
417  $value = CHtml::value($data, $column->name);
418  }
419 
420  return !isset($value)
421  ? $column->grid->nullDisplay
422  : $column->grid->getFormatter()->format(
423  $value,
424  $column->type
425  );
426  }
427 }