File indexing completed on 2024-12-22 05:37:08
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Text_Table 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * Zend_Text_Table enables developers to create tables out of characters 0024 * 0025 * @category Zend 0026 * @package Zend_Text_Table 0027 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0028 * @license http://framework.zend.com/license/new-bsd New BSD License 0029 */ 0030 class Zend_Text_Table 0031 { 0032 /** 0033 * Auto seperator settings 0034 */ 0035 const AUTO_SEPARATE_NONE = 0x0; 0036 const AUTO_SEPARATE_HEADER = 0x1; 0037 const AUTO_SEPARATE_FOOTER = 0x2; 0038 const AUTO_SEPARATE_ALL = 0x4; 0039 0040 /** 0041 * Decorator used for the table borders 0042 * 0043 * @var Zend_Text_Table_Decorator_Interface 0044 */ 0045 protected $_decorator = null; 0046 0047 /** 0048 * List of all column widths 0049 * 0050 * @var array 0051 */ 0052 protected $_columnWidths = null; 0053 0054 /** 0055 * Rows of the table 0056 * 0057 * @var array 0058 */ 0059 protected $_rows = array(); 0060 0061 /** 0062 * Auto separation mode 0063 * 0064 * @var integer 0065 */ 0066 protected $_autoSeparate = self::AUTO_SEPARATE_ALL; 0067 0068 /** 0069 * Padding for columns 0070 * 0071 * @var integer 0072 */ 0073 protected $_padding = 0; 0074 0075 /** 0076 * Default column aligns for rows created by appendRow(array $data) 0077 * 0078 * @var array 0079 */ 0080 protected $_defaultColumnAligns = array(); 0081 0082 /** 0083 * Plugin loader for decorators 0084 * 0085 * @var string 0086 */ 0087 protected $_pluginLoader = null; 0088 0089 /** 0090 * Charset which is used for input by default 0091 * 0092 * @var string 0093 */ 0094 protected static $_inputCharset = 'utf-8'; 0095 0096 /** 0097 * Charset which is used internally 0098 * 0099 * @var string 0100 */ 0101 protected static $_outputCharset = 'utf-8'; 0102 0103 /** 0104 * Option keys to skip when calling setOptions() 0105 * 0106 * @var array 0107 */ 0108 protected $_skipOptions = array( 0109 'options', 0110 'config', 0111 'defaultColumnAlign', 0112 ); 0113 0114 /** 0115 * Create a basic table object 0116 * 0117 * @param array $columnsWidths List of all column widths 0118 * @param Zend_Config|array $options Configuration options 0119 * @throws Zend_Text_Table_Exception When no columns widths were set 0120 */ 0121 public function __construct($options = null) 0122 { 0123 // Set options 0124 if (is_array($options)) { 0125 $this->setOptions($options); 0126 } else if ($options instanceof Zend_Config) { 0127 $this->setConfig($options); 0128 } 0129 0130 // Check if column widths were set 0131 // @todo When column widths were not set, assume auto-sizing 0132 if ($this->_columnWidths === null) { 0133 // require_once 'Zend/Text/Table/Exception.php'; 0134 throw new Zend_Text_Table_Exception('You must define the column widths'); 0135 } 0136 0137 // If no decorator was given, use default unicode decorator 0138 if ($this->_decorator === null) { 0139 if (self::getOutputCharset() === 'utf-8') { 0140 $this->setDecorator('unicode'); 0141 } else { 0142 $this->setDecorator('ascii'); 0143 } 0144 } 0145 } 0146 0147 /** 0148 * Set options from array 0149 * 0150 * @param array $options Configuration for Zend_Text_Table 0151 * @return Zend_Text_Table 0152 */ 0153 public function setOptions(array $options) 0154 { 0155 foreach ($options as $key => $value) { 0156 if (in_array(strtolower($key), $this->_skipOptions)) { 0157 continue; 0158 } 0159 0160 $method = 'set' . ucfirst($key); 0161 if (method_exists($this, $method)) { 0162 $this->$method($value); 0163 } 0164 } 0165 0166 return $this; 0167 } 0168 0169 /** 0170 * Set options from config object 0171 * 0172 * @param Zend_Config $config Configuration for Zend_Text_Table 0173 * @return Zend_Text_Table 0174 */ 0175 public function setConfig(Zend_Config $config) 0176 { 0177 return $this->setOptions($config->toArray()); 0178 } 0179 0180 /** 0181 * Set column widths 0182 * 0183 * @param array $columnWidths Widths of all columns 0184 * @throws Zend_Text_Table_Exception When no columns were supplied 0185 * @throws Zend_Text_Table_Exception When a column has an invalid width 0186 * @return Zend_Text_Table 0187 */ 0188 public function setColumnWidths(array $columnWidths) 0189 { 0190 if (count($columnWidths) === 0) { 0191 // require_once 'Zend/Text/Table/Exception.php'; 0192 throw new Zend_Text_Table_Exception('You must supply at least one column'); 0193 } 0194 0195 foreach ($columnWidths as $columnNum => $columnWidth) { 0196 if (is_int($columnWidth) === false or $columnWidth < 1) { 0197 // require_once 'Zend/Text/Table/Exception.php'; 0198 throw new Zend_Text_Table_Exception('Column ' . $columnNum . ' has an invalid' 0199 . ' column width'); 0200 } 0201 } 0202 0203 $this->_columnWidths = $columnWidths; 0204 0205 return $this; 0206 } 0207 0208 /** 0209 * Set auto separation mode 0210 * 0211 * @param integer $autoSeparate Auto separation mode 0212 * @return Zend_Text_Table 0213 */ 0214 public function setAutoSeparate($autoSeparate) 0215 { 0216 $this->_autoSeparate = (int) $autoSeparate; 0217 return $this; 0218 } 0219 0220 /** 0221 * Set decorator 0222 * 0223 * @param Zend_Text_Table_Decorator_Interface|string $decorator Decorator to use 0224 * @return Zend_Text_Table 0225 */ 0226 public function setDecorator($decorator) 0227 { 0228 if ($decorator instanceof Zend_Text_Table_Decorator_Interface) { 0229 $this->_decorator = $decorator; 0230 } else { 0231 $classname = $this->getPluginLoader()->load($decorator); 0232 $this->_decorator = new $classname; 0233 } 0234 0235 return $this; 0236 } 0237 0238 /** 0239 * Set the column padding 0240 * 0241 * @param integer $padding The padding for the columns 0242 * @return Zend_Text_Table 0243 */ 0244 public function setPadding($padding) 0245 { 0246 $this->_padding = max(0, (int) $padding); 0247 return $this; 0248 } 0249 0250 /** 0251 * Get the plugin loader for decorators 0252 * 0253 * @return Zend_Loader_PluginLoader 0254 */ 0255 public function getPluginLoader() 0256 { 0257 if ($this->_pluginLoader === null) { 0258 $prefix = 'Zend_Text_Table_Decorator_'; 0259 $pathPrefix = 'Zend/Text/Table/Decorator/'; 0260 0261 // require_once 'Zend/Loader/PluginLoader.php'; 0262 $this->_pluginLoader = new Zend_Loader_PluginLoader(array($prefix => $pathPrefix)); 0263 } 0264 0265 return $this->_pluginLoader; 0266 } 0267 0268 /** 0269 * Set default column align for rows created by appendRow(array $data) 0270 * 0271 * @param integer $columnNum 0272 * @param string $align 0273 * @return Zend_Text_Table 0274 */ 0275 public function setDefaultColumnAlign($columnNum, $align) 0276 { 0277 $this->_defaultColumnAligns[$columnNum] = $align; 0278 0279 return $this; 0280 } 0281 0282 /** 0283 * Set the input charset for column contents 0284 * 0285 * @param string $charset 0286 */ 0287 public static function setInputCharset($charset) 0288 { 0289 self::$_inputCharset = strtolower($charset); 0290 } 0291 0292 /** 0293 * Get the input charset for column contents 0294 * 0295 * @param string $charset 0296 */ 0297 public static function getInputCharset() 0298 { 0299 return self::$_inputCharset; 0300 } 0301 0302 /** 0303 * Set the output charset for column contents 0304 * 0305 * @param string $charset 0306 */ 0307 public static function setOutputCharset($charset) 0308 { 0309 self::$_outputCharset = strtolower($charset); 0310 } 0311 0312 /** 0313 * Get the output charset for column contents 0314 * 0315 * @param string $charset 0316 */ 0317 public static function getOutputCharset() 0318 { 0319 return self::$_outputCharset; 0320 } 0321 0322 /** 0323 * Append a row to the table 0324 * 0325 * @param array|Zend_Text_Table_Row $row The row to append to the table 0326 * @throws Zend_Text_Table_Exception When $row is neither an array nor Zend_Zext_Table_Row 0327 * @throws Zend_Text_Table_Exception When a row contains too many columns 0328 * @return Zend_Text_Table 0329 */ 0330 public function appendRow($row) 0331 { 0332 if (!is_array($row) && !($row instanceof Zend_Text_Table_Row)) { 0333 // require_once 'Zend/Text/Table/Exception.php'; 0334 throw new Zend_Text_Table_Exception('$row must be an array or instance of Zend_Text_Table_Row'); 0335 } 0336 0337 if (is_array($row)) { 0338 if (count($row) > count($this->_columnWidths)) { 0339 // require_once 'Zend/Text/Table/Exception.php'; 0340 throw new Zend_Text_Table_Exception('Row contains too many columns'); 0341 } 0342 0343 // require_once 'Zend/Text/Table/Row.php'; 0344 // require_once 'Zend/Text/Table/Column.php'; 0345 0346 $data = $row; 0347 $row = new Zend_Text_Table_Row(); 0348 $colNum = 0; 0349 foreach ($data as $columnData) { 0350 if (isset($this->_defaultColumnAligns[$colNum])) { 0351 $align = $this->_defaultColumnAligns[$colNum]; 0352 } else { 0353 $align = null; 0354 } 0355 0356 $row->appendColumn(new Zend_Text_Table_Column($columnData, $align)); 0357 $colNum++; 0358 } 0359 } 0360 0361 $this->_rows[] = $row; 0362 0363 return $this; 0364 } 0365 0366 /** 0367 * Render the table 0368 * 0369 * @throws Zend_Text_Table_Exception When no rows were added to the table 0370 * @return string 0371 */ 0372 public function render() 0373 { 0374 // There should be at least one row 0375 if (count($this->_rows) === 0) { 0376 // require_once 'Zend/Text/Table/Exception.php'; 0377 throw new Zend_Text_Table_Exception('No rows were added to the table yet'); 0378 } 0379 0380 // Initiate the result variable 0381 $result = ''; 0382 0383 // Count total columns 0384 $totalNumColumns = count($this->_columnWidths); 0385 0386 // Now render all rows, starting from the first one 0387 $numRows = count($this->_rows); 0388 foreach ($this->_rows as $rowNum => $row) { 0389 // Get all column widths 0390 if (isset($columnWidths) === true) { 0391 $lastColumnWidths = $columnWidths; 0392 } 0393 0394 $renderedRow = $row->render($this->_columnWidths, $this->_decorator, $this->_padding); 0395 $columnWidths = $row->getColumnWidths(); 0396 $numColumns = count($columnWidths); 0397 0398 // Check what we have to draw 0399 if ($rowNum === 0) { 0400 // If this is the first row, draw the table top 0401 $result .= $this->_decorator->getTopLeft(); 0402 0403 foreach ($columnWidths as $columnNum => $columnWidth) { 0404 $result .= str_repeat($this->_decorator->getHorizontal(), 0405 $columnWidth); 0406 0407 if (($columnNum + 1) === $numColumns) { 0408 $result .= $this->_decorator->getTopRight(); 0409 } else { 0410 $result .= $this->_decorator->getHorizontalDown(); 0411 } 0412 } 0413 0414 $result .= "\n"; 0415 } else { 0416 // Else check if we have to draw the row separator 0417 if ($this->_autoSeparate & self::AUTO_SEPARATE_ALL) { 0418 $drawSeparator = true; 0419 } else if ($rowNum === 1 && $this->_autoSeparate & self::AUTO_SEPARATE_HEADER) { 0420 $drawSeparator = true; 0421 } else if ($rowNum === ($numRows - 1) && $this->_autoSeparate & self::AUTO_SEPARATE_FOOTER) { 0422 $drawSeparator = true; 0423 } else { 0424 $drawSeparator = false; 0425 } 0426 0427 if ($drawSeparator) { 0428 $result .= $this->_decorator->getVerticalRight(); 0429 0430 $currentUpperColumn = 0; 0431 $currentLowerColumn = 0; 0432 $currentUpperWidth = 0; 0433 $currentLowerWidth = 0; 0434 0435 // Loop through all column widths 0436 foreach ($this->_columnWidths as $columnNum => $columnWidth) { 0437 // Add the horizontal line 0438 $result .= str_repeat($this->_decorator->getHorizontal(), 0439 $columnWidth); 0440 0441 // If this is the last line, break out 0442 if (($columnNum + 1) === $totalNumColumns) { 0443 break; 0444 } 0445 0446 // Else check, which connector style has to be used 0447 $connector = 0x0; 0448 $currentUpperWidth += $columnWidth; 0449 $currentLowerWidth += $columnWidth; 0450 0451 if ($lastColumnWidths[$currentUpperColumn] === $currentUpperWidth) { 0452 $connector |= 0x1; 0453 $currentUpperColumn += 1; 0454 $currentUpperWidth = 0; 0455 } else { 0456 $currentUpperWidth += 1; 0457 } 0458 0459 if ($columnWidths[$currentLowerColumn] === $currentLowerWidth) { 0460 $connector |= 0x2; 0461 $currentLowerColumn += 1; 0462 $currentLowerWidth = 0; 0463 } else { 0464 $currentLowerWidth += 1; 0465 } 0466 0467 switch ($connector) { 0468 case 0x0: 0469 $result .= $this->_decorator->getHorizontal(); 0470 break; 0471 0472 case 0x1: 0473 $result .= $this->_decorator->getHorizontalUp(); 0474 break; 0475 0476 case 0x2: 0477 $result .= $this->_decorator->getHorizontalDown(); 0478 break; 0479 0480 case 0x3: 0481 $result .= $this->_decorator->getCross(); 0482 break; 0483 0484 default: 0485 // This can never happen, but the CS tells I have to have it ... 0486 break; 0487 } 0488 } 0489 0490 $result .= $this->_decorator->getVerticalLeft() . "\n"; 0491 } 0492 } 0493 0494 // Add the rendered row to the result 0495 $result .= $renderedRow; 0496 0497 // If this is the last row, draw the table bottom 0498 if (($rowNum + 1) === $numRows) { 0499 $result .= $this->_decorator->getBottomLeft(); 0500 0501 foreach ($columnWidths as $columnNum => $columnWidth) { 0502 $result .= str_repeat($this->_decorator->getHorizontal(), 0503 $columnWidth); 0504 0505 if (($columnNum + 1) === $numColumns) { 0506 $result .= $this->_decorator->getBottomRight(); 0507 } else { 0508 $result .= $this->_decorator->getHorizontalUp(); 0509 } 0510 } 0511 0512 $result .= "\n"; 0513 } 0514 } 0515 0516 return $result; 0517 } 0518 0519 /** 0520 * Magic method which returns the rendered table 0521 * 0522 * @return string 0523 */ 0524 public function __toString() 0525 { 0526 try { 0527 return $this->render(); 0528 } catch (Exception $e) { 0529 trigger_error($e->getMessage(), E_USER_ERROR); 0530 } 0531 0532 } 0533 }