Finish merging Solution into CommandeLine

master
Julien Rosset 6 years ago
parent 183b738c50
commit 3d869f684f

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

File diff suppressed because it is too large Load Diff

@ -1,279 +0,0 @@
<?php
/**
* Déclaration de la classe CommandLine\Solution
*/
namespace CommandLine;
use Fidit\v3\Exception\InvalidArgument;
use CommandLine\Exception\IncorrectParse;
use CommandLine\Exception\MissingArgument;
use CommandLine\Exception\TooMuchValues;
use CommandLine\Argument\IArgument;
use CommandLine\Argument\Option\IArgumentOption;
use CommandLine\Argument\Option\IArgumentOptionSecondary;
use CommandLine\Argument\ParseResult;
use CommandLine\Argument\Value\IArgumentValue;
use stdClass;
/**
* Représente *une* solution d'une ligne de commande.
*
* @package CommandLine
*/
class Solution {
/**
* @var IArgumentValue[] Liste des arguments de la ligne de commande
*/
protected $_arguments = array();
/**
* @var IArgumentOption[] Liste des options de la ligne de commande
*/
protected $_options = array();
/**
* Crée un nouvelle solution.
*/
public function __construct () {
}
/**
* Ajoute un argument
*
* @param int $order Ordre de l'argument.
* @param IArgumentValue $argument L'argument
*
* @return $this
*
* @throws InvalidArgument Si les arguments secondaires (le cas échéant) sont invalides.
*
* @see $_arguments
*/
public function addArgument ($order, IArgumentValue $argument) {
if(is_null($order) || !is_numeric($order))
throw new InvalidArgument($order, 'L\'ordre n\'est pas un nombre');
if(array_key_exists($order, $this->_arguments))
throw new InvalidArgument($order, 'Cet ordre est déjà utilisé pour un autre argument');
$this->_arguments[$order] = $argument;
return $this;
}
/**
* Liste des arguments de la solution.
*
* @return IArgumentValue[] Les arguments.
*/
public function getArguments () {
ksort($this->_arguments);
return $this->_arguments;
}
/**
* Le prochain ordre disponible pour un argument
*
* @return int La prochaine position
*/
public function getNextOrder () {
$keys = array_keys($this->_arguments);
if(count($keys) < 1)
return 1;
return max($keys) + 1;
}
/**
* Ajoute une option
*
* @param IArgumentOption $option L'option
*
* @return $this
*
* @throws InvalidArgument Si les arguments secondaires (le cas échéant) sont invalides.
*
* @see $_options
*/
public function addOption (IArgumentOption $option) {
if(array_key_exists($option->getName(), $this->_options))
throw new InvalidArgument($option, 'Il existe déjà une autre option avec le même nom');
$this->_options[$option->getName()] = $option;
if($option instanceof IArgumentOptionSecondary) {
foreach($option->getOthersOptions() as $option_second)
$this->addOption($option_second);
}
return $this;
}
/**
* Liste des options de la solution.
*
* @return IArgumentOption[] Les options.
*/
public function getOptions () {
return $this->_options;
}
/**
* Traite la solution pour en sortir les valeurs.
*
* @param string[] $argv La liste des arguments
* @param IArgumentOption[] $common_options La liste des options communes
*
* @return stdClass Les valeurs extraites.
* @throws MissingArgument Quand un argument est manquant ou en quantité insuffisante
* @throws InvalidArgument Quand un argument n'arrive pas à parser sa valeur
* @throws TooMuchValues Quand la solution ne consumme pas la totalité des arguments
*/
public function parseExplicit ($argv, $common_options) {
$stop = false;
/** @var IArgumentOption[] $options */$options = array_merge($common_options, $this->getOptions());
$values = $this->_parseOptions($argv, $options, $stop);
if($stop)
return $values;
$arguments = $this->getArguments();
foreach($arguments as $ordre => $argument) {
$min = $argument->getOccurMin();
self::_parseXTimes($argv, $values, $argument, $min);
$max = $argument->getOccurMax();
if(is_null($max) || $max > $min) {
$nbArgs = $this->_getNbArgumentRestant($ordre);
if($nbArgs >= 0 && count($argv) > $nbArgs) {
$nbParse = count($argv) - $nbArgs;
if(!is_null($max))
$nbParse = min($nbParse, $max - $min);
self::_parseXTimes($argv, $values, $argument, $nbParse, $min);
}
}
}
if(count($argv))
throw new TooMuchValues($argv, 'Trop de paramètres');
// Valeurs par défaut
foreach($options as $option) {
if(!isset($values->{$option->getVarName()}))
$values->{$option->getVarName()} = $option->getDefault();
}
foreach($arguments as $argument) {
if(!isset($values->{$argument->getVarName()}))
$values->{$argument->getVarName()} = $argument->getDefault();
}
return $values;
}
/**
* Parse des options.
*
* @param string[] $argv La liste des arguments
* @param IArgumentOption[] $options La liste des options
* @param boolean $stop Arrêt du parsage ?
*
* @return stdClass Les options extraites
* @throws IncorrectParse Si le parsage d'une des options échoue
*/
protected static function _parseOptions (&$argv, $options, &$stop) {
$values = new stdClass();
$stop = false;
foreach($options as $option) {
do {
$argv_option = $argv;
$find = false;
while(count($argv_option) > 0) {
$result = $option->parse($argv_option);
if(!is_null($result)) {
if($option->isStoppingParse())
$values = new stdClass();
self::_setValue($values, $option, $result, $option->allowMultiple() ? 2 : 1);
if($option->isStoppingParse()) {
$stop = true;
return $values;
}
array_splice($argv, count($argv) - count($argv_option), $result->getConsume());
$find = true;
break;
}
array_shift($argv_option);
}
} while(count($argv_option) > 1 && (!$find || $option->allowMultiple()));
}
return $values;
}
/**
* Parse un argument X fois
*
* @param string[] $argv Liste des arguments
* @param stdClass $values Les valeurs de sortie
* @param IArgumentValue $argument L'argument à parser
* @param int $xTimes Le nombre de fois à parser
* @param int $offset L'offset pour le n° d'occurence
*
* @throws MissingArgument Si l'argument n'est pas en quantité suffisante
* @throws IncorrectParse Si l'argument échoue à se parser
*/
protected static function _parseXTimes (&$argv, &$values, $argument, $xTimes, $offset = 0) {
if($xTimes > count($argv))
throw new MissingArgument($argument, 'L\'argument est en quantité insuffisante (' . count($argv) . ' / ' . $xTimes . ')');
for($curr = 1; $curr <= $xTimes; $curr++) {
$result = $argument->parse($argv);
if(is_null($result))
throw new MissingArgument($argument, 'L\'occurence n° ' . ($offset + $curr) . ' de l\'argument ne correspond pas');
self::_setValue($values, $argument, $result, $argument->getOccurMax());
$argv = array_slice($argv, $result->getConsume());
}
}
/**
* Ajoute le résultat d'un argument aux valeurs de sortie
*
* @param stdClass $values Les valeurs de sortie, auxquelles ajouter la résultat
* @param IArgument $argument L'argument actuel
* @param ParseResult $result Le résultat de l'argument
* @param int|null $max Le nombre max de valeur autorisé
*/
protected static function _setValue (&$values, $argument, $result, $max) {
if(is_null($max) || $max > 1) {
if(!isset($values->{$argument->getVarName()}))
$values->{$argument->getVarName()} = array();
$values->{$argument->getVarName()}[] = $result->getValue();
}
else
$values->{$argument->getVarName()} = $result->getValue();
}
/**
* Calcule le nombre d'argument restant à honorer.
*
* @param int $ordre_start L'ordre de l'argument en cours
*
* @return int Le nombre d'argument restant, ou -1 si un argument "illimité"
*/
protected function _getNbArgumentRestant ($ordre_start) {
$nb = 0;
foreach($this->getArguments() as $ordre => $argument) {
if($ordre <= $ordre_start)
continue;
$max = $argument->getOccurMax();
if(is_null($max))
return -1;
$nb += $max;
}
return $nb;
}
}
Loading…
Cancel
Save