_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; } }