diff --git a/lib/vendor/Symfony/Components/Console/Application.php b/lib/vendor/Symfony/Components/Console/Application.php new file mode 100644 index 000000000..e26319be7 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Application.php @@ -0,0 +1,804 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * An Application is the container for a collection of commands. + * + * It is the main entry point of a Console application. + * + * This class is optimized for a standard CLI environment. + * + * Usage: + * + * $app = new Application('myapp', '1.0 (stable)'); + * $app->addCommand(new SimpleCommand()); + * $app->run(); + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class Application +{ + protected $commands; + protected $aliases; + protected $application; + protected $wantHelps = false; + protected $runningCommand; + protected $name; + protected $version; + protected $catchExceptions; + protected $autoExit; + protected $definition; + protected $helperSet; + + /** + * Constructor. + * + * @param string $name The name of the application + * @param string $version The version of the application + */ + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') + { + $this->name = $name; + $this->version = $version; + $this->catchExceptions = true; + $this->autoExit = true; + $this->commands = array(); + $this->aliases = array(); + $this->helperSet = new HelperSet(array( + new FormatterHelper(), + new DialogHelper(), + )); + + $this->addCommand(new HelpCommand()); + $this->addCommand(new ListCommand()); + + $this->definition = new InputDefinition(array( + new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), + + new InputOption('--help', '-h', InputOption::PARAMETER_NONE, 'Display this help message.'), + new InputOption('--quiet', '-q', InputOption::PARAMETER_NONE, 'Do not output any message.'), + new InputOption('--verbose', '-v', InputOption::PARAMETER_NONE, 'Increase verbosity of messages.'), + new InputOption('--version', '-V', InputOption::PARAMETER_NONE, 'Display this program version.'), + new InputOption('--color', '-c', InputOption::PARAMETER_NONE, 'Force ANSI color output.'), + new InputOption('--no-interaction', '-n', InputOption::PARAMETER_NONE, 'Do not ask any interactive question.'), + )); + } + + /** + * Runs the current application. + * + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return integer 0 if everything went fine, or an error code + */ + public function run(InputInterface $input = null, OutputInterface $output = null) + { + if (null === $input) + { + $input = new ArgvInput(); + } + + if (null === $output) + { + $output = new ConsoleOutput(); + } + + try + { + $statusCode = $this->doRun($input, $output); + } + catch (\Exception $e) + { + if (!$this->catchExceptions) + { + throw $e; + } + + $this->renderException($e, $output); + $statusCode = $e->getCode(); + + $statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1; + } + + if ($this->autoExit) + { + // @codeCoverageIgnoreStart + exit($statusCode); + // @codeCoverageIgnoreEnd + } + else + { + return $statusCode; + } + } + + /** + * Runs the current application. + * + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return integer 0 if everything went fine, or an error code + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + $name = $input->getFirstArgument('command'); + + if (true === $input->hasParameterOption(array('--color', '-c'))) + { + $output->setDecorated(true); + } + + if (true === $input->hasParameterOption(array('--help', '-H'))) + { + if (!$name) + { + $name = 'help'; + $input = new ArrayInput(array('command' => 'help')); + } + else + { + $this->wantHelps = true; + } + } + + if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) + { + $input->setInteractive(false); + } + + if (true === $input->hasParameterOption(array('--quiet', '-q'))) + { + $output->setVerbosity(Output::VERBOSITY_QUIET); + } + elseif (true === $input->hasParameterOption(array('--verbose', '-v'))) + { + $output->setVerbosity(Output::VERBOSITY_VERBOSE); + } + + if (true === $input->hasParameterOption(array('--version', '-V'))) + { + $output->writeln($this->getLongVersion()); + + return 0; + } + + if (!$name) + { + $name = 'list'; + $input = new ArrayInput(array('command' => 'list')); + } + + // the command name MUST be the first element of the input + $command = $this->findCommand($name); + + $this->runningCommand = $command; + $statusCode = $command->run($input, $output); + $this->runningCommand = null; + + return is_numeric($statusCode) ? $statusCode : 0; + } + + /** + * Set a helper set to be used with the command. + * + * @param HelperSet $helperSet The helper set + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Get the helper set associated with the command + * + * @return HelperSet The HelperSet isntance associated with this command + */ + public function getHelperSet() + { + return $this->helperSet; + } + + /** + * Gets the InputDefinition related to this Application. + * + * @return InputDefinition The InputDefinition instance + */ + public function getDefinition() + { + return $this->definition; + } + + /** + * Gets the help message. + * + * @return string A help message. + */ + public function getHelp() + { + $messages = array( + $this->getLongVersion(), + '', + 'Usage:', + sprintf(" [options] command [arguments]\n"), + 'Options:', + ); + + foreach ($this->definition->getOptions() as $option) + { + $messages[] = sprintf(' %-29s %s %s', + '--'.$option->getName().'', + $option->getShortcut() ? '-'.$option->getShortcut().'' : ' ', + $option->getDescription() + ); + } + + return implode("\n", $messages); + } + + /** + * Sets whether to catch exceptions or not during commands execution. + * + * @param Boolean $boolean Whether to catch exceptions or not during commands execution + */ + public function setCatchExceptions($boolean) + { + $this->catchExceptions = (Boolean) $boolean; + } + + /** + * Sets whether to automatically exit after a command execution or not. + * + * @param Boolean $boolean Whether to automatically exit after a command execution or not + */ + public function setAutoExit($boolean) + { + $this->autoExit = (Boolean) $boolean; + } + + /** + * Gets the name of the application. + * + * @return string The application name + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the application name. + * + * @param string $name The application name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Gets the application version. + * + * @return string The application version + */ + public function getVersion() + { + return $this->version; + } + + /** + * Sets the application version. + * + * @param string $version The application version + */ + public function setVersion($version) + { + $this->version = $version; + } + + /** + * Returns the long version of the application. + * + * @return string The long application version + */ + public function getLongVersion() + { + if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) + { + return sprintf('%s version %s', $this->getName(), $this->getVersion()); + } + else + { + return 'Console Tool'; + } + } + + /** + * Registers a new command. + * + * @param string $name The command name + * + * @return Command The newly created command + */ + public function register($name) + { + return $this->addCommand(new Command($name)); + } + + /** + * Adds an array of command objects. + * + * @param array $commands An array of commands + */ + public function addCommands(array $commands) + { + foreach ($commands as $command) + { + $this->addCommand($command); + } + } + + /** + * Adds a command object. + * + * If a command with the same name already exists, it will be overridden. + * + * @param Command $command A Command object + * + * @return Command The registered command + */ + public function addCommand(Command $command) + { + $command->setApplication($this); + + $this->commands[$command->getFullName()] = $command; + + foreach ($command->getAliases() as $alias) + { + $this->aliases[$alias] = $command; + } + + return $command; + } + + /** + * Returns a registered command by name or alias. + * + * @param string $name The command name or alias + * + * @return Command A Command object + */ + public function getCommand($name) + { + if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) + { + throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); + } + + $command = isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name]; + + if ($this->wantHelps) + { + $this->wantHelps = false; + + $helpCommand = $this->getCommand('help'); + $helpCommand->setCommand($command); + + return $helpCommand; + } + + return $command; + } + + /** + * Returns true if the command exists, false otherwise + * + * @param string $name The command name or alias + * + * @return Boolean true if the command exists, false otherwise + */ + public function hasCommand($name) + { + return isset($this->commands[$name]) || isset($this->aliases[$name]); + } + + /** + * Returns an array of all unique namespaces used by currently registered commands. + * + * It does not returns the global namespace which always exists. + * + * @return array An array of namespaces + */ + public function getNamespaces() + { + $namespaces = array(); + foreach ($this->commands as $command) + { + if ($command->getNamespace()) + { + $namespaces[$command->getNamespace()] = true; + } + } + + return array_keys($namespaces); + } + + /** + * Finds a registered namespace by a name or an abbreviation. + * + * @return string A registered namespace + */ + public function findNamespace($namespace) + { + $abbrevs = static::getAbbreviations($this->getNamespaces()); + + if (!isset($abbrevs[$namespace])) + { + throw new \InvalidArgumentException(sprintf('There are no commands defined in the "%s" namespace.', $namespace)); + } + + if (count($abbrevs[$namespace]) > 1) + { + throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$namespace]))); + } + + return $abbrevs[$namespace][0]; + } + + /** + * Finds a command by name or alias. + * + * Contrary to getCommand, this command tries to find the best + * match if you give it an abbreviation of a name or alias. + * + * @param string $name A command name or a command alias + * + * @return Command A Command instance + */ + public function findCommand($name) + { + // namespace + $namespace = ''; + if (false !== $pos = strpos($name, ':')) + { + $namespace = $this->findNamespace(substr($name, 0, $pos)); + $name = substr($name, $pos + 1); + } + + $fullName = $namespace ? $namespace.':'.$name : $name; + + // name + $commands = array(); + foreach ($this->commands as $command) + { + if ($command->getNamespace() == $namespace) + { + $commands[] = $command->getName(); + } + } + + $abbrevs = static::getAbbreviations($commands); + if (isset($abbrevs[$name]) && 1 == count($abbrevs[$name])) + { + return $this->getCommand($namespace ? $namespace.':'.$abbrevs[$name][0] : $abbrevs[$name][0]); + } + + if (isset($abbrevs[$name]) && count($abbrevs[$name]) > 1) + { + $suggestions = $this->getAbbreviationSuggestions(array_map(function ($command) use ($namespace) { return $namespace.':'.$command; }, $abbrevs[$name])); + + throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $suggestions)); + } + + // aliases + $abbrevs = static::getAbbreviations(array_keys($this->aliases)); + if (!isset($abbrevs[$fullName])) + { + throw new \InvalidArgumentException(sprintf('Command "%s" is not defined.', $fullName)); + } + + if (count($abbrevs[$fullName]) > 1) + { + throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $this->getAbbreviationSuggestions($abbrevs[$fullName]))); + } + + return $this->getCommand($abbrevs[$fullName][0]); + } + + /** + * Gets the commands (registered in the given namespace if provided). + * + * The array keys are the full names and the values the command instances. + * + * @param string $namespace A namespace name + * + * @return array An array of Command instances + */ + public function getCommands($namespace = null) + { + if (null === $namespace) + { + return $this->commands; + } + + $commands = array(); + foreach ($this->commands as $name => $command) + { + if ($namespace === $command->getNamespace()) + { + $commands[$name] = $command; + } + } + + return $commands; + } + + /** + * Returns an array of possible abbreviations given a set of names. + * + * @param array An array of names + * + * @return array An array of abbreviations + */ + static public function getAbbreviations($names) + { + $abbrevs = array(); + foreach ($names as $name) + { + for ($len = strlen($name) - 1; $len > 0; --$len) + { + $abbrev = substr($name, 0, $len); + if (!isset($abbrevs[$abbrev])) + { + $abbrevs[$abbrev] = array($name); + } + else + { + $abbrevs[$abbrev][] = $name; + } + } + } + + // Non-abbreviations always get entered, even if they aren't unique + foreach ($names as $name) + { + $abbrevs[$name] = array($name); + } + + return $abbrevs; + } + + /** + * Returns a text representation of the Application. + * + * @param string $namespace An optional namespace name + * + * @return string A string representing the Application + */ + public function asText($namespace = null) + { + $commands = $namespace ? $this->getCommands($this->findNamespace($namespace)) : $this->commands; + + $messages = array($this->getHelp(), ''); + if ($namespace) + { + $messages[] = sprintf("Available commands for the \"%s\" namespace:", $namespace); + } + else + { + $messages[] = 'Available commands:'; + } + + $width = 0; + foreach ($commands as $command) + { + $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width; + } + $width += 2; + + // add commands by namespace + foreach ($this->sortCommands($commands) as $space => $commands) + { + if (!$namespace && '_global' !== $space) + { + $messages[] = ''.$space.''; + } + + foreach ($commands as $command) + { + $aliases = $command->getAliases() ? ' ('.implode(', ', $command->getAliases()).')' : ''; + + $messages[] = sprintf(" %-${width}s %s%s", ($command->getNamespace() ? ':' : '').$command->getName(), $command->getDescription(), $aliases); + } + } + + return implode("\n", $messages); + } + + /** + * Returns an XML representation of the Application. + * + * @param string $namespace An optional namespace name + * @param Boolean $asDom Whether to return a DOM or an XML string + * + * @return string|DOMDocument An XML string representing the Application + */ + public function asXml($namespace = null, $asDom = false) + { + $commands = $namespace ? $this->getCommands($this->findNamespace($namespace)) : $this->commands; + + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $dom->appendChild($xml = $dom->createElement('symfony')); + + $xml->appendChild($commandsXML = $dom->createElement('commands')); + + if ($namespace) + { + $commandsXML->setAttribute('namespace', $namespace); + } + else + { + $xml->appendChild($namespacesXML = $dom->createElement('namespaces')); + } + + // add commands by namespace + foreach ($this->sortCommands($commands) as $space => $commands) + { + if (!$namespace) + { + $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); + $namespaceArrayXML->setAttribute('id', $space); + } + + foreach ($commands as $command) + { + if (!$namespace) + { + $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); + $commandXML->appendChild($dom->createTextNode($command->getName())); + } + + $commandXML = new \DOMDocument('1.0', 'UTF-8'); + $commandXML->formatOutput = true; + $commandXML->loadXML($command->asXml()); + $node = $commandXML->getElementsByTagName('command')->item(0); + $node = $dom->importNode($node, true); + + $commandsXML->appendChild($node); + } + } + + return $asDom ? $dom : $dom->saveXml(); + } + + /** + * Renders a catched exception. + * + * @param Exception $e An exception instance + * @param OutputInterface $output An OutputInterface instance + */ + public function renderException($e, $output) + { + $strlen = function ($string) + { + return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string); + }; + + $title = sprintf(' [%s] ', get_class($e)); + $len = $strlen($title); + $lines = array(); + foreach (explode("\n", $e->getMessage()) as $line) + { + $lines[] = sprintf(' %s ', $line); + $len = max($strlen($line) + 4, $len); + } + + $messages = array(str_repeat(' ', $len), $title.str_repeat(' ', $len - $strlen($title))); + + foreach ($lines as $line) + { + $messages[] = $line.str_repeat(' ', $len - $strlen($line)); + } + + $messages[] = str_repeat(' ', $len); + + $output->writeln("\n"); + foreach ($messages as $message) + { + $output->writeln("$message"); + } + $output->writeln("\n"); + + if (null !== $this->runningCommand) + { + $output->writeln(sprintf('%s', sprintf($this->runningCommand->getSynopsis(), $this->getName()))); + $output->writeln("\n"); + } + + if (Output::VERBOSITY_VERBOSE === $output->getVerbosity()) + { + $output->writeln('Exception trace:'); + + // exception related properties + $trace = $e->getTrace(); + array_unshift($trace, array( + 'function' => '', + 'file' => $e->getFile() != null ? $e->getFile() : 'n/a', + 'line' => $e->getLine() != null ? $e->getLine() : 'n/a', + 'args' => array(), + )); + + for ($i = 0, $count = count($trace); $i < $count; $i++) + { + $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : ''; + $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : ''; + $function = $trace[$i]['function']; + $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a'; + $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a'; + + $output->writeln(sprintf(' %s%s%s() at %s:%s', $class, $type, $function, $file, $line)); + } + + $output->writeln("\n"); + } + } + + private function sortCommands($commands) + { + $namespacedCommands = array(); + foreach ($commands as $name => $command) + { + $key = $command->getNamespace() ? $command->getNamespace() : '_global'; + + if (!isset($namespacedCommands[$key])) + { + $namespacedCommands[$key] = array(); + } + + $namespacedCommands[$key][$name] = $command; + } + ksort($namespacedCommands); + + foreach ($namespacedCommands as $name => &$commands) + { + ksort($commands); + } + + return $namespacedCommands; + } + + private function getAbbreviationSuggestions($abbrevs) + { + return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); + } +} diff --git a/lib/vendor/Symfony/Components/Console/Command/Command.php b/lib/vendor/Symfony/Components/Console/Command/Command.php new file mode 100644 index 000000000..bbde5f94e --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Command/Command.php @@ -0,0 +1,508 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Base class for all commands. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class Command +{ + protected $name; + protected $namespace; + protected $aliases; + protected $definition; + protected $help; + protected $application; + protected $description; + protected $ignoreValidationErrors; + protected $formatter; + protected $applicationDefinitionMerged; + protected $code; + + /** + * Constructor. + * + * @param string $name The name of the command + */ + public function __construct($name = null) + { + $this->definition = new InputDefinition(); + $this->ignoreValidationErrors = false; + $this->applicationDefinitionMerged = false; + $this->aliases = array(); + + if (null !== $name) + { + $this->setName($name); + } + + $this->configure(); + + if (!$this->name) + { + throw new \LogicException('The command name cannot be empty.'); + } + } + + /** + * Sets the application instance for this command. + * + * @param Application $application An Application instance + */ + public function setApplication(Application $application = null) + { + $this->application = $application; + } + + /** + * Configures the current command. + */ + protected function configure() + { + } + + /** + * Executes the current command. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return integer 0 if everything went fine, or an error code + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + throw new \LogicException('You must override the execute() method in the concrete command class.'); + } + + /** + * Interacts with the user. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + } + + /** + * Initializes the command just after the input has been validated. + * + * This is mainly useful when a lot of commands extends one main command + * where some things need to be initialized based on the input arguments and options. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + } + + /** + * Runs the command. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + public function run(InputInterface $input, OutputInterface $output) + { + // add the application arguments and options + $this->mergeApplicationDefinition(); + + // bind the input against the command specific arguments/options + try + { + $input->bind($this->definition); + } + catch (\Exception $e) + { + if (!$this->ignoreValidationErrors) + { + throw $e; + } + } + + $this->initialize($input, $output); + + if ($input->isInteractive()) + { + $this->interact($input, $output); + } + + $input->validate(); + + if ($this->code) + { + return call_user_func($this->code, $input, $output); + } + else + { + return $this->execute($input, $output); + } + } + + /** + * Sets the code to execute when running this command. + * + * @param \Closure $code A \Closure + * + * @return Command The current instance + */ + public function setCode(\Closure $code) + { + $this->code = $code; + + return $this; + } + + /** + * Merges the application definition with the command definition. + */ + protected function mergeApplicationDefinition() + { + if (null === $this->application || true === $this->applicationDefinitionMerged) + { + return; + } + + $this->definition->setArguments(array_merge( + $this->application->getDefinition()->getArguments(), + $this->definition->getArguments() + )); + + $this->definition->addOptions($this->application->getDefinition()->getOptions()); + + $this->applicationDefinitionMerged = true; + } + + /** + * Sets an array of argument and option instances. + * + * @param array|Definition $definition An array of argument and option instances or a definition instance + * + * @return Command The current instance + */ + public function setDefinition($definition) + { + if ($definition instanceof InputDefinition) + { + $this->definition = $definition; + } + else + { + $this->definition->setDefinition($definition); + } + + $this->applicationDefinitionMerged = false; + + return $this; + } + + /** + * Gets the InputDefinition attached to this Command. + * + * @return InputDefinition $definition An InputDefinition instance + */ + public function getDefinition() + { + return $this->definition; + } + + /** + * Adds an argument. + * + * @param string $name The argument name + * @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) + * + * @return Command The current instance + */ + public function addArgument($name, $mode = null, $description = '', $default = null) + { + $this->definition->addArgument(new InputArgument($name, $mode, $description, $default)); + + return $this; + } + + /** + * Adds an option. + * + * @param string $name The option name + * @param string $shortcut The shortcut (can be null) + * @param integer $mode The option mode: self::PARAMETER_REQUIRED, self::PARAMETER_NONE or self::PARAMETER_OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (must be null for self::PARAMETER_REQUIRED or self::PARAMETER_NONE) + * + * @return Command The current instance + */ + public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default)); + + return $this; + } + + /** + * Sets the name of the command. + * + * This method can set both the namespace and the name if + * you separate them by a colon (:) + * + * $command->setName('foo:bar'); + * + * @param string $name The command name + * + * @return Command The current instance + */ + public function setName($name) + { + if (false !== $pos = strpos($name, ':')) + { + $namespace = substr($name, 0, $pos); + $name = substr($name, $pos + 1); + } + else + { + $namespace = $this->namespace; + } + + if (!$name) + { + throw new \InvalidArgumentException('A command name cannot be empty'); + } + + $this->namespace = $namespace; + $this->name = $name; + + return $this; + } + + /** + * Returns the command namespace. + * + * @return string The command namespace + */ + public function getNamespace() + { + return $this->namespace; + } + + /** + * Returns the command name + * + * @return string The command name + */ + public function getName() + { + return $this->name; + } + + /** + * Returns the fully qualified command name. + * + * @return string The fully qualified command name + */ + public function getFullName() + { + return $this->getNamespace() ? $this->getNamespace().':'.$this->getName() : $this->getName(); + } + + /** + * Sets the description for the command. + * + * @param string $description The description for the command + * + * @return Command The current instance + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * Returns the description for the command. + * + * @return string The description for the command + */ + public function getDescription() + { + return $this->description; + } + + /** + * Sets the help for the command. + * + * @param string $help The help for the command + * + * @return Command The current instance + */ + public function setHelp($help) + { + $this->help = $help; + + return $this; + } + + /** + * Returns the help for the command. + * + * @return string The help for the command + */ + public function getHelp() + { + return $this->help; + } + + /** + * Sets the aliases for the command. + * + * @param array $aliases An array of aliases for the command + * + * @return Command The current instance + */ + public function setAliases($aliases) + { + $this->aliases = $aliases; + + return $this; + } + + /** + * Returns the aliases for the command. + * + * @return array An array of aliases for the command + */ + public function getAliases() + { + return $this->aliases; + } + + /** + * Returns the synopsis for the command. + * + * @return string The synopsis + */ + public function getSynopsis() + { + return sprintf('%s %s', $this->getFullName(), $this->definition->getSynopsis()); + } + + /** + * Gets a helper instance by name. + * + * @param string $name The helper name + * + * @return mixed The helper value + * + * @throws \InvalidArgumentException if the helper is not defined + */ + protected function getHelper($name) + { + return $this->application->getHelperSet()->get($name); + } + + /** + * Gets a helper instance by name. + * + * @param string $name The helper name + * + * @return mixed The helper value + * + * @throws \InvalidArgumentException if the helper is not defined + */ + public function __get($name) + { + return $this->application->getHelperSet()->get($name); + } + + /** + * Returns a text representation of the command. + * + * @return string A string representing the command + */ + public function asText() + { + $messages = array( + 'Usage:', + ' '.$this->getSynopsis(), + '', + ); + + if ($this->getAliases()) + { + $messages[] = 'Aliases: '.implode(', ', $this->getAliases()).''; + } + + $messages[] = $this->definition->asText(); + + if ($help = $this->getHelp()) + { + $messages[] = 'Help:'; + $messages[] = ' '.implode("\n ", explode("\n", $help))."\n"; + } + + return implode("\n", $messages); + } + + /** + * Returns an XML representation of the command. + * + * @param Boolean $asDom Whether to return a DOM or an XML string + * + * @return string|DOMDocument An XML string representing the command + */ + public function asXml($asDom = false) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $dom->appendChild($commandXML = $dom->createElement('command')); + $commandXML->setAttribute('id', $this->getFullName()); + $commandXML->setAttribute('namespace', $this->getNamespace() ? $this->getNamespace() : '_global'); + $commandXML->setAttribute('name', $this->getName()); + + $commandXML->appendChild($usageXML = $dom->createElement('usage')); + $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), ''))); + + $commandXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $this->getDescription())))); + + $commandXML->appendChild($helpXML = $dom->createElement('help')); + $help = $this->help; + $helpXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $help)))); + + $commandXML->appendChild($aliasesXML = $dom->createElement('aliases')); + foreach ($this->getAliases() as $alias) + { + $aliasesXML->appendChild($aliasXML = $dom->createElement('alias')); + $aliasXML->appendChild($dom->createTextNode($alias)); + } + + $definition = $this->definition->asXml(true); + $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true)); + $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true)); + + return $asDom ? $dom : $dom->saveXml(); + } +} diff --git a/lib/vendor/Symfony/Components/Console/Command/HelpCommand.php b/lib/vendor/Symfony/Components/Console/Command/HelpCommand.php new file mode 100644 index 000000000..8258c5c18 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Command/HelpCommand.php @@ -0,0 +1,83 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * HelpCommand displays the help for a given command. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class HelpCommand extends Command +{ + protected $command; + + /** + * @see Command + */ + protected function configure() + { + $this->ignoreValidationErrors = true; + + $this + ->setDefinition(array( + new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), + new InputOption('xml', null, InputOption::PARAMETER_NONE, 'To output help as XML'), + )) + ->setName('help') + ->setAliases(array('?')) + ->setDescription('Displays help for a command') + ->setHelp(<<help command displays help for a given command: + + ./symfony help test:all + +You can also output the help as XML by using the --xml option: + + ./symfony help --xml test:all +EOF + ); + } + + public function setCommand(Command $command) + { + $this->command = $command; + } + + /** + * @see Command + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (null === $this->command) + { + $this->command = $this->application->getCommand($input->getArgument('command_name')); + } + + if ($input->getOption('xml')) + { + $output->writeln($this->command->asXml(), Output::OUTPUT_RAW); + } + else + { + $output->writeln($this->command->asText()); + } + } +} diff --git a/lib/vendor/Symfony/Components/Console/Command/ListCommand.php b/lib/vendor/Symfony/Components/Console/Command/ListCommand.php new file mode 100644 index 000000000..3fddbc224 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Command/ListCommand.php @@ -0,0 +1,72 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * ListCommand displays the list of all available commands for the application. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class ListCommand extends Command +{ + /** + * @see Command + */ + protected function configure() + { + $this + ->setDefinition(array( + new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), + new InputOption('xml', null, InputOption::PARAMETER_NONE, 'To output help as XML'), + )) + ->setName('list') + ->setDescription('Lists commands') + ->setHelp(<<list command lists all commands: + + ./symfony list + +You can also display the commands for a specific namespace: + + ./symfony list test + +You can also output the information as XML by using the --xml option: + + ./symfony list --xml +EOF + ); + } + + /** + * @see Command + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if ($input->getOption('xml')) + { + $output->writeln($this->application->asXml($input->getArgument('namespace')), Output::OUTPUT_RAW); + } + else + { + $output->writeln($this->application->asText($input->getArgument('namespace'))); + } + } +} diff --git a/lib/vendor/Symfony/Components/Console/Helper/DialogHelper.php b/lib/vendor/Symfony/Components/Console/Helper/DialogHelper.php new file mode 100644 index 000000000..a19c3d949 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Helper/DialogHelper.php @@ -0,0 +1,119 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * The Dialog class provides helpers to interact with the user. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class DialogHelper extends Helper +{ + /** + * Asks a question to the user. + * + * @param OutputInterface $output + * @param string|array $question The question to ask + * @param string $default The default answer if none is given by the user + * + * @param string The user answer + */ + public function ask(OutputInterface $output, $question, $default = null) + { + // @codeCoverageIgnoreStart + $output->writeln($question); + + $ret = trim(fgets(STDIN)); + + return $ret ? $ret : $default; + // @codeCoverageIgnoreEnd + } + + /** + * Asks a confirmation to the user. + * + * The question will be asked until the user answer by nothing, yes, or no. + * + * @param OutputInterface $output + * @param string|array $question The question to ask + * @param Boolean $default The default answer if the user enters nothing + * + * @param Boolean true if the user has confirmed, false otherwise + */ + public function askConfirmation(OutputInterface $output, $question, $default = true) + { + // @codeCoverageIgnoreStart + $answer = 'z'; + while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) + { + $answer = $this->ask($output, $question); + } + + if (false === $default) + { + return $answer && 'y' == strtolower($answer[0]); + } + else + { + return !$answer || 'y' == strtolower($answer[0]); + } + // @codeCoverageIgnoreEnd + } + + /** + * Asks for a value and validates the response. + * + * @param OutputInterface $output + * @param string|array $question + * @param Closure $validator + * @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite) + * + * @return mixed + */ + public function askAndValidate(OutputInterface $output, $question, \Closure $validator, $attempts = false) + { + // @codeCoverageIgnoreStart + $error = null; + while (false === $attempts || $attempts--) + { + if (null !== $error) + { + $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error')); + } + + $value = $this->ask($output, $question, null); + + try + { + return $validator($value); + } + catch (\Exception $error) + { + } + } + + throw $error; + // @codeCoverageIgnoreEnd + } + + /** + * Returns the helper's canonical name + */ + public function getName() + { + return 'dialog'; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Helper/FormatterHelper.php b/lib/vendor/Symfony/Components/Console/Helper/FormatterHelper.php new file mode 100644 index 000000000..6eedca733 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Helper/FormatterHelper.php @@ -0,0 +1,89 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * The Formatter class provides helpers to format messages. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class FormatterHelper extends Helper +{ + /** + * Formats a message within a section. + * + * @param string $section The section name + * @param string $message The message + * @param string $style The style to apply to the section + */ + public function formatSection($section, $message, $style = 'info') + { + return sprintf("<%s>[%s] %s", $style, $section, $style, $message); + } + + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + * @param string $style The style to apply to the whole block + * @param Boolean $large Whether to return a large block + * + * @return string The formatter message + */ + public function formatBlock($messages, $style, $large = false) + { + if (!is_array($messages)) + { + $messages = array($messages); + } + + $len = 0; + $lines = array(); + foreach ($messages as $message) + { + $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); + $len = max($this->strlen($message) + ($large ? 4 : 2), $len); + } + + $messages = $large ? array(str_repeat(' ', $len)) : array(); + foreach ($lines as $line) + { + $messages[] = $line.str_repeat(' ', $len - $this->strlen($line)); + } + if ($large) + { + $messages[] = str_repeat(' ', $len); + } + + foreach ($messages as &$message) + { + $message = sprintf('<%s>%s', $style, $message, $style); + } + + return implode("\n", $messages); + } + + protected function strlen($string) + { + return function_exists('mb_strlen') ? mb_strlen($string) : strlen($string); + } + + /** + * Returns the helper's canonical name + */ + public function getName() + { + return 'formatter'; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Helper/Helper.php b/lib/vendor/Symfony/Components/Console/Helper/Helper.php new file mode 100644 index 000000000..f083b47ab --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Helper/Helper.php @@ -0,0 +1,45 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Helper is the base class for all helper classes. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +abstract class Helper implements HelperInterface +{ + protected + $helperSet = null; + + /** + * Sets the helper set associated with this helper. + * + * @param HelperSet $helperSet A HelperSet instance + */ + public function setHelperSet(HelperSet $helperSet = null) + { + $this->helperSet = $helperSet; + } + + /** + * Gets the helper set associated with this helper. + * + * @return HelperSet A HelperSet instance + */ + public function getHelperSet() + { + return $this->helperSet; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Helper/HelperInterface.php b/lib/vendor/Symfony/Components/Console/Helper/HelperInterface.php new file mode 100644 index 000000000..f3de9aa65 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Helper/HelperInterface.php @@ -0,0 +1,43 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * HelperInterface is the interface all helpers must implement. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +interface HelperInterface +{ + /** + * Sets the helper set associated with this helper. + * + * @param HelperSet $helperSet A HelperSet instance + */ + function setHelperSet(HelperSet $helperSet = null); + + /** + * Gets the helper set associated with this helper. + * + * @return HelperSet A HelperSet instance + */ + function getHelperSet(); + + /** + * Returns the canonical name of this helper. + * + * @return string The canonical name + */ + function getName(); +} diff --git a/lib/vendor/Symfony/Components/Console/Helper/HelperSet.php b/lib/vendor/Symfony/Components/Console/Helper/HelperSet.php new file mode 100644 index 000000000..67d764f52 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Helper/HelperSet.php @@ -0,0 +1,104 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * HelperSet represents a set of helpers to be used with a command. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class HelperSet +{ + protected + $helpers = array(), + $command = null; + + public function __construct(array $helpers = array()) + { + foreach ($helpers as $alias => $helper) + { + $this->set($helper, is_int($alias) ? null : $alias); + } + } + + /** + * Sets a helper. + * + * @param HelperInterface $value The helper instance + * @param string $alias An alias + */ + public function set(HelperInterface $helper, $alias = null) + { + $this->helpers[$helper->getName()] = $helper; + if (null !== $alias) + { + $this->helpers[$alias] = $helper; + } + + $helper->setHelperSet($this); + } + + /** + * Returns true if the helper if defined. + * + * @param string $name The helper name + * + * @return Boolean true if the helper is defined, false otherwise + */ + public function has($name) + { + return isset($this->helpers[$name]); + } + + /** + * Gets a helper value. + * + * @param string $name The helper name + * + * @return HelperInterface The helper instance + * + * @throws \InvalidArgumentException if the helper is not defined + */ + public function get($name) + { + if (!$this->has($name)) + { + throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); + } + + return $this->helpers[$name]; + } + + /** + * Sets the command associated with this helper set. + * + * @param Command $command A Command instance + */ + public function setCommand(Command $command = null) + { + $this->command = $command; + } + + /** + * Gets the command associated with this helper set. + * + * @return Command A Command instance + */ + public function getCommand() + { + return $this->command; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Input/ArgvInput.php b/lib/vendor/Symfony/Components/Console/Input/ArgvInput.php new file mode 100644 index 000000000..a140219bf --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/ArgvInput.php @@ -0,0 +1,284 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * ArgvInput represents an input coming from the CLI arguments. + * + * Usage: + * + * $input = new ArgvInput(); + * + * By default, the `$_SERVER['argv']` array is used for the input values. + * + * This can be overriden by explicitly passing the input values in the constructor: + * + * $input = new ArgvInput($_SERVER['argv']); + * + * If you pass it yourself, don't forget that the first element of the array + * is the name of the running program. + * + * When passing an argument to the constructor, be sure that it respects + * the same rules as the argv one. It's almost always better to use the + * `StringInput` when you want to provide your own input. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + * + * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 + */ +class ArgvInput extends Input +{ + protected $tokens; + protected $parsed; + + /** + * Constructor. + * + * @param array $argv An array of parameters from the CLI (in the argv format) + * @param InputDefinition $definition A InputDefinition instance + */ + public function __construct(array $argv = null, InputDefinition $definition = null) + { + if (null === $argv) + { + $argv = $_SERVER['argv']; + } + + // strip the program name + array_shift($argv); + + $this->tokens = $argv; + + parent::__construct($definition); + } + + /** + * Processes command line arguments. + */ + protected function parse() + { + $this->parsed = $this->tokens; + while ($token = array_shift($this->parsed)) + { + if ('--' === substr($token, 0, 2)) + { + $this->parseLongOption($token); + } + elseif ('-' === $token[0]) + { + $this->parseShortOption($token); + } + else + { + $this->parseArgument($token); + } + } + } + + /** + * Parses a short option. + * + * @param string $token The current token. + */ + protected function parseShortOption($token) + { + $name = substr($token, 1); + + if (strlen($name) > 1) + { + if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptParameter()) + { + // an option with a value (with no space) + $this->addShortOption($name[0], substr($name, 1)); + } + else + { + $this->parseShortOptionSet($name); + } + } + else + { + $this->addShortOption($name, null); + } + } + + /** + * Parses a short option set. + * + * @param string $token The current token + */ + protected function parseShortOptionSet($name) + { + $len = strlen($name); + for ($i = 0; $i < $len; $i++) + { + if (!$this->definition->hasShortcut($name[$i])) + { + throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i])); + } + + $option = $this->definition->getOptionForShortcut($name[$i]); + if ($option->acceptParameter()) + { + $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1)); + + break; + } + else + { + $this->addLongOption($option->getName(), true); + } + } + } + + /** + * Parses a long option. + * + * @param string $token The current token + */ + protected function parseLongOption($token) + { + $name = substr($token, 2); + + if (false !== $pos = strpos($name, '=')) + { + $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1)); + } + else + { + $this->addLongOption($name, null); + } + } + + /** + * Parses an argument. + * + * @param string $token The current token + */ + protected function parseArgument($token) + { + if (!$this->definition->hasArgument(count($this->arguments))) + { + throw new \RuntimeException('Too many arguments.'); + } + + $this->arguments[$this->definition->getArgument(count($this->arguments))->getName()] = $token; + } + + /** + * Adds a short option value. + * + * @param string $shortcut The short option key + * @param mixed $value The value for the option + */ + protected function addShortOption($shortcut, $value) + { + if (!$this->definition->hasShortcut($shortcut)) + { + throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @param string $name The long option key + * @param mixed $value The value for the option + */ + protected function addLongOption($name, $value) + { + if (!$this->definition->hasOption($name)) + { + throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + } + + $option = $this->definition->getOption($name); + + if (null === $value && $option->acceptParameter()) + { + // if option accepts an optional or mandatory argument + // let's see if there is one provided + $next = array_shift($this->parsed); + if ('-' !== $next[0]) + { + $value = $next; + } + else + { + array_unshift($this->parsed, $next); + } + } + + if (null === $value) + { + if ($option->isParameterRequired()) + { + throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + } + + $value = $option->isParameterOptional() ? $option->getDefault() : true; + } + + $this->options[$name] = $value; + } + + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument() + { + foreach ($this->tokens as $token) + { + if ($token && '-' === $token[0]) + { + continue; + } + + return $token; + } + } + + /** + * Returns true if the raw parameters (not parsed) contains a value. + * + * This method is to be used to introspect the input parameters + * before it has been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * + * @return Boolean true if the value is contained in the raw parameters + */ + public function hasParameterOption($values) + { + if (!is_array($values)) + { + $values = array($values); + } + + foreach ($this->tokens as $v) + { + if (in_array($v, $values)) + { + return true; + } + } + + return false; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Input/ArrayInput.php b/lib/vendor/Symfony/Components/Console/Input/ArrayInput.php new file mode 100644 index 000000000..3ae6154d3 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/ArrayInput.php @@ -0,0 +1,174 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * ArrayInput represents an input provided as an array. + * + * Usage: + * + * $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar')); + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class ArrayInput extends Input +{ + protected $parameters; + + /** + * Constructor. + * + * @param array $param An array of parameters + * @param InputDefinition $definition A InputDefinition instance + */ + public function __construct(array $parameters, InputDefinition $definition = null) + { + $this->parameters = $parameters; + + parent::__construct($definition); + } + + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument() + { + foreach ($this->parameters as $key => $value) + { + if ($key && '-' === $key[0]) + { + continue; + } + + return $value; + } + } + + /** + * Returns true if the raw parameters (not parsed) contains a value. + * + * This method is to be used to introspect the input parameters + * before it has been validated. It must be used carefully. + * + * @param string|array $value The values to look for in the raw parameters (can be an array) + * + * @return Boolean true if the value is contained in the raw parameters + */ + public function hasParameterOption($values) + { + if (!is_array($values)) + { + $values = array($values); + } + + foreach ($this->parameters as $k => $v) + { + if (!is_int($k)) + { + $v = $k; + } + + if (in_array($v, $values)) + { + return true; + } + } + + return false; + } + + /** + * Processes command line arguments. + */ + protected function parse() + { + foreach ($this->parameters as $key => $value) + { + if ('--' === substr($key, 0, 2)) + { + $this->addLongOption(substr($key, 2), $value); + } + elseif ('-' === $key[0]) + { + $this->addShortOption(substr($key, 1), $value); + } + else + { + $this->addArgument($key, $value); + } + } + } + + /** + * Adds a short option value. + * + * @param string $shortcut The short option key + * @param mixed $value The value for the option + */ + protected function addShortOption($shortcut, $value) + { + if (!$this->definition->hasShortcut($shortcut)) + { + throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @param string $name The long option key + * @param mixed $value The value for the option + */ + protected function addLongOption($name, $value) + { + if (!$this->definition->hasOption($name)) + { + throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + } + + $option = $this->definition->getOption($name); + + if (null === $value) + { + if ($option->isParameterRequired()) + { + throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + } + + $value = $option->isParameterOptional() ? $option->getDefault() : true; + } + + $this->options[$name] = $value; + } + + /** + * Adds an argument value. + * + * @param string $name The argument name + * @param mixed $value The value for the argument + */ + protected function addArgument($name, $value) + { + if (!$this->definition->hasArgument($name)) + { + throw new \RuntimeException(sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Input/Input.php b/lib/vendor/Symfony/Components/Console/Input/Input.php new file mode 100644 index 000000000..9e9e5f482 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/Input.php @@ -0,0 +1,198 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Input is the base class for all concrete Input classes. + * + * Three concrete classes are provided by default: + * + * * `ArgvInput`: The input comes from the CLI arguments (argv) + * * `StringInput`: The input is provided as a string + * * `ArrayInput`: The input is provided as an array + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +abstract class Input implements InputInterface +{ + protected $definition; + protected $options; + protected $arguments; + protected $interactive = true; + + /** + * Constructor. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function __construct(InputDefinition $definition = null) + { + if (null === $definition) + { + $this->definition = new InputDefinition(); + } + else + { + $this->bind($definition); + $this->validate(); + } + } + + /** + * Binds the current Input instance with the given arguments and options. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function bind(InputDefinition $definition) + { + $this->arguments = array(); + $this->options = array(); + $this->definition = $definition; + + $this->parse(); + } + + /** + * Processes command line arguments. + */ + abstract protected function parse(); + + public function validate() + { + if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) + { + throw new \RuntimeException('Not enough arguments.'); + } + } + + public function isInteractive() + { + return $this->interactive; + } + + public function setInteractive($interactive) + { + $this->interactive = (Boolean) $interactive; + } + + /** + * Returns the argument values. + * + * @return array An array of argument values + */ + public function getArguments() + { + return array_merge($this->definition->getArgumentDefaults(), $this->arguments); + } + + /** + * Returns the argument value for a given argument name. + * + * @param string $name The argument name + * + * @return mixed The argument value + */ + public function getArgument($name) + { + if (!$this->definition->hasArgument($name)) + { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault(); + } + + /** + * Sets an argument value by name. + * + * @param string $name The argument name + * @param string $value The argument value + */ + public function setArgument($name, $value) + { + if (!$this->definition->hasArgument($name)) + { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|integer $name The InputArgument name or position + * + * @return Boolean true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name) + { + return $this->definition->hasArgument($name); + } + + /** + * Returns the options values. + * + * @return array An array of option values + */ + public function getOptions() + { + return array_merge($this->definition->getOptionDefaults(), $this->options); + } + + /** + * Returns the option value for a given option name. + * + * @param string $name The option name + * + * @return mixed The option value + */ + public function getOption($name) + { + if (!$this->definition->hasOption($name)) + { + throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + } + + /** + * Sets an option value by name. + * + * @param string $name The option name + * @param string $value The option value + */ + public function setOption($name, $value) + { + if (!$this->definition->hasOption($name)) + { + throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + $this->options[$name] = $value; + } + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return Boolean true if the InputOption object exists, false otherwise + */ + public function hasOption($name) + { + return $this->definition->hasOption($name); + } +} diff --git a/lib/vendor/Symfony/Components/Console/Input/InputArgument.php b/lib/vendor/Symfony/Components/Console/Input/InputArgument.php new file mode 100644 index 000000000..9b5925b4b --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/InputArgument.php @@ -0,0 +1,134 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Represents a command line argument. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class InputArgument +{ + const REQUIRED = 1; + const OPTIONAL = 2; + const IS_ARRAY = 4; + + protected $name; + protected $mode; + protected $default; + protected $description; + + /** + * Constructor. + * + * @param string $name The argument name + * @param integer $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (for self::OPTIONAL mode only) + */ + public function __construct($name, $mode = null, $description = '', $default = null) + { + if (null === $mode) + { + $mode = self::OPTIONAL; + } + else if (is_string($mode) || $mode > 7) + { + throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->mode = $mode; + $this->description = $description; + + $this->setDefault($default); + } + + /** + * Returns the argument name. + * + * @return string The argument name + */ + public function getName() + { + return $this->name; + } + + /** + * Returns true if the argument is required. + * + * @return Boolean true if parameter mode is self::REQUIRED, false otherwise + */ + public function isRequired() + { + return self::REQUIRED === (self::REQUIRED & $this->mode); + } + + /** + * Returns true if the argument can take multiple values. + * + * @return Boolean true if mode is self::IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); + } + + /** + * Sets the default value. + * + * @param mixed $default The default value + */ + public function setDefault($default = null) + { + if (self::REQUIRED === $this->mode && null !== $default) + { + throw new \LogicException('Cannot set a default value except for Parameter::OPTIONAL mode.'); + } + + if ($this->isArray()) + { + if (null === $default) + { + $default = array(); + } + else if (!is_array($default)) + { + throw new \LogicException('A default value for an array argument must be an array.'); + } + } + + $this->default = $default; + } + + /** + * Returns the default value. + * + * @return mixed The default value + */ + public function getDefault() + { + return $this->default; + } + + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Input/InputDefinition.php b/lib/vendor/Symfony/Components/Console/Input/InputDefinition.php new file mode 100644 index 000000000..2977e7fd6 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/InputDefinition.php @@ -0,0 +1,507 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * A InputDefinition represents a set of valid command line arguments and options. + * + * Usage: + * + * $definition = new InputDefinition(array( + * new InputArgument('name', InputArgument::REQUIRED), + * new InputOption('foo', 'f', InputOption::PARAMETER_REQUIRED), + * )); + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class InputDefinition +{ + protected $arguments; + protected $requiredCount; + protected $hasAnArrayArgument = false; + protected $hasOptional; + protected $options; + protected $shortcuts; + + /** + * Constructor. + * + * @param array $definition An array of InputArgument and InputOption instance + */ + public function __construct(array $definition = array()) + { + $this->setDefinition($definition); + } + + public function setDefinition(array $definition) + { + $arguments = array(); + $options = array(); + foreach ($definition as $item) + { + if ($item instanceof InputOption) + { + $options[] = $item; + } + else + { + $arguments[] = $item; + } + } + + $this->setArguments($arguments); + $this->setOptions($options); + } + + /** + * Sets the InputArgument objects. + * + * @param array $arguments An array of InputArgument objects + */ + public function setArguments($arguments = array()) + { + $this->arguments = array(); + $this->requiredCount = 0; + $this->hasOptional = false; + $this->addArguments($arguments); + } + + /** + * Add an array of InputArgument objects. + * + * @param array $arguments An array of InputArgument objects + */ + public function addArguments($arguments = array()) + { + if (null !== $arguments) + { + foreach ($arguments as $argument) + { + $this->addArgument($argument); + } + } + } + + /** + * Add an InputArgument object. + * + * @param InputArgument $argument An InputArgument object + */ + public function addArgument(InputArgument $argument) + { + if (isset($this->arguments[$argument->getName()])) + { + throw new \LogicException(sprintf('An argument with name "%s" already exist.', $argument->getName())); + } + + if ($this->hasAnArrayArgument) + { + throw new \LogicException('Cannot add an argument after an array argument.'); + } + + if ($argument->isRequired() && $this->hasOptional) + { + throw new \LogicException('Cannot add a required argument after an optional one.'); + } + + if ($argument->isArray()) + { + $this->hasAnArrayArgument = true; + } + + if ($argument->isRequired()) + { + ++$this->requiredCount; + } + else + { + $this->hasOptional = true; + } + + $this->arguments[$argument->getName()] = $argument; + } + + /** + * Returns an InputArgument by name or by position. + * + * @param string|integer $name The InputArgument name or position + * + * @return InputArgument An InputArgument object + */ + public function getArgument($name) + { + $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; + + if (!$this->hasArgument($name)) + { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + return $arguments[$name]; + } + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|integer $name The InputArgument name or position + * + * @return Boolean true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name) + { + $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; + + return isset($arguments[$name]); + } + + /** + * Gets the array of InputArgument objects. + * + * @return array An array of InputArgument objects + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Returns the number of InputArguments. + * + * @return integer The number of InputArguments + */ + public function getArgumentCount() + { + return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments); + } + + /** + * Returns the number of required InputArguments. + * + * @return integer The number of required InputArguments + */ + public function getArgumentRequiredCount() + { + return $this->requiredCount; + } + + /** + * Gets the default values. + * + * @return array An array of default values + */ + public function getArgumentDefaults() + { + $values = array(); + foreach ($this->arguments as $argument) + { + $values[$argument->getName()] = $argument->getDefault(); + } + + return $values; + } + + /** + * Sets the InputOption objects. + * + * @param array $options An array of InputOption objects + */ + public function setOptions($options = array()) + { + $this->options = array(); + $this->shortcuts = array(); + $this->addOptions($options); + } + + /** + * Add an array of InputOption objects. + * + * @param array $options An array of InputOption objects + */ + public function addOptions($options = array()) + { + foreach ($options as $option) + { + $this->addOption($option); + } + } + + /** + * Add an InputOption object. + * + * @param InputOption $option An InputOption object + */ + public function addOption(InputOption $option) + { + if (isset($this->options[$option->getName()])) + { + throw new \LogicException(sprintf('An option named "%s" already exist.', $option->getName())); + } + else if (isset($this->shortcuts[$option->getShortcut()])) + { + throw new \LogicException(sprintf('An option with shortcut "%s" already exist.', $option->getShortcut())); + } + + $this->options[$option->getName()] = $option; + if ($option->getShortcut()) + { + $this->shortcuts[$option->getShortcut()] = $option->getName(); + } + } + + /** + * Returns an InputOption by name. + * + * @param string $name The InputOption name + * + * @return InputOption A InputOption object + */ + public function getOption($name) + { + if (!$this->hasOption($name)) + { + throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + } + + return $this->options[$name]; + } + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return Boolean true if the InputOption object exists, false otherwise + */ + public function hasOption($name) + { + return isset($this->options[$name]); + } + + /** + * Gets the array of InputOption objects. + * + * @return array An array of InputOption objects + */ + public function getOptions() + { + return $this->options; + } + + /** + * Returns true if an InputOption object exists by shortcut. + * + * @param string $name The InputOption shortcut + * + * @return Boolean true if the InputOption object exists, false otherwise + */ + public function hasShortcut($name) + { + return isset($this->shortcuts[$name]); + } + + /** + * Gets an InputOption by shortcut. + * + * @return InputOption An InputOption object + */ + public function getOptionForShortcut($shortcut) + { + return $this->getOption($this->shortcutToName($shortcut)); + } + + /** + * Gets an array of default values. + * + * @return array An array of all default values + */ + public function getOptionDefaults() + { + $values = array(); + foreach ($this->options as $option) + { + $values[$option->getName()] = $option->getDefault(); + } + + return $values; + } + + /** + * Returns the InputOption name given a shortcut. + * + * @param string $shortcut The shortcut + * + * @return string The InputOption name + */ + protected function shortcutToName($shortcut) + { + if (!isset($this->shortcuts[$shortcut])) + { + throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + return $this->shortcuts[$shortcut]; + } + + /** + * Gets the synopsis. + * + * @return string The synopsis + */ + public function getSynopsis() + { + $elements = array(); + foreach ($this->getOptions() as $option) + { + $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; + $elements[] = sprintf('['.($option->isParameterRequired() ? '%s--%s="..."' : ($option->isParameterOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName()); + } + + foreach ($this->getArguments() as $argument) + { + $elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : '')); + + if ($argument->isArray()) + { + $elements[] = sprintf('... [%sN]', $argument->getName()); + } + } + + return implode(' ', $elements); + } + + /** + * Returns a textual representation of the InputDefinition. + * + * @return string A string representing the InputDefinition + */ + public function asText() + { + // find the largest option or argument name + $max = 0; + foreach ($this->getOptions() as $option) + { + $max = strlen($option->getName()) + 2 > $max ? strlen($option->getName()) + 2 : $max; + } + foreach ($this->getArguments() as $argument) + { + $max = strlen($argument->getName()) > $max ? strlen($argument->getName()) : $max; + } + ++$max; + + $text = array(); + + if ($this->getArguments()) + { + $text[] = 'Arguments:'; + foreach ($this->getArguments() as $argument) + { + if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) + { + $default = sprintf(' (default: %s)', is_array($argument->getDefault()) ? str_replace("\n", '', var_export($argument->getDefault(), true)): $argument->getDefault()); + } + else + { + $default = ''; + } + + $text[] = sprintf(" %-${max}s %s%s", $argument->getName(), $argument->getDescription(), $default); + } + + $text[] = ''; + } + + if ($this->getOptions()) + { + $text[] = 'Options:'; + + foreach ($this->getOptions() as $option) + { + if ($option->acceptParameter() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) + { + $default = sprintf(' (default: %s)', is_array($option->getDefault()) ? str_replace("\n", '', print_r($option->getDefault(), true)): $option->getDefault()); + } + else + { + $default = ''; + } + + $multiple = $option->isArray() ? ' (multiple values allowed)' : ''; + $text[] = sprintf(' %-'.$max.'s %s%s%s%s', '--'.$option->getName().'', $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '', $option->getDescription(), $default, $multiple); + } + + $text[] = ''; + } + + return implode("\n", $text); + } + + /** + * Returns an XML representation of the InputDefinition. + * + * @param Boolean $asDom Whether to return a DOM or an XML string + * + * @return string|DOMDocument An XML string representing the InputDefinition + */ + public function asXml($asDom = false) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $dom->appendChild($definitionXML = $dom->createElement('definition')); + + $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); + foreach ($this->getArguments() as $argument) + { + $argumentsXML->appendChild($argumentXML = $dom->createElement('argument')); + $argumentXML->setAttribute('name', $argument->getName()); + $argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); + $argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); + $argumentXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); + + $argumentXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = is_array($argument->getDefault()) ? $argument->getDefault() : ($argument->getDefault() ? array($argument->getDefault()) : array()); + foreach ($defaults as $default) + { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + + $definitionXML->appendChild($optionsXML = $dom->createElement('options')); + foreach ($this->getOptions() as $option) + { + $optionsXML->appendChild($optionXML = $dom->createElement('option')); + $optionXML->setAttribute('name', '--'.$option->getName()); + $optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : ''); + $optionXML->setAttribute('accept_parameter', $option->acceptParameter() ? 1 : 0); + $optionXML->setAttribute('is_parameter_required', $option->isParameterRequired() ? 1 : 0); + $optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); + $optionXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); + + if ($option->acceptParameter()) + { + $optionXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = is_array($option->getDefault()) ? $option->getDefault() : ($option->getDefault() ? array($option->getDefault()) : array()); + foreach ($defaults as $default) + { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + } + + return $asDom ? $dom : $dom->saveXml(); + } +} diff --git a/lib/vendor/Symfony/Components/Console/Input/InputInterface.php b/lib/vendor/Symfony/Components/Console/Input/InputInterface.php new file mode 100644 index 000000000..953553e78 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/InputInterface.php @@ -0,0 +1,58 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * InputInterface is the interface implemented by all input classes. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +interface InputInterface +{ + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + function getFirstArgument(); + + /** + * Returns true if the raw parameters (not parsed) contains a value. + * + * This method is to be used to introspect the input parameters + * before it has been validated. It must be used carefully. + * + * @param string $value The value to look for in the raw parameters + * + * @return Boolean true if the value is contained in the raw parameters + */ + function hasParameterOption($value); + + /** + * Binds the current Input instance with the given arguments and options. + * + * @param InputDefinition $definition A InputDefinition instance + */ + function bind(InputDefinition $definition); + + function validate(); + + function getArguments(); + + function getArgument($name); + + function getOptions(); + + function getOption($name); +} diff --git a/lib/vendor/Symfony/Components/Console/Input/InputOption.php b/lib/vendor/Symfony/Components/Console/Input/InputOption.php new file mode 100644 index 000000000..46a47d0d5 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/InputOption.php @@ -0,0 +1,191 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Represents a command line option. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class InputOption +{ + const PARAMETER_NONE = 1; + const PARAMETER_REQUIRED = 2; + const PARAMETER_OPTIONAL = 4; + const PARAMETER_IS_ARRAY = 8; + + protected $name; + protected $shortcut; + protected $mode; + protected $default; + protected $description; + + /** + * Constructor. + * + * @param string $name The option name + * @param string $shortcut The shortcut (can be null) + * @param integer $mode The option mode: self::PARAMETER_REQUIRED, self::PARAMETER_NONE or self::PARAMETER_OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (must be null for self::PARAMETER_REQUIRED or self::PARAMETER_NONE) + */ + public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + if ('--' === substr($name, 0, 2)) + { + $name = substr($name, 2); + } + + if (empty($shortcut)) + { + $shortcut = null; + } + + if (null !== $shortcut) + { + if ('-' === $shortcut[0]) + { + $shortcut = substr($shortcut, 1); + } + } + + if (null === $mode) + { + $mode = self::PARAMETER_NONE; + } + else if (!is_int($mode) || $mode > 15) + { + throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->shortcut = $shortcut; + $this->mode = $mode; + $this->description = $description; + + if ($this->isArray() && !$this->acceptParameter()) + { + throw new \InvalidArgumentException('Impossible to have an option mode PARAMETER_IS_ARRAY if the option does not accept a parameter.'); + } + + $this->setDefault($default); + } + + /** + * Returns the shortcut. + * + * @return string The shortcut + */ + public function getShortcut() + { + return $this->shortcut; + } + + /** + * Returns the name. + * + * @return string The name + */ + public function getName() + { + return $this->name; + } + + /** + * Returns true if the option accept a parameter. + * + * @return Boolean true if parameter mode is not self::PARAMETER_NONE, false otherwise + */ + public function acceptParameter() + { + return $this->isParameterRequired() || $this->isParameterOptional(); + } + + /** + * Returns true if the option requires a parameter. + * + * @return Boolean true if parameter mode is self::PARAMETER_REQUIRED, false otherwise + */ + public function isParameterRequired() + { + return self::PARAMETER_REQUIRED === (self::PARAMETER_REQUIRED & $this->mode); + } + + /** + * Returns true if the option takes an optional parameter. + * + * @return Boolean true if parameter mode is self::PARAMETER_OPTIONAL, false otherwise + */ + public function isParameterOptional() + { + return self::PARAMETER_OPTIONAL === (self::PARAMETER_OPTIONAL & $this->mode); + } + + /** + * Returns true if the option can take multiple values. + * + * @return Boolean true if mode is self::PARAMETER_IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::PARAMETER_IS_ARRAY === (self::PARAMETER_IS_ARRAY & $this->mode); + } + + /** + * Sets the default value. + * + * @param mixed $default The default value + */ + public function setDefault($default = null) + { + if (self::PARAMETER_NONE === (self::PARAMETER_NONE & $this->mode) && null !== $default) + { + throw new \LogicException('Cannot set a default value when using Option::PARAMETER_NONE mode.'); + } + + if ($this->isArray()) + { + if (null === $default) + { + $default = array(); + } + elseif (!is_array($default)) + { + throw new \LogicException('A default value for an array option must be an array.'); + } + } + + $this->default = $this->acceptParameter() ? $default : false; + } + + /** + * Returns the default value. + * + * @return mixed The default value + */ + public function getDefault() + { + return $this->default; + } + + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Input/StringInput.php b/lib/vendor/Symfony/Components/Console/Input/StringInput.php new file mode 100644 index 000000000..c66f7b9dc --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Input/StringInput.php @@ -0,0 +1,80 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * StringInput represents an input provided as a string. + * + * Usage: + * + * $input = new StringInput('foo --bar="foobar"'); + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class StringInput extends ArgvInput +{ + const REGEX_STRING = '([^ ]+?)(?: |(?tokens = $this->tokenize($input); + } + + protected function tokenize($input) + { + $input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input); + + $tokens = array(); + $length = strlen($input); + $cursor = 0; + while ($cursor < $length) + { + if (preg_match('/\s+/A', $input, $match, null, $cursor)) + { + } + elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) + { + $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2))); + } + elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) + { + $tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2)); + } + elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) + { + $tokens[] = stripcslashes($match[1]); + } + else + { + // should never happen + // @codeCoverageIgnoreStart + throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10))); + // @codeCoverageIgnoreEnd + } + + $cursor += strlen($match[0]); + } + + return $tokens; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Output/ConsoleOutput.php b/lib/vendor/Symfony/Components/Console/Output/ConsoleOutput.php new file mode 100644 index 000000000..7950c25ec --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Output/ConsoleOutput.php @@ -0,0 +1,41 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * ConsoleOutput is the default class for all CLI output. It uses STDOUT. + * + * This class is a convenient wrapper around `StreamOutput`. + * + * $output = new ConsoleOutput(); + * + * This is equivalent to: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class ConsoleOutput extends StreamOutput +{ + /** + * Constructor. + * + * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE) + * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing) + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null) + { + parent::__construct(fopen('php://stdout', 'w'), $verbosity, $decorated); + } +} diff --git a/lib/vendor/Symfony/Components/Console/Output/NullOutput.php b/lib/vendor/Symfony/Components/Console/Output/NullOutput.php new file mode 100644 index 000000000..86e2c326f --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Output/NullOutput.php @@ -0,0 +1,34 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * NullOutput suppresses all output. + * + * $output = new NullOutput(); + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class NullOutput extends Output +{ + /** + * Writes a message to the output. + * + * @param string $message A message to write to the output + * @param Boolean $newline Whether to add a newline or not + */ + public function doWrite($message, $newline) + { + } +} diff --git a/lib/vendor/Symfony/Components/Console/Output/Output.php b/lib/vendor/Symfony/Components/Console/Output/Output.php new file mode 100644 index 000000000..7bfa8bf01 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Output/Output.php @@ -0,0 +1,230 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Base class for output classes. + * + * There is three level of verbosity: + * + * * normal: no option passed (normal output - information) + * * verbose: -v (more output - debug) + * * quiet: -q (no output) + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +abstract class Output implements OutputInterface +{ + const VERBOSITY_QUIET = 0; + const VERBOSITY_NORMAL = 1; + const VERBOSITY_VERBOSE = 2; + + const OUTPUT_NORMAL = 0; + const OUTPUT_RAW = 1; + const OUTPUT_PLAIN = 2; + + protected $verbosity; + protected $decorated; + + static protected $styles = array( + 'error' => array('bg' => 'red', 'fg' => 'white'), + 'info' => array('fg' => 'green'), + 'comment' => array('fg' => 'yellow'), + 'question' => array('bg' => 'cyan', 'fg' => 'black'), + ); + static protected $options = array('bold' => 1, 'underscore' => 4, 'blink' => 5, 'reverse' => 7, 'conceal' => 8); + static protected $foreground = array('black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'white' => 37); + static protected $background = array('black' => 40, 'red' => 41, 'green' => 42, 'yellow' => 43, 'blue' => 44, 'magenta' => 45, 'cyan' => 46, 'white' => 47); + + /** + * Constructor. + * + * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE) + * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing) + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null) + { + $this->decorated = (Boolean) $decorated; + $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity; + } + + /** + * Sets a new style. + * + * @param string $name The style name + * @param array $options An array of options + */ + static public function setStyle($name, $options = array()) + { + static::$styles[strtolower($name)] = $options; + } + + /** + * Sets the decorated flag. + * + * @param Boolean $decorated Whether to decorated the messages or not + */ + public function setDecorated($decorated) + { + $this->decorated = (Boolean) $decorated; + } + + /** + * Gets the decorated flag. + * + * @return Boolean true if the output will decorate messages, false otherwise + */ + public function isDecorated() + { + return $this->decorated; + } + + /** + * Sets the verbosity of the output. + * + * @param integer $level The level of verbosity + */ + public function setVerbosity($level) + { + $this->verbosity = (int) $level; + } + + /** + * Gets the current verbosity of the output. + * + * @return integer The current level of verbosity + */ + public function getVerbosity() + { + return $this->verbosity; + } + + /** + * Writes a message to the output and adds a newline at the end. + * + * @param string|array $messages The message as an array of lines of a single string + * @param integer $type The type of output + */ + public function writeln($messages, $type = 0) + { + $this->write($messages, true, $type); + } + + /** + * Writes a message to the output. + * + * @param string|array $messages The message as an array of lines of a single string + * @param Boolean $newline Whether to add a newline or not + * @param integer $type The type of output + */ + public function write($messages, $newline = false, $type = 0) + { + if (self::VERBOSITY_QUIET === $this->verbosity) + { + return; + } + + if (!is_array($messages)) + { + $messages = array($messages); + } + + foreach ($messages as $message) + { + switch ($type) + { + case Output::OUTPUT_NORMAL: + $message = $this->format($message); + break; + case Output::OUTPUT_RAW: + break; + case Output::OUTPUT_PLAIN: + $message = strip_tags($this->format($message)); + break; + default: + throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type)); + } + + $this->doWrite($message, $newline); + } + } + + /** + * Writes a message to the output. + * + * @param string $message A message to write to the output + * @param Boolean $newline Whether to add a newline or not + */ + abstract public function doWrite($message, $newline); + + /** + * Formats a message according to the given styles. + * + * @param string $message The message to style + * + * @return string The styled message + */ + protected function format($message) + { + $message = preg_replace_callback('#<([a-z][a-z0-9\-_]+)>#i', array($this, 'replaceStartStyle'), $message); + + return preg_replace_callback('##i', array($this, 'replaceEndStyle'), $message); + } + + protected function replaceStartStyle($match) + { + if (!$this->decorated) + { + return ''; + } + + if (!isset(static::$styles[strtolower($match[1])])) + { + throw new \InvalidArgumentException(sprintf('Unknown style "%s".', $match[1])); + } + + $parameters = static::$styles[strtolower($match[1])]; + $codes = array(); + + if (isset($parameters['fg'])) + { + $codes[] = static::$foreground[$parameters['fg']]; + } + + if (isset($parameters['bg'])) + { + $codes[] = static::$background[$parameters['bg']]; + } + + foreach (static::$options as $option => $value) + { + if (isset($parameters[$option]) && $parameters[$option]) + { + $codes[] = $value; + } + } + + return "\033[".implode(';', $codes)."m"; + } + + protected function replaceEndStyle($match) + { + if (!$this->decorated) + { + return ''; + } + + return "\033[0m"; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Output/OutputInterface.php b/lib/vendor/Symfony/Components/Console/Output/OutputInterface.php new file mode 100644 index 000000000..26bc6b76e --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Output/OutputInterface.php @@ -0,0 +1,44 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * OutputInterface is the interface implemented by all Output classes. + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +interface OutputInterface +{ + /** + * Writes a message to the output. + * + * @param string|array $messages The message as an array of lines of a single string + * @param integer $type The type of output + */ + public function write($messages, $type = 0); + + /** + * Sets the verbosity of the output. + * + * @param integer $level The level of verbosity + */ + public function setVerbosity($level); + + /** + * Sets the decorated flag. + * + * @param Boolean $decorated Whether to decorated the messages or not + */ + public function setDecorated($decorated); +} diff --git a/lib/vendor/Symfony/Components/Console/Output/StreamOutput.php b/lib/vendor/Symfony/Components/Console/Output/StreamOutput.php new file mode 100644 index 000000000..fdb74debe --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Output/StreamOutput.php @@ -0,0 +1,109 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * StreamOutput writes the output to a given stream. + * + * Usage: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * As `StreamOutput` can use any stream, you can also use a file: + * + * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); + * + * @package symfony + * @subpackage console + * @author Fabien Potencier + */ +class StreamOutput extends Output +{ + protected $stream; + + /** + * Constructor. + * + * @param mixed $stream A stream resource + * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE) + * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing) + */ + public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null) + { + if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) + { + throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); + } + + $this->stream = $stream; + + if (null === $decorated) + { + $decorated = $this->hasColorSupport($decorated); + } + + parent::__construct($verbosity, $decorated); + } + + /** + * Gets the stream attached to this StreamOutput instance. + * + * @return resource A stream resource + */ + public function getStream() + { + return $this->stream; + } + + /** + * Writes a message to the output. + * + * @param string $message A message to write to the output + * @param Boolean $newline Whether to add a newline or not + */ + public function doWrite($message, $newline) + { + if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) + { + // @codeCoverageIgnoreStart + // should never happen + throw new \RuntimeException('Unable to write output.'); + // @codeCoverageIgnoreEnd + } + + flush(); + } + + /** + * Returns true if the stream supports colorization. + * + * Colorization is disabled if not supported by the stream: + * + * - windows without ansicon + * - non tty consoles + * + * @return Boolean true if the stream supports colorization, false otherwise + */ + protected function hasColorSupport() + { + // @codeCoverageIgnoreStart + if (DIRECTORY_SEPARATOR == '\\') + { + return false !== getenv('ANSICON'); + } + else + { + return function_exists('posix_isatty') && @posix_isatty($this->stream); + } + // @codeCoverageIgnoreEnd + } +} diff --git a/lib/vendor/Symfony/Components/Console/Shell.php b/lib/vendor/Symfony/Components/Console/Shell.php new file mode 100644 index 000000000..f91965c0b --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Shell.php @@ -0,0 +1,146 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * A Shell wraps an Application to add shell capabilities to it. + * + * This class only works with a PHP compiled with readline support + * (either --with-readline or --with-libedit) + * + * @package symfony + * @subpackage cli + * @author Fabien Potencier + */ +class Shell +{ + protected $application; + protected $history; + protected $output; + + /** + * Constructor. + * + * If there is no readline support for the current PHP executable + * a \RuntimeException exception is thrown. + * + * @param Application $application An application instance + */ + public function __construct(Application $application) + { + if (!function_exists('readline')) + { + throw new \RuntimeException('Unable to start the shell as the Readline extension is not enabled.'); + } + + $this->application = $application; + $this->history = getenv('HOME').'/.history_'.$application->getName(); + $this->output = new ConsoleOutput(); + } + + /** + * Runs the shell. + */ + public function run() + { + $this->application->setAutoExit(false); + $this->application->setCatchExceptions(true); + + readline_read_history($this->history); + readline_completion_function(array($this, 'autocompleter')); + + $this->output->writeln($this->getHeader()); + while (true) + { + $command = readline($this->application->getName().' > '); + + if (false === $command) + { + $this->output->writeln("\n"); + + break; + } + + readline_add_history($command); + readline_write_history($this->history); + + if (0 !== $ret = $this->application->run(new StringInput($command), $this->output)) + { + $this->output->writeln(sprintf('The command terminated with an error status (%s)', $ret)); + } + } + } + + /** + * Tries to return autocompletion for the current entered text. + * + * @param string $text The last segment of the entered text + * @param integer $position The current position + */ + protected function autocompleter($text, $position) + { + $info = readline_info(); + $text = substr($info['line_buffer'], 0, $info['end']); + + if ($info['point'] !== $info['end']) + { + return true; + } + + // task name? + if (false === strpos($text, ' ') || !$text) + { + return array_keys($this->application->getCommands()); + } + + // options and arguments? + try + { + $command = $this->application->findCommand(substr($text, 0, strpos($text, ' '))); + } + catch (\Exception $e) + { + return true; + } + + $list = array('--help'); + foreach ($command->getDefinition()->getOptions() as $option) + { + $list[] = '--'.$option->getName(); + } + + return $list; + } + + /** + * Returns the shell header. + * + * @return string The header string + */ + protected function getHeader() + { + return <<{$this->application->getName()} shell ({$this->application->getVersion()}). + +At the prompt, type help for some help, +or list to get a list available commands. + +To exit the shell, type ^D. + +EOF; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Tester/ApplicationTester.php b/lib/vendor/Symfony/Components/Console/Tester/ApplicationTester.php new file mode 100644 index 000000000..aa31f71cb --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Tester/ApplicationTester.php @@ -0,0 +1,92 @@ +application = $application; + } + + /** + * Executes the application. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * + * @param array $input An array of arguments and options + * @param array $options An array of options + */ + public function run(array $input, $options = array()) + { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) + { + $this->input->setInteractive($options['interactive']); + } + + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) + { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) + { + $this->output->setVerbosity($options['verbosity']); + } + + $ret = $this->application->run($this->input, $this->output); + + rewind($this->output->getStream()); + + return $this->display = stream_get_contents($this->output->getStream()); + } + + /** + * Gets the display returned by the last execution of the application. + * + * @return string The display + */ + public function getDisplay() + { + return $this->display; + } + + /** + * Gets the input instance used by the last execution of the application. + * + * @return InputInterface The current input instance + */ + public function getInput() + { + return $this->input; + } + + /** + * Gets the output instance used by the last execution of the application. + * + * @return OutputInterface The current output instance + */ + public function getOutput() + { + return $this->output; + } +} diff --git a/lib/vendor/Symfony/Components/Console/Tester/CommandTester.php b/lib/vendor/Symfony/Components/Console/Tester/CommandTester.php new file mode 100644 index 000000000..bc0ee8879 --- /dev/null +++ b/lib/vendor/Symfony/Components/Console/Tester/CommandTester.php @@ -0,0 +1,92 @@ +command = $command; + } + + /** + * Executes the command. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * + * @param array $input An array of arguments and options + * @param array $options An array of options + */ + public function execute(array $input, array $options = array()) + { + $this->input = new ArrayInput(array_merge($input, array('command' => $this->command->getFullName()))); + if (isset($options['interactive'])) + { + $this->input->setInteractive($options['interactive']); + } + + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) + { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) + { + $this->output->setVerbosity($options['verbosity']); + } + + $ret = $this->command->run($this->input, $this->output); + + rewind($this->output->getStream()); + + return $this->display = stream_get_contents($this->output->getStream()); + } + + /** + * Gets the display returned by the last execution of the command. + * + * @return string The display + */ + public function getDisplay() + { + return $this->display; + } + + /** + * Gets the input instance used by the last execution of the command. + * + * @return InputInterface The current input instance + */ + public function getInput() + { + return $this->input; + } + + /** + * Gets the output instance used by the last execution of the command. + * + * @return OutputInterface The current output instance + */ + public function getOutput() + { + return $this->output; + } +} diff --git a/lib/vendor/Symfony/Components/Yaml/Dumper.php b/lib/vendor/Symfony/Components/Yaml/Dumper.php new file mode 100644 index 000000000..2db3f6cf1 --- /dev/null +++ b/lib/vendor/Symfony/Components/Yaml/Dumper.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Dumper dumps PHP variables to YAML strings. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + */ +class Dumper +{ + /** + * Dumps a PHP value to YAML. + * + * @param mixed $input The PHP value + * @param integer $inline The level where you switch to inline YAML + * @param integer $indent The level o indentation indentation (used internally) + * + * @return string The YAML representation of the PHP value + */ + public function dump($input, $inline = 0, $indent = 0) + { + $output = ''; + $prefix = $indent ? str_repeat(' ', $indent) : ''; + + if ($inline <= 0 || !is_array($input) || empty($input)) + { + $output .= $prefix.Inline::dump($input); + } + else + { + $isAHash = array_keys($input) !== range(0, count($input) - 1); + + foreach ($input as $key => $value) + { + $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value); + + $output .= sprintf('%s%s%s%s', + $prefix, + $isAHash ? Inline::dump($key).':' : '-', + $willBeInlined ? ' ' : "\n", + $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2) + ).($willBeInlined ? "\n" : ''); + } + } + + return $output; + } +} diff --git a/lib/vendor/Symfony/Components/Yaml/Exception.php b/lib/vendor/Symfony/Components/Yaml/Exception.php new file mode 100644 index 000000000..49cb7949e --- /dev/null +++ b/lib/vendor/Symfony/Components/Yaml/Exception.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Exception class used by all exceptions thrown by the component. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + */ +class Exception extends \Exception +{ +} diff --git a/lib/vendor/Symfony/Components/Yaml/Inline.php b/lib/vendor/Symfony/Components/Yaml/Inline.php new file mode 100644 index 000000000..854f4bba5 --- /dev/null +++ b/lib/vendor/Symfony/Components/Yaml/Inline.php @@ -0,0 +1,410 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Inline implements a YAML parser/dumper for the YAML inline syntax. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + */ +class Inline +{ + const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')'; + + /** + * Convert a YAML string to a PHP array. + * + * @param string $value A YAML string + * + * @return array A PHP array representing the YAML string + */ + static public function load($value) + { + $value = trim($value); + + if (0 == strlen($value)) + { + return ''; + } + + switch ($value[0]) + { + case '[': + return self::parseSequence($value); + case '{': + return self::parseMapping($value); + default: + return self::parseScalar($value); + } + } + + /** + * Dumps a given PHP variable to a YAML string. + * + * @param mixed $value The PHP variable to convert + * + * @return string The YAML string representing the PHP array + */ + static public function dump($value) + { + $trueValues = '1.1' == Yaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true'); + $falseValues = '1.1' == Yaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false'); + + switch (true) + { + case is_resource($value): + throw new Exception('Unable to dump PHP resources in a YAML file.'); + case is_object($value): + return '!!php/object:'.serialize($value); + case is_array($value): + return self::dumpArray($value); + case null === $value: + return 'null'; + case true === $value: + return 'true'; + case false === $value: + return 'false'; + case ctype_digit($value): + return is_string($value) ? "'$value'" : (int) $value; + case is_numeric($value): + return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value); + case false !== strpos($value, "\n") || false !== strpos($value, "\r"): + return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value)); + case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value): + return sprintf("'%s'", str_replace('\'', '\'\'', $value)); + case '' == $value: + return "''"; + case preg_match(self::getTimestampRegex(), $value): + return "'$value'"; + case in_array(strtolower($value), $trueValues): + return "'$value'"; + case in_array(strtolower($value), $falseValues): + return "'$value'"; + case in_array(strtolower($value), array('null', '~')): + return "'$value'"; + default: + return $value; + } + } + + /** + * Dumps a PHP array to a YAML string. + * + * @param array $value The PHP array to dump + * + * @return string The YAML string representing the PHP array + */ + static protected function dumpArray($value) + { + // array + $keys = array_keys($value); + if ( + (1 == count($keys) && '0' == $keys[0]) + || + (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (integer) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2)) + { + $output = array(); + foreach ($value as $val) + { + $output[] = self::dump($val); + } + + return sprintf('[%s]', implode(', ', $output)); + } + + // mapping + $output = array(); + foreach ($value as $key => $val) + { + $output[] = sprintf('%s: %s', self::dump($key), self::dump($val)); + } + + return sprintf('{ %s }', implode(', ', $output)); + } + + /** + * Parses a scalar to a YAML string. + * + * @param scalar $scalar + * @param string $delimiters + * @param array $stringDelimiter + * @param integer $i + * @param boolean $evaluate + * + * @return string A YAML string + */ + static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true) + { + if (in_array($scalar[$i], $stringDelimiters)) + { + // quoted scalar + $output = self::parseQuotedScalar($scalar, $i); + } + else + { + // "normal" string + if (!$delimiters) + { + $output = substr($scalar, $i); + $i += strlen($output); + + // remove comments + if (false !== $strpos = strpos($output, ' #')) + { + $output = rtrim(substr($output, 0, $strpos)); + } + } + else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) + { + $output = $match[1]; + $i += strlen($output); + } + else + { + throw new ParserException(sprintf('Malformed inline YAML string (%s).', $scalar)); + } + + $output = $evaluate ? self::evaluateScalar($output) : $output; + } + + return $output; + } + + /** + * Parses a quoted scalar to YAML. + * + * @param string $scalar + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseQuotedScalar($scalar, &$i) + { + if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/A', substr($scalar, $i), $match)) + { + throw new ParserException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i))); + } + + $output = substr($match[0], 1, strlen($match[0]) - 2); + + if ('"' == $scalar[$i]) + { + // evaluate the string + $output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output); + } + else + { + // unescape ' + $output = str_replace('\'\'', '\'', $output); + } + + $i += strlen($match[0]); + + return $output; + } + + /** + * Parses a sequence to a YAML string. + * + * @param string $sequence + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseSequence($sequence, &$i = 0) + { + $output = array(); + $len = strlen($sequence); + $i += 1; + + // [foo, bar, ...] + while ($i < $len) + { + switch ($sequence[$i]) + { + case '[': + // nested sequence + $output[] = self::parseSequence($sequence, $i); + break; + case '{': + // nested mapping + $output[] = self::parseMapping($sequence, $i); + break; + case ']': + return $output; + case ',': + case ' ': + break; + default: + $isQuoted = in_array($sequence[$i], array('"', "'")); + $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i); + + if (!$isQuoted && false !== strpos($value, ': ')) + { + // embedded mapping? + try + { + $value = self::parseMapping('{'.$value.'}'); + } + catch (\InvalidArgumentException $e) + { + // no, it's not + } + } + + $output[] = $value; + + --$i; + } + + ++$i; + } + + throw new ParserException(sprintf('Malformed inline YAML string %s', $sequence)); + } + + /** + * Parses a mapping to a YAML string. + * + * @param string $mapping + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseMapping($mapping, &$i = 0) + { + $output = array(); + $len = strlen($mapping); + $i += 1; + + // {foo: bar, bar:foo, ...} + while ($i < $len) + { + switch ($mapping[$i]) + { + case ' ': + case ',': + ++$i; + continue 2; + case '}': + return $output; + } + + // key + $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false); + + // value + $done = false; + while ($i < $len) + { + switch ($mapping[$i]) + { + case '[': + // nested sequence + $output[$key] = self::parseSequence($mapping, $i); + $done = true; + break; + case '{': + // nested mapping + $output[$key] = self::parseMapping($mapping, $i); + $done = true; + break; + case ':': + case ' ': + break; + default: + $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i); + $done = true; + --$i; + } + + ++$i; + + if ($done) + { + continue 2; + } + } + } + + throw new ParserException(sprintf('Malformed inline YAML string %s', $mapping)); + } + + /** + * Evaluates scalars and replaces magic values. + * + * @param string $scalar + * + * @return string A YAML string + */ + static protected function evaluateScalar($scalar) + { + $scalar = trim($scalar); + + $trueValues = '1.1' == Yaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true'); + $falseValues = '1.1' == Yaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false'); + + switch (true) + { + case 'null' == strtolower($scalar): + case '' == $scalar: + case '~' == $scalar: + return null; + case 0 === strpos($scalar, '!str'): + return (string) substr($scalar, 5); + case 0 === strpos($scalar, '! '): + return intval(self::parseScalar(substr($scalar, 2))); + case 0 === strpos($scalar, '!!php/object:'): + return unserialize(substr($scalar, 13)); + case ctype_digit($scalar): + $raw = $scalar; + $cast = intval($scalar); + return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw); + case in_array(strtolower($scalar), $trueValues): + return true; + case in_array(strtolower($scalar), $falseValues): + return false; + case is_numeric($scalar): + return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar); + case 0 == strcasecmp($scalar, '.inf'): + case 0 == strcasecmp($scalar, '.NaN'): + return -log(0); + case 0 == strcasecmp($scalar, '-.inf'): + return log(0); + case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): + return floatval(str_replace(',', '', $scalar)); + case preg_match(self::getTimestampRegex(), $scalar): + return strtotime($scalar); + default: + return (string) $scalar; + } + } + + static protected function getTimestampRegex() + { + return <<[0-9][0-9][0-9][0-9]) + -(?P[0-9][0-9]?) + -(?P[0-9][0-9]?) + (?:(?:[Tt]|[ \t]+) + (?P[0-9][0-9]?) + :(?P[0-9][0-9]) + :(?P[0-9][0-9]) + (?:\.(?P[0-9]*))? + (?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?) + (?::(?P[0-9][0-9]))?))?)? + $~x +EOF; + } +} diff --git a/lib/vendor/Symfony/Components/Yaml/Parser.php b/lib/vendor/Symfony/Components/Yaml/Parser.php new file mode 100644 index 000000000..330f9a1ef --- /dev/null +++ b/lib/vendor/Symfony/Components/Yaml/Parser.php @@ -0,0 +1,587 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Parser parses YAML strings to convert them to PHP arrays. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + */ +class Parser +{ + protected $offset = 0; + protected $lines = array(); + protected $currentLineNb = -1; + protected $currentLine = ''; + protected $refs = array(); + + /** + * Constructor + * + * @param integer $offset The offset of YAML document (used for line numbers in error messages) + */ + public function __construct($offset = 0) + { + $this->offset = $offset; + } + + /** + * Parses a YAML string to a PHP value. + * + * @param string $value A YAML string + * + * @return mixed A PHP value + * + * @throws \InvalidArgumentException If the YAML is not valid + */ + public function parse($value) + { + $this->currentLineNb = -1; + $this->currentLine = ''; + $this->lines = explode("\n", $this->cleanup($value)); + + $data = array(); + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + continue; + } + + // tab? + if (preg_match('#^\t+#', $this->currentLine)) + { + throw new ParserException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + $isRef = $isInPlace = $isProcessed = false; + if (preg_match('#^\-((?P\s+)(?P.+?))?\s*$#', $this->currentLine, $values)) + { + if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + // array + if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new Parser($c); + $parser->refs =& $this->refs; + $data[] = $parser->parse($this->getNextEmbedBlock()); + } + else + { + if (isset($values['leadspaces']) + && ' ' == $values['leadspaces'] + && preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{].*?) *\:(\s+(?P.+?))?\s*$#', $values['value'], $matches)) + { + // this is a compact notation element, add to next block and parse + $c = $this->getRealCurrentLineNb(); + $parser = new Parser($c); + $parser->refs =& $this->refs; + + $block = $values['value']; + if (!$this->isNextLineIndented()) + { + $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2); + } + + $data[] = $parser->parse($block); + } + else + { + $data[] = $this->parseValue($values['value']); + } + } + } + else if (preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"].*?) *\:(\s+(?P.+?))?\s*$#', $this->currentLine, $values)) + { + $key = Inline::parseScalar($values['key']); + + if ('<<' === $key) + { + if (isset($values['value']) && '*' === substr($values['value'], 0, 1)) + { + $isInPlace = substr($values['value'], 1); + if (!array_key_exists($isInPlace, $this->refs)) + { + throw new ParserException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + else + { + if (isset($values['value']) && $values['value'] !== '') + { + $value = $values['value']; + } + else + { + $value = $this->getNextEmbedBlock(); + } + $c = $this->getRealCurrentLineNb() + 1; + $parser = new Parser($c); + $parser->refs =& $this->refs; + $parsed = $parser->parse($value); + + $merged = array(); + if (!is_array($parsed)) + { + throw new ParserException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + else if (isset($parsed[0])) + { + // Numeric array, merge individual elements + foreach (array_reverse($parsed) as $parsedItem) + { + if (!is_array($parsedItem)) + { + throw new ParserException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem)); + } + $merged = array_merge($parsedItem, $merged); + } + } + else + { + // Associative array, merge + $merged = array_merge($merge, $parsed); + } + + $isProcessed = $merged; + } + } + else if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + if ($isProcessed) + { + // Merge keys + $data = $isProcessed; + } + // hash + else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + // if next line is less indented or equal, then it means that the current value is null + if ($this->isNextLineIndented()) + { + $data[$key] = null; + } + else + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new Parser($c); + $parser->refs =& $this->refs; + $data[$key] = $parser->parse($this->getNextEmbedBlock()); + } + } + else + { + if ($isInPlace) + { + $data = $this->refs[$isInPlace]; + } + else + { + $data[$key] = $this->parseValue($values['value']); + } + } + } + else + { + // 1-liner followed by newline + if (2 == count($this->lines) && empty($this->lines[1])) + { + $value = Inline::load($this->lines[0]); + if (is_array($value)) + { + $first = reset($value); + if ('*' === substr($first, 0, 1)) + { + $data = array(); + foreach ($value as $alias) + { + $data[] = $this->refs[substr($alias, 1)]; + } + $value = $data; + } + } + + return $value; + } + + switch (preg_last_error()) + { + case PREG_INTERNAL_ERROR: + $error = 'Internal PCRE error on line'; + break; + case PREG_BACKTRACK_LIMIT_ERROR: + $error = 'pcre.backtrack_limit reached on line'; + break; + case PREG_RECURSION_LIMIT_ERROR: + $error = 'pcre.recursion_limit reached on line'; + break; + case PREG_BAD_UTF8_ERROR: + $error = 'Malformed UTF-8 data on line'; + break; + case PREG_BAD_UTF8_OFFSET_ERROR: + $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line'; + break; + default: + $error = 'Unable to parse line'; + } + + throw new ParserException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + if ($isRef) + { + $this->refs[$isRef] = end($data); + } + } + + return empty($data) ? null : $data; + } + + /** + * Returns the current line number (takes the offset into account). + * + * @return integer The current line number + */ + protected function getRealCurrentLineNb() + { + return $this->currentLineNb + $this->offset; + } + + /** + * Returns the current line indentation. + * + * @return integer The current line indentation + */ + protected function getCurrentLineIndentation() + { + return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' ')); + } + + /** + * Returns the next embed block of YAML. + * + * @param integer $indentation The indent level at which the block is to be read, or null for default + * + * @return string A YAML string + */ + protected function getNextEmbedBlock($indentation = null) + { + $this->moveToNextLine(); + + if (null === $indentation) + { + $newIndent = $this->getCurrentLineIndentation(); + + if (!$this->isCurrentLineEmpty() && 0 == $newIndent) + { + throw new ParserException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + else + { + $newIndent = $indentation; + } + + $data = array(substr($this->currentLine, $newIndent)); + + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + if ($this->isCurrentLineBlank()) + { + $data[] = substr($this->currentLine, $newIndent); + } + + continue; + } + + $indent = $this->getCurrentLineIndentation(); + + if (preg_match('#^(?P *)$#', $this->currentLine, $match)) + { + // empty line + $data[] = $match['text']; + } + else if ($indent >= $newIndent) + { + $data[] = substr($this->currentLine, $newIndent); + } + else if (0 == $indent) + { + $this->moveToPreviousLine(); + + break; + } + else + { + throw new ParserException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + + return implode("\n", $data); + } + + /** + * Moves the parser to the next line. + */ + protected function moveToNextLine() + { + if ($this->currentLineNb >= count($this->lines) - 1) + { + return false; + } + + $this->currentLine = $this->lines[++$this->currentLineNb]; + + return true; + } + + /** + * Moves the parser to the previous line. + */ + protected function moveToPreviousLine() + { + $this->currentLine = $this->lines[--$this->currentLineNb]; + } + + /** + * Parses a YAML value. + * + * @param string $value A YAML value + * + * @return mixed A PHP value + */ + protected function parseValue($value) + { + if ('*' === substr($value, 0, 1)) + { + if (false !== $pos = strpos($value, '#')) + { + $value = substr($value, 1, $pos - 2); + } + else + { + $value = substr($value, 1); + } + + if (!array_key_exists($value, $this->refs)) + { + throw new ParserException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine)); + } + return $this->refs[$value]; + } + + if (preg_match('/^(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?$/', $value, $matches)) + { + $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : ''; + + return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers))); + } + else + { + return Inline::load($value); + } + } + + /** + * Parses a folded scalar. + * + * @param string $separator The separator that was used to begin this folded scalar (| or >) + * @param string $indicator The indicator that was used to begin this folded scalar (+ or -) + * @param integer $indentation The indentation that was used to begin this folded scalar + * + * @return string The text value + */ + protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0) + { + $separator = '|' == $separator ? "\n" : ' '; + $text = ''; + + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineBlank()) + { + $text .= "\n"; + + $notEOF = $this->moveToNextLine(); + } + + if (!$notEOF) + { + return ''; + } + + if (!preg_match('#^(?P'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P.*)$#', $this->currentLine, $matches)) + { + $this->moveToPreviousLine(); + + return ''; + } + + $textIndent = $matches['indent']; + $previousIndent = 0; + + $text .= $matches['text'].$separator; + while ($this->currentLineNb + 1 < count($this->lines)) + { + $this->moveToNextLine(); + + if (preg_match('#^(?P {'.strlen($textIndent).',})(?P.+)$#', $this->currentLine, $matches)) + { + if (' ' == $separator && $previousIndent != $matches['indent']) + { + $text = substr($text, 0, -1)."\n"; + } + $previousIndent = $matches['indent']; + + $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator); + } + else if (preg_match('#^(?P *)$#', $this->currentLine, $matches)) + { + $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n"; + } + else + { + $this->moveToPreviousLine(); + + break; + } + } + + if (' ' == $separator) + { + // replace last separator by a newline + $text = preg_replace('/ (\n*)$/', "\n$1", $text); + } + + switch ($indicator) + { + case '': + $text = preg_replace('#\n+$#s', "\n", $text); + break; + case '+': + break; + case '-': + $text = preg_replace('#\n+$#s', '', $text); + break; + } + + return $text; + } + + /** + * Returns true if the next line is indented. + * + * @return Boolean Returns true if the next line is indented, false otherwise + */ + protected function isNextLineIndented() + { + $currentIndentation = $this->getCurrentLineIndentation(); + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineEmpty()) + { + $notEOF = $this->moveToNextLine(); + } + + if (false === $notEOF) + { + return false; + } + + $ret = false; + if ($this->getCurrentLineIndentation() <= $currentIndentation) + { + $ret = true; + } + + $this->moveToPreviousLine(); + + return $ret; + } + + /** + * Returns true if the current line is blank or if it is a comment line. + * + * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise + */ + protected function isCurrentLineEmpty() + { + return $this->isCurrentLineBlank() || $this->isCurrentLineComment(); + } + + /** + * Returns true if the current line is blank. + * + * @return Boolean Returns true if the current line is blank, false otherwise + */ + protected function isCurrentLineBlank() + { + return '' == trim($this->currentLine, ' '); + } + + /** + * Returns true if the current line is a comment line. + * + * @return Boolean Returns true if the current line is a comment line, false otherwise + */ + protected function isCurrentLineComment() + { + //checking explicitly the first char of the trim is faster than loops or strpos + $ltrimmedLine = ltrim($this->currentLine, ' '); + return $ltrimmedLine[0] === '#'; + } + + /** + * Cleanups a YAML string to be parsed. + * + * @param string $value The input YAML string + * + * @return string A cleaned up YAML string + */ + protected function cleanup($value) + { + $value = str_replace(array("\r\n", "\r"), "\n", $value); + + if (!preg_match("#\n$#", $value)) + { + $value .= "\n"; + } + + // strip YAML header + $count = 0; + $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#s', '', $value, -1, $count); + $this->offset += $count; + + // remove leading comments and/or --- + $trimmedValue = preg_replace('#^((\#.*?\n)|(\-\-\-.*?\n))*#s', '', $value, -1, $count); + if ($count == 1) + { + // items have been removed, update the offset + $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); + $value = $trimmedValue; + } + + return $value; + } +} diff --git a/lib/vendor/Symfony/Components/Yaml/ParserException.php b/lib/vendor/Symfony/Components/Yaml/ParserException.php new file mode 100644 index 000000000..5ba22291d --- /dev/null +++ b/lib/vendor/Symfony/Components/Yaml/ParserException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Exception class used by all exceptions thrown by the component. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + */ +class ParserException extends Exception +{ +} diff --git a/lib/vendor/Symfony/Components/Yaml/Yaml.php b/lib/vendor/Symfony/Components/Yaml/Yaml.php new file mode 100644 index 000000000..ff8671d5f --- /dev/null +++ b/lib/vendor/Symfony/Components/Yaml/Yaml.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Yaml offers convenience methods to load and dump YAML. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + */ +class Yaml +{ + static protected $spec = '1.2'; + + /** + * Sets the YAML specification version to use. + * + * @param string $version The YAML specification version + */ + static public function setSpecVersion($version) + { + if (!in_array($version, array('1.1', '1.2'))) + { + throw new \InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version)); + } + + self::$spec = $version; + } + + /** + * Gets the YAML specification version to use. + * + * @return string The YAML specification version + */ + static public function getSpecVersion() + { + return self::$spec; + } + + /** + * Loads YAML into a PHP array. + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. + * + * Usage: + * + * $array = Yaml::load('config.yml'); + * print_r($array); + * + * + * @param string $input Path of YAML file or string containing YAML + * + * @return array The YAML converted to a PHP array + * + * @throws \InvalidArgumentException If the YAML is not valid + */ + public static function load($input) + { + $file = ''; + + // if input is a file, process it + if (strpos($input, "\n") === false && is_file($input)) + { + $file = $input; + + ob_start(); + $retval = include($input); + $content = ob_get_clean(); + + // if an array is returned by the config file assume it's in plain php form else in YAML + $input = is_array($retval) ? $retval : $content; + } + + // if an array is returned by the config file assume it's in plain php form else in YAML + if (is_array($input)) + { + return $input; + } + + $yaml = new Parser(); + + try + { + $ret = $yaml->parse($input); + } + catch (\Exception $e) + { + throw new \InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage())); + } + + return $ret; + } + + /** + * Dumps a PHP array to a YAML string. + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. + * + * @param array $array PHP array + * @param integer $inline The level where you switch to inline YAML + * + * @return string A YAML string representing the original PHP array + */ + public static function dump($array, $inline = 2) + { + $yaml = new Dumper(); + + return $yaml->dump($array, $inline); + } +}