atelierspierrot/library

View on GitHub
src/Library/CommandLine/Helper.php

Summary

Maintainability
F
5 days
Test Coverage
<?php
/**
 * This file is part of the Library package.
 *
 * Copyleft (ↄ) 2013-2016 Pierre Cassat <me@e-piwi.fr> and contributors
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * The source code of this package is available online at 
 * <http://github.com/atelierspierrot/library>.
 */

namespace Library\CommandLine;

use \InvalidArgumentException;
use \Library\CodeParser;
use \Library\CommandLine\Formater;
use \Library\CommandLine\Stream;

/**
 * @author  piwi <me@e-piwi.fr>
 */
class Helper
{

    public static function getopt(array $options)
    {
        $short_options = implode('', array_keys($options['argv_options']));
        $long_options = array_keys($options['argv_long_options']);
        if (!empty($options['commands'])) {
            foreach(array_keys($options['commands']) as $_cmd) {
                array_push($long_options, $_cmd);
            }
        }
        if (!empty($options['aliases'])) {
            foreach(array_keys($options['aliases']) as $_ali) {
                array_push($long_options, $_ali);
            }
        }
        return getopt( $short_options, $long_options );
    }

    public static function getOptionMethod(array $options, $arg = null)
    {
        if (empty($arg)) return null;
        foreach(array($arg, $arg.':', $arg.'::') as $_arg) {
            if (array_key_exists($_arg, $options['argv_options'])) {
                return $options['argv_options'][$_arg];
            } elseif (array_key_exists($_arg, $options['argv_long_options'])) {
                return $options['argv_long_options'][$_arg];
            }
        }
        return null;
    }

    public static function getOptionDescription($arg, $caller)
    {
        if (!is_object($caller) || !($caller instanceof CommandLineControllerInterface)) {
            throw new InvalidArgumentException(
                sprintf('Argument 2 for method "%s::getOptionDescription" must be an object and implement the "CommandLineControllerInterface" interface!', __CLASS__)
            );
        }
        $_meth_descr = 'get'.ucfirst($arg).'Description';
        if (method_exists($caller, $_meth_descr)) {
            $ctt = $caller->$_meth_descr();
        } else {
            $code_parser = new CodeParser( get_class($caller).':run'.ucfirst($arg).'Command', CodeParser::PARSE_METHOD );
            if ($str = $code_parser->get_shortDescription()) {
                $ctt = $str;
            } else {
                $ctt = $_meth;
            }
        }
        return $ctt;
    }

    public static function treatOptions(array $options, $caller)
    {
        if (!is_object($caller) || !($caller instanceof CommandLineControllerInterface)) {
            throw new InvalidArgumentException(
                sprintf('Argument 2 for method "%s::treatOptions" must be an object and implement the "CommandLineControllerInterface" interface!', __CLASS__)
            );
        }
        $params = self::getopt($options);
        foreach($params as $_opt_name=>$_opt_val) {
            $_meth=null;
            if (array_key_exists($_opt_name, $options['argv_options'])) {
                $_meth = $options['argv_options'][$_opt_name];
            } elseif (array_key_exists($_opt_name, $options['argv_long_options'])) {
                $_meth = $options['argv_long_options'][$_opt_name];
            }

            if (!empty($_meth)) {
                $_cls_meth = 'run'.ucfirst($_meth).'Command';
                if (method_exists($caller, $_cls_meth) AND !in_array($_cls_meth, $caller->getDoneMethods())) {
                    $caller->addDoneMethod( $_cls_meth );
                    $caller->$_cls_meth( $_opt_val );
                }
            }
        }
    }

    public static function getOptionHelp($arg, $caller)
    {
        if (!is_object($caller) || !($caller instanceof CommandLineControllerInterface)) {
            throw new InvalidArgumentException(
                sprintf('Argument 2 for method "%s::getOptionHelp" must be an object and implement the "CommandLineControllerInterface" interface!', __CLASS__)
            );
        }
        $_meth_descr = 'get'.ucfirst($arg).'Help';
        if (method_exists($caller, $_meth_descr)) {
            $ctt = $caller->$_meth_descr();
        } else {
            $code_parser = new CodeParser( get_class($caller).':run'.ucfirst($arg).'Command', CodeParser::PARSE_METHOD );
            if ($str = $code_parser->get_longDescription()) {
                $ctt = $str;
            } else {
                $ctt = $_meth;
            }
        }
        return $ctt;
    }

    /**
     */
    public static function getHelpInfo(array $options = array(), Formater $formater, $caller)
    {
        if (!is_object($caller) || !($caller instanceof CommandLineControllerInterface)) {
            throw new InvalidArgumentException(
                sprintf('Argument 3 for method "%s::getHelpInfo" must be an object and implement the "CommandLineControllerInterface" interface!', __CLASS__)
            );
        }
        $tmp_options_list = $tmp_commands_list = $tmp_alias_list = array();
        foreach($options['argv_options'] as $_optn=>$_methodn) {
            if (in_array($_methodn, $options['commands'])) {
                if (!isset($tmp_commands_list[$_methodn]))
                    $tmp_commands_list[$_methodn] = array();
                $tmp_commands_list[$_methodn][] = '-'.$_optn;
            } elseif (in_array($_methodn, $options['aliases'])) {
                if (!isset($tmp_alias_list[$_methodn]))
                    $tmp_alias_list[$_methodn] = array();
                $tmp_alias_list[$_methodn][] = '-'.$_optn;
            } else {
                if (!isset($tmp_options_list[$_methodn]))
                    $tmp_options_list[$_methodn] = array();
                $tmp_options_list[$_methodn][] = '-'.$_optn;
            }
        }
        foreach($options['argv_long_options'] as $_loptn=>$_lmethodn) {
            if (!isset($tmp_options_list[$_lmethodn]))
                $tmp_options_list[$_lmethodn] = array();
            $tmp_options_list[$_lmethodn][] = '--'.$_loptn;
        }

        $options_list = array();
        foreach($tmp_options_list as $_meth=>$_options) {
            $title = str_replace( ':', '', implode('|', $_options) );
            if (substr_count(implode('|', $_options),'::'))
                $title .= ' <opt.arg>';
            elseif (substr_count(implode('|', $_options),':'))
                $title .= ' <arg>';
            $options_list[$title] = self::getOptionDescription( $_meth, $caller );
        }

        foreach($options['commands'] as $_optn=>$_methodn) {
            if (!isset($tmp_commands_list[$_methodn]))
                $tmp_commands_list[$_methodn] = array();
            $tmp_commands_list[$_methodn][] = $_optn;
        }

        $commands_list = array();
        foreach($tmp_commands_list as $_meth=>$_options) {
            $title = str_replace( ':', '', implode('|', $_options) );
            if (substr_count(implode('|', $_options),'::'))
                $title .= ' <opt.arg>';
            elseif (substr_count(implode('|', $_options),':'))
                $title .= ' <arg>';
            $commands_list[$title] = self::getOptionDescription( $_meth, $caller );
        }

        foreach($options['aliases'] as $_optn=>$_methodn) {
            if (!isset($tmp_alias_list[$_methodn]))
                $tmp_alias_list[$_methodn] = array();
            $tmp_alias_list[$_methodn][] = $_optn;
        }

        $alias_list = array();
        foreach($tmp_alias_list as $_meth=>$_options) {
            $title = str_replace( ':', '', implode('|', $_options) );
            if (substr_count(implode('|', $_options),'::'))
                $title .= ' <opt.arg>';
            elseif (substr_count(implode('|', $_options),':'))
                $title .= ' <arg>';
            $alias_list[$title] = self::getOptionDescription( $_meth, $caller );
        }

        $help_str = self::formatHelpString(
            $caller->getVersionString(),
            array(
                'Usage'=>"
    \$ php {$caller->getScript()} -[<var>options</var>] <var>command</var> [<var>arguments</var>]
                ",
                'List of available options'=>$options_list,
                'List of available commands'=>$commands_list,
                'List of available aliases'=>$alias_list,
                'Notes'=>'The equal sign is required if the argument is optional : <var>-e=all</var> / <var>--env=all</var>.
It is optional if the argument is required : <var>-e all</var> / <var>--env all</var>.
You can group one letter options in a unique string (option with arguments may be last) : <var>-xhe=all</var>.
You can write as many options you like : <var>-x --env=all</var>.',
            ),
            $formater
        );
        return $help_str;
    }

    public static function formatHelpString($title = null, $contents = null, Formater $formater)
    {
        if (empty($contents)) return '';
        if (empty($title)) $title = 'Help';
        if (!is_array($contents)) $contents = array( $contents );

        $help_ctt='';
        foreach( $contents as $ctt_ttl=>$ctt_ctt ) {
            if (!empty($ctt_ctt)) {
                if (!empty($ctt_ttl))
                    $help_ctt .= "<bold>{$ctt_ttl}:</bold>".Formater::$nl;
                if (is_string($ctt_ctt))
                    $help_ctt .= $ctt_ctt.Formater::$nl;
                else {
                    $ctt_str='';

                    // les cles sont des chaines ?
                    $keys_are_strings = false;
                    $_strs = array_keys($ctt_ctt);
                    for($i=0;$i<count($_strs);$i++)
                        if (is_string($_strs[$i]))
                            $keys_are_strings = true;

                    // taille max si chaines
                    if ($keys_are_strings === true) {
                        $maxlength=0;
                        foreach($_strs as $_ttl)
                            if (strlen($_ttl)>$maxlength) $maxlength=strlen($_ttl);
                        foreach($ctt_ctt as $opt_ttl=>$opt_ctt) {
                            if (is_array($opt_ctt)) {
                                for($_k=0;$_k<count($opt_ctt);$_k++) {
                                    if ($_k==0)
                                        $ctt_str .= '  <list_title>'.str_pad($opt_ttl, $maxlength).'</list_title>  '.$opt_ctt[$_k].Formater::$nl;
                                    else
                                        $ctt_str .= '  '.str_pad('', $maxlength).'  '.$opt_ctt[$_k].Formater::$nl;
                                }
                            } else
                                $ctt_str .= '  <list_title>'.str_pad($opt_ttl, $maxlength).'</list_title>  '.$opt_ctt.Formater::$nl;
                        }

                    } else {
                        foreach($ctt_ctt as $opt_ttl=>$opt_ctt)
                            $ctt_str .= '  '.$opt_ctt.Formater::$nl;
                    }
                    $help_ctt .= $ctt_str.Formater::$nl;
                }
            }
        }

        $help_str = <<<EOT

<info>{$title} help</info>

{$help_ctt}
EOT;
        return $help_str;
    }

}