1: <?php
2:
3: namespace Deimos\CLI;
4:
5: use Deimos\CLI\Exceptions\CLIRun;
6: use Deimos\CLI\Exceptions\Required;
7: use Deimos\CLI\Exceptions\UndefinedVariable;
8:
9: class CLI
10: {
11:
12: 13: 14:
15: protected $argv;
16:
17: 18: 19:
20: protected $variables = [];
21:
22: 23: 24:
25: protected $aliases;
26:
27: 28: 29:
30: protected $requiredList;
31:
32: 33: 34:
35: protected $storage;
36:
37: 38: 39:
40: protected $commands = [];
41:
42: 43: 44:
45: protected $run;
46:
47: 48: 49: 50: 51:
52: public function __construct(array $argv)
53: {
54: $this->argv = $argv;
55:
56: if (!empty($this->argv))
57: {
58:
59: array_shift($this->argv);
60: }
61: }
62:
63: 64: 65: 66: 67:
68: public function variable($name)
69: {
70: return ($this->variables[$name] = new Variable($name));
71: }
72:
73: 74: 75:
76: protected function init()
77: {
78: $this->aliases = [];
79: $this->requiredList = [];
80:
81: 82: 83:
84: foreach ($this->variables as $variable)
85: {
86: if ($variable->isRequired())
87: {
88: $this->requiredList[] = $variable->name();
89: }
90:
91:
92: foreach ($variable->aliases() as $alias)
93: {
94: $this->aliases[$alias] = $variable;
95: }
96: }
97:
98: return implode(' ', $this->argv);
99: }
100:
101: 102: 103: 104: 105:
106: protected function value($data)
107: {
108: return is_array($data) && isset($data[1]) ? $data[1] : $data;
109: }
110:
111: 112: 113:
114: protected function initStorage(array &$array)
115: {
116: foreach ($array as $item)
117: {
118: $value = $this->value($item);
119:
120: if (in_array($value, ['-', '--'], false))
121: {
122: break;
123: }
124:
125: $data = array_shift($array);
126:
127: if ($value !== ' ')
128: {
129: $this->storage[] = $this->value($data);
130: }
131: }
132: }
133:
134: 135: 136: 137: 138:
139: protected function initVariable(array &$array)
140: {
141: $isAlias = false;
142: $isKey = false;
143: $key = null;
144:
145: foreach ($array as $item)
146: {
147: $item = array_shift($array);
148: $value = $this->value($item);
149:
150: if ($value === ' ')
151: {
152: continue;
153: }
154:
155: if (!$isKey && in_array($value, ['-', '--'], true))
156: {
157: $isAlias = $value === '-';
158: $isKey = true;
159: continue;
160: }
161:
162: if ($isKey)
163: {
164: $key = $value;
165: $isKey = false;
166:
167: if ($isAlias && !isset($this->aliases[$key]))
168: {
169: throw new UndefinedVariable('Not found alias \'' . $key . '\'');
170: }
171:
172: $this->commands[$key] = [];
173: continue;
174: }
175:
176: $stringValue = '';
177:
178: while ($value !== ' ')
179: {
180: if ($value === null)
181: {
182: break;
183: }
184:
185: $stringValue .= $value;
186:
187: $item = array_shift($array);
188: $value = $this->value($item);
189: }
190:
191: if (strlen($stringValue) > 0)
192: {
193: $this->commands[$key][] = $stringValue;
194: }
195:
196: }
197: }
198:
199: 200: 201: 202:
203: protected function initRequired()
204: {
205: foreach ($this->requiredList as $name)
206: {
207: 208: 209: 210:
211: $variable = $this->variables[$name];
212: $aliasList = $variable->aliases();
213:
214: if (!isset($this->commands[$name]))
215: {
216: $keys = array_keys($this->commands);
217: foreach ($aliasList as $alias)
218: {
219: if (in_array($alias, $keys, true))
220: {
221: continue 2;
222: }
223: }
224:
225: throw new Required('Not found required argument \'' . $name . '\'');
226: }
227:
228: continue;
229:
230: }
231:
232: return true;
233: }
234:
235: 236: 237:
238: protected function initUndefined()
239: {
240: foreach ($this->commands as $command => &$data)
241: {
242: if (!isset($this->variables[$command]) && !isset($this->aliases[$command]))
243: {
244: throw new UndefinedVariable('Not found variable \'' . $command . '\'');
245: }
246: }
247: }
248:
249: protected function loadCommand(array $commands)
250: {
251: $this->commands = [];
252:
253: foreach ($commands as $name => $value)
254: {
255: 256: 257:
258: $variable = $this->aliases[$name];
259:
260: if ($variable === null)
261: {
262: $variable = $this->variables[$name];
263: }
264:
265: if (count($value))
266: {
267: if ($variable->isBoolType())
268: {
269: $value = $value[0];
270: }
271:
272: $variable->setValue($value);
273: }
274: else if ($variable->isBoolType())
275: {
276: $variable->setValue(true);
277: }
278:
279: $this->commands[$variable->name()] = $variable->isBoolType()
280: ? (bool)$variable->value() :
281: $variable->value();
282: }
283:
284: foreach ($this->variables as $variable)
285: {
286: if (!isset($this->commands[$variable->name()]))
287: {
288: $this->commands[$variable->name()] = $variable->value();
289: }
290: }
291:
292: $this->run = true;
293: }
294:
295: protected function &commands()
296: {
297: if (!$this->run)
298: {
299: throw new CLIRun('Start the run method');
300: }
301:
302: return $this->commands;
303: }
304:
305: 306: 307:
308: public function storage()
309: {
310: return $this->storage;
311: }
312:
313: 314: 315: 316: 317:
318: public function asArray()
319: {
320: return $this->commands();
321: }
322:
323: 324: 325: 326: 327: 328: 329:
330: public function __get($name)
331: {
332: if (isset($this->aliases[$name]))
333: {
334: 335: 336:
337: $variable = $this->aliases[$name];
338: $name = $variable->name();
339: }
340:
341: $commands = &$this->commands();
342:
343: return $commands[$name];
344: }
345:
346: 347: 348: 349: 350: 351:
352: final public function __set($name, $value)
353: {
354: throw new \InvalidArgumentException(__METHOD__);
355: }
356:
357: 358: 359: 360: 361: 362: 363:
364: public function __isset($name)
365: {
366: $commands = &$this->commands();
367:
368: return isset($commands[$name]);
369: }
370:
371: 372: 373: 374: 375:
376: public function run()
377: {
378: if ($this->run)
379: {
380: throw new \InvalidArgumentException(__METHOD__);
381: }
382:
383: $string = $this->init();
384: $tokenizer = new Tokenizer($string);
385:
386: $storage = $tokenizer->run();
387: $this->initStorage($storage);
388: $this->initVariable($storage);
389: $this->initRequired();
390: $this->initUndefined();
391: $this->loadCommand($this->commands);
392: }
393:
394: }