Overview

Namespaces

  • PHP
  • PhpOptions
    • Types

Classes

  • Arguments
  • Option
  • Options

Exceptions

  • InvalidArgumentException
  • LogicException
  • UserBadCallException
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: /**
  4:  * PhpOptions
  5:  * @link https://github.com/masicek/PhpOptions
  6:  * @author Viktor Mašíček <viktor@masicek.net>
  7:  * @license "New" BSD License
  8:  */
  9: 
 10: namespace PhpOptions;
 11: 
 12: require_once __DIR__ . '/Exceptions.php';
 13: require_once __DIR__ . '/Arguments.php';
 14: 
 15: /**
 16:  * Class for better work with PHP comand-line options
 17:  *
 18:  * @author Viktor Mašíček <viktor@masicek.net>
 19:  */
 20: class Options
 21: {
 22: 
 23:     /**
 24:      * Version of PhpOptions
 25:      */
 26:     const VERSION = '1.3.0';
 27: 
 28:     /**
 29:      * Max length of one line
 30:      */
 31:     const HELP_MAX_LENGTH = 75;
 32: 
 33:     /**
 34:      * List of possible options
 35:      *
 36:      * @var array of Option
 37:      */
 38:     private $options = array();
 39: 
 40:     /**
 41:      * List of value of deffined options
 42:      *
 43:      * @var array ([name of option] => [value of option])
 44:      */
 45:     private $optionsValues = array();
 46: 
 47:     /**
 48:      * Mapping short variants to name of options
 49:      *
 50:      * @var array ([short variant] => [name of option])
 51:      */
 52:     private $optionsShorts = array();
 53: 
 54:     /**
 55:      * Mapping long variants to name of options
 56:      *
 57:      * @var array ([long variant] => [name of option])
 58:      */
 59:     private $optionsLongs = array();
 60: 
 61:     /**
 62:      * Default option and its value
 63:      *
 64:      * @var array ('name' => [name of option], 'value' => [value of option])
 65:      */
 66:     private $defaults = NULL;
 67: 
 68:     /**
 69:      * Common description show in help
 70:      *
 71:      * @var string
 72:      */
 73:     private $description = '';
 74: 
 75:     /**
 76:      * List groups with names of options that belong to groups
 77:      *
 78:      * @var array ([name of group] => array of names of options)
 79:      */
 80:     private $groups = array();
 81: 
 82: 
 83:     /**
 84:      * Control that script run from command line
 85:      *
 86:      * @throws UserBadCallException Script have to run from command line.
 87:      */
 88:     public function __construct()
 89:     {
 90:         if (php_sapi_name() !== 'cli')
 91:         {   // @codeCoverageIgnoreStart
 92:             throw new UserBadCallException('Script have to run from command line.');
 93:         }   // @codeCoverageIgnoreEnd
 94:     }
 95: 
 96: 
 97:     /**
 98:      * Return array of arguments in command-line.
 99:      *
100:      * @return array
101:      */
102:     public static function arguments()
103:     {
104:         return Arguments::getArguments();
105:     }
106: 
107: 
108:     /**
109:      * Add option
110:      *
111:      * @param array|Option $options Added options
112:      *
113:      * @return Options
114:      */
115:     public function add($options = array())
116:     {
117:         if (!is_array($options))
118:         {
119:             $options = array($options);
120:         }
121: 
122:         foreach ($options as $option)
123:         {
124:             $this->addOne($option);
125:         }
126: 
127:         return $this;
128:     }
129: 
130: 
131:     /**
132:      * Set default option if any options is set
133:      *
134:      * @param string $name Name of option
135:      *
136:      * @throws InvalidArgumentException Unknown option.
137:      * @return Options
138:      */
139:     public function defaults($name)
140:     {
141:         if (!isset($this->options[$name]))
142:         {
143:             throw new InvalidArgumentException($name . ': Unknown option.');
144:         }
145: 
146:         $value = $this->options[$name]->getDefaults();
147:         $this->defaults['name'] = $name;
148:         $this->defaults['value'] = $value;
149:         if (is_null($value))
150:         {
151:             $this->defaults['value'] = TRUE;
152:         }
153: 
154:         return $this;
155:     }
156: 
157: 
158:     /**
159:      * Set text of common description in generated help
160:      *
161:      * @param string $description Text of common description
162:      *
163:      * @return Options
164:      */
165:     public function description($description)
166:     {
167:         $this->description = $description;
168:         return $this;
169:     }
170: 
171: 
172:     /**
173:      * Return value of option.
174:      * For set option without value return TRUE.
175:      * If option is not set, return FALSE.
176:      *
177:      * @param string $name Name of option or short or long option with prefix ('-' or '--')
178:      *
179:      * @throws InvalidArgumentException Unknown option
180:      * @return mixed
181:      */
182:     public function get($name)
183:     {
184:         $nameInput = $name;
185: 
186:         // long variant to name
187:         if (substr($name, 0, 2) == '--')
188:         {
189:             $long = substr($name, 2);
190:             $name = isset($this->optionsLongs[$long]) ? $this->optionsLongs[$long] : NULL;
191:         }
192:         // short variant to name
193:         elseif (substr($name, 0, 1) == '-')
194:         {
195:             $short = substr($name, 1);
196:             $name = isset($this->optionsShorts[$short]) ? $this->optionsShorts[$short] : NULL;
197:         }
198: 
199:         if (!isset($this->optionsValues[$name]))
200:         {
201:             throw new InvalidArgumentException($nameInput . ': Unknown option.');
202:         }
203: 
204:         // default option
205:         if (!is_null($this->defaults) && ($this->defaults['name'] == $name) && (count(Arguments::options()) == 0))
206:         {
207:             return $this->defaults['value'];
208:         }
209: 
210:         return $this->optionsValues[$name];
211:     }
212: 
213: 
214:     /**
215:      * Define dependences of options.
216:      *
217:      * @param string $main Main option for which we define needed options
218:      * @param string|array $needed Needed options for main option
219:      * @param string $groupName Name of group into which put all options (main + needed)
220:      *
221:      * @throws InvalidArgumentException Unknown option
222:      * @throws UserBadCallException Some option need some another option
223:      * @return Options
224:      */
225:     public function dependences($main, $needed, $groupName = NULL)
226:     {
227:         if (!is_array($needed))
228:         {
229:             $needed = array($needed);
230:         }
231: 
232:         if (!isset($this->optionsValues[$main]))
233:         {
234:             throw new InvalidArgumentException($main . ': Unknown option.');
235:         }
236: 
237:         $neededOptions = array();
238:         foreach ($needed as $name)
239:         {
240:             if (!isset($this->optionsValues[$name]))
241:             {
242:                 throw new InvalidArgumentException($name . ': Unknown option.');
243:             }
244:             $neededOptions[] = $this->options[$name];
245:         }
246: 
247:         // if main option is defined, check needed options
248:         if ($this->get($main) !== FALSE)
249:         {
250:             foreach ($needed as $name)
251:             {
252:                 if ($this->get($name) === FALSE)
253:                 {
254:                     $mainOptions = $this->options[$main]->getOptions();
255:                     $nameOptions = $this->options[$name]->getOptions();
256:                     throw new UserBadCallException('Option "' . $mainOptions . '" needs option "'. $nameOptions . '".');
257:                 }
258:             }
259:         }
260: 
261:         $this->options[$main]->dependences($neededOptions);
262: 
263:         // make group
264:         if ($groupName)
265:         {
266:             array_unshift($needed, $main);
267:             $this->group($groupName, $needed);
268:         }
269: 
270:         return $this;
271:     }
272: 
273: 
274:     /**
275:      * Define groups of options
276:      *
277:      * @param string $name Name of group
278:      * @param string|array $options List of options names
279:      *
280:      * @return Options
281:      */
282:     public function group($name, $options)
283:     {
284:         if (in_array($name, array_keys($this->groups)))
285:         {
286:             throw new LogicException($name . ': Group already exists.');
287:         }
288: 
289:         if (!is_array($options))
290:         {
291:             $options = array($options);
292:         }
293: 
294:         foreach ($options as $optionName)
295:         {
296:             if (!isset($this->options[$optionName]))
297:             {
298:                 throw new LogicException($optionName . ': Option does not exist.');
299:             }
300:         }
301: 
302:         $this->groups[$name] = $options;
303: 
304:         return $this;
305:     }
306: 
307: 
308:     /**
309:      * Return "help" made from descriptions of options
310:      *
311:      * @return string
312:      */
313:     public function getHelp($maxLength = self::HELP_MAX_LENGTH)
314:     {
315:         $help = $this->wordwrap($this->description, $maxLength) . PHP_EOL . PHP_EOL;
316: 
317:         $optionsNongroup = $this->options;
318: 
319:         $indent = 0;
320:         if ($this->groups)
321:         {
322:             foreach ($this->groups as $groupName => $optionsNames)
323:             {
324:                 $help .= $this->wordwrap($groupName, $maxLength) . PHP_EOL;
325:                 foreach ($optionsNames as $optionName)
326:                 {
327:                     $help .= $this->options[$optionName]->getHelp($maxLength, 1) . PHP_EOL;
328:                     if (isset($optionsNongroup[$optionName]))
329:                     {
330:                         unset($optionsNongroup[$optionName]);
331:                     }
332:                 }
333:             }
334: 
335:             if (count($optionsNongroup) > 0)
336:             {
337:                 $help .= PHP_EOL . $this->wordwrap('NON GROUP OPTIONS:', $maxLength) . PHP_EOL;
338:             }
339:             $indent = 1;
340:         }
341: 
342:         // print non group options
343:         foreach ($optionsNongroup as $option)
344:         {
345:             $help .= $option->getHelp($maxLength, $indent) . PHP_EOL;
346:         }
347: 
348:         return $help;
349:     }
350: 
351: 
352:     // ---- private ----
353: 
354: 
355:     /**
356:      * Add one option
357:      *
358:      * @param Option $option Added option
359:      *
360:      * @return void
361:      */
362:     private function addOne(Option $option)
363:     {
364:         $this->checkConflicts($option);
365:         $name = $option->getName();
366:         $this->options[$name] = $option;
367:         $this->optionsValues[$name] = $option->getValue((bool)($this->defaults['value']));
368:         if ($option->getShort())
369:         {
370:             $this->optionsShorts[$option->getShort()] = $name;
371:         }
372:         if ($option->getLong())
373:         {
374:             $this->optionsLongs[$option->getLong()] = $name;
375:         }
376:     }
377: 
378: 
379:     /**
380:      * Check conflict between added option and input option
381:      *
382:      * @param Option $option Checked option
383:      *
384:      * @throws LogicException Option already exist.
385:      * @throws LogicException Option with set short variant already exist.
386:      * @throws LogicException Option with set long variant already exist.
387:      * @return void
388:      */
389:     private function checkConflicts(Option $option)
390:     {
391:         $name = $option->getName();
392:         if (isset($this->options[$name]))
393:         {
394:             throw new LogicException($name . ': Option already exists.');
395:         }
396: 
397:         $short = $option->getShort();
398:         if (in_array($short, array_keys($this->optionsShorts)))
399:         {
400:             throw new LogicException($name . ': Option with short variant "' . $short . '" already exists.');
401:         }
402: 
403:         $long = $option->getLong();
404:         if (in_array($long, array_keys($this->optionsLongs)))
405:         {
406:             throw new LogicException($name . ': Option with long variant "' . $long . '" already exists.');
407:         }
408:     }
409: 
410: 
411:     /**
412:      * Wrapping input sring on maximal length
413:      *
414:      * @param string $string Wrapped string
415:      * @param int $maxLength Maximla length of one line
416:      *
417:      * @return string
418:      */
419:     private function wordwrap($string, $maxLength)
420:     {
421:         return wordwrap($string, $maxLength, PHP_EOL, TRUE);
422:     }
423: 
424: 
425: }
426: 
PhpOptions API documentation generated by ApiGen.
Generated using the TokenReflection library.