web/lib/Zend/Text/Table.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     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.
       
    14  *
       
    15  * @category  Zend
       
    16  * @package   Zend_Text_Table
       
    17  * @copyright  Copyright (c) 2005-2010 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 20096 2010-01-06 02:05:09Z bkarwin $
       
    20  */
       
    21 
       
    22 /**
       
    23  * Zend_Text_Table enables developers to create tables out of characters
       
    24  *
       
    25  * @category  Zend
       
    26  * @package   Zend_Text_Table
       
    27  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    28  * @license   http://framework.zend.com/license/new-bsd     New BSD License
       
    29  */
       
    30 class Zend_Text_Table
       
    31 {
       
    32     /**
       
    33      * Auto seperator settings
       
    34      */
       
    35     const AUTO_SEPARATE_NONE   = 0x0;
       
    36     const AUTO_SEPARATE_HEADER = 0x1;
       
    37     const AUTO_SEPARATE_FOOTER = 0x2;
       
    38     const AUTO_SEPARATE_ALL    = 0x4;
       
    39 
       
    40     /**
       
    41      * Decorator used for the table borders
       
    42      *
       
    43      * @var Zend_Text_Table_Decorator_Interface
       
    44      */
       
    45     protected $_decorator = null;
       
    46 
       
    47     /**
       
    48      * List of all column widths
       
    49      *
       
    50      * @var array
       
    51      */
       
    52     protected $_columnWidths = null;
       
    53 
       
    54     /**
       
    55      * Rows of the table
       
    56      *
       
    57      * @var array
       
    58      */
       
    59     protected $_rows = array();
       
    60 
       
    61     /**
       
    62      * Auto separation mode
       
    63      *
       
    64      * @var integer
       
    65      */
       
    66     protected $_autoSeparate = self::AUTO_SEPARATE_ALL;
       
    67 
       
    68     /**
       
    69      * Padding for columns
       
    70      *
       
    71      * @var integer
       
    72      */
       
    73     protected $_padding = 0;
       
    74 
       
    75     /**
       
    76      * Default column aligns for rows created by appendRow(array $data)
       
    77      *
       
    78      * @var array
       
    79      */
       
    80     protected $_defaultColumnAligns = array();
       
    81 
       
    82     /**
       
    83      * Plugin loader for decorators
       
    84      *
       
    85      * @var string
       
    86      */
       
    87     protected $_pluginLoader = null;
       
    88 
       
    89     /**
       
    90      * Charset which is used for input by default
       
    91      *
       
    92      * @var string
       
    93      */
       
    94     protected static $_inputCharset = 'utf-8';
       
    95 
       
    96     /**
       
    97      * Charset which is used internally
       
    98      *
       
    99      * @var string
       
   100      */
       
   101     protected static $_outputCharset = 'utf-8';
       
   102 
       
   103     /**
       
   104      * Option keys to skip when calling setOptions()
       
   105      *
       
   106      * @var array
       
   107      */
       
   108     protected $_skipOptions = array(
       
   109         'options',
       
   110         'config',
       
   111         'defaultColumnAlign',
       
   112     );
       
   113 
       
   114     /**
       
   115      * Create a basic table object
       
   116      *
       
   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
       
   120      */
       
   121     public function __construct($options = null)
       
   122     {
       
   123         // Set options
       
   124         if (is_array($options)) {
       
   125             $this->setOptions($options);
       
   126         } else if ($options instanceof Zend_Config) {
       
   127             $this->setConfig($options);
       
   128         }
       
   129 
       
   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');
       
   135         }
       
   136 
       
   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');
       
   141             } else {
       
   142                 $this->setDecorator('ascii');
       
   143             }
       
   144         }
       
   145     }
       
   146 
       
   147     /**
       
   148      * Set options from array
       
   149      *
       
   150      * @param  array $options Configuration for Zend_Text_Table
       
   151      * @return Zend_Text_Table
       
   152      */
       
   153     public function setOptions(array $options)
       
   154     {
       
   155         foreach ($options as $key => $value) {
       
   156             if (in_array(strtolower($key), $this->_skipOptions)) {
       
   157                 continue;
       
   158             }
       
   159 
       
   160             $method = 'set' . ucfirst($key);
       
   161             if (method_exists($this, $method)) {
       
   162                 $this->$method($value);
       
   163             }
       
   164         }
       
   165 
       
   166         return $this;
       
   167     }
       
   168 
       
   169     /**
       
   170      * Set options from config object
       
   171      *
       
   172      * @param  Zend_Config $config Configuration for Zend_Text_Table
       
   173      * @return Zend_Text_Table
       
   174      */
       
   175     public function setConfig(Zend_Config $config)
       
   176     {
       
   177         return $this->setOptions($config->toArray());
       
   178     }
       
   179 
       
   180     /**
       
   181      * Set column widths
       
   182      *
       
   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
       
   187      */
       
   188     public function setColumnWidths(array $columnWidths)
       
   189     {
       
   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');
       
   193         }
       
   194 
       
   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'
       
   199                                                     . ' column width');
       
   200             }
       
   201         }
       
   202 
       
   203         $this->_columnWidths = $columnWidths;
       
   204 
       
   205         return $this;
       
   206     }
       
   207 
       
   208     /**
       
   209      * Set auto separation mode
       
   210      *
       
   211      * @param  integer $autoSeparate Auto separation mode
       
   212      * @return Zend_Text_Table
       
   213      */
       
   214     public function setAutoSeparate($autoSeparate)
       
   215     {
       
   216         $this->_autoSeparate = (int) $autoSeparate;
       
   217         return $this;
       
   218     }
       
   219 
       
   220     /**
       
   221      * Set decorator
       
   222      *
       
   223      * @param  Zend_Text_Table_Decorator_Interface|string $decorator Decorator to use
       
   224      * @return Zend_Text_Table
       
   225      */
       
   226     public function setDecorator($decorator)
       
   227     {
       
   228         if ($decorator instanceof Zend_Text_Table_Decorator_Interface) {
       
   229             $this->_decorator = $decorator;
       
   230         } else {
       
   231             $classname        = $this->getPluginLoader()->load($decorator);
       
   232             $this->_decorator = new $classname;
       
   233         }
       
   234 
       
   235         return $this;
       
   236     }
       
   237 
       
   238     /**
       
   239      * Set the column padding
       
   240      *
       
   241      * @param  integer $padding The padding for the columns
       
   242      * @return Zend_Text_Table
       
   243      */
       
   244     public function setPadding($padding)
       
   245     {
       
   246         $this->_padding = max(0, (int) $padding);
       
   247         return $this;
       
   248     }
       
   249 
       
   250     /**
       
   251      * Get the plugin loader for decorators
       
   252      *
       
   253      * @return Zend_Loader_PluginLoader
       
   254      */
       
   255     public function getPluginLoader()
       
   256     {
       
   257         if ($this->_pluginLoader === null) {
       
   258             $prefix     = 'Zend_Text_Table_Decorator_';
       
   259             $pathPrefix = 'Zend/Text/Table/Decorator/';
       
   260 
       
   261             require_once 'Zend/Loader/PluginLoader.php';
       
   262             $this->_pluginLoader = new Zend_Loader_PluginLoader(array($prefix => $pathPrefix));
       
   263         }
       
   264 
       
   265         return $this->_pluginLoader;
       
   266     }
       
   267 
       
   268     /**
       
   269      * Set default column align for rows created by appendRow(array $data)
       
   270      *
       
   271      * @param  integer $columnNum
       
   272      * @param  string  $align
       
   273      * @return Zend_Text_Table
       
   274      */
       
   275     public function setDefaultColumnAlign($columnNum, $align)
       
   276     {
       
   277         $this->_defaultColumnAligns[$columnNum] = $align;
       
   278 
       
   279         return $this;
       
   280     }
       
   281 
       
   282     /**
       
   283      * Set the input charset for column contents
       
   284      *
       
   285      * @param string $charset
       
   286      */
       
   287     public static function setInputCharset($charset)
       
   288     {
       
   289         self::$_inputCharset = strtolower($charset);
       
   290     }
       
   291 
       
   292     /**
       
   293      * Get the input charset for column contents
       
   294      *
       
   295      * @param string $charset
       
   296      */
       
   297     public static function getInputCharset()
       
   298     {
       
   299         return self::$_inputCharset;
       
   300     }
       
   301 
       
   302     /**
       
   303      * Set the output charset for column contents
       
   304      *
       
   305      * @param string $charset
       
   306      */
       
   307     public static function setOutputCharset($charset)
       
   308     {
       
   309         self::$_outputCharset = strtolower($charset);
       
   310     }
       
   311 
       
   312     /**
       
   313      * Get the output charset for column contents
       
   314      *
       
   315      * @param string $charset
       
   316      */
       
   317     public static function getOutputCharset()
       
   318     {
       
   319         return self::$_outputCharset;
       
   320     }
       
   321 
       
   322     /**
       
   323      * Append a row to the table
       
   324      *
       
   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
       
   329      */
       
   330     public function appendRow($row)
       
   331     {
       
   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');
       
   335         }
       
   336 
       
   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');
       
   341             }
       
   342 
       
   343             require_once 'Zend/Text/Table/Row.php';
       
   344 
       
   345             $data   = $row;
       
   346             $row    = new Zend_Text_Table_Row();
       
   347             $colNum = 0;
       
   348             foreach ($data as $columnData) {
       
   349                 if (isset($this->_defaultColumnAligns[$colNum])) {
       
   350                     $align = $this->_defaultColumnAligns[$colNum];
       
   351                 } else {
       
   352                     $align = null;
       
   353                 }
       
   354 
       
   355                 $row->appendColumn(new Zend_Text_Table_Column($columnData, $align));
       
   356                 $colNum++;
       
   357             }
       
   358         }
       
   359 
       
   360         $this->_rows[] = $row;
       
   361 
       
   362         return $this;
       
   363     }
       
   364 
       
   365     /**
       
   366      * Render the table
       
   367      *
       
   368      * @throws Zend_Text_Table_Exception When no rows were added to the table
       
   369      * @return string
       
   370      */
       
   371     public function render()
       
   372     {
       
   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');
       
   377         }
       
   378 
       
   379         // Initiate the result variable
       
   380         $result = '';
       
   381 
       
   382         // Count total columns
       
   383         $totalNumColumns = count($this->_columnWidths);
       
   384 
       
   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;
       
   391             }
       
   392 
       
   393             $renderedRow  = $row->render($this->_columnWidths, $this->_decorator, $this->_padding);
       
   394             $columnWidths = $row->getColumnWidths();
       
   395             $numColumns   = count($columnWidths);
       
   396 
       
   397             // Check what we have to draw
       
   398             if ($rowNum === 0) {
       
   399                 // If this is the first row, draw the table top
       
   400                 $result .= $this->_decorator->getTopLeft();
       
   401 
       
   402                 foreach ($columnWidths as $columnNum => $columnWidth) {
       
   403                     $result .= str_repeat($this->_decorator->getHorizontal(),
       
   404                                           $columnWidth);
       
   405 
       
   406                     if (($columnNum + 1) === $numColumns) {
       
   407                         $result .= $this->_decorator->getTopRight();
       
   408                     } else {
       
   409                         $result .= $this->_decorator->getHorizontalDown();
       
   410                     }
       
   411                 }
       
   412 
       
   413                 $result .= "\n";
       
   414             } else {
       
   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;
       
   422                 } else {
       
   423                     $drawSeparator = false;
       
   424                 }
       
   425 
       
   426                 if ($drawSeparator) {
       
   427                     $result .= $this->_decorator->getVerticalRight();
       
   428 
       
   429                     $currentUpperColumn = 0;
       
   430                     $currentLowerColumn = 0;
       
   431                     $currentUpperWidth  = 0;
       
   432                     $currentLowerWidth  = 0;
       
   433 
       
   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(),
       
   438                                               $columnWidth);
       
   439 
       
   440                         // If this is the last line, break out
       
   441                         if (($columnNum + 1) === $totalNumColumns) {
       
   442                             break;
       
   443                         }
       
   444 
       
   445                         // Else check, which connector style has to be used
       
   446                         $connector          = 0x0;
       
   447                         $currentUpperWidth += $columnWidth;
       
   448                         $currentLowerWidth += $columnWidth;
       
   449 
       
   450                         if ($lastColumnWidths[$currentUpperColumn] === $currentUpperWidth) {
       
   451                             $connector          |= 0x1;
       
   452                             $currentUpperColumn += 1;
       
   453                             $currentUpperWidth   = 0;
       
   454                         } else {
       
   455                             $currentUpperWidth += 1;
       
   456                         }
       
   457 
       
   458                         if ($columnWidths[$currentLowerColumn] === $currentLowerWidth) {
       
   459                             $connector          |= 0x2;
       
   460                             $currentLowerColumn += 1;
       
   461                             $currentLowerWidth   = 0;
       
   462                         } else {
       
   463                             $currentLowerWidth += 1;
       
   464                         }
       
   465 
       
   466                         switch ($connector) {
       
   467                             case 0x0:
       
   468                                 $result .= $this->_decorator->getHorizontal();
       
   469                                 break;
       
   470 
       
   471                             case 0x1:
       
   472                                 $result .= $this->_decorator->getHorizontalUp();
       
   473                                 break;
       
   474 
       
   475                             case 0x2:
       
   476                                 $result .= $this->_decorator->getHorizontalDown();
       
   477                                 break;
       
   478 
       
   479                             case 0x3:
       
   480                                 $result .= $this->_decorator->getCross();
       
   481                                 break;
       
   482 
       
   483                             default:
       
   484                                 // This can never happen, but the CS tells I have to have it ...
       
   485                                 break;
       
   486                         }
       
   487                     }
       
   488 
       
   489                     $result .= $this->_decorator->getVerticalLeft() . "\n";
       
   490                 }
       
   491             }
       
   492 
       
   493             // Add the rendered row to the result
       
   494             $result .= $renderedRow;
       
   495 
       
   496             // If this is the last row, draw the table bottom
       
   497             if (($rowNum + 1) === $numRows) {
       
   498                 $result .= $this->_decorator->getBottomLeft();
       
   499 
       
   500                 foreach ($columnWidths as $columnNum => $columnWidth) {
       
   501                     $result .= str_repeat($this->_decorator->getHorizontal(),
       
   502                                           $columnWidth);
       
   503 
       
   504                     if (($columnNum + 1) === $numColumns) {
       
   505                         $result .= $this->_decorator->getBottomRight();
       
   506                     } else {
       
   507                         $result .= $this->_decorator->getHorizontalUp();
       
   508                     }
       
   509                 }
       
   510 
       
   511                 $result .= "\n";
       
   512             }
       
   513         }
       
   514 
       
   515         return $result;
       
   516     }
       
   517 
       
   518     /**
       
   519      * Magic method which returns the rendered table
       
   520      *
       
   521      * @return string
       
   522      */
       
   523     public function __toString()
       
   524     {
       
   525         try {
       
   526             return $this->render();
       
   527         } catch (Exception $e) {
       
   528             trigger_error($e->getMessage(), E_USER_ERROR);
       
   529         }
       
   530 
       
   531     }
       
   532 }