Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/fact/chart/PhabricatorChartFunctionArgumentParser.php
12256 views
1
<?php
2
3
final class PhabricatorChartFunctionArgumentParser
4
extends Phobject {
5
6
private $function;
7
private $rawArguments;
8
private $unconsumedArguments;
9
private $haveAllArguments = false;
10
private $unparsedArguments;
11
private $argumentMap = array();
12
private $argumentPosition = 0;
13
private $argumentValues = array();
14
private $repeatableArgument = null;
15
16
public function setFunction(PhabricatorChartFunction $function) {
17
$this->function = $function;
18
return $this;
19
}
20
21
public function getFunction() {
22
return $this->function;
23
}
24
25
public function setRawArguments(array $arguments) {
26
$this->rawArguments = $arguments;
27
$this->unconsumedArguments = $arguments;
28
}
29
30
public function addArgument(PhabricatorChartFunctionArgument $spec) {
31
$name = $spec->getName();
32
if (!strlen($name)) {
33
throw new Exception(
34
pht(
35
'Chart function "%s" emitted an argument specification with no '.
36
'argument name. Argument specifications must have unique names.',
37
$this->getFunctionArgumentSignature()));
38
}
39
40
$type = $spec->getType();
41
if (!strlen($type)) {
42
throw new Exception(
43
pht(
44
'Chart function "%s" emitted an argument specification ("%s") with '.
45
'no type. Each argument specification must have a valid type.',
46
$this->getFunctionArgumentSignature(),
47
$name));
48
}
49
50
if (isset($this->argumentMap[$name])) {
51
throw new Exception(
52
pht(
53
'Chart function "%s" emitted multiple argument specifications '.
54
'with the same name ("%s"). Each argument specification must have '.
55
'a unique name.',
56
$this->getFunctionArgumentSignature(),
57
$name));
58
}
59
60
if ($this->repeatableArgument) {
61
if ($spec->getRepeatable()) {
62
throw new Exception(
63
pht(
64
'Chart function "%s" emitted multiple repeatable argument '.
65
'specifications ("%s" and "%s"). Only one argument may be '.
66
'repeatable and it must be the last argument.',
67
$this->getFunctionArgumentSignature(),
68
$name,
69
$this->repeatableArgument->getName()));
70
} else {
71
throw new Exception(
72
pht(
73
'Chart function "%s" emitted a repeatable argument ("%s"), then '.
74
'another argument ("%s"). No arguments are permitted after a '.
75
'repeatable argument.',
76
$this->getFunctionArgumentSignature(),
77
$this->repeatableArgument->getName(),
78
$name));
79
}
80
}
81
82
if ($spec->getRepeatable()) {
83
$this->repeatableArgument = $spec;
84
}
85
86
$this->argumentMap[$name] = $spec;
87
$this->unparsedArguments[] = $spec;
88
89
return $this;
90
}
91
92
public function parseArgument(
93
PhabricatorChartFunctionArgument $spec) {
94
$this->addArgument($spec);
95
return $this->parseArguments();
96
}
97
98
public function setHaveAllArguments($have_all) {
99
$this->haveAllArguments = $have_all;
100
return $this;
101
}
102
103
public function getAllArguments() {
104
return array_values($this->argumentMap);
105
}
106
107
public function getRawArguments() {
108
return $this->rawArguments;
109
}
110
111
public function parseArguments() {
112
$have_count = count($this->rawArguments);
113
$want_count = count($this->argumentMap);
114
115
if ($this->haveAllArguments) {
116
if ($this->repeatableArgument) {
117
if ($want_count > $have_count) {
118
throw new Exception(
119
pht(
120
'Function "%s" expects %s or more argument(s), but only %s '.
121
'argument(s) were provided.',
122
$this->getFunctionArgumentSignature(),
123
$want_count,
124
$have_count));
125
}
126
} else if ($want_count !== $have_count) {
127
throw new Exception(
128
pht(
129
'Function "%s" expects %s argument(s), but %s argument(s) were '.
130
'provided.',
131
$this->getFunctionArgumentSignature(),
132
$want_count,
133
$have_count));
134
}
135
}
136
137
while ($this->unparsedArguments) {
138
$argument = array_shift($this->unparsedArguments);
139
$name = $argument->getName();
140
141
if (!$this->unconsumedArguments) {
142
throw new Exception(
143
pht(
144
'Function "%s" expects at least %s argument(s), but only %s '.
145
'argument(s) were provided.',
146
$this->getFunctionArgumentSignature(),
147
$want_count,
148
$have_count));
149
}
150
151
$raw_argument = array_shift($this->unconsumedArguments);
152
$this->argumentPosition++;
153
154
$is_repeatable = $argument->getRepeatable();
155
156
// If this argument is repeatable and we have more arguments, add it
157
// back to the end of the list so we can continue parsing.
158
if ($is_repeatable && $this->unconsumedArguments) {
159
$this->unparsedArguments[] = $argument;
160
}
161
162
try {
163
$value = $argument->newValue($raw_argument);
164
} catch (Exception $ex) {
165
throw new Exception(
166
pht(
167
'Argument "%s" (in position "%s") to function "%s" is '.
168
'invalid: %s',
169
$name,
170
$this->argumentPosition,
171
$this->getFunctionArgumentSignature(),
172
$ex->getMessage()));
173
}
174
175
if ($is_repeatable) {
176
if (!isset($this->argumentValues[$name])) {
177
$this->argumentValues[$name] = array();
178
}
179
$this->argumentValues[$name][] = $value;
180
} else {
181
$this->argumentValues[$name] = $value;
182
}
183
}
184
}
185
186
public function getArgumentValue($key) {
187
if (!array_key_exists($key, $this->argumentValues)) {
188
throw new Exception(
189
pht(
190
'Function "%s" is requesting an argument ("%s") that it did '.
191
'not define.',
192
$this->getFunctionArgumentSignature(),
193
$key));
194
}
195
196
return $this->argumentValues[$key];
197
}
198
199
private function getFunctionArgumentSignature() {
200
$argument_list = array();
201
foreach ($this->argumentMap as $key => $spec) {
202
$argument_list[] = $key;
203
}
204
205
if (!$this->haveAllArguments || $this->repeatableArgument) {
206
$argument_list[] = '...';
207
}
208
209
return sprintf(
210
'%s(%s)',
211
$this->getFunction()->getFunctionKey(),
212
implode(', ', $argument_list));
213
}
214
215
}
216
217