Overview

Namespaces

  • mechanicious
    • Columnizer
    • Extensions
      • Bs3Table
    • Support
    • Tableman
    • TablemanExtension
    • Test
      • Tableman
  • PHP

Classes

  • Tableman
  • TablemanCollection
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php namespace mechanicious\Tableman;
  2: 
  3: use mechanicious\Columnizer\ColumnBag;
  4: use mechanicious\Columnizer\Column;
  5: use mechanicious\Columnizer\Columnizer;
  6: use mechanicious\TablemanExtension\TablemanExtension;
  7: use mechanicious\TablemanExtension\Config;
  8: use Illuminate\Support\Collection;
  9: 
 10: /**
 11: * Tableman
 12: * Provides a convenient API for manipulation and 
 13: * creation of tables.
 14: */
 15: class Tableman extends TablemanCollection
 16: {
 17:   use \mechanicious\Support\ArrayableTrait;
 18: 
 19:   /**
 20:    * Holds the extensions
 21:    * @var array
 22:    */
 23:   protected $exts = array();
 24: 
 25:   public function __construct(ColumnBag $cols)
 26:   {
 27:     $this->items = $cols->all();
 28:   }
 29: 
 30:   /**
 31:    *  Get JSON representation of the data
 32:    * 
 33:    * @return string
 34:    */
 35:   public function getJson($format = 'column')
 36:   {
 37:     switch ($format) {
 38:       case 'column':
 39:         return $json = $this->toJson();
 40:       break;
 41: 
 42:       default:
 43:         $collection = new Collection($this->getRows());
 44:         return $json = $collection->toJson();
 45:       break;
 46:     }
 47:   }
 48:   
 49: 
 50:   private function getHtml(){// TODO
 51:   }
 52:   
 53:   private function getXml(){// TODO
 54:   }
 55: 
 56:   /**
 57:    * Returns whatever the callback function returns
 58:    *  
 59:    * @param  closure $callback
 60:    * @return mixed
 61:    */
 62:   public function withdraw(\closure $callback)
 63:   {
 64:     return $callback($this);
 65:   }
 66: 
 67:   /**
 68:    * Sort columns with a callback function
 69:    * 
 70:    * @param  closure $callback
 71:    * @callback function($previous, $current) {// -1, 0, 1}
 72:    * @usage http://php.net/manual/en/function.uasort.php#refsect1-function.uasort-parameters
 73:    * @return mechanicious\Tableman\Tableman
 74:    */
 75:   public function sortColumns(\closure $callback)
 76:   {
 77:     $this->sort($callback);
 78:     return $this;
 79:   }
 80: 
 81:   /**
 82:    * Reverse the order of columns
 83:    *  
 84:    * @return mechanicious\Tableman\Tableman
 85:    */
 86:   public function reverse()
 87:   {
 88:     $this->items = array_reverse($this->items);
 89:     return $this;
 90:   }
 91: 
 92:   /**
 93:    * Reverse the order of columns, alias of Tableman::reverse
 94:    *  
 95:    * @return mechanicious\Tableman\Tableman
 96:    */
 97:   public function reverseColumns()
 98:   {
 99:     $this->reverse();
100:     return $this;
101:   }
102: 
103:   /**
104:    * Put columns into a desired order
105:    * 
106:    * @return mechanicious\Tableman\Tableman
107:    */
108:   public function orderColumns(array $order = array())
109:   {
110:     array_walk($order, function() use(&$order) {
111:       $this->sort(function($previous, $current) use($order) {
112:         // Find the $current and $previous column headers in the $order array
113:         // provided by the user. Get the offsets from the $order provided by the user.
114:         $prevOffset    = array_search($previous->getHeader(), $order);
115:         $currentOffset = array_search($current->getHeader(), $order);
116:         // ... And then just simply compare those together.  
117:         if($prevOffset == $currentOffset) return 0;
118:         return ($prevOffset < $currentOffset) ? -1 : 1;
119:       });
120:     });
121:   }
122: 
123:   /**
124:    * Get the columns
125:    * 
126:    * @return array
127:    */
128:   public function getColumns()
129:   {
130:     return $this->items;
131:   }
132: 
133:   /**
134:    * Get order of columns
135:    * 
136:    * @return array
137:    */
138:   public function getColumnOrder()
139:   {
140:     return array_keys($this->items);
141:   }
142: 
143:   /**
144:    * Get current headers of columns
145:    * 
146:    * @return array
147:    */
148:   public function getColumnHeaders()
149:   {
150:     return array_keys($this->items);
151:   }
152: 
153:   /**
154:    * Check if a column exists
155:    *  
156:    * @return bool
157:    */
158:   public function columnExists($header)
159:   {
160:     return in_array($header, $this->getColumnHeaders());
161:   }
162: 
163:   /**
164:    * Check if a certain column has a certain value
165:    * 
166:    * @param  string $header
167:    * @param  mixed $needle
168:    * @return bool
169:    */
170:   public function columnHas($header, $needle)
171:   {
172:     return in_array($needle, $this->items[$header]->toArray());
173:   }
174: 
175:   /**
176:    * Add column at a particular offset
177:    * 
178:    * @param Column $col
179:    * @param int $offset
180:    */
181:   public function addColumn(Column $col, $offset)
182:   {
183:     $header = $col->getHeader();
184:     // If user is adding an already existing index, then
185:     // we'll assume the client intends to replace the columns.
186:     if($this->columnExists($header)) $this->forget($header);
187:     // Create expected order
188:     $columnOrder = $this->getColumnHeaders();
189:     array_splice($columnOrder, $offset, 0, $header);
190:     // Add column into the items
191:     $this->items[$header] = $this->padData($col);
192:     // Apply our order
193:     $this->orderColumns($columnOrder);
194:     return $this;
195:   }
196: 
197:   /**
198:    * Symmetrize data if the given column is asymmetric  
199:    * 
200:    * @param  mechanicious\Columnizer\Column $col
201:    * @return mechanicious\Columnizer\Column
202:    */
203:   public function padData(Column $col, $padValue = null)
204:   {
205:     if( ( $colSize = count($col) ) > ( $dataSize = count($this->first()) ) )
206:     {
207:       $this->eachColumn(function(&$ref, &$column, $header) use($colSize, $padValue) {
208:         $column->items = array_pad($column->all(), $colSize, $padValue);
209:       });
210:     }
211:     else
212:     {
213:      $col->items = array_pad($col->all(), $dataSize, $padValue);
214:     }
215:     // Either way return the column back.
216:     return $col;
217:   }
218: 
219:   /**
220:    * Prepend column
221:    * 
222:    * @param  Column $col
223:    * @return mechanicious\Tableman\Tableman
224:    */
225:   public function prependColumn(Column $col)
226:   {
227:     $this->items[$col->getHeader()] = $this->padData($col);
228:     $order = $this->getColumnHeaders();
229:     array_unshift($order, $col->getHeader());
230:     $this->orderColumns($order);
231:     return $this;
232:   }
233: 
234:   /**
235:    * Append column
236:    * 
237:    * @param  Column $col
238:    * @return mechanicious\Tableman\Tableman
239:    */
240:   public function appendColumn(Column $col)
241:   {
242:     $this->items[$col->getHeader()] = $this->padData($col);
243:     return $this;
244:   }
245: 
246:   /**
247:    * Remove the last column
248:    *   
249:    * @param  string $header
250:    * @return mechanicious\Tableman\Tableman
251:    */
252:   public function popColumn()
253:   {
254:     $this->pop();
255:     return $this;
256:   }
257: 
258:   /**
259:    * Remove first column
260:    * 
261:    * @param  string $header
262:    * @return mechanicious\Tableman\Tableman
263:    */
264:   public function shiftColumn()
265:   {
266:     $this->shift();
267:     return $this;
268:   }
269: 
270:   /**
271:    * Remove a column the header
272:    * 
273:    * @param  string $header
274:    * @return mechanicious\Tableman\Tableman
275:    */
276:   public function removeColumn($header)
277:   {
278:     $this->forget($header);
279:     return $this;
280:   }
281: 
282:   /**
283:    * Check if tho columns carry same content
284:    * 
285:    * @param  string $a
286:    * @param  string $b
287:    * @return boolean
288:    */
289:   public function compareColumnContent($colA, $colB)
290:   {
291:     return (bool) ($colA->toJson() === $colB->toJson());
292:   }
293: 
294:   /**
295:    * Replace column by another column
296:    * 
297:    * @param  Column $col
298:    * @param  string $header
299:    * @return mechanicious\Tableman\Tableman
300:    */
301:   public function replaceColumn(Column $col, $header)
302:   {
303:     if( ! in_array($header, array_keys($this->items))) throw new \Exception("column {$header} don't exist in " . implode(', ', array_keys($this->items)));
304:     
305:     $this->items[$header] = $col;
306:     if($header !== $col->getHeader())
307:     {
308:       $this->renameColumns(array($header => $col->getHeader()));
309:     } 
310:       
311:     return $this;
312:   }
313: 
314:   /**
315:    * Apply a callback on each row belonging to a specified column
316:    * 
317:    * @param     closure $callback
318:    * @callback  function(&$ref, &$row, $rowIndex) {}
319:    * @return    mechanicious\Tableman\Tableman
320:    */
321:   public function eachRowOf($header, \closure $callback)
322:   {
323:     array_walk($this->items[$header]->items, function(&$row, $rowIndex) use($callback)
324:     {
325:       $callback($this, $row, $rowIndex);
326:     });
327:     return $this;
328:   }
329: 
330:   /**
331:    * Apply a callback on each row
332:    * 
333:    * @param     closure $callback
334:    * @callback  function(&$ref, &$row, $rowIndex) {}
335:    * @return    mechanicious\Tableman\Tableman
336:    */
337:   public function eachRow(\closure $callback) 
338:   {
339:     array_walk($this->getRows(), function(&$row, $rowIndex) use($callback)
340:     {
341:       $callback($this, $row, $rowIndex);
342:     });
343:     return $this;
344:   }
345: 
346:   /**
347:    * Apply a callback on each cell
348:    * 
349:    * @param     closure $callback
350:    * @callback  function(&$ref, &$cell, &$row, $rowIndex) {}
351:    * @return    mechanicious\Tableman\Tableman
352:    */
353:   public function eachCell(\closure $callback) 
354:   {
355:     array_walk($this->getRows(), function(&$row, $rowIndex) use(&$rows, $callback) {
356:       foreach($row as $index => &$cell)
357:       {
358:         $callback($this, $cell, $row, $rowIndex);
359:       }
360:     });
361:     return $this;
362:   }
363: 
364:   /**
365:    * Apply a callback on each column
366:    * 
367:    * @param     closure $callback
368:    * @callback  function(&$ref, &$column, $header) {}
369:    * @return    mechanicious\Tableman\Tableman
370:    */
371:   public function eachColumn(\closure $callback) 
372:   {
373:     array_walk($this->items, function(&$column, &$columnHeader) use($callback, &$columns) {
374:       $callback($this, $column, $columnHeader);      
375:     });
376:     return $this;
377:   }
378: 
379:   /**
380:    * Get a column by it's header
381:    *   
382:    * @param  string $header
383:    * @return mechanicious\Columnizer\Column;
384:    */
385:   public function getColumn($header)
386:   {
387:     return $this[$header];
388:   }
389: 
390:   /**
391:    * Get columns
392:    * 
393:    * @return array
394:    */
395:   public function getAllColumns()
396:   {
397:     return $this->items;
398:   }
399: 
400:   /**
401:    * Get referenced-rows as an array
402:    * 
403:    * @return  array
404:    */
405:   public function getRows()
406:   {
407:     $items  = &$this->items;
408:     $mergee = array();
409:     $columnNames = array_keys($this->items);
410:     // We assume the present data is symmetric
411:     for($i = 0; $i < count($this->first()); $i++)
412:     {
413:       $row = array();
414:       foreach($items as $header => &$column)
415:       {
416:         $row[$header] = &$column->items[$i];
417:       }
418:       $mergee[] = $row;
419:     }
420:     return $mergee;
421:   }
422: 
423:   /**
424:    * Rename Headers
425:    * 
426:    * @return void
427:    */
428:   public function renameColumns(array $headers = array())
429:   {
430:     $items = $this->items;
431:     // We need a copy because the order will be overridden by the replace routine
432:     // because in a certain situation some replacements will be skipped while still
433:     // appending the other columns.
434:     $headersCopy = $this->getColumnHeaders(); 
435:     array_walk($headers, function($newKey, $oldKey) use(&$items, &$headersCopy) {
436:       if($newKey !== $oldKey) // No need to bother when headers are same
437:       {
438:         $column = new Column($items[$oldKey]->all(), $newKey);
439:         $this->forget($oldKey);
440:         $this->put($newKey, $column);
441:         // Replace the old header from $headersCopy with the new header
442:         $headersCopy[array_search($oldKey, $headersCopy)] = $newKey;
443:       }
444:     });
445:     // Order columns like they where before.
446:     $this->orderColumns($headersCopy);
447:     return $this;
448:   }
449: 
450:   public function __call($name, $args)
451:   {
452:     $autloadedClasses = get_declared_classes();
453: 
454:     // Don't bother, it seems we did what's needed already before.
455:     if(in_array($name, array_keys($this->exts))) return $this->exts[$name]->make($this, new Config($args[0]));
456: 
457:     /**
458:      * Use existing class mechanism
459:      */
460:     $found = false;
461:     // Let's see if the class is loaded first.
462:     array_walk($autloadedClasses, function($class, $index) use($name, &$found) {
463:       if(is_string($found)) return;
464:       $segments = explode('\\', $class);
465:       // We assume the last segment of a fully-qualified-classname is equal to the
466:       // entry in the array.
467:       if(last($segments) === $name) return $found = $class;
468:     });
469:     // Make sure it's a TablemanExtension
470:     if($found && ($instance = new $found) instanceof TablemanExtension)
471:     {
472:       $this->exts[$name] = $instance;
473:       return $this->exts[$name]->make($this, new Config($args[0]));
474:     } 
475: 
476:     /*
477:      * Load non-existent class mechanism
478:      */
479:     $ext_reg = require "/../Config/ExtensionRegister.php";
480:     if( ! in_array($name, array_keys($ext_reg))) throw new \Exception("method {$name} is not a part of " . __CLASS__);
481:     require_once $ext_reg[$name]['relative_path'];
482:     $classname = $ext_reg[$name]['fully_qualified_classname'];
483:     $instance = new $classname;
484:     $this->exts[$name] = $instance;
485:     if( ! isset($args[0])) throw new \Exception("you must provide a config for {$name}");
486:     if( ! is_array($args[0])) throw new \Exception("config for {$name} must be an array");
487:     return $this->exts[$name]->make($this, new Config($args[0]));
488:   }
489: }
API documentation generated by ApiGen 2.8.0