7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
16 * @package Zend_Text_Table
17 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id: Table.php 16209 2009-06-21 19:20:34Z thomas $
23 * Zend_Text_Table enables developers to create tables out of characters
26 * @package Zend_Text_Table
27 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
28 * @license http://framework.zend.com/license/new-bsd New BSD License
33 * Auto seperator settings
35 const AUTO_SEPARATE_NONE
= 0x0;
36 const AUTO_SEPARATE_HEADER
= 0x1;
37 const AUTO_SEPARATE_FOOTER
= 0x2;
38 const AUTO_SEPARATE_ALL
= 0x4;
41 * Decorator used for the table borders
43 * @var Zend_Text_Table_Decorator_Interface
45 protected $_decorator = null;
48 * List of all column widths
52 protected $_columnWidths = null;
59 protected $_rows = array();
62 * Auto separation mode
66 protected $_autoSeparate = self
::AUTO_SEPARATE_ALL
;
73 protected $_padding = 0;
76 * Default column aligns for rows created by appendRow(array $data)
80 protected $_defaultColumnAligns = array();
83 * Plugin loader for decorators
87 protected $_pluginLoader = null;
90 * Charset which is used for input by default
94 protected static $_inputCharset = 'utf-8';
97 * Charset which is used internally
101 protected static $_outputCharset = 'utf-8';
104 * Option keys to skip when calling setOptions()
108 protected $_skipOptions = array(
111 'defaultColumnAlign',
115 * Create a basic table object
117 * @param array $columnsWidths List of all column widths
118 * @param Zend_Config|array $options Configuration options
119 * @throws Zend_Text_Table_Exception When no columns widths were set
121 public function __construct($options = null)
124 if (is_array($options)) {
125 $this->setOptions($options);
126 } else if ($options instanceof Zend_Config
) {
127 $this->setConfig($options);
130 // Check if column widths were set
131 // @todo When column widths were not set, assume auto-sizing
132 if ($this->_columnWidths
=== null) {
133 require_once 'Zend/Text/Table/Exception.php';
134 throw new Zend_Text_Table_Exception('You must define the column widths');
137 // If no decorator was given, use default unicode decorator
138 if ($this->_decorator
=== null) {
139 if (self
::getOutputCharset() === 'utf-8') {
140 $this->setDecorator('unicode');
142 $this->setDecorator('ascii');
148 * Set options from array
150 * @param array $options Configuration for Zend_Text_Table
151 * @return Zend_Text_Table
153 public function setOptions(array $options)
155 foreach ($options as $key => $value) {
156 if (in_array(strtolower($key), $this->_skipOptions
)) {
160 $method = 'set' . ucfirst($key);
161 if (method_exists($this, $method)) {
162 $this->$method($value);
170 * Set options from config object
172 * @param Zend_Config $config Configuration for Zend_Text_Table
173 * @return Zend_Text_Table
175 public function setConfig(Zend_Config
$config)
177 return $this->setOptions($config->toArray());
183 * @param array $columnWidths Widths of all columns
184 * @throws Zend_Text_Table_Exception When no columns were supplied
185 * @throws Zend_Text_Table_Exception When a column has an invalid width
186 * @return Zend_Text_Table
188 public function setColumnWidths(array $columnWidths)
190 if (count($columnWidths) === 0) {
191 require_once 'Zend/Text/Table/Exception.php';
192 throw new Zend_Text_Table_Exception('You must supply at least one column');
195 foreach ($columnWidths as $columnNum => $columnWidth) {
196 if (is_int($columnWidth) === false or $columnWidth < 1) {
197 require_once 'Zend/Text/Table/Exception.php';
198 throw new Zend_Text_Table_Exception('Column ' . $columnNum . ' has an invalid'
203 $this->_columnWidths
= $columnWidths;
209 * Set auto separation mode
211 * @param integer $autoSeparate Auto separation mode
212 * @return Zend_Text_Table
214 public function setAutoSeparate($autoSeparate)
216 $this->_autoSeparate
= (int) $autoSeparate;
223 * @param Zend_Text_Table_Decorator_Interface|string $decorator Decorator to use
224 * @return Zend_Text_Table
226 public function setDecorator($decorator)
228 if ($decorator instanceof Zend_Text_Table_Decorator_Interface
) {
229 $this->_decorator
= $decorator;
231 $classname = $this->getPluginLoader()->load($decorator);
232 $this->_decorator
= new $classname;
239 * Set the column padding
241 * @param integer $padding The padding for the columns
242 * @return Zend_Text_Table
244 public function setPadding($padding)
246 $this->_padding
= max(0, (int) $padding);
251 * Get the plugin loader for decorators
253 * @return Zend_Loader_PluginLoader
255 public function getPluginLoader()
257 if ($this->_pluginLoader
=== null) {
258 $prefix = 'Zend_Text_Table_Decorator_';
259 $pathPrefix = 'Zend/Text/Table/Decorator/';
261 require_once 'Zend/Loader/PluginLoader.php';
262 $this->_pluginLoader
= new Zend_Loader_PluginLoader(array($prefix => $pathPrefix));
265 return $this->_pluginLoader
;
269 * Set default column align for rows created by appendRow(array $data)
271 * @param integer $columnNum
272 * @param string $align
273 * @return Zend_Text_Table
275 public function setDefaultColumnAlign($columnNum, $align)
277 $this->_defaultColumnAligns
[$columnNum] = $align;
283 * Set the input charset for column contents
285 * @param string $charset
287 public static function setInputCharset($charset)
289 self
::$_inputCharset = strtolower($charset);
293 * Get the input charset for column contents
295 * @param string $charset
297 public static function getInputCharset()
299 return self
::$_inputCharset;
303 * Set the output charset for column contents
305 * @param string $charset
307 public static function setOutputCharset($charset)
309 self
::$_outputCharset = strtolower($charset);
313 * Get the output charset for column contents
315 * @param string $charset
317 public static function getOutputCharset()
319 return self
::$_outputCharset;
323 * Append a row to the table
325 * @param array|Zend_Text_Table_Row $row The row to append to the table
326 * @throws Zend_Text_Table_Exception When $row is neither an array nor Zend_Zext_Table_Row
327 * @throws Zend_Text_Table_Exception When a row contains too many columns
328 * @return Zend_Text_Table
330 public function appendRow($row)
332 if (!is_array($row) && !($row instanceof Zend_Text_Table_Row
)) {
333 require_once 'Zend/Text/Table/Exception.php';
334 throw new Zend_Text_Table_Exception('$row must be an array or instance of Zend_Text_Table_Row');
337 if (is_array($row)) {
338 if (count($row) > count($this->_columnWidths
)) {
339 require_once 'Zend/Text/Table/Exception.php';
340 throw new Zend_Text_Table_Exception('Row contains too many columns');
343 require_once 'Zend/Text/Table/Row.php';
346 $row = new Zend_Text_Table_Row();
348 foreach ($data as $columnData) {
349 if (isset($this->_defaultColumnAligns
[$colNum])) {
350 $align = $this->_defaultColumnAligns
[$colNum];
355 $row->appendColumn(new Zend_Text_Table_Column($columnData, $align));
360 $this->_rows
[] = $row;
368 * @throws Zend_Text_Table_Exception When no rows were added to the table
371 public function render()
373 // There should be at least one row
374 if (count($this->_rows
) === 0) {
375 require_once 'Zend/Text/Table/Exception.php';
376 throw new Zend_Text_Table_Exception('No rows were added to the table yet');
379 // Initiate the result variable
382 // Count total columns
383 $totalNumColumns = count($this->_columnWidths
);
385 // Now render all rows, starting from the first one
386 $numRows = count($this->_rows
);
387 foreach ($this->_rows
as $rowNum => $row) {
388 // Get all column widths
389 if (isset($columnWidths) === true) {
390 $lastColumnWidths = $columnWidths;
393 $renderedRow = $row->render($this->_columnWidths
, $this->_decorator
, $this->_padding
);
394 $columnWidths = $row->getColumnWidths();
395 $numColumns = count($columnWidths);
397 // Check what we have to draw
399 // If this is the first row, draw the table top
400 $result .= $this->_decorator
->getTopLeft();
402 foreach ($columnWidths as $columnNum => $columnWidth) {
403 $result .= str_repeat($this->_decorator
->getHorizontal(),
406 if (($columnNum +
1) === $numColumns) {
407 $result .= $this->_decorator
->getTopRight();
409 $result .= $this->_decorator
->getHorizontalDown();
415 // Else check if we have to draw the row separator
416 if ($this->_autoSeparate
& self
::AUTO_SEPARATE_ALL
) {
417 $drawSeparator = true;
418 } else if ($rowNum === 1 && $this->_autoSeparate
& self
::AUTO_SEPARATE_HEADER
) {
419 $drawSeparator = true;
420 } else if ($rowNum === ($numRows - 1) && $this->_autoSeparate
& self
::AUTO_SEPARATE_FOOTER
) {
421 $drawSeparator = true;
423 $drawSeparator = false;
426 if ($drawSeparator) {
427 $result .= $this->_decorator
->getVerticalRight();
429 $currentUpperColumn = 0;
430 $currentLowerColumn = 0;
431 $currentUpperWidth = 0;
432 $currentLowerWidth = 0;
434 // Loop through all column widths
435 foreach ($this->_columnWidths
as $columnNum => $columnWidth) {
436 // Add the horizontal line
437 $result .= str_repeat($this->_decorator
->getHorizontal(),
440 // If this is the last line, break out
441 if (($columnNum +
1) === $totalNumColumns) {
445 // Else check, which connector style has to be used
447 $currentUpperWidth +
= $columnWidth;
448 $currentLowerWidth +
= $columnWidth;
450 if ($lastColumnWidths[$currentUpperColumn] === $currentUpperWidth) {
452 $currentUpperColumn +
= 1;
453 $currentUpperWidth = 0;
455 $currentUpperWidth +
= 1;
458 if ($columnWidths[$currentLowerColumn] === $currentLowerWidth) {
460 $currentLowerColumn +
= 1;
461 $currentLowerWidth = 0;
463 $currentLowerWidth +
= 1;
466 switch ($connector) {
468 $result .= $this->_decorator
->getHorizontal();
472 $result .= $this->_decorator
->getHorizontalUp();
476 $result .= $this->_decorator
->getHorizontalDown();
480 $result .= $this->_decorator
->getCross();
484 // This can never happen, but the CS tells I have to have it ...
489 $result .= $this->_decorator
->getVerticalLeft() . "\n";
493 // Add the rendered row to the result
494 $result .= $renderedRow;
496 // If this is the last row, draw the table bottom
497 if (($rowNum +
1) === $numRows) {
498 $result .= $this->_decorator
->getBottomLeft();
500 foreach ($columnWidths as $columnNum => $columnWidth) {
501 $result .= str_repeat($this->_decorator
->getHorizontal(),
504 if (($columnNum +
1) === $numColumns) {
505 $result .= $this->_decorator
->getBottomRight();
507 $result .= $this->_decorator
->getHorizontalUp();
519 * Magic method which returns the rendered table
523 public function __toString()
526 return $this->render();
527 } catch (Exception
$e) {
528 trigger_error($e->getMessage(), E_USER_ERROR
);