Update to Drupal 8.1.0. For more information, see https://www.drupal.org/drupal-8.1.0-release-notes

This commit is contained in:
Pantheon Automation 2016-04-20 09:56:34 -07:00 committed by Greg Anderson
parent b11a755ba8
commit c0a0d5a94c
6920 changed files with 64395 additions and 57312 deletions

View file

@ -67,8 +67,8 @@ class ApcClassLoader
*/
public function __construct($prefix, $decorated)
{
if (!extension_loaded('apc')) {
throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.');
if (!function_exists('apcu_fetch')) {
throw new \RuntimeException('Unable to use ApcClassLoader as APC is not installed.');
}
if (!method_exists($decorated, 'findFile')) {
@ -122,8 +122,8 @@ class ApcClassLoader
*/
public function findFile($class)
{
if (false === $file = apc_fetch($this->prefix.$class)) {
apc_store($this->prefix.$class, $file = $this->decorated->findFile($class));
if (false === $file = apcu_fetch($this->prefix.$class)) {
apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class));
}
return $file;

View file

@ -76,7 +76,7 @@ class ApcUniversalClassLoader extends UniversalClassLoader
*/
public function __construct($prefix)
{
if (!extension_loaded('apc')) {
if (!function_exists('apcu_fetch')) {
throw new \RuntimeException('Unable to use ApcUniversalClassLoader as APC is not enabled.');
}
@ -92,8 +92,8 @@ class ApcUniversalClassLoader extends UniversalClassLoader
*/
public function findFile($class)
{
if (false === $file = apc_fetch($this->prefix.$class)) {
apc_store($this->prefix.$class, $file = parent::findFile($class));
if (false === $file = apcu_fetch($this->prefix.$class)) {
apcu_store($this->prefix.$class, $file = parent::findFile($class));
}
return $file;

View file

@ -116,8 +116,8 @@ class ClassCollectionLoader
}
// cache the core classes
if (!is_dir(dirname($cache))) {
mkdir(dirname($cache), 0777, true);
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
self::writeCacheFile($cache, '<?php '.$content);
@ -137,8 +137,8 @@ class ClassCollectionLoader
public static function fixNamespaceDeclarations($source)
{
if (!function_exists('token_get_all') || !self::$useTokenizer) {
if (preg_match('/namespace(.*?)\s*;/', $source)) {
$source = preg_replace('/namespace(.*?)\s*;/', "namespace$1\n{", $source)."}\n";
if (preg_match('/(^|\s)namespace(.*?)\s*;/', $source)) {
$source = preg_replace('/(^|\s)namespace(.*?)\s*;/', "$1namespace$2\n{", $source)."}\n";
}
return $source;
@ -149,8 +149,9 @@ class ClassCollectionLoader
$inNamespace = false;
$tokens = token_get_all($source);
for (reset($tokens); false !== $token = current($tokens); next($tokens)) {
if (is_string($token)) {
for ($i = 0; isset($tokens[$i]); ++$i) {
$token = $tokens[$i];
if (!isset($token[1]) || 'b"' === $token) {
$rawChunk .= $token;
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
// strip comments
@ -162,12 +163,12 @@ class ClassCollectionLoader
$rawChunk .= $token[1];
// namespace name and whitespaces
while (($t = next($tokens)) && is_array($t) && in_array($t[0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) {
$rawChunk .= $t[1];
while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) {
$rawChunk .= $tokens[$i][1];
}
if ('{' === $t) {
if ('{' === $tokens[$i]) {
$inNamespace = false;
prev($tokens);
--$i;
} else {
$rawChunk = rtrim($rawChunk)."\n{";
$inNamespace = true;
@ -175,8 +176,8 @@ class ClassCollectionLoader
} elseif (T_START_HEREDOC === $token[0]) {
$output .= self::compressCode($rawChunk).$token[1];
do {
$token = next($tokens);
$output .= is_string($token) ? $token : $token[1];
$token = $tokens[++$i];
$output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token;
} while ($token[0] !== T_END_HEREDOC);
$output .= "\n";
$rawChunk = '';
@ -192,7 +193,15 @@ class ClassCollectionLoader
$rawChunk .= "}\n";
}
return $output.self::compressCode($rawChunk);
$output .= self::compressCode($rawChunk);
if (PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
unset($tokens, $rawChunk);
gc_mem_caches();
}
return $output;
}
/**

View file

@ -97,7 +97,7 @@ class ClassLoader
$paths
));
} elseif (!in_array($paths, $this->prefixes[$prefix])) {
$this->prefixes[$prefix][] = $paths;
$this->prefixes[$prefix][] = $paths;
}
} else {
$this->prefixes[$prefix] = array_unique((array) $paths);

View file

@ -72,6 +72,11 @@ class ClassMapGenerator
$classes = self::findClasses($path);
if (PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches();
}
foreach ($classes as $class) {
$map[$class] = $path;
}
@ -95,10 +100,10 @@ class ClassMapGenerator
$classes = array();
$namespace = '';
for ($i = 0, $max = count($tokens); $i < $max; ++$i) {
for ($i = 0; isset($tokens[$i]); ++$i) {
$token = $tokens[$i];
if (is_string($token)) {
if (!isset($token[1])) {
continue;
}
@ -108,9 +113,9 @@ class ClassMapGenerator
case T_NAMESPACE:
$namespace = '';
// If there is a namespace, extract it
while (($t = $tokens[++$i]) && is_array($t)) {
if (in_array($t[0], array(T_STRING, T_NS_SEPARATOR))) {
$namespace .= $t[1];
while (isset($tokens[++$i][1])) {
if (in_array($tokens[$i][0], array(T_STRING, T_NS_SEPARATOR))) {
$namespace .= $tokens[$i][1];
}
}
$namespace .= '\\';
@ -121,7 +126,7 @@ class ClassMapGenerator
// Skip usage of ::class constant
$isClassConstant = false;
for ($j = $i - 1; $j > 0; --$j) {
if (is_string($tokens[$j])) {
if (!isset($tokens[$j][1])) {
break;
}
@ -134,14 +139,15 @@ class ClassMapGenerator
}
if ($isClassConstant) {
continue;
break;
}
// Find the classname
while (($t = $tokens[++$i]) && is_array($t)) {
while (isset($tokens[++$i][1])) {
$t = $tokens[$i];
if (T_STRING === $t[0]) {
$class .= $t[1];
} elseif ($class !== '' && T_WHITESPACE == $t[0]) {
} elseif ('' !== $class && T_WHITESPACE === $t[0]) {
break;
}
}

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,85 +1,14 @@
ClassLoader Component
=====================
ClassLoader loads your project classes automatically if they follow some
standard PHP conventions.
The ClassLoader object is able to autoload classes that implement the PSR-0
standard or the PEAR naming convention.
First, register the autoloader:
```php
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ClassLoader.php';
use Symfony\Component\ClassLoader\ClassLoader;
$loader = new ClassLoader();
$loader->register();
```
Then, register some namespaces with the `addPrefix()` method:
```php
$loader->addPrefix('Symfony', __DIR__.'/src');
$loader->addPrefix('Monolog', __DIR__.'/vendor/monolog/src');
```
The `addPrefix()` method takes a namespace prefix and a path where to
look for the classes as arguments.
You can also register a sub-namespaces:
```php
$loader->addPrefix('Doctrine\\Common', __DIR__.'/vendor/doctrine-common/lib');
```
The order of registration is significant and the first registered namespace
takes precedence over later registered one.
You can also register more than one path for a given namespace:
```php
$loader->addPrefix('Symfony', array(__DIR__.'/src', __DIR__.'/symfony/src'));
```
Alternatively, you can use the `addPrefixes()` method to register more
than one namespace at once:
```php
$loader->addPrefixes(array(
'Symfony' => array(__DIR__.'/src', __DIR__.'/symfony/src'),
'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib',
'Doctrine' => __DIR__.'/vendor/doctrine/lib',
'Monolog' => __DIR__.'/vendor/monolog/src',
));
```
For better performance, you can use the APC class loader:
```php
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ClassLoader.php';
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ApcClassLoader.php';
use Symfony\Component\ClassLoader\ClassLoader;
use Symfony\Component\ClassLoader\ApcClassLoader;
$loader = new ClassLoader();
$loader->addPrefix('Symfony', __DIR__.'/src');
$loader = new ApcClassLoader('apc.prefix.', $loader);
$loader->register();
```
Furthermore, the component provides tools to aggregate classes into a single
file, which is especially useful to improve performance on servers that do not
provide byte caches.
The ClassLoader component provides tools to autoload your classes and cache
their locations for performance.
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/ClassLoader/
$ composer install
$ phpunit
* [Documentation](https://symfony.com/doc/current/components/class_loader/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View file

@ -17,17 +17,21 @@
],
"minimum-stability": "dev",
"require": {
"php": ">=5.3.9"
"php": ">=5.3.9",
"symfony/polyfill-apcu": "~1.1"
},
"require-dev": {
"symfony/finder": "~2.0,>=2.0.5"
"symfony/finder": "~2.0,>=2.0.5|~3.0.0"
},
"autoload": {
"psr-4": { "Symfony\\Component\\ClassLoader\\": "" }
"psr-4": { "Symfony\\Component\\ClassLoader\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "2.8-dev"
}
}
}

View file

@ -13,6 +13,7 @@ namespace Symfony\Component\Console;
use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Helper\QuestionHelper;
@ -38,6 +39,8 @@ use Symfony\Component\Console\Helper\TableHelper;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
@ -309,8 +312,12 @@ class Application
*/
public function getLongVersion()
{
if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
if ('UNKNOWN' !== $this->getName()) {
if ('UNKNOWN' !== $this->getVersion()) {
return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
}
return sprintf('<info>%s</info>', $this->getName());
}
return '<info>Console Tool</info>';
@ -360,7 +367,7 @@ class Application
}
if (null === $command->getDefinition()) {
throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
}
$this->commands[$command->getName()] = $command;
@ -379,12 +386,12 @@ class Application
*
* @return Command A Command object
*
* @throws \InvalidArgumentException When command name given does not exist
* @throws CommandNotFoundException When command name given does not exist
*/
public function get($name)
{
if (!isset($this->commands[$name])) {
throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
}
$command = $this->commands[$name];
@ -423,7 +430,7 @@ class Application
public function getNamespaces()
{
$namespaces = array();
foreach ($this->commands as $command) {
foreach ($this->all() as $command) {
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
foreach ($command->getAliases() as $alias) {
@ -441,7 +448,7 @@ class Application
*
* @return string A registered namespace
*
* @throws \InvalidArgumentException When namespace is incorrect or ambiguous
* @throws CommandNotFoundException When namespace is incorrect or ambiguous
*/
public function findNamespace($namespace)
{
@ -462,12 +469,12 @@ class Application
$message .= implode("\n ", $alternatives);
}
throw new \InvalidArgumentException($message);
throw new CommandNotFoundException($message, $alternatives);
}
$exact = in_array($namespace, $namespaces, true);
if (count($namespaces) > 1 && !$exact) {
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
throw new CommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
}
return $exact ? $namespace : reset($namespaces);
@ -483,7 +490,7 @@ class Application
*
* @return Command A Command instance
*
* @throws \InvalidArgumentException When command name is incorrect or ambiguous
* @throws CommandNotFoundException When command name is incorrect or ambiguous
*/
public function find($name)
{
@ -508,7 +515,7 @@ class Application
$message .= implode("\n ", $alternatives);
}
throw new \InvalidArgumentException($message);
throw new CommandNotFoundException($message, $alternatives);
}
// filter out aliases for commands which are already on the list
@ -525,7 +532,7 @@ class Application
if (count($commands) > 1 && !$exact) {
$suggestions = $this->getAbbreviationSuggestions(array_values($commands));
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
throw new CommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions), array_values($commands));
}
return $this->get($exact ? $name : reset($commands));
@ -631,6 +638,8 @@ class Application
*/
public function renderException($e, $output)
{
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
do {
$title = sprintf(' [%s] ', get_class($e));
@ -653,7 +662,7 @@ class Application
}
}
$messages = array('', '');
$messages = array();
$messages[] = $emptyLine = $formatter->format(sprintf('<error>%s</error>', str_repeat(' ', $len)));
$messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title)))));
foreach ($lines as $line) {
@ -661,12 +670,11 @@ class Application
}
$messages[] = $emptyLine;
$messages[] = '';
$messages[] = '';
$output->writeln($messages, OutputInterface::OUTPUT_RAW);
$output->writeln($messages, OutputInterface::OUTPUT_RAW | OutputInterface::VERBOSITY_QUIET);
if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$output->writeln('<comment>Exception trace:</comment>');
$output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);
// exception related properties
$trace = $e->getTrace();
@ -684,18 +692,16 @@ class Application
$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 <info>%s:%s</info>', $class, $type, $function, $file, $line));
$output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), OutputInterface::VERBOSITY_QUIET);
}
$output->writeln('');
$output->writeln('');
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
}
} while ($e = $e->getPrevious());
if (null !== $this->runningCommand) {
$output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())));
$output->writeln('');
$output->writeln('');
$output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
}
}
@ -838,6 +844,14 @@ class Application
return $command->run($input, $output);
}
// bind before the console.command event, so the listeners have access to input options/arguments
try {
$command->mergeApplicationDefinition();
$input->bind($command->getDefinition());
} catch (ExceptionInterface $e) {
// ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition
}
$event = new ConsoleCommandEvent($command, $input, $output);
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
@ -1066,11 +1080,7 @@ class Application
private function stringWidth($string)
{
if (!function_exists('mb_strwidth')) {
return strlen($string);
}
if (false === $encoding = mb_detect_encoding($string)) {
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return strlen($string);
}
@ -1082,12 +1092,7 @@ class Application
// str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
// additionally, array_slice() is not enough as some character has doubled width.
// we need a function to split string not by character count but by string width
if (!function_exists('mb_strwidth')) {
return str_split($string, $width);
}
if (false === $encoding = mb_detect_encoding($string)) {
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return str_split($string, $width);
}

View file

@ -1,6 +1,17 @@
CHANGELOG
=========
2.8.3
-----
* remove readline support from the question helper as it caused issues
2.8.0
-----
* use readline for user input in the question helper when available to allow
the use of arrow keys
2.6.0
-----

View file

@ -13,6 +13,7 @@ namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
@ -21,6 +22,8 @@ use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
/**
* Base class for all commands.
@ -49,7 +52,7 @@ class Command
*
* @param string|null $name The name of the command; passing null means it must be set in configure()
*
* @throws \LogicException When the command name is empty
* @throws LogicException When the command name is empty
*/
public function __construct($name = null)
{
@ -62,7 +65,7 @@ class Command
$this->configure();
if (!$this->name) {
throw new \LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
}
}
@ -154,13 +157,13 @@ class Command
*
* @return null|int null or 0 if everything went fine, or an error code
*
* @throws \LogicException When this abstract method is not implemented
* @throws LogicException When this abstract method is not implemented
*
* @see setCode()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
throw new \LogicException('You must override the execute() method in the concrete command class.');
throw new LogicException('You must override the execute() method in the concrete command class.');
}
/**
@ -219,7 +222,7 @@ class Command
// bind the input against the command specific arguments/options
try {
$input->bind($this->definition);
} catch (\Exception $e) {
} catch (ExceptionInterface $e) {
if (!$this->ignoreValidationErrors) {
throw $e;
}
@ -269,14 +272,21 @@ class Command
*
* @return Command The current instance
*
* @throws \InvalidArgumentException
* @throws InvalidArgumentException
*
* @see execute()
*/
public function setCode($code)
{
if (!is_callable($code)) {
throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
throw new InvalidArgumentException('Invalid callable provided to Command::setCode.');
}
if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
$r = new \ReflectionFunction($code);
if (null === $r->getClosureThis()) {
$code = \Closure::bind($code, $this);
}
}
$this->code = $code;
@ -380,7 +390,7 @@ class Command
* @param string $shortcut The shortcut (can be null)
* @param int $mode The option mode: One of the InputOption::VALUE_* constants
* @param string $description A description text
* @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or InputOption::VALUE_NONE)
* @param mixed $default The default value (must be null for InputOption::VALUE_NONE)
*
* @return Command The current instance
*/
@ -403,7 +413,7 @@ class Command
*
* @return Command The current instance
*
* @throws \InvalidArgumentException When the name is invalid
* @throws InvalidArgumentException When the name is invalid
*/
public function setName($name)
{
@ -520,12 +530,12 @@ class Command
*
* @return Command The current instance
*
* @throws \InvalidArgumentException When an alias is invalid
* @throws InvalidArgumentException When an alias is invalid
*/
public function setAliases($aliases)
{
if (!is_array($aliases) && !$aliases instanceof \Traversable) {
throw new \InvalidArgumentException('$aliases must be an array or an instance of \Traversable');
throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable');
}
foreach ($aliases as $alias) {
@ -598,7 +608,7 @@ class Command
*
* @return mixed The helper value
*
* @throws \InvalidArgumentException if the helper is not defined
* @throws InvalidArgumentException if the helper is not defined
*/
public function getHelper($name)
{
@ -655,12 +665,12 @@ class Command
*
* @param string $name
*
* @throws \InvalidArgumentException When the name is invalid
* @throws InvalidArgumentException When the name is invalid
*/
private function validateName($name)
{
if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
}
}
}

View file

@ -42,7 +42,7 @@ class HelpCommand extends Command
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
))
->setDescription('Displays help for a command')
->setHelp(<<<EOF
->setHelp(<<<'EOF'
The <info>%command.name%</info> command displays help for a given command:
<info>php %command.full_name% list</info>

View file

@ -34,7 +34,7 @@ class ListCommand extends Command
->setName('list')
->setDefinition($this->createDefinition())
->setDescription('Lists commands')
->setHelp(<<<EOF
->setHelp(<<<'EOF'
The <info>%command.name%</info> command lists all commands:
<info>php %command.full_name%</info>

View file

@ -13,6 +13,7 @@ namespace Symfony\Component\Console\Descriptor;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
@ -89,12 +90,12 @@ class ApplicationDescription
*
* @return Command
*
* @throws \InvalidArgumentException
* @throws CommandNotFoundException
*/
public function getCommand($name)
{
if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
throw new \InvalidArgumentException(sprintf('Command %s does not exist.', $name));
throw new CommandNotFoundException(sprintf('Command %s does not exist.', $name));
}
return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];

View file

@ -17,6 +17,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
@ -54,7 +55,7 @@ abstract class Descriptor implements DescriptorInterface
$this->describeApplication($object, $options);
break;
default:
throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object)));
throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object)));
}
}

View file

@ -173,7 +173,7 @@ class TextDescriptor extends Descriptor
$width = $this->getColumnWidth($description->getCommands());
foreach ($description->getCommands() as $command) {
$this->writeText(sprintf("%-${width}s %s", $command->getName(), $command->getDescription()), $options);
$this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
$this->writeText("\n");
}
} else {
@ -236,10 +236,10 @@ class TextDescriptor extends Descriptor
private function formatDefaultValue($default)
{
if (PHP_VERSION_ID < 50400) {
return str_replace('\/', '/', json_encode($default));
return str_replace(array('\/', '\\\\'), array('/', '\\'), json_encode($default));
}
return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}
/**

View file

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Exception;
/**
* Represents an incorrect command name typed in the console.
*
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{
private $alternatives;
/**
* @param string $message Exception message to throw.
* @param array $alternatives List of similar defined names.
* @param int $code Exception code.
* @param Exception $previous previous exception used for the exception chaining.
*/
public function __construct($message, array $alternatives = array(), $code = 0, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->alternatives = $alternatives;
}
/**
* @return array A list of similar defined names.
*/
public function getAlternatives()
{
return $this->alternatives;
}
}

View file

@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Exception;
/**
* ExceptionInterface.
*
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
interface ExceptionInterface
{
}

View file

@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Exception;
/**
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

View file

@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Exception;
/**
* Represents an incorrect option name typed in the console.
*
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
{
}

View file

@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Exception;
/**
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
class LogicException extends \LogicException implements ExceptionInterface
{
}

View file

@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Exception;
/**
* @author Jérôme Tamarelle <jerome@tamarelle.net>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Formatter;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* Formatter class for console output.
*
@ -31,7 +33,15 @@ class OutputFormatter implements OutputFormatterInterface
*/
public static function escape($text)
{
return preg_replace('/([^\\\\]?)</', '$1\\<', $text);
$text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
if ('\\' === substr($text, -1)) {
$len = strlen($text);
$text = rtrim($text, '\\');
$text .= str_repeat('<<', $len - strlen($text));
}
return $text;
}
/**
@ -106,12 +116,12 @@ class OutputFormatter implements OutputFormatterInterface
*
* @return OutputFormatterStyleInterface
*
* @throws \InvalidArgumentException When style isn't defined
* @throws InvalidArgumentException When style isn't defined
*/
public function getStyle($name)
{
if (!$this->hasStyle($name)) {
throw new \InvalidArgumentException(sprintf('Undefined style: %s', $name));
throw new InvalidArgumentException(sprintf('Undefined style: %s', $name));
}
return $this->styles[strtolower($name)];
@ -129,7 +139,7 @@ class OutputFormatter implements OutputFormatterInterface
$message = (string) $message;
$offset = 0;
$output = '';
$tagRegex = '[a-z][a-z0-9_=;-]*';
$tagRegex = '[a-z][a-z0-9_=;-]*+';
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
foreach ($matches[0] as $i => $match) {
$pos = $match[1];
@ -164,6 +174,10 @@ class OutputFormatter implements OutputFormatterInterface
$output .= $this->applyCurrentStyle(substr($message, $offset));
if (false !== strpos($output, '<<')) {
return strtr($output, array('\\<' => '<', '<<' => '\\'));
}
return str_replace('\\<', '<', $output);
}

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Formatter;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* Formatter style class for defining styles.
*
@ -77,7 +79,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
*
* @param string|null $color The color name
*
* @throws \InvalidArgumentException When the color name isn't defined
* @throws InvalidArgumentException When the color name isn't defined
*/
public function setForeground($color = null)
{
@ -88,7 +90,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
}
if (!isset(static::$availableForegroundColors[$color])) {
throw new \InvalidArgumentException(sprintf(
throw new InvalidArgumentException(sprintf(
'Invalid foreground color specified: "%s". Expected one of (%s)',
$color,
implode(', ', array_keys(static::$availableForegroundColors))
@ -103,7 +105,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
*
* @param string|null $color The color name
*
* @throws \InvalidArgumentException When the color name isn't defined
* @throws InvalidArgumentException When the color name isn't defined
*/
public function setBackground($color = null)
{
@ -114,7 +116,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
}
if (!isset(static::$availableBackgroundColors[$color])) {
throw new \InvalidArgumentException(sprintf(
throw new InvalidArgumentException(sprintf(
'Invalid background color specified: "%s". Expected one of (%s)',
$color,
implode(', ', array_keys(static::$availableBackgroundColors))
@ -129,12 +131,12 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
*
* @param string $option The option name
*
* @throws \InvalidArgumentException When the option name isn't defined
* @throws InvalidArgumentException When the option name isn't defined
*/
public function setOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new \InvalidArgumentException(sprintf(
throw new InvalidArgumentException(sprintf(
'Invalid option specified: "%s". Expected one of (%s)',
$option,
implode(', ', array_keys(static::$availableOptions))
@ -151,12 +153,12 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
*
* @param string $option The option name
*
* @throws \InvalidArgumentException When the option name isn't defined
* @throws InvalidArgumentException When the option name isn't defined
*/
public function unsetOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new \InvalidArgumentException(sprintf(
throw new InvalidArgumentException(sprintf(
'Invalid option specified: "%s". Expected one of (%s)',
$option,
implode(', ', array_keys(static::$availableOptions))

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Formatter;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
@ -62,7 +64,7 @@ class OutputFormatterStyleStack
*
* @return OutputFormatterStyleInterface
*
* @throws \InvalidArgumentException When style tags incorrectly nested
* @throws InvalidArgumentException When style tags incorrectly nested
*/
public function pop(OutputFormatterStyleInterface $style = null)
{
@ -82,7 +84,7 @@ class OutputFormatterStyleStack
}
}
throw new \InvalidArgumentException('Incorrectly nested style tag found.');
throw new InvalidArgumentException('Incorrectly nested style tag found.');
}
/**

View file

@ -17,6 +17,7 @@ use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* This class adds helper method to describe objects in various formats.
@ -54,7 +55,7 @@ class DescriptorHelper extends Helper
* @param object $object
* @param array $options
*
* @throws \InvalidArgumentException when the given format is not supported
* @throws InvalidArgumentException when the given format is not supported
*/
public function describe(OutputInterface $output, $object, array $options = array())
{
@ -64,7 +65,7 @@ class DescriptorHelper extends Helper
), $options);
if (!isset($this->descriptors[$options['format']])) {
throw new \InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
}
$descriptor = $this->descriptors[$options['format']];

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
@ -48,15 +51,19 @@ class DialogHelper extends InputAwareHelper
*
* @return int|string|array The selected value or values (the key of the choices array)
*
* @throws \InvalidArgumentException
* @throws InvalidArgumentException
*/
public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$width = max(array_map('strlen', array_keys($choices)));
$messages = (array) $question;
foreach ($choices as $key => $value) {
$messages[] = sprintf(" [<info>%-${width}s</info>] %s", $key, $value);
$messages[] = sprintf(" [<info>%-{$width}s</info>] %s", $key, $value);
}
$output->writeln($messages);
@ -68,7 +75,7 @@ class DialogHelper extends InputAwareHelper
if ($multiselect) {
// Check for a separated comma values
if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
throw new \InvalidArgumentException(sprintf($errorMessage, $picked));
throw new InvalidArgumentException(sprintf($errorMessage, $picked));
}
$selectedChoices = explode(',', $selectedChoices);
} else {
@ -79,7 +86,7 @@ class DialogHelper extends InputAwareHelper
foreach ($selectedChoices as $value) {
if (empty($choices[$value])) {
throw new \InvalidArgumentException(sprintf($errorMessage, $value));
throw new InvalidArgumentException(sprintf($errorMessage, $value));
}
$multiselectChoices[] = $value;
}
@ -104,7 +111,7 @@ class DialogHelper extends InputAwareHelper
*
* @return string The user answer
*
* @throws \RuntimeException If there is no data to read in the input stream
* @throws RuntimeException If there is no data to read in the input stream
*/
public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null)
{
@ -112,6 +119,10 @@ class DialogHelper extends InputAwareHelper
return $default;
}
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$output->write($question);
$inputStream = $this->inputStream ?: STDIN;
@ -119,7 +130,7 @@ class DialogHelper extends InputAwareHelper
if (null === $autocomplete || !$this->hasSttyAvailable()) {
$ret = fgets($inputStream, 4096);
if (false === $ret) {
throw new \RuntimeException('Aborted');
throw new RuntimeException('Aborted');
}
$ret = trim($ret);
} else {
@ -265,10 +276,14 @@ class DialogHelper extends InputAwareHelper
*
* @return string The answer
*
* @throws \RuntimeException In case the fallback is deactivated and the response can not be hidden
* @throws RuntimeException In case the fallback is deactivated and the response can not be hidden
*/
public function askHiddenResponse(OutputInterface $output, $question, $fallback = true)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
if ('\\' === DIRECTORY_SEPARATOR) {
$exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
@ -300,7 +315,7 @@ class DialogHelper extends InputAwareHelper
shell_exec(sprintf('stty %s', $sttyMode));
if (false === $value) {
throw new \RuntimeException('Aborted');
throw new RuntimeException('Aborted');
}
$value = trim($value);
@ -323,7 +338,7 @@ class DialogHelper extends InputAwareHelper
return $this->ask($output, $question);
}
throw new \RuntimeException('Unable to hide the response');
throw new RuntimeException('Unable to hide the response');
}
/**
@ -370,8 +385,8 @@ class DialogHelper extends InputAwareHelper
*
* @return string The response
*
* @throws \Exception When any of the validators return an error
* @throws \RuntimeException In case the fallback is deactivated and the response can not be hidden
* @throws \Exception When any of the validators return an error
* @throws RuntimeException In case the fallback is deactivated and the response can not be hidden
*/
public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true)
{
@ -458,7 +473,7 @@ class DialogHelper extends InputAwareHelper
* @param callable $interviewer A callable that will ask for a question and return the result
* @param OutputInterface $output An Output instance
* @param callable $validator A PHP callback
* @param int|false $attempts Max number of times to ask before giving up ; false will ask infinitely
* @param int|false $attempts Max number of times to ask before giving up; false will ask infinitely
*
* @return string The validated response
*
@ -466,6 +481,10 @@ class DialogHelper extends InputAwareHelper
*/
private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$e = null;
while (false === $attempts || $attempts--) {
if (null !== $e) {

View file

@ -51,11 +51,7 @@ abstract class Helper implements HelperInterface
*/
public static function strlen($string)
{
if (!function_exists('mb_strwidth')) {
return strlen($string);
}
if (false === $encoding = mb_detect_encoding($string)) {
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return strlen($string);
}

View file

@ -12,6 +12,7 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* HelperSet represents a set of helpers to be used with a command.
@ -70,12 +71,12 @@ class HelperSet implements \IteratorAggregate
*
* @return HelperInterface The helper instance
*
* @throws \InvalidArgumentException if the helper is not defined
* @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));
throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
}
if ('dialog' === $name && $this->helpers[$name] instanceof DialogHelper) {

View file

@ -13,6 +13,7 @@ namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\LogicException;
/**
* The ProgressBar provides helpers to display progress output.
@ -67,10 +68,8 @@ class ProgressBar
// disable overwrite when output does not support ANSI codes.
$this->overwrite = false;
if ($this->max > 10) {
// set a reasonable redraw frequency so output isn't flooded
$this->setRedrawFrequency($max / 10);
}
// set a reasonable redraw frequency so output isn't flooded
$this->setRedrawFrequency($max / 10);
}
$this->startTime = time();
@ -316,11 +315,11 @@ class ProgressBar
/**
* Sets the redraw frequency.
*
* @param int $freq The frequency in steps
* @param int|float $freq The frequency in steps
*/
public function setRedrawFrequency($freq)
{
$this->redrawFreq = (int) $freq;
$this->redrawFreq = max((int) $freq, 1);
}
/**
@ -346,7 +345,7 @@ class ProgressBar
*
* @param int $step Number of steps to advance
*
* @throws \LogicException
* @throws LogicException
*/
public function advance($step = 1)
{
@ -360,7 +359,7 @@ class ProgressBar
*
* @param int $step The current progress
*
* @throws \LogicException
* @throws LogicException
*/
public function setCurrent($step)
{
@ -384,13 +383,13 @@ class ProgressBar
*
* @param int $step The current progress
*
* @throws \LogicException
* @throws LogicException
*/
public function setProgress($step)
{
$step = (int) $step;
if ($step < $this->step) {
throw new \LogicException('You can\'t regress the progress bar.');
throw new LogicException('You can\'t regress the progress bar.');
}
if ($this->max && $step > $this->max) {
@ -580,7 +579,7 @@ class ProgressBar
},
'remaining' => function (ProgressBar $bar) {
if (!$bar->getMaxSteps()) {
throw new \LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
}
if (!$bar->getProgress()) {
@ -593,7 +592,7 @@ class ProgressBar
},
'estimated' => function (ProgressBar $bar) {
if (!$bar->getMaxSteps()) {
throw new \LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
}
if (!$bar->getProgress()) {

View file

@ -12,7 +12,9 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\LogicException;
/**
* The Progress class provides helpers to display progress output.
@ -193,6 +195,10 @@ class ProgressHelper extends Helper
*/
public function start(OutputInterface $output, $max = null)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$this->startTime = time();
$this->current = 0;
$this->max = (int) $max;
@ -236,7 +242,7 @@ class ProgressHelper extends Helper
* @param int $step Number of steps to advance
* @param bool $redraw Whether to redraw or not
*
* @throws \LogicException
* @throws LogicException
*/
public function advance($step = 1, $redraw = false)
{
@ -249,18 +255,18 @@ class ProgressHelper extends Helper
* @param int $current The current progress
* @param bool $redraw Whether to redraw or not
*
* @throws \LogicException
* @throws LogicException
*/
public function setCurrent($current, $redraw = false)
{
if (null === $this->startTime) {
throw new \LogicException('You must start the progress bar before calling setCurrent().');
throw new LogicException('You must start the progress bar before calling setCurrent().');
}
$current = (int) $current;
if ($current < $this->current) {
throw new \LogicException('You can\'t regress the progress bar');
throw new LogicException('You can\'t regress the progress bar');
}
if (0 === $this->current) {
@ -282,12 +288,12 @@ class ProgressHelper extends Helper
*
* @param bool $finish Forces the end result
*
* @throws \LogicException
* @throws LogicException
*/
public function display($finish = false)
{
if (null === $this->startTime) {
throw new \LogicException('You must start the progress bar before calling display().');
throw new LogicException('You must start the progress bar before calling display().');
}
$message = $this->format;
@ -315,7 +321,7 @@ class ProgressHelper extends Helper
public function finish()
{
if (null === $this->startTime) {
throw new \LogicException('You must start the progress bar before calling finish().');
throw new LogicException('You must start the progress bar before calling finish().');
}
if (null !== $this->startTime) {

View file

@ -0,0 +1,322 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
class ProgressIndicator
{
private $output;
private $startTime;
private $format;
private $message;
private $indicatorValues;
private $indicatorCurrent;
private $indicatorChangeInterval;
private $indicatorUpdateTime;
private $lastMessagesLength;
private $started = false;
private static $formatters;
private static $formats;
/**
* @param OutputInterface $output
* @param string|null $format Indicator format
* @param int $indicatorChangeInterval Change interval in milliseconds
* @param array|null $indicatorValues Animated indicator characters
*/
public function __construct(OutputInterface $output, $format = null, $indicatorChangeInterval = 100, $indicatorValues = null)
{
$this->output = $output;
if (null === $format) {
$format = $this->determineBestFormat();
}
if (null === $indicatorValues) {
$indicatorValues = array('-', '\\', '|', '/');
}
$indicatorValues = array_values($indicatorValues);
if (2 > count($indicatorValues)) {
throw new \InvalidArgumentException('Must have at least 2 indicator value characters.');
}
$this->format = self::getFormatDefinition($format);
$this->indicatorChangeInterval = $indicatorChangeInterval;
$this->indicatorValues = $indicatorValues;
$this->startTime = time();
}
/**
* Sets the current indicator message.
*
* @param string|null $message
*/
public function setMessage($message)
{
$this->message = $message;
$this->display();
}
/**
* Gets the current indicator message.
*
* @return string|null
*
* @internal for PHP 5.3 compatibility
*/
public function getMessage()
{
return $this->message;
}
/**
* Gets the progress bar start time.
*
* @return int The progress bar start time
*
* @internal for PHP 5.3 compatibility
*/
public function getStartTime()
{
return $this->startTime;
}
/**
* Gets the current animated indicator character.
*
* @return string
*
* @internal for PHP 5.3 compatibility
*/
public function getCurrentValue()
{
return $this->indicatorValues[$this->indicatorCurrent % count($this->indicatorValues)];
}
/**
* Starts the indicator output.
*
* @param $message
*/
public function start($message)
{
if ($this->started) {
throw new \LogicException('Progress indicator already started.');
}
$this->message = $message;
$this->started = true;
$this->lastMessagesLength = 0;
$this->startTime = time();
$this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
$this->indicatorCurrent = 0;
$this->display();
}
/**
* Advances the indicator.
*/
public function advance()
{
if (!$this->started) {
throw new \LogicException('Progress indicator has not yet been started.');
}
if (!$this->output->isDecorated()) {
return;
}
$currentTime = $this->getCurrentTimeInMilliseconds();
if ($currentTime < $this->indicatorUpdateTime) {
return;
}
$this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
++$this->indicatorCurrent;
$this->display();
}
/**
* Finish the indicator with message.
*
* @param $message
*/
public function finish($message)
{
if (!$this->started) {
throw new \LogicException('Progress indicator has not yet been started.');
}
$this->message = $message;
$this->display();
$this->output->writeln('');
$this->started = false;
}
/**
* Gets the format for a given name.
*
* @param string $name The format name
*
* @return string|null A format string
*/
public static function getFormatDefinition($name)
{
if (!self::$formats) {
self::$formats = self::initFormats();
}
return isset(self::$formats[$name]) ? self::$formats[$name] : null;
}
/**
* Sets a placeholder formatter for a given name.
*
* This method also allow you to override an existing placeholder.
*
* @param string $name The placeholder name (including the delimiter char like %)
* @param callable $callable A PHP callable
*/
public static function setPlaceholderFormatterDefinition($name, $callable)
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}
self::$formatters[$name] = $callable;
}
/**
* Gets the placeholder formatter for a given name.
*
* @param string $name The placeholder name (including the delimiter char like %)
*
* @return callable|null A PHP callable
*/
public static function getPlaceholderFormatterDefinition($name)
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}
return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
}
private function display()
{
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
return;
}
$self = $this;
$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
return call_user_func($formatter, $self);
}
return $matches[0];
}, $this->format));
}
private function determineBestFormat()
{
switch ($this->output->getVerbosity()) {
// OutputInterface::VERBOSITY_QUIET: display is disabled anyway
case OutputInterface::VERBOSITY_VERBOSE:
return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
case OutputInterface::VERBOSITY_VERY_VERBOSE:
case OutputInterface::VERBOSITY_DEBUG:
return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
default:
return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
}
}
/**
* Overwrites a previous message to the output.
*
* @param string $message The message
*/
private function overwrite($message)
{
// append whitespace to match the line's length
if (null !== $this->lastMessagesLength) {
if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $message)) {
$message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
}
}
if ($this->output->isDecorated()) {
$this->output->write("\x0D");
$this->output->write($message);
} else {
$this->output->writeln($message);
}
$this->lastMessagesLength = 0;
$len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $message);
if ($len > $this->lastMessagesLength) {
$this->lastMessagesLength = $len;
}
}
private function getCurrentTimeInMilliseconds()
{
return round(microtime(true) * 1000);
}
private static function initPlaceholderFormatters()
{
return array(
'indicator' => function (ProgressIndicator $indicator) {
return $indicator->getCurrentValue();
},
'message' => function (ProgressIndicator $indicator) {
return $indicator->getMessage();
},
'elapsed' => function (ProgressIndicator $indicator) {
return Helper::formatTime(time() - $indicator->getStartTime());
},
'memory' => function () {
return Helper::formatMemory(memory_get_usage(true));
},
);
}
private static function initFormats()
{
return array(
'normal' => ' %indicator% %message%',
'normal_no_ansi' => ' %message%',
'verbose' => ' %indicator% %message% (%elapsed:6s%)',
'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
);
}
}

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -38,7 +40,7 @@ class QuestionHelper extends Helper
*
* @return string The user answer
*
* @throws \RuntimeException If there is no data to read in the input stream
* @throws RuntimeException If there is no data to read in the input stream
*/
public function ask(InputInterface $input, OutputInterface $output, Question $question)
{
@ -70,12 +72,12 @@ class QuestionHelper extends Helper
*
* @param resource $stream The input stream
*
* @throws \InvalidArgumentException In case the stream is not a resource
* @throws InvalidArgumentException In case the stream is not a resource
*/
public function setInputStream($stream)
{
if (!is_resource($stream)) {
throw new \InvalidArgumentException('Input stream must be a valid resource.');
throw new InvalidArgumentException('Input stream must be a valid resource.');
}
$this->inputStream = $stream;
@ -162,11 +164,12 @@ class QuestionHelper extends Helper
$message = $question->getQuestion();
if ($question instanceof ChoiceQuestion) {
$width = max(array_map('strlen', array_keys($question->getChoices())));
$maxWidth = max(array_map(array($this, 'strlen'), array_keys($question->getChoices())));
$messages = (array) $question->getQuestion();
foreach ($question->getChoices() as $key => $value) {
$messages[] = sprintf(" [<info>%-${width}s</info>] %s", $key, $value);
$width = $maxWidth - $this->strlen($key);
$messages[] = ' [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value;
}
$output->writeln($messages);
@ -319,7 +322,7 @@ class QuestionHelper extends Helper
*
* @return string The answer
*
* @throws \RuntimeException In case the fallback is deactivated and the response cannot be hidden
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
*/
private function getHiddenResponse(OutputInterface $output, $inputStream)
{
@ -351,7 +354,7 @@ class QuestionHelper extends Helper
shell_exec(sprintf('stty %s', $sttyMode));
if (false === $value) {
throw new \RuntimeException('Aborted');
throw new RuntimeException('Aborted');
}
$value = trim($value);
@ -369,7 +372,7 @@ class QuestionHelper extends Helper
return $value;
}
throw new \RuntimeException('Unable to hide the response.');
throw new RuntimeException('Unable to hide the response.');
}
/**

View file

@ -11,6 +11,7 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
@ -32,13 +33,13 @@ class SymfonyQuestionHelper extends QuestionHelper
{
$validator = $question->getValidator();
$question->setValidator(function ($value) use ($validator) {
if (null !== $validator && is_callable($validator)) {
if (null !== $validator) {
$value = $validator($value);
}
// make required
if (!is_array($value) && !is_bool($value) && 0 === strlen($value)) {
throw new \Exception('A value is required.');
throw new LogicException('A value is required.');
}
return $value;

View file

@ -12,6 +12,7 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* Provides helpers to display a table.
@ -19,6 +20,7 @@ use Symfony\Component\Console\Output\OutputInterface;
* @author Fabien Potencier <fabien@symfony.com>
* @author Саша Стаменковић <umpirsky@gmail.com>
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
* @author Max Grigorian <maxakawizard@gmail.com>
*/
class Table
{
@ -60,6 +62,11 @@ class Table
*/
private $style;
/**
* @var array
*/
private $columnStyles = array();
private static $styles;
public function __construct(OutputInterface $output)
@ -102,7 +109,7 @@ class Table
}
if (!self::$styles[$name]) {
throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}
return self::$styles[$name];
@ -122,7 +129,7 @@ class Table
} elseif (isset(self::$styles[$name])) {
$this->style = self::$styles[$name];
} else {
throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}
return $this;
@ -138,6 +145,47 @@ class Table
return $this->style;
}
/**
* Sets table column style.
*
* @param int $columnIndex Column index
* @param TableStyle|string $name The style name or a TableStyle instance
*
* @return Table
*/
public function setColumnStyle($columnIndex, $name)
{
$columnIndex = intval($columnIndex);
if ($name instanceof TableStyle) {
$this->columnStyles[$columnIndex] = $name;
} elseif (isset(self::$styles[$name])) {
$this->columnStyles[$columnIndex] = self::$styles[$name];
} else {
throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}
return $this;
}
/**
* Gets the current style for a column.
*
* If style was not set, it returns the global table style.
*
* @param int $columnIndex Column index
*
* @return TableStyle
*/
public function getColumnStyle($columnIndex)
{
if (isset($this->columnStyles[$columnIndex])) {
return $this->columnStyles[$columnIndex];
}
return $this->getStyle();
}
public function setHeaders(array $headers)
{
$headers = array_values($headers);
@ -175,7 +223,7 @@ class Table
}
if (!is_array($row)) {
throw new \InvalidArgumentException('A row must be an array or a TableSeparator instance.');
throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
}
$this->rows[] = array_values($row);
@ -205,24 +253,26 @@ class Table
public function render()
{
$this->calculateNumberOfColumns();
$this->rows = $this->buildTableRows($this->rows);
$this->headers = $this->buildTableRows($this->headers);
$rows = $this->buildTableRows($this->rows);
$headers = $this->buildTableRows($this->headers);
$this->calculateColumnsWidth(array_merge($headers, $rows));
$this->renderRowSeparator();
if (!empty($this->headers)) {
foreach ($this->headers as $header) {
if (!empty($headers)) {
foreach ($headers as $header) {
$this->renderRow($header, $this->style->getCellHeaderFormat());
$this->renderRowSeparator();
}
}
foreach ($this->rows as $row) {
foreach ($rows as $row) {
if ($row instanceof TableSeparator) {
$this->renderRowSeparator();
} else {
$this->renderRow($row, $this->style->getCellRowFormat());
}
}
if (!empty($this->rows)) {
if (!empty($rows)) {
$this->renderRowSeparator();
}
@ -246,7 +296,7 @@ class Table
$markup = $this->style->getCrossingChar();
for ($column = 0; $column < $count; ++$column) {
$markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->getColumnWidth($column)).$this->style->getCrossingChar();
$markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->columnWidths[$column]).$this->style->getCrossingChar();
}
$this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
@ -292,25 +342,27 @@ class Table
private function renderCell(array $row, $column, $cellFormat)
{
$cell = isset($row[$column]) ? $row[$column] : '';
$width = $this->getColumnWidth($column);
$width = $this->columnWidths[$column];
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
// add the width of the following columns(numbers of colspan).
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
$width += $this->getColumnSeparatorWidth() + $this->getColumnWidth($nextColumn);
$width += $this->getColumnSeparatorWidth() + $this->columnWidths[$nextColumn];
}
}
// str_pad won't work properly with multi-byte strings, we need to fix the padding
if (function_exists('mb_strwidth') && false !== $encoding = mb_detect_encoding($cell)) {
if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
$width += strlen($cell) - mb_strwidth($cell, $encoding);
}
$style = $this->getColumnStyle($column);
if ($cell instanceof TableSeparator) {
$this->output->write(sprintf($this->style->getBorderFormat(), str_repeat($this->style->getHorizontalBorderChar(), $width)));
$this->output->write(sprintf($style->getBorderFormat(), str_repeat($style->getHorizontalBorderChar(), $width)));
} else {
$width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
$content = sprintf($this->style->getCellRowContentFormat(), $cell);
$this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType())));
$content = sprintf($style->getCellRowContentFormat(), $cell);
$this->output->write(sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType())));
}
}
@ -332,7 +384,7 @@ class Table
$columns[] = $this->getNumberOfColumns($row);
}
return $this->numberOfColumns = max($columns);
$this->numberOfColumns = max($columns);
}
private function buildTableRows($rows)
@ -343,7 +395,6 @@ class Table
// Remove any new line breaks and replace it with a new line
foreach ($rows[$rowKey] as $column => $cell) {
$rows[$rowKey] = $this->fillCells($rows[$rowKey], $column);
if (!strstr($cell, "\n")) {
continue;
}
@ -363,7 +414,7 @@ class Table
$tableRows = array();
foreach ($rows as $rowKey => $row) {
$tableRows[] = $row;
$tableRows[] = $this->fillCells($row);
if (isset($unmergedRows[$rowKey])) {
$tableRows = array_merge($tableRows, $unmergedRows[$rowKey]);
}
@ -429,21 +480,23 @@ class Table
* fill cells for a row that contains colspan > 1.
*
* @param array $row
* @param int $column
*
* @return array
*/
private function fillCells($row, $column)
private function fillCells($row)
{
$cell = $row[$column];
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
// insert empty value into rows at column position
array_splice($row, $position, 0, '');
$newRow = array();
foreach ($row as $column => $cell) {
$newRow[] = $cell;
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
// insert empty value at column position
$newRow[] = '';
}
}
}
return $row;
return $newRow ?: $row;
}
/**
@ -487,7 +540,7 @@ class Table
*
* @param array $row
*
* @return array()
* @return array
*/
private function getRowColumns($row)
{
@ -503,34 +556,29 @@ class Table
}
/**
* Gets column width.
* Calculates columns widths.
*
* @param int $column
*
* @return int
* @param array $rows
*/
private function getColumnWidth($column)
private function calculateColumnsWidth($rows)
{
if (isset($this->columnWidths[$column])) {
return $this->columnWidths[$column];
}
for ($column = 0; $column < $this->numberOfColumns; ++$column) {
$lengths = array();
foreach ($rows as $row) {
if ($row instanceof TableSeparator) {
continue;
}
foreach (array_merge($this->headers, $this->rows) as $row) {
if ($row instanceof TableSeparator) {
continue;
$lengths[] = $this->getCellWidth($row, $column);
}
$lengths[] = $this->getCellWidth($row, $column);
$this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
}
return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
}
/**
* Gets column width.
*
* @param int $column
*
* @return int
*/
private function getColumnSeparatorWidth()

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
@ -39,7 +41,7 @@ class TableCell
// check option names
if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
throw new \InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
}
$this->options = array_merge($this->options, $options);

View file

@ -13,6 +13,7 @@ namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* Provides helpers to display table output.
@ -50,7 +51,7 @@ class TableHelper extends Helper
*
* @return TableHelper
*
* @throws \InvalidArgumentException when the table layout is not known
* @throws InvalidArgumentException when the table layout is not known
*/
public function setLayout($layout)
{
@ -68,8 +69,8 @@ class TableHelper extends Helper
break;
default:
throw new \InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout));
};
throw new InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout));
}
return $this;
}

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
/**
* Defines the styles for a Table.
*
@ -39,7 +42,7 @@ class TableStyle
public function setPaddingChar($paddingChar)
{
if (!$paddingChar) {
throw new \LogicException('The padding char must not be empty');
throw new LogicException('The padding char must not be empty');
}
$this->paddingChar = $paddingChar;
@ -235,7 +238,7 @@ class TableStyle
public function setPadType($padType)
{
if (!in_array($padType, array(STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH), true)) {
throw new \InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
}
$this->padType = $padType;

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Input;
use Symfony\Component\Console\Exception\RuntimeException;
/**
* ArgvInput represents an input coming from the CLI arguments.
*
@ -114,14 +116,14 @@ class ArgvInput extends Input
*
* @param string $name The current token
*
* @throws \RuntimeException When option given doesn't exist
* @throws RuntimeException When option given doesn't exist
*/
private 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]));
throw new RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
}
$option = $this->definition->getOptionForShortcut($name[$i]);
@ -156,7 +158,7 @@ class ArgvInput extends Input
*
* @param string $token The current token
*
* @throws \RuntimeException When too many arguments are given
* @throws RuntimeException When too many arguments are given
*/
private function parseArgument($token)
{
@ -174,7 +176,7 @@ class ArgvInput extends Input
// unexpected argument
} else {
throw new \RuntimeException('Too many arguments.');
throw new RuntimeException('Too many arguments.');
}
}
@ -184,12 +186,12 @@ class ArgvInput extends Input
* @param string $shortcut The short option key
* @param mixed $value The value for the option
*
* @throws \RuntimeException When option given doesn't exist
* @throws RuntimeException When option given doesn't exist
*/
private function addShortOption($shortcut, $value)
{
if (!$this->definition->hasShortcut($shortcut)) {
throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
}
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
@ -201,12 +203,12 @@ class ArgvInput extends Input
* @param string $name The long option key
* @param mixed $value The value for the option
*
* @throws \RuntimeException When option given doesn't exist
* @throws RuntimeException When option given doesn't exist
*/
private function addLongOption($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
}
$option = $this->definition->getOption($name);
@ -217,7 +219,7 @@ class ArgvInput extends Input
}
if (null !== $value && !$option->acceptValue()) {
throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
}
if (null === $value && $option->acceptValue() && count($this->parsed)) {
@ -235,7 +237,7 @@ class ArgvInput extends Input
if (null === $value) {
if ($option->isValueRequired()) {
throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name));
}
if (!$option->isArray()) {

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Input;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\InvalidOptionException;
/**
* ArrayInput represents an input provided as an array.
*
@ -149,12 +152,12 @@ class ArrayInput extends Input
* @param string $shortcut The short option key
* @param mixed $value The value for the option
*
* @throws \InvalidArgumentException When option given doesn't exist
* @throws InvalidOptionException When option given doesn't exist
*/
private function addShortOption($shortcut, $value)
{
if (!$this->definition->hasShortcut($shortcut)) {
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut));
}
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
@ -166,20 +169,20 @@ class ArrayInput extends Input
* @param string $name The long option key
* @param mixed $value The value for the option
*
* @throws \InvalidArgumentException When option given doesn't exist
* @throws \InvalidArgumentException When a required value is missing
* @throws InvalidOptionException When option given doesn't exist
* @throws InvalidOptionException When a required value is missing
*/
private function addLongOption($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
}
$option = $this->definition->getOption($name);
if (null === $value) {
if ($option->isValueRequired()) {
throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name));
throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name));
}
$value = $option->isValueOptional() ? $option->getDefault() : true;
@ -194,12 +197,12 @@ class ArrayInput extends Input
* @param string $name The argument name
* @param mixed $value The value for the argument
*
* @throws \InvalidArgumentException When argument given doesn't exist
* @throws InvalidArgumentException When argument given doesn't exist
*/
private function addArgument($name, $value)
{
if (!$this->definition->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
$this->arguments[$name] = $value;

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Input;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
/**
* Input is the base class for all concrete Input classes.
*
@ -69,7 +72,7 @@ abstract class Input implements InputInterface
/**
* Validates the input.
*
* @throws \RuntimeException When not enough arguments are given
* @throws RuntimeException When not enough arguments are given
*/
public function validate()
{
@ -81,7 +84,7 @@ abstract class Input implements InputInterface
});
if (count($missingArguments) > 0) {
throw new \RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
}
}
@ -122,12 +125,12 @@ abstract class Input implements InputInterface
*
* @return mixed The argument value
*
* @throws \InvalidArgumentException When argument given doesn't exist
* @throws InvalidArgumentException When argument given doesn't exist
*/
public function getArgument($name)
{
if (!$this->definition->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $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();
@ -139,12 +142,12 @@ abstract class Input implements InputInterface
* @param string $name The argument name
* @param string $value The argument value
*
* @throws \InvalidArgumentException When argument given doesn't exist
* @throws InvalidArgumentException When argument given doesn't exist
*/
public function setArgument($name, $value)
{
if (!$this->definition->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
$this->arguments[$name] = $value;
@ -179,12 +182,12 @@ abstract class Input implements InputInterface
*
* @return mixed The option value
*
* @throws \InvalidArgumentException When option given doesn't exist
* @throws InvalidArgumentException When option given doesn't exist
*/
public function getOption($name)
{
if (!$this->definition->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $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();
@ -196,12 +199,12 @@ abstract class Input implements InputInterface
* @param string $name The option name
* @param string|bool $value The option value
*
* @throws \InvalidArgumentException When option given doesn't exist
* @throws InvalidArgumentException When option given doesn't exist
*/
public function setOption($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
}
$this->options[$name] = $value;

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Input;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
/**
* Represents a command line argument.
*
@ -35,14 +38,14 @@ class InputArgument
* @param string $description A description text
* @param mixed $default The default value (for self::OPTIONAL mode only)
*
* @throws \InvalidArgumentException When argument mode is not valid
* @throws InvalidArgumentException When argument mode is not valid
*/
public function __construct($name, $mode = null, $description = '', $default = null)
{
if (null === $mode) {
$mode = self::OPTIONAL;
} elseif (!is_int($mode) || $mode > 7 || $mode < 1) {
throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
}
$this->name = $name;
@ -87,19 +90,19 @@ class InputArgument
*
* @param mixed $default The default value
*
* @throws \LogicException When incorrect default value is given
* @throws LogicException When incorrect default value is given
*/
public function setDefault($default = null)
{
if (self::REQUIRED === $this->mode && null !== $default) {
throw new \LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
}
if ($this->isArray()) {
if (null === $default) {
$default = array();
} elseif (!is_array($default)) {
throw new \LogicException('A default value for an array argument must be an array.');
throw new LogicException('A default value for an array argument must be an array.');
}
}

View file

@ -14,6 +14,8 @@ namespace Symfony\Component\Console\Input;
use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
/**
* A InputDefinition represents a set of valid command line arguments and options.
@ -100,20 +102,20 @@ class InputDefinition
*
* @param InputArgument $argument An InputArgument object
*
* @throws \LogicException When incorrect argument is given
* @throws LogicException When incorrect argument is given
*/
public function addArgument(InputArgument $argument)
{
if (isset($this->arguments[$argument->getName()])) {
throw new \LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
}
if ($this->hasAnArrayArgument) {
throw new \LogicException('Cannot add an argument after an array argument.');
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.');
throw new LogicException('Cannot add a required argument after an optional one.');
}
if ($argument->isArray()) {
@ -136,12 +138,12 @@ class InputDefinition
*
* @return InputArgument An InputArgument object
*
* @throws \InvalidArgumentException When argument given doesn't exist
* @throws InvalidArgumentException When argument given doesn't exist
*/
public function getArgument($name)
{
if (!$this->hasArgument($name)) {
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
@ -237,18 +239,18 @@ class InputDefinition
*
* @param InputOption $option An InputOption object
*
* @throws \LogicException When option given already exist
* @throws LogicException When option given already exist
*/
public function addOption(InputOption $option)
{
if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
}
if ($option->getShortcut()) {
foreach (explode('|', $option->getShortcut()) as $shortcut) {
if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
}
}
}
@ -268,12 +270,12 @@ class InputDefinition
*
* @return InputOption A InputOption object
*
* @throws \InvalidArgumentException When option given doesn't exist
* @throws InvalidArgumentException When option given doesn't exist
*/
public function getOption($name)
{
if (!$this->hasOption($name)) {
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
}
return $this->options[$name];
@ -347,12 +349,12 @@ class InputDefinition
*
* @return string The InputOption name
*
* @throws \InvalidArgumentException When option given does not exist
* @throws InvalidArgumentException When option given does not exist
*/
private function shortcutToName($shortcut)
{
if (!isset($this->shortcuts[$shortcut])) {
throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
}
return $this->shortcuts[$shortcut];

View file

@ -88,7 +88,7 @@ interface InputInterface
* @param string $name The argument name
* @param string $value The argument value
*
* @throws \InvalidArgumentException When argument given doesn't exist
* @throws InvalidArgumentException When argument given doesn't exist
*/
public function setArgument($name, $value);
@ -123,7 +123,7 @@ interface InputInterface
* @param string $name The option name
* @param string|bool $value The option value
*
* @throws \InvalidArgumentException When option given doesn't exist
* @throws InvalidArgumentException When option given doesn't exist
*/
public function setOption($name, $value);

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Input;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
/**
* Represents a command line option.
*
@ -36,9 +39,9 @@ class InputOption
* @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
* @param int $mode The option mode: One of the VALUE_* constants
* @param string $description A description text
* @param mixed $default The default value (must be null for self::VALUE_REQUIRED or self::VALUE_NONE)
* @param mixed $default The default value (must be null for self::VALUE_NONE)
*
* @throws \InvalidArgumentException If option mode is invalid or incompatible
* @throws InvalidArgumentException If option mode is invalid or incompatible
*/
public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
{
@ -47,7 +50,7 @@ class InputOption
}
if (empty($name)) {
throw new \InvalidArgumentException('An option name cannot be empty.');
throw new InvalidArgumentException('An option name cannot be empty.');
}
if (empty($shortcut)) {
@ -63,14 +66,14 @@ class InputOption
$shortcut = implode('|', $shortcuts);
if (empty($shortcut)) {
throw new \InvalidArgumentException('An option shortcut cannot be empty.');
throw new InvalidArgumentException('An option shortcut cannot be empty.');
}
}
if (null === $mode) {
$mode = self::VALUE_NONE;
} elseif (!is_int($mode) || $mode > 15 || $mode < 1) {
throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
}
$this->name = $name;
@ -79,7 +82,7 @@ class InputOption
$this->description = $description;
if ($this->isArray() && !$this->acceptValue()) {
throw new \InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
}
$this->setDefault($default);
@ -150,19 +153,19 @@ class InputOption
*
* @param mixed $default The default value
*
* @throws \LogicException When incorrect default value is given
* @throws LogicException When incorrect default value is given
*/
public function setDefault($default = null)
{
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
throw new \LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
throw new LogicException('Cannot set a default value when using InputOption::VALUE_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.');
throw new LogicException('A default value for an array option must be an array.');
}
}

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Input;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* StringInput represents an input provided as a string.
*
@ -55,7 +57,7 @@ class StringInput extends ArgvInput
*
* @return array An array of tokens
*
* @throws \InvalidArgumentException When unable to parse input (should never happen)
* @throws InvalidArgumentException When unable to parse input (should never happen)
*/
private function tokenize($input)
{
@ -72,7 +74,7 @@ class StringInput extends ArgvInput
$tokens[] = stripcslashes($match[1]);
} else {
// should never happen
throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
}
$cursor += strlen($match[0]);

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -131,7 +131,7 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
PHP_OS,
);
return false !== stristr(implode(';', $checks), 'OS400');
return false !== stripos(implode(';', $checks), 'OS400');
}
/**

View file

@ -96,7 +96,7 @@ class NullOutput implements OutputInterface
/**
* {@inheritdoc}
*/
public function writeln($messages, $type = self::OUTPUT_NORMAL)
public function writeln($messages, $options = self::OUTPUT_NORMAL)
{
// do nothing
}
@ -104,7 +104,7 @@ class NullOutput implements OutputInterface
/**
* {@inheritdoc}
*/
public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
{
// do nothing
}

View file

@ -117,22 +117,28 @@ abstract class Output implements OutputInterface
/**
* {@inheritdoc}
*/
public function writeln($messages, $type = self::OUTPUT_NORMAL)
public function writeln($messages, $options = self::OUTPUT_NORMAL)
{
$this->write($messages, true, $type);
$this->write($messages, true, $options);
}
/**
* {@inheritdoc}
*/
public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
{
if (self::VERBOSITY_QUIET === $this->verbosity) {
$messages = (array) $messages;
$types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
$type = $types & $options ?: self::OUTPUT_NORMAL;
$verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
$verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;
if ($verbosity > $this->getVerbosity()) {
return;
}
$messages = (array) $messages;
foreach ($messages as $message) {
switch ($type) {
case OutputInterface::OUTPUT_NORMAL:
@ -143,8 +149,6 @@ abstract class Output implements OutputInterface
case OutputInterface::OUTPUT_PLAIN:
$message = strip_tags($this->formatter->format($message));
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
}
$this->doWrite($message, $newline);

View file

@ -20,36 +20,32 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
*/
interface OutputInterface
{
const VERBOSITY_QUIET = 0;
const VERBOSITY_NORMAL = 1;
const VERBOSITY_VERBOSE = 2;
const VERBOSITY_VERY_VERBOSE = 3;
const VERBOSITY_DEBUG = 4;
const VERBOSITY_QUIET = 16;
const VERBOSITY_NORMAL = 32;
const VERBOSITY_VERBOSE = 64;
const VERBOSITY_VERY_VERBOSE = 128;
const VERBOSITY_DEBUG = 256;
const OUTPUT_NORMAL = 0;
const OUTPUT_RAW = 1;
const OUTPUT_PLAIN = 2;
const OUTPUT_NORMAL = 1;
const OUTPUT_RAW = 2;
const OUTPUT_PLAIN = 4;
/**
* Writes a message to the output.
*
* @param string|array $messages The message as an array of lines or a single string
* @param bool $newline Whether to add a newline
* @param int $type The type of output (one of the OUTPUT constants)
*
* @throws \InvalidArgumentException When unknown output type is given
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL);
public function write($messages, $newline = false, $options = 0);
/**
* Writes a message to the output and adds a newline at the end.
*
* @param string|array $messages The message as an array of lines or a single string
* @param int $type The type of output (one of the OUTPUT constants)
*
* @throws \InvalidArgumentException When unknown output type is given
* @param string|array $messages The message as an array of lines of a single string
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
public function writeln($messages, $type = self::OUTPUT_NORMAL);
public function writeln($messages, $options = 0);
/**
* Sets the verbosity of the output.

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Output;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
@ -38,12 +40,12 @@ class StreamOutput extends Output
* @param bool|null $decorated Whether to decorate messages (null for auto-guessing)
* @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
*
* @throws \InvalidArgumentException When first argument is not a real stream
* @throws InvalidArgumentException When first argument is not a real stream
*/
public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
{
if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
}
$this->stream = $stream;
@ -72,7 +74,7 @@ class StreamOutput extends Output
{
if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {
// should never happen
throw new \RuntimeException('Unable to write output.');
throw new RuntimeException('Unable to write output.');
}
fflush($this->stream);

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Question;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* Represents a choice question.
*
@ -126,7 +128,7 @@ class ChoiceQuestion extends Question
if ($multiselect) {
// Check for a separated comma values
if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
throw new \InvalidArgumentException(sprintf($errorMessage, $selected));
throw new InvalidArgumentException(sprintf($errorMessage, $selected));
}
$selectedChoices = explode(',', $selectedChoices);
} else {
@ -143,7 +145,7 @@ class ChoiceQuestion extends Question
}
if (count($results) > 1) {
throw new \InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
}
$result = array_search($value, $choices);
@ -159,7 +161,7 @@ class ChoiceQuestion extends Question
}
if (false === $result) {
throw new \InvalidArgumentException(sprintf($errorMessage, $value));
throw new InvalidArgumentException(sprintf($errorMessage, $value));
}
$multiselectChoices[] = (string) $result;

View file

@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Question;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
/**
* Represents a Question.
*
@ -76,12 +79,12 @@ class Question
*
* @return Question The current instance
*
* @throws \LogicException In case the autocompleter is also used
* @throws LogicException In case the autocompleter is also used
*/
public function setHidden($hidden)
{
if ($this->autocompleterValues) {
throw new \LogicException('A hidden question cannot use the autocompleter.');
throw new LogicException('A hidden question cannot use the autocompleter.');
}
$this->hidden = (bool) $hidden;
@ -130,23 +133,23 @@ class Question
*
* @return Question The current instance
*
* @throws \InvalidArgumentException
* @throws \LogicException
* @throws InvalidArgumentException
* @throws LogicException
*/
public function setAutocompleterValues($values)
{
if (is_array($values) && $this->isAssoc($values)) {
$values = array_merge(array_keys($values), array_values($values));
if (is_array($values)) {
$values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
}
if (null !== $values && !is_array($values)) {
if (!$values instanceof \Traversable || $values instanceof \Countable) {
throw new \InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.');
if (!$values instanceof \Traversable || !$values instanceof \Countable) {
throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.');
}
}
if ($this->hidden) {
throw new \LogicException('A hidden question cannot use the autocompleter.');
throw new LogicException('A hidden question cannot use the autocompleter.');
}
$this->autocompleterValues = $values;
@ -187,12 +190,12 @@ class Question
*
* @return Question The current instance
*
* @throws \InvalidArgumentException In case the number of attempts is invalid.
* @throws InvalidArgumentException In case the number of attempts is invalid.
*/
public function setMaxAttempts($attempts)
{
if (null !== $attempts && $attempts < 1) {
throw new \InvalidArgumentException('Maximum number of attempts must be a positive value.');
throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
}
$this->attempts = $attempts;

View file

@ -1,67 +1,20 @@
Console Component
=================
Console eases the creation of beautiful and testable command line interfaces.
The Application object manages the CLI application:
```php
use Symfony\Component\Console\Application;
$console = new Application();
$console->run();
```
The ``run()`` method parses the arguments and options passed on the command
line and executes the right command.
Registering a new command can easily be done via the ``register()`` method,
which returns a ``Command`` instance:
```php
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
$console
->register('ls')
->setDefinition(array(
new InputArgument('dir', InputArgument::REQUIRED, 'Directory name'),
))
->setDescription('Displays the files in the given directory')
->setCode(function (InputInterface $input, OutputInterface $output) {
$dir = $input->getArgument('dir');
$output->writeln(sprintf('Dir listing for <info>%s</info>', $dir));
})
;
```
You can also register new commands via classes.
The component provides a lot of features like output coloring, input and
output abstractions (so that you can easily unit-test your commands),
validation, automatic help messages, ...
Tests
-----
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/Console/
$ composer install
$ phpunit
Third Party
-----------
`Resources/bin/hiddeninput.exe` is a third party binary provided within this
component. Find sources and license at https://github.com/Seldaek/hidden-input.
The Console component eases the creation of beautiful and testable command line
interfaces.
Resources
---------
[The Console Component](https://symfony.com/doc/current/components/console.html)
* [Documentation](https://symfony.com/doc/current/components/console/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
[How to create a Console Command](https://symfony.com/doc/current/cookbook/console/console_command.html)
Credits
-------
`Resources/bin/hiddeninput.exe` is a third party binary provided within this
component. Find sources and license at https://github.com/Seldaek/hidden-input.

View file

@ -11,6 +11,7 @@
namespace Symfony\Component\Console;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Process\ProcessBuilder;
@ -22,6 +23,8 @@ use Symfony\Component\Process\PhpExecutableFinder;
* Support for history and completion only works with a PHP compiled
* with readline support (either --with-readline or --with-libedit)
*
* @deprecated since version 2.8, to be removed in 3.0.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Martin Hasoň <martin.hason@gmail.com>
*/
@ -43,6 +46,8 @@ class Shell
*/
public function __construct(Application $application)
{
@trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
$this->hasReadline = function_exists('readline');
$this->application = $application;
$this->history = getenv('HOME').'/.history_'.$application->getName();
@ -67,7 +72,7 @@ class Shell
if ($this->processIsolation) {
$finder = new PhpExecutableFinder();
$php = $finder->find();
$this->output->writeln(<<<EOF
$this->output->writeln(<<<'EOF'
<info>Running with process isolation, you should consider this:</info>
* each command is executed as separate process,
* commands don't support interactivity, all params must be passed explicitly,
@ -222,7 +227,7 @@ EOF;
$this->processIsolation = (bool) $processIsolation;
if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) {
throw new \RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
throw new RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
}
}
}

View file

@ -12,6 +12,7 @@
namespace Symfony\Component\Console\Style;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\ProgressBar;
@ -109,7 +110,7 @@ class SymfonyStyle extends OutputStyle
$this->autoPrependBlock();
$this->writeln(array(
sprintf('<comment>%s</>', $message),
sprintf('<comment>%s</>', str_repeat('=', strlen($message))),
sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
));
$this->newLine();
}
@ -122,7 +123,7 @@ class SymfonyStyle extends OutputStyle
$this->autoPrependBlock();
$this->writeln(array(
sprintf('<comment>%s</>', $message),
sprintf('<comment>%s</>', str_repeat('-', strlen($message))),
sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
));
$this->newLine();
}
@ -148,14 +149,22 @@ class SymfonyStyle extends OutputStyle
{
$this->autoPrependText();
if (!is_array($message)) {
$this->writeln(sprintf(' // %s', $message));
return;
$messages = is_array($message) ? array_values($message) : array($message);
foreach ($messages as $message) {
$this->writeln(sprintf(' %s', $message));
}
}
foreach ($message as $element) {
$this->text($element);
/**
* {@inheritdoc}
*/
public function comment($message)
{
$this->autoPrependText();
$messages = is_array($message) ? array_values($message) : array($message);
foreach ($messages as $message) {
$this->writeln(sprintf(' // %s', $message));
}
}
@ -294,7 +303,7 @@ class SymfonyStyle extends OutputStyle
{
$progressBar = parent::createProgressBar($max);
if ('\\' === DIRECTORY_SEPARATOR) {
if ('\\' !== DIRECTORY_SEPARATOR) {
$progressBar->setEmptyBarCharacter('░'); // light shade character \u2591
$progressBar->setProgressCharacter('');
$progressBar->setBarCharacter('▓'); // dark shade character \u2593
@ -361,7 +370,7 @@ class SymfonyStyle extends OutputStyle
private function getProgressBar()
{
if (!$this->progressBar) {
throw new \RuntimeException('The ProgressBar is not started.');
throw new RuntimeException('The ProgressBar is not started.');
}
return $this->progressBar;

View file

@ -16,11 +16,12 @@
}
],
"require": {
"php": ">=5.3.9"
"php": ">=5.3.9",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"symfony/event-dispatcher": "~2.1",
"symfony/process": "~2.1",
"symfony/event-dispatcher": "~2.1|~3.0.0",
"symfony/process": "~2.1|~3.0.0",
"psr/log": "~1.0"
},
"suggest": {
@ -29,12 +30,15 @@
"psr/log": "For using the console logger"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Console\\": "" }
"psr-4": { "Symfony\\Component\\Console\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "2.8-dev"
}
}
}

View file

@ -26,4 +26,14 @@
</exclude>
</whitelist>
</filter>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
<arguments>
<array>
<element key="time-sensitive"><string>Symfony\Component\Console</string></element>
</array>
</arguments>
</listener>
</listeners>
</phpunit>

View file

@ -1,6 +1,12 @@
CHANGELOG
=========
2.8.0
-----
* Added the `CssSelectorConverter` class as a non-static API for the component.
* Deprecated the `CssSelector` static API of the component.
2.1.0
-----

View file

@ -11,12 +11,7 @@
namespace Symfony\Component\CssSelector;
use Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
use Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
use Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
use Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
use Symfony\Component\CssSelector\XPath\Translator;
@trigger_error('The '.__NAMESPACE__.'\CssSelector class is deprecated since version 2.8 and will be removed in 3.0. Use directly the \Symfony\Component\CssSelector\CssSelectorConverter class instead.', E_USER_DEPRECATED);
/**
* CssSelector is the main entry point of the component and can convert CSS
@ -61,6 +56,8 @@ use Symfony\Component\CssSelector\XPath\Translator;
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated as of 2.8, will be removed in 3.0. Use the \Symfony\Component\CssSelector\CssSelectorConverter class instead.
*/
class CssSelector
{
@ -78,20 +75,9 @@ class CssSelector
*/
public static function toXPath($cssExpr, $prefix = 'descendant-or-self::')
{
$translator = new Translator();
$converter = new CssSelectorConverter(self::$html);
if (self::$html) {
$translator->registerExtension(new HtmlExtension($translator));
}
$translator
->registerParserShortcut(new EmptyStringParser())
->registerParserShortcut(new ElementParser())
->registerParserShortcut(new ClassParser())
->registerParserShortcut(new HashParser())
;
return $translator->cssToXPath($cssExpr, $prefix);
return $converter->toXPath($cssExpr, $prefix);
}
/**

View file

@ -0,0 +1,65 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\CssSelector;
use Symfony\Component\CssSelector\Parser\Shortcut\ClassParser;
use Symfony\Component\CssSelector\Parser\Shortcut\ElementParser;
use Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser;
use Symfony\Component\CssSelector\Parser\Shortcut\HashParser;
use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension;
use Symfony\Component\CssSelector\XPath\Translator;
/**
* CssSelectorConverter is the main entry point of the component and can convert CSS
* selectors to XPath expressions.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class CssSelectorConverter
{
private $translator;
/**
* @param bool $html Whether HTML support should be enabled. Disable it for XML documents.
*/
public function __construct($html = true)
{
$this->translator = new Translator();
if ($html) {
$this->translator->registerExtension(new HtmlExtension($this->translator));
}
$this->translator
->registerParserShortcut(new EmptyStringParser())
->registerParserShortcut(new ElementParser())
->registerParserShortcut(new ClassParser())
->registerParserShortcut(new HashParser())
;
}
/**
* Translates a CSS expression to its XPath equivalent.
*
* Optionally, a prefix can be added to the resulting XPath
* expression with the $prefix parameter.
*
* @param string $cssExpr The CSS expression.
* @param string $prefix An optional prefix for the XPath expression.
*
* @return string
*/
public function toXPath($cssExpr, $prefix = 'descendant-or-self::')
{
return $this->translator->cssToXPath($cssExpr, $prefix);
}
}

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
abstract class AbstractNode implements NodeInterface
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class AttributeNode extends AbstractNode
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class ClassNode extends AbstractNode
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class CombinedSelectorNode extends AbstractNode
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class ElementNode extends AbstractNode
{

View file

@ -20,6 +20,8 @@ use Symfony\Component\CssSelector\Parser\Token;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class FunctionNode extends AbstractNode
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class HashNode extends AbstractNode
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class NegationNode extends AbstractNode
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
interface NodeInterface
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class PseudoNode extends AbstractNode
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Node;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class SelectorNode extends AbstractNode
{

View file

@ -20,6 +20,8 @@ namespace Symfony\Component\CssSelector\Node;
* @see http://www.w3.org/TR/selectors/#specificity
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class Specificity
{

View file

@ -21,6 +21,8 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class CommentHandler implements HandlerInterface
{

View file

@ -21,6 +21,8 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
interface HandlerInterface
{

View file

@ -24,6 +24,8 @@ use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class HashHandler implements HandlerInterface
{

View file

@ -24,6 +24,8 @@ use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class IdentifierHandler implements HandlerInterface
{

View file

@ -23,6 +23,8 @@ use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class NumberHandler implements HandlerInterface
{

View file

@ -26,6 +26,8 @@ use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class StringHandler implements HandlerInterface
{

View file

@ -22,6 +22,8 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class WhitespaceHandler implements HandlerInterface
{

View file

@ -22,6 +22,8 @@ use Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class Parser implements ParserInterface
{

View file

@ -20,6 +20,8 @@ use Symfony\Component\CssSelector\Node\SelectorNode;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
interface ParserInterface
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Parser;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class Reader
{

View file

@ -23,6 +23,8 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class ClassParser implements ParserInterface
{

View file

@ -22,6 +22,8 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class ElementParser implements ParserInterface
{

View file

@ -26,6 +26,8 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class EmptyStringParser implements ParserInterface
{

View file

@ -23,6 +23,8 @@ use Symfony\Component\CssSelector\Parser\ParserInterface;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class HashParser implements ParserInterface
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Parser;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class Token
{

View file

@ -21,6 +21,8 @@ use Symfony\Component\CssSelector\Exception\SyntaxErrorException;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class TokenStream
{

View file

@ -23,6 +23,8 @@ use Symfony\Component\CssSelector\Parser\TokenStream;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class Tokenizer
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Parser\Tokenizer;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class TokenizerEscaping
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\Parser\Tokenizer;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class TokenizerPatterns
{

View file

@ -1,47 +1,20 @@
CssSelector Component
=====================
CssSelector converts CSS selectors to XPath expressions.
The component only goal is to convert CSS selectors to their XPath
equivalents:
```php
use Symfony\Component\CssSelector\CssSelector;
print CssSelector::toXPath('div.item > h4 > a');
```
HTML and XML are different
--------------------------
The `CssSelector` component comes with an `HTML` extension which is enabled by
default. If you need to use this component with `XML` documents, you have to
disable this `HTML` extension. That's because, `HTML` tag & attribute names
are always lower-cased, but case-sensitive in `XML`:
```php
// disable `HTML` extension:
CssSelector::disableHtmlExtension();
// re-enable `HTML` extension:
CssSelector::enableHtmlExtension();
```
When the `HTML` extension is enabled, tag names are lower-cased, attribute
names are lower-cased, the following extra pseudo-classes are supported:
`checked`, `link`, `disabled`, `enabled`, `selected`, `invalid`, `hover`,
`visited`, and the `lang()` function is also added.
The CssSelector component converts CSS selectors to XPath expressions.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/css_selector.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
Credits
-------
This component is a port of the Python cssselect library
[v0.7.1](https://github.com/SimonSapin/cssselect/releases/tag/v0.7.1),
which is distributed under the BSD license.
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/CssSelector/
$ composer install
$ phpunit

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\XPath\Extension;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
abstract class AbstractExtension implements ExtensionInterface
{

View file

@ -21,6 +21,8 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class AttributeMatchingExtension extends AbstractExtension
{

View file

@ -20,6 +20,8 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class CombinationExtension extends AbstractExtension
{

View file

@ -18,6 +18,8 @@ namespace Symfony\Component\CssSelector\XPath\Extension;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
interface ExtensionInterface
{

View file

@ -25,6 +25,8 @@ use Symfony\Component\CssSelector\XPath\XPathExpr;
* which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class FunctionExtension extends AbstractExtension
{

Some files were not shown because too many files have changed in this diff Show more