Файл: cobisja/BootHelp/src/Table.php
Строк: 427
<?php
/**
 * The MIT License
 *
 * Copyright 2015 cobisja.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
namespace cobisjaBootHelp;
use cobisjaBootHelpBase;
use cobisjaBootHelpHelpersContentTag;
/**
 * Generates an HTML block tag that follows the Bootstrap documentation
 * on how to display <strong>Table</strong> component.
 *
 * See {@link http://getbootstrap.com/css/#tables} for more information.
 */
class Table extends Base
{
    /**
     * Initializes the Table instance.
     *
     * @param mixed    $content_or_options_with_block the display options for Table.
     * @param Callable $block Block to generate customized Table's content.
     */
    public function __construct($content_or_options_with_block, $block = null)
    {
        $num_args = $this->getFunctionNumArgs(func_get_args());
        $content_block = is_callable(func_get_arg($num_args-1)) ? func_get_arg($num_args-1) : null;
        if (1 === $num_args) {
            $options = [];
            $content = is_null($content_block) ? $content_or_options_with_block : call_user_func($content_block);
        } else {
            if (is_array($content_or_options_with_block) && is_array($block)) {
                $content = $content_or_options_with_block;
                $options = $block;
            } else {
                $options = $content_or_options_with_block;
                $content = call_user_func($content_block);
            }
        }
        $table = $this->buildTable($content, $options);
        $this->setHtmlObject($table->getHtmlObject());
    }
    
    /**
     * Builds the Table component.
     * 
     * @param mixed $content Table's content
     * @param array $options Table's options to customize the component generation.
     * 
     * @return ContentTag a ContentTag instance that represents the Table group.
     */
    private function buildTable($content, array $options)
    {
        !is_array($content) ? $content = [$content] : null;
        $is_responsive = Base::getAndUnset('responsive', $options);
        
        $table_content = $this->buildTableContent($content, $options);
        
        $this->getTableClass($options);
        Base::appendClass($options, 'table');
        $table = new ContentTag('table', $table_content, $options);
        
        if ($is_responsive) {
            $table = new ContentTag('div', $table, ['class'=>'table-responsive']);
        }
        
        return $table;
    }
    
    /**
     * Builds the Table's content
     * 
     * @param mixed $content list of elements that makes the Table's content.
     * @param array $options options for building the Table's component.
     * 
     * @return array Table's content as array.
     */
    private function buildTableContent($content, &$options)
    {
        return array_filter(
            [
                $this->buildTableCaption($options),
                $this->buildTableHeading($content, $options),
                $this->buildTableRows($content, $options)
            ],
            'strlen'
        );
    }
    
    /**
     * Gets and builds the optional Table's caption.
     * 
     * @param mixed $options options for building the Table's component.
     * 
     * @return ContenTag a ContentTag instance that represents the Table's caption.
     */
    private function buildTableCaption(&$options)
    {
        $caption = Base::getAndUnset('caption', $options);
        return !is_null($caption) ? new ContentTag('caption', $caption) : null;
    }
    
    /**
     * Builds the optional Table's head.
     * 
     * @param mixed $content list of elements that makes the Table's content.
     * @param array $options options for building the Table's component.
     * @param mixed $heading a boolean value indicates if the first rows of the content will be the table head.
     * 
     * @return ContentTag a ContentTag instance that represents the Table's head.
     */
    private function buildTableHeading(&$content, array &$options)
    {
        $header_options = Base::getAndUnset('header_options', $options);
        $header = Base::getAndUnset('header', $options);
        
        if (is_bool($header) && $header) {
            $header = array_shift($content);
        }
        if (is_null($header)) {
            return null;
        }
        
        $head_object = new ContentTag(
            'tr',
            array_map(
                function ($cell_head) {
                    return new ContentTag('th', $cell_head);
                },
                $header
            )
        );
        return new ContentTag('thead', $head_object, $header_options);
    }
    
    /**
     * Builds the Table's content.
     * 
     * @param mixed $content list of elements that makes the Table's content.
     * @param array $options options for building the Table's component.
     * 
     * @return ContentTag a ContentTag instance that represents the Table's content.
     */
    private function buildTableRows($content, array &$options)
    {
        $global_row_options = Base::getAndUnset('rows_options', $options);
        $body_options = Base::getAndUnset('body_options', $options);
        $rows = [];
        
        foreach ($content as $row) {
            $row_options = is_null($global_row_options) ? [] : $global_row_options;
            $cells = [];
            $local_row_options = $this->getRowOptions($row);
            
            foreach ($row as $cell) {
                if (!is_array($cell)) {
                    $cell_content = $cell;
                    $cell_options = [];
                } else {
                    $cell_content = array_shift($cell);
                    $cell_options = $cell;
                    Base::appendClass($cell_options, Base::getAndUnset('context', $cell_options));
                }
                $cell_options['scope'] = Base::getAndUnset('scope', $cell_options);
                $cell = new ContentTag(
                    (is_null($cell_options['scope']) ? 'td': 'th'),
                    $cell_content,
                    $cell_options
                );
                $cells[] = $cell;
            }
            Base::setOptions($row_options, $local_row_options);
            Base::appendClass($local_row_options, Base::getAndUnset('context', $local_row_options));
            $rows[] = new ContentTag('tr', $cells, $local_row_options);
        }
        
        $table_body = new ContentTag('tbody', $rows, $body_options);
        
        return $table_body;
    }
    
    /**
     * Sets the specific table's class for options 'striped', 'bordered', 'hover' and/or 'condensed'.
     * 
     * @param array $options options for building the Table's component.
     */
    private function getTableClass(array &$options)
    {
        foreach (['striped', 'bordered', 'hover', 'condensed'] as $klass) {
            if (Base::getAndUnset($klass, $options)) {
                Base::appendClass($options, 'table-' . $klass);
            }
        }
    }
    
    /**
     * Gets the specific options for a specific table row.
     * 
     * @param array $content list of elements that makes the Table's content.
     * 
     * @return array row's options.
     */
    private function getRowOptions(array &$content)
    {
        $row_options = [];
        foreach ($content as $option => $value) {
            if (!is_numeric($option)) {
                $row_options[$option] = $value;
                unset($content[$option]);
            }
        }
        
        return $row_options;
    }
}