Overview

Namespaces

  • CzProject
    • PhpCli
      • Application
      • Bridges
      • Inputs
      • Outputs
      • Parameters

Classes

  • CzProject\PhpCli\Application\Application
  • CzProject\PhpCli\Application\ApplicationRequest
  • CzProject\PhpCli\Bridges\NetteDIExtension
  • CzProject\PhpCli\Console
  • CzProject\PhpCli\ConsoleFactory
  • CzProject\PhpCli\Inputs\DefaultInputProvider
  • CzProject\PhpCli\Inputs\ReadlineInputProvider
  • CzProject\PhpCli\Outputs\BaseOutput
  • CzProject\PhpCli\Outputs\ColoredOutput
  • CzProject\PhpCli\Outputs\MemoryOutput
  • CzProject\PhpCli\Outputs\NullOutput
  • CzProject\PhpCli\Outputs\TextOutput
  • CzProject\PhpCli\Parameters\DefaultParameterParser
  • CzProject\PhpCli\Parameters\Helpers

Interfaces

  • CzProject\PhpCli\Application\ICommand
  • CzProject\PhpCli\IInputProvider
  • CzProject\PhpCli\IOutputProvider
  • CzProject\PhpCli\IParameterParser

Exceptions

  • CzProject\PhpCli\ApplicationException
  • CzProject\PhpCli\ConsoleException
  • CzProject\PhpCli\Exception
  • CzProject\PhpCli\InputException
  • CzProject\PhpCli\InvalidArgumentException
  • CzProject\PhpCli\InvalidValueException
  • CzProject\PhpCli\MissingException
  • CzProject\PhpCli\MissingParameterException
  • CzProject\PhpCli\OutputException
  • CzProject\PhpCli\ParameterParserException
  • CzProject\PhpCli\StaticClassException
  • Overview
  • Namespace
  • Class
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 
<?php

    namespace CzProject\PhpCli\Application;

    use CzProject\PhpCli\ApplicationException;
    use CzProject\PhpCli\Console;
    use CzProject\PhpCli\ConsoleFactory;


    class Application
    {
        /** @var Console */
        protected $console;

        /** @var array */
        protected $commands;

        /** @var string|NULL */
        protected $applicationName;

        /** @var string|NULL */
        protected $defaultCommand;


        public function __construct(Console $console = NULL)
        {
            $this->console = $console ? $console : ConsoleFactory::createConsole();
        }


        /**
         * @param  string|NULL
         * @return static
         */
        public function setDefaultCommand($defaultCommand)
        {
            $this->defaultCommand = $defaultCommand;
            return $this;
        }


        /**
         * @param  ICommand
         * @return static
         */
        public function addCommand(ICommand $command)
        {
            $this->setCommand($command->getName(), $command);
            return $this;
        }


        /**
         * @param  string
         * @param  ICommand
         * @return static
         */
        public function setCommand($name, ICommand $command)
        {
            $this->commands[$name] = $command;
            return $this;
        }


        /**
         * @param  string|NULL
         * @return static
         */
        public function setApplicationName($applicationName)
        {
            $this->applicationName = $applicationName;
            return $this;
        }


        public function run(array $rawParameters = NULL)
        {
            $parameters = $this->console->getParameters();

            if ($parameters === NULL && $rawParameters === NULL) {
                if (isset($_SERVER['argv']) && is_array($_SERVER['argv'])) {
                    $rawParameters = $_SERVER['argv'];
                }
            }

            if ($rawParameters !== NULL) {
                $parameters = $this->console->processRawParameters($rawParameters);
            }

            if (empty($parameters)) {
                $this->printHelp();

            } else {
                $request = $this->createRequest($parameters);

                if (!$request) {
                    throw new ApplicationException('Missing command name.');
                }

                $commandName = $request->getCommandName();

                if (!isset($this->commands[$commandName])) {
                    throw new ApplicationException("Unknow command '$commandName'.");
                }

                $command = $this->commands[$commandName];
                $commandOptions = $command->getOptions();
                $options = $this->processOptions($request->getOptions(), $commandOptions !== NULL ? $commandOptions : array());
                $command->run($this->console, $options, $request->getArguments());
            }
        }


        public function printException(\Exception $e)
        {
            $console = $this->console;
            $console->nl();
            $console->error('ERROR: ' . $e->getMessage());
            $console->nl();
            $console->nl();
            $console->error('Details:');
            $console->nl();
            $console->error(' - type: ' . get_class($e));
            $console->nl();
            $console->error(' - code: ' . $e->getCode());
            $console->nl();
            $console->error(' - file: ' . $e->getFile());
            $console->nl();
            $console->error(' - line: ' . $e->getLine());
            $console->nl();
        }


        protected function createRequest(array $parameters)
        {
            $command = NULL;
            $options = array();
            $arguments = array();

            foreach ($parameters as $parameterName => $parameterValue) {
                if (is_string($parameterName)) { // option
                    $options[$parameterName] = $parameterValue;

                } else { // command name or argument
                    if ($command === NULL) {
                        $command = $parameterValue;

                    } else {
                        $arguments[] = $parameterValue;
                    }
                }
            }

            if ($command === NULL) {
                $command = $this->defaultCommand;

                if ($command === NULL) {
                    return NULL;
                }
            }

            return new ApplicationRequest($command, $options, $arguments);
        }


        /**
         * @return array
         */
        protected function processOptions(array $options, array $definitions)
        {
            $result = array();

            foreach ($definitions as $name => $definition) {
                $originalName = $name;
                $originalValue = NULL;
                $isAlias = FALSE;

                if (isset($options[$name])) {
                    $originalValue = $options[$name];
                    unset($options[$name]);
                }

                if (is_string($definition) || isset($definition['alias'])) {
                    $aliasName = is_string($definition) ? $definition : $definition['alias'];

                    if (!is_string($aliasName)) {
                        throw new ApplicationException("Alias in option '$optionName' must be string, " . gettype($aliasName) . ' given.');
                    }

                    if (!isset($definitions[$aliasName])) {
                        throw new ApplicationException("Unknow alias '$aliasName' in option '$name'.");
                    }

                    $definition = $definitions[$aliasName];
                    $name = $aliasName;
                    $isAlias = TRUE;
                }

                if ($isAlias && $originalValue === NULL) {
                    continue;
                }

                if (!is_array($definition)) {
                    throw new ApplicationException("Definition of option '$name' must be array, " . gettype($definition) . ' given.');
                }

                if (array_key_exists($name, $result)) { // because aliases
                    throw new ApplicationException("Value for option '$name' already exists. Remove option '$originalName' from parameters.");
                }

                $result[$name] = $this->processOption($name, $originalValue, $definition);
            }

            if (!empty($options)) {
                $labels = array_map(function ($label) {
                    return '\'' . $label . '\'';
                }, array_keys($options));

                throw new ApplicationException("Unknow options " . implode(', ', $labels) . '.');
            }

            return $result;
        }


        protected function processOption($name, $value, array $definition)
        {
            static $types = array(
                'boolean',
                'bool',
                'integer',
                'int',
                'float',
                'string',
            );

            if (!isset($definition['type'])) {
                throw new ApplicationException("Missing 'type' definition for option '$name'.");
            }

            if (!is_string($definition['type'])) {
                throw new ApplicationException("Invalid 'type' definition for option '$name'. Type must be string, " . gettype($definition['type']) . ' given.');
            }

            $type = strtolower($definition['type']);
            $required = isset($definition['required']) && $definition['required'];
            $nullable = isset($definition['nullable']) && $definition['nullable'];
            $repeatable = isset($definition['repeatable']) && $definition['repeatable'];
            $defaultValue = isset($definition['defaultValue']) ? $definition['defaultValue'] : NULL;
            $value = isset($value) ? $value : $defaultValue;

            if (!in_array($type, $types, TRUE)) {
                throw new ApplicationException("Unknow type '$type' in definition for option '$name'.");
            }

            if ($value === NULL && $required) {
                throw new ApplicationException("Missing value for required option '$name'.");
            }

            if ($repeatable && !is_array($value)) {
                $value = array($value);
            }

            if (!$repeatable && is_array($value)) {
                throw new ApplicationException("Multiple values for option '$name'.");
            }

            if ($nullable && ((is_array($value) && empty($value)) || $value === '')) {
                $value = NULL;
            }

            // set type
            if ($value !== NULL) {
                if (is_array($value)) {
                    $values = array();

                    foreach ($value as $val) {
                        $values[] = $this->convertType($name, $val, $type);
                    }

                    $value = $values;

                } else {
                    $value = $this->convertType($name, $value, $type);
                }
            }

            return $value;
        }


        protected function convertType($name, $value, $type)
        {
            if ($type === 'bool' || $type === 'boolean') {
                if (is_string($value)) {
                    $lValue = strtolower($value);

                    if ($lValue === 'yes' || $lValue === 'y' || $lValue === 'on' || $lValue === 'true' || $lValue === '1') {
                        return TRUE;

                    } elseif ($lValue === 'no' || $lValue === 'n' || $lValue === 'off' || $lValue === 'false' || $lValue === '0') {
                        return FALSE;
                    }

                } elseif (is_bool($value) || is_int($value) || is_float($value)) {
                    return (bool) $value;
                }

                throw new \CzProject\PhpCli\InvalidValueException("Invalid boolean value for option '$name'.");

            } elseif ($type === 'string' || $type === 'int' || $type === 'integer' || $type === 'float') {
                settype($value, $type);
                return $value;
            }

            throw new \CzProject\PhpCli\InvalidArgumentException("Unknow type '$type'.");
        }


        protected function printHelp()
        {
            if (isset($this->applicationName)) {
                $this->console->nl()
                    ->output($this->applicationName)
                    ->nl();
            }

            $this->console->nl()
                ->warning('Usage:')
                ->nl()
                ->output('  command [options] -- [arguments]')
                ->nl();

            $this->console->nl()
                ->warning('Available commands:')
                ->nl();

            $len = 0;

            foreach ($this->commands as $commandName => $command) {
                $len = max($len, strlen($commandName));
            }

            foreach ($this->commands as $commandName => $command) {
                $commandDescription = $command->getDescription();
                $this->console->output('  ')
                    ->success($commandName);

                if (isset($commandDescription)) {
                    $this->console->output(str_repeat(' ', $len - strlen($commandName)))
                        ->output('  ')
                        ->output($commandDescription);
                }

                $this->console->nl();
            }

            $this->console->nl();
        }
    }
czproject/phpcli master API documentation API documentation generated by ApiGen