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 }