amercier/php-cli-helpers

View on GitHub
src/Cli/Helpers/Parameter.php

Summary

Maintainability
A
1 hr
Test Coverage
A
100%
<?php

namespace Cli\Helpers;

/**
 * Cli\Helpers\Parameter
 * =====================
 *
 * Utility class to handle command-line parameters.
 *
 * Example
 * -------
 *
 * Considering the following command
 *
 *     my-script.php -u myname -p mypassord
 *     my-script.php --username myname --password mypassord
 *     my-script.php -u myname -p
 *     my-script.php -u myname -p mypassord -v
 *     my-script.php -u myname -p mypassord --verbose
 *     my-script.php -u myname -p mypassord -h server.example.com
 *     my-script.php -u myname -p mypassord --host server.example.com
 *
 * Where:
 *
 *     -u USERNAME, --username USERNAME   User name (required)
 *     -p PASSWORD, --password PASSWORD   Password (required)
 *     -u HOST, --host HOST               Host (optional, defaults to 127.0.0.1)
 *     -v, --verbose                      Verbose switch (optional)
 *
 * Usage:
 *
 * ```php
 * use Cli\Helpers\Parameter as Parameter;
 * $options = Parameter::getFromCommandLine(array(
 *         'host'     => new Parameter('h', 'host'    , '127.0.0.1'),
 *         'username' => new Parameter('u', 'username', Parameter::VALUE_REQUIRED),
 *         'password' => new Parameter('p', 'password', Parameter::VALUE_REQUIRED),
 *         'verbose'  => new Parameter('v', 'verbose' , Parameter::VALUE_NO_VALUE),
 *     ));
 * var_dump( $options );
 * ```
 *
 * Executing this with `my-script.php -u myname -p mypassord` or `my-script.php
 * --username=myname --password=mypassord` will display:
 *
 * ```php
 * array(4) {
 *     'host'     => '127.0.0.1',
 *     'username' => 'myusername',
 *     'password' => 'mypassword',
 *     'verbose'  => false,
 * }
 * ```
 *
 * Executing this with `my-script.php -u myname -p mypassord -h
 * server.example.com -v` will display:
 *
 * ```php
 * array(4) {
 *     'host'     => 'server.example.com',
 *     'username' => 'myusername',
 *     'password' => 'mypassword',
 *     'verbose'  => true
 * }
 * ```
 *
 * Executing this with `my-script.php -u myname` will result in a
 * `Cli\Helpers\Exception\MissingRequiredParameter` exception because the
 * options '-p/--password' is required.
 *
 * Executing this with `my-script.php -u myname -p` will result in a
 * `Cli\Helpers\Exception\MissingParameterValue` exception because
 * the options '-p/--password' requires a value.
 *
 * Executing this with `my-script.php -u myname -p password --passsword
 * password` will result in a
 * `Cli\Helpers\Exception\ConflictingParameters` exception because
 * the options '-p/--password' cannot be used with the short and long switches
 * cannot be used simultaneously.
 */
class Parameter
{
    const VALUE_REQUIRED = 'ac67ede5a84eb5a1add7ff4440e9a485'; // md5('required');
    const VALUE_NO_VALUE = 'e3cd7dd8951e151fb2e06104940064a0'; // md5('no value');

    protected $short;
    protected $long;
    protected $defaultValue;

    public function __construct($short, $long, $defaultValue = self::VALUE_REQUIRED)
    {
        $this->short = $short;
        $this->long = $long;
        $this->defaultValue = $defaultValue;
    }

    public function getShort()
    {
        return $this->short;
    }

    public function getLong()
    {
        return $this->long;
    }

    public function getShortSwitch()
    {
        return '-' . $this->getShort();
    }

    public function getLongSwitch()
    {
        return '--' . $this->getLong();
    }

    public function getDefaultValue()
    {
        return $this->defaultValue;
    }

    public function getValue($arguments)
    {
        // Parse arguments
        $index = -1;
        foreach ($arguments as $i => $value) {
            if ($i !== 0 && ($value === $this->getShortSwitch() || $value === $this->getLongSwitch())) {
                // Prevent short and long options simultaneously
                if ($index !== -1) {
                    throw new Exception\ConflictingParameters($this, $arguments);
                }

                $index = $i;
            }
        }

        // If it's a switch parameter (ex: -v/--verbose) return true if it was given, false otherwise
        if ($this->defaultValue === self::VALUE_NO_VALUE) {
            return $index !== -1;
        }

        // If it's a value parameter (ex: -h/--host 127.0.0.1)...

        // Return the value if it exists
        if ($index  !== -1 && $index < count($arguments) - 1) {
            return $arguments[ $index + 1 ];
        }

        // No value
        if ($this->defaultValue === self::VALUE_REQUIRED) {
            // required
            throw $index === -1
                ? new Exception\MissingRequiredParameter($this, $arguments)
                : new Exception\MissingParameterValue($this, $arguments);
        } else {
            // default value exists
            return $this->defaultValue;
        }
    }

    public static function getFromCommandLine(array $parameters, $arguments = null)
    {
        global $argv;
        $options = array();
        foreach ($parameters as $key => $parameter) {
            $options[ $key ] = $parameter->getValue($arguments === null ? $argv : $arguments);
        }

        return $options;
    }

    public function __toString()
    {
        return $this->getShortSwitch() . ', ' . $this->getLongSwitch();
    }
}