Path: blob/master/src/applications/fact/chart/PhabricatorChartFunctionArgumentParser.php
12256 views
<?php12final class PhabricatorChartFunctionArgumentParser3extends Phobject {45private $function;6private $rawArguments;7private $unconsumedArguments;8private $haveAllArguments = false;9private $unparsedArguments;10private $argumentMap = array();11private $argumentPosition = 0;12private $argumentValues = array();13private $repeatableArgument = null;1415public function setFunction(PhabricatorChartFunction $function) {16$this->function = $function;17return $this;18}1920public function getFunction() {21return $this->function;22}2324public function setRawArguments(array $arguments) {25$this->rawArguments = $arguments;26$this->unconsumedArguments = $arguments;27}2829public function addArgument(PhabricatorChartFunctionArgument $spec) {30$name = $spec->getName();31if (!strlen($name)) {32throw new Exception(33pht(34'Chart function "%s" emitted an argument specification with no '.35'argument name. Argument specifications must have unique names.',36$this->getFunctionArgumentSignature()));37}3839$type = $spec->getType();40if (!strlen($type)) {41throw new Exception(42pht(43'Chart function "%s" emitted an argument specification ("%s") with '.44'no type. Each argument specification must have a valid type.',45$this->getFunctionArgumentSignature(),46$name));47}4849if (isset($this->argumentMap[$name])) {50throw new Exception(51pht(52'Chart function "%s" emitted multiple argument specifications '.53'with the same name ("%s"). Each argument specification must have '.54'a unique name.',55$this->getFunctionArgumentSignature(),56$name));57}5859if ($this->repeatableArgument) {60if ($spec->getRepeatable()) {61throw new Exception(62pht(63'Chart function "%s" emitted multiple repeatable argument '.64'specifications ("%s" and "%s"). Only one argument may be '.65'repeatable and it must be the last argument.',66$this->getFunctionArgumentSignature(),67$name,68$this->repeatableArgument->getName()));69} else {70throw new Exception(71pht(72'Chart function "%s" emitted a repeatable argument ("%s"), then '.73'another argument ("%s"). No arguments are permitted after a '.74'repeatable argument.',75$this->getFunctionArgumentSignature(),76$this->repeatableArgument->getName(),77$name));78}79}8081if ($spec->getRepeatable()) {82$this->repeatableArgument = $spec;83}8485$this->argumentMap[$name] = $spec;86$this->unparsedArguments[] = $spec;8788return $this;89}9091public function parseArgument(92PhabricatorChartFunctionArgument $spec) {93$this->addArgument($spec);94return $this->parseArguments();95}9697public function setHaveAllArguments($have_all) {98$this->haveAllArguments = $have_all;99return $this;100}101102public function getAllArguments() {103return array_values($this->argumentMap);104}105106public function getRawArguments() {107return $this->rawArguments;108}109110public function parseArguments() {111$have_count = count($this->rawArguments);112$want_count = count($this->argumentMap);113114if ($this->haveAllArguments) {115if ($this->repeatableArgument) {116if ($want_count > $have_count) {117throw new Exception(118pht(119'Function "%s" expects %s or more argument(s), but only %s '.120'argument(s) were provided.',121$this->getFunctionArgumentSignature(),122$want_count,123$have_count));124}125} else if ($want_count !== $have_count) {126throw new Exception(127pht(128'Function "%s" expects %s argument(s), but %s argument(s) were '.129'provided.',130$this->getFunctionArgumentSignature(),131$want_count,132$have_count));133}134}135136while ($this->unparsedArguments) {137$argument = array_shift($this->unparsedArguments);138$name = $argument->getName();139140if (!$this->unconsumedArguments) {141throw new Exception(142pht(143'Function "%s" expects at least %s argument(s), but only %s '.144'argument(s) were provided.',145$this->getFunctionArgumentSignature(),146$want_count,147$have_count));148}149150$raw_argument = array_shift($this->unconsumedArguments);151$this->argumentPosition++;152153$is_repeatable = $argument->getRepeatable();154155// If this argument is repeatable and we have more arguments, add it156// back to the end of the list so we can continue parsing.157if ($is_repeatable && $this->unconsumedArguments) {158$this->unparsedArguments[] = $argument;159}160161try {162$value = $argument->newValue($raw_argument);163} catch (Exception $ex) {164throw new Exception(165pht(166'Argument "%s" (in position "%s") to function "%s" is '.167'invalid: %s',168$name,169$this->argumentPosition,170$this->getFunctionArgumentSignature(),171$ex->getMessage()));172}173174if ($is_repeatable) {175if (!isset($this->argumentValues[$name])) {176$this->argumentValues[$name] = array();177}178$this->argumentValues[$name][] = $value;179} else {180$this->argumentValues[$name] = $value;181}182}183}184185public function getArgumentValue($key) {186if (!array_key_exists($key, $this->argumentValues)) {187throw new Exception(188pht(189'Function "%s" is requesting an argument ("%s") that it did '.190'not define.',191$this->getFunctionArgumentSignature(),192$key));193}194195return $this->argumentValues[$key];196}197198private function getFunctionArgumentSignature() {199$argument_list = array();200foreach ($this->argumentMap as $key => $spec) {201$argument_list[] = $key;202}203204if (!$this->haveAllArguments || $this->repeatableArgument) {205$argument_list[] = '...';206}207208return sprintf(209'%s(%s)',210$this->getFunction()->getFunctionKey(),211implode(', ', $argument_list));212}213214}215216217