remove dependencies
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
/Tests export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
@@ -1,2 +0,0 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
@@ -1,118 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* ApcClassLoader implements a wrapping autoloader cached in APC for PHP 5.3.
|
||||
*
|
||||
* It expects an object implementing a findFile method to find the file. This
|
||||
* allow using it as a wrapper around the other loaders of the component (the
|
||||
* ClassLoader and the UniversalClassLoader for instance) but also around any
|
||||
* other autoloader following this convention (the Composer one for instance)
|
||||
*
|
||||
* $loader = new ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* $cachedLoader = new ApcClassLoader('my_prefix', $loader);
|
||||
*
|
||||
* // activate the cached autoloader
|
||||
* $cachedLoader->register();
|
||||
*
|
||||
* // eventually deactivate the non-cached loader if it was registered previously
|
||||
* // to be sure to use the cached one.
|
||||
* $loader->unregister();
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Kris Wallsmith <kris@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ApcClassLoader
|
||||
{
|
||||
private $prefix;
|
||||
private $classFinder;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $prefix A prefix to create a namespace in APC
|
||||
* @param object $classFinder An object that implements findFile() method.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($prefix, $classFinder)
|
||||
{
|
||||
if (!extension_loaded('apc')) {
|
||||
throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.');
|
||||
}
|
||||
|
||||
if (!method_exists($classFinder, 'findFile')) {
|
||||
throw new \InvalidArgumentException('The class finder must implement a "findFile" method.');
|
||||
}
|
||||
|
||||
$this->prefix = $prefix;
|
||||
$this->classFinder = $classFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param Boolean $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return Boolean|null True, if loaded
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
require $file;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a file by class name while caching lookups to APC.
|
||||
*
|
||||
* @param string $class A class name to resolve to file
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
if (false === $file = apc_fetch($this->prefix.$class)) {
|
||||
apc_store($this->prefix.$class, $file = $this->classFinder->findFile($class));
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* ApcUniversalClassLoader implements a "universal" autoloader cached in APC for PHP 5.3.
|
||||
*
|
||||
* It is able to load classes that use either:
|
||||
*
|
||||
* * The technical interoperability standards for PHP 5.3 namespaces and
|
||||
* class names (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md);
|
||||
*
|
||||
* * The PEAR naming convention for classes (http://pear.php.net/).
|
||||
*
|
||||
* Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
|
||||
* looked for in a list of locations to ease the vendoring of a sub-set of
|
||||
* classes for large projects.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* require 'vendor/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
|
||||
* require 'vendor/symfony/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php';
|
||||
*
|
||||
* use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
|
||||
*
|
||||
* $loader = new ApcUniversalClassLoader('apc.prefix.');
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->registerNamespaces(array(
|
||||
* 'Symfony\Component' => __DIR__.'/component',
|
||||
* 'Symfony' => __DIR__.'/framework',
|
||||
* 'Sensio' => array(__DIR__.'/src', __DIR__.'/vendor'),
|
||||
* ));
|
||||
*
|
||||
* // register a library using the PEAR naming convention
|
||||
* $loader->registerPrefixes(array(
|
||||
* 'Swift_' => __DIR__.'/Swift',
|
||||
* ));
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Kris Wallsmith <kris@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ApcUniversalClassLoader extends UniversalClassLoader
|
||||
{
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $prefix A prefix to create a namespace in APC
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($prefix)
|
||||
{
|
||||
if (!extension_loaded('apc')) {
|
||||
throw new \RuntimeException('Unable to use ApcUniversalClassLoader as APC is not enabled.');
|
||||
}
|
||||
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a file by class name while caching lookups to APC.
|
||||
*
|
||||
* @param string $class A class name to resolve to file
|
||||
*
|
||||
* @return string|null The path, if found
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
if (false === $file = apc_fetch($this->prefix.$class)) {
|
||||
apc_store($this->prefix.$class, $file = parent::findFile($class));
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added a DebugClassLoader able to wrap any autoloader providing a findFile
|
||||
method
|
||||
* added a new ApcClassLoader and XcacheClassLoader using composition to wrap
|
||||
other loaders
|
||||
* added a new ClassLoader which does not distinguish between namespaced and
|
||||
pear-like classes (as the PEAR convention is a subset of PSR-0) and
|
||||
supports using Composer's namespace maps
|
||||
* added a class map generator
|
||||
* added support for loading globally-installed PEAR packages
|
||||
@@ -1,333 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* ClassCollectionLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ClassCollectionLoader
|
||||
{
|
||||
private static $loaded;
|
||||
private static $seen;
|
||||
private static $useTokenizer = true;
|
||||
|
||||
/**
|
||||
* Loads a list of classes and caches them in one big file.
|
||||
*
|
||||
* @param array $classes An array of classes to load
|
||||
* @param string $cacheDir A cache directory
|
||||
* @param string $name The cache name prefix
|
||||
* @param Boolean $autoReload Whether to flush the cache when the cache is stale or not
|
||||
* @param Boolean $adaptive Whether to remove already declared classes or not
|
||||
* @param string $extension File extension of the resulting file
|
||||
*
|
||||
* @throws \InvalidArgumentException When class can't be loaded
|
||||
*/
|
||||
public static function load($classes, $cacheDir, $name, $autoReload, $adaptive = false, $extension = '.php')
|
||||
{
|
||||
// each $name can only be loaded once per PHP process
|
||||
if (isset(self::$loaded[$name])) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$loaded[$name] = true;
|
||||
|
||||
$declared = array_merge(get_declared_classes(), get_declared_interfaces());
|
||||
if (function_exists('get_declared_traits')) {
|
||||
$declared = array_merge($declared, get_declared_traits());
|
||||
}
|
||||
|
||||
if ($adaptive) {
|
||||
// don't include already declared classes
|
||||
$classes = array_diff($classes, $declared);
|
||||
|
||||
// the cache is different depending on which classes are already declared
|
||||
$name = $name.'-'.substr(md5(implode('|', $classes)), 0, 5);
|
||||
}
|
||||
|
||||
$classes = array_unique($classes);
|
||||
|
||||
$cache = $cacheDir.'/'.$name.$extension;
|
||||
|
||||
// auto-reload
|
||||
$reload = false;
|
||||
if ($autoReload) {
|
||||
$metadata = $cacheDir.'/'.$name.$extension.'.meta';
|
||||
if (!is_file($metadata) || !is_file($cache)) {
|
||||
$reload = true;
|
||||
} else {
|
||||
$time = filemtime($cache);
|
||||
$meta = unserialize(file_get_contents($metadata));
|
||||
|
||||
sort($meta[1]);
|
||||
sort($classes);
|
||||
|
||||
if ($meta[1] != $classes) {
|
||||
$reload = true;
|
||||
} else {
|
||||
foreach ($meta[0] as $resource) {
|
||||
if (!is_file($resource) || filemtime($resource) > $time) {
|
||||
$reload = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$reload && is_file($cache)) {
|
||||
require_once $cache;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$files = array();
|
||||
$content = '';
|
||||
foreach (self::getOrderedClasses($classes) as $class) {
|
||||
if (in_array($class->getName(), $declared)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$files[] = $class->getFileName();
|
||||
|
||||
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName()));
|
||||
|
||||
// add namespace declaration for global code
|
||||
if (!$class->inNamespace()) {
|
||||
$c = "\nnamespace\n{\n".self::stripComments($c)."\n}\n";
|
||||
} else {
|
||||
$c = self::fixNamespaceDeclarations('<?php '.$c);
|
||||
$c = preg_replace('/^\s*<\?php/', '', $c);
|
||||
}
|
||||
|
||||
$content .= $c;
|
||||
}
|
||||
|
||||
// cache the core classes
|
||||
if (!is_dir(dirname($cache))) {
|
||||
mkdir(dirname($cache), 0777, true);
|
||||
}
|
||||
self::writeCacheFile($cache, '<?php '.$content);
|
||||
|
||||
if ($autoReload) {
|
||||
// save the resources
|
||||
self::writeCacheFile($metadata, serialize(array($files, $classes)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds brackets around each namespace if it's not already the case.
|
||||
*
|
||||
* @param string $source Namespace string
|
||||
*
|
||||
* @return string Namespaces with brackets
|
||||
*/
|
||||
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";
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
$inNamespace = false;
|
||||
$tokens = token_get_all($source);
|
||||
|
||||
for ($i = 0, $max = count($tokens); $i < $max; $i++) {
|
||||
$token = $tokens[$i];
|
||||
if (is_string($token)) {
|
||||
$output .= $token;
|
||||
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
|
||||
// strip comments
|
||||
continue;
|
||||
} elseif (T_NAMESPACE === $token[0]) {
|
||||
if ($inNamespace) {
|
||||
$output .= "}\n";
|
||||
}
|
||||
$output .= $token[1];
|
||||
|
||||
// namespace name and whitespaces
|
||||
while (($t = $tokens[++$i]) && is_array($t) && in_array($t[0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) {
|
||||
$output .= $t[1];
|
||||
}
|
||||
if (is_string($t) && '{' === $t) {
|
||||
$inNamespace = false;
|
||||
--$i;
|
||||
} else {
|
||||
$output = rtrim($output);
|
||||
$output .= "\n{";
|
||||
$inNamespace = true;
|
||||
}
|
||||
} else {
|
||||
$output .= $token[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($inNamespace) {
|
||||
$output .= "}\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a cache file.
|
||||
*
|
||||
* @param string $file Filename
|
||||
* @param string $content Temporary file content
|
||||
*
|
||||
* @throws \RuntimeException when a cache file cannot be written
|
||||
*/
|
||||
private static function writeCacheFile($file, $content)
|
||||
{
|
||||
$tmpFile = tempnam(dirname($file), basename($file));
|
||||
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
|
||||
@chmod($file, 0666 & ~umask());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes comments from a PHP source string.
|
||||
*
|
||||
* We don't use the PHP php_strip_whitespace() function
|
||||
* as we want the content to be readable and well-formatted.
|
||||
*
|
||||
* @param string $source A PHP string
|
||||
*
|
||||
* @return string The PHP string with the comments removed
|
||||
*/
|
||||
private static function stripComments($source)
|
||||
{
|
||||
if (!function_exists('token_get_all')) {
|
||||
return $source;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
foreach (token_get_all($source) as $token) {
|
||||
if (is_string($token)) {
|
||||
$output .= $token;
|
||||
} elseif (!in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
|
||||
$output .= $token[1];
|
||||
}
|
||||
}
|
||||
|
||||
// replace multiple new lines with a single newline
|
||||
$output = preg_replace(array('/\s+$/Sm', '/\n+/S'), "\n", $output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ordered array of passed classes including all their dependencies.
|
||||
*
|
||||
* @param array $classes
|
||||
*
|
||||
* @return array An array of sorted \ReflectionClass instances (dependencies added if needed)
|
||||
*
|
||||
* @throws \InvalidArgumentException When a class can't be loaded
|
||||
*/
|
||||
private static function getOrderedClasses(array $classes)
|
||||
{
|
||||
$map = array();
|
||||
self::$seen = array();
|
||||
foreach ($classes as $class) {
|
||||
try {
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new \InvalidArgumentException(sprintf('Unable to load class "%s"', $class));
|
||||
}
|
||||
|
||||
$map = array_merge($map, self::getClassHierarchy($reflectionClass));
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
private static function getClassHierarchy(\ReflectionClass $class)
|
||||
{
|
||||
if (isset(self::$seen[$class->getName()])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
self::$seen[$class->getName()] = true;
|
||||
|
||||
$classes = array($class);
|
||||
$parent = $class;
|
||||
while (($parent = $parent->getParentClass()) && $parent->isUserDefined() && !isset(self::$seen[$parent->getName()])) {
|
||||
self::$seen[$parent->getName()] = true;
|
||||
|
||||
array_unshift($classes, $parent);
|
||||
}
|
||||
|
||||
if (function_exists('get_declared_traits')) {
|
||||
foreach ($classes as $c) {
|
||||
foreach (self::getTraits($c) as $trait) {
|
||||
self::$seen[$trait->getName()] = true;
|
||||
|
||||
array_unshift($classes, $trait);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge(self::getInterfaces($class), $classes);
|
||||
}
|
||||
|
||||
private static function getInterfaces(\ReflectionClass $class)
|
||||
{
|
||||
$classes = array();
|
||||
|
||||
foreach ($class->getInterfaces() as $interface) {
|
||||
$classes = array_merge($classes, self::getInterfaces($interface));
|
||||
}
|
||||
|
||||
if ($class->isUserDefined() && $class->isInterface() && !isset(self::$seen[$class->getName()])) {
|
||||
self::$seen[$class->getName()] = true;
|
||||
|
||||
$classes[] = $class;
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
private static function getTraits(\ReflectionClass $class)
|
||||
{
|
||||
$traits = $class->getTraits();
|
||||
$classes = array();
|
||||
while ($trait = array_pop($traits)) {
|
||||
if ($trait->isUserDefined() && !isset(self::$seen[$trait->getName()])) {
|
||||
$classes[] = $trait;
|
||||
|
||||
$traits = array_merge($traits, $trait->getTraits());
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only useful for testing.
|
||||
*/
|
||||
public static function enableTokenizer($bool)
|
||||
{
|
||||
self::$useTokenizer = (Boolean) $bool;
|
||||
}
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* ClassLoader implements an PSR-0 class loader
|
||||
*
|
||||
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
|
||||
*
|
||||
* $loader = new ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->addPrefix('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->addPrefix('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (e.g. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
private $prefixes = array();
|
||||
private $fallbackDirs = array();
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* Returns prefixes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
return $this->prefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns fallback directories.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds prefixes.
|
||||
*
|
||||
* @param array $prefixes Prefixes to add
|
||||
*/
|
||||
public function addPrefixes(array $prefixes)
|
||||
{
|
||||
foreach ($prefixes as $prefix => $path) {
|
||||
$this->addPrefix($prefix, $path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of classes
|
||||
*
|
||||
* @param string $prefix The classes prefix
|
||||
* @param array|string $paths The location(s) of the classes
|
||||
*/
|
||||
public function addPrefix($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
foreach ((array) $paths as $path) {
|
||||
$this->fallbackDirs[] = $path;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (isset($this->prefixes[$prefix])) {
|
||||
$this->prefixes[$prefix] = array_merge(
|
||||
$this->prefixes[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
} else {
|
||||
$this->prefixes[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include for class files.
|
||||
*
|
||||
* @param Boolean $useIncludePath
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param Boolean $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return Boolean|null True, if loaded
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
require $file;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|null The path, if found
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
if ('\\' == $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR;
|
||||
$className = substr($class, $pos + 1);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$classPath = null;
|
||||
$className = $class;
|
||||
}
|
||||
|
||||
$classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
|
||||
|
||||
foreach ($this->prefixes as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
|
||||
return $dir . DIRECTORY_SEPARATOR . $classPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->fallbackDirs as $dir) {
|
||||
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
|
||||
return $dir . DIRECTORY_SEPARATOR . $classPath;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* ClassMapGenerator
|
||||
*
|
||||
* @author Gyula Sallai <salla016@gmail.com>
|
||||
*/
|
||||
class ClassMapGenerator
|
||||
{
|
||||
/**
|
||||
* Generate a class map file
|
||||
*
|
||||
* @param array|string $dirs Directories or a single path to search in
|
||||
* @param string $file The name of the class map file
|
||||
*/
|
||||
public static function dump($dirs, $file)
|
||||
{
|
||||
$dirs = (array) $dirs;
|
||||
$maps = array();
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
$maps = array_merge($maps, static::createMap($dir));
|
||||
}
|
||||
|
||||
file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all files in the given directory searching for classes
|
||||
*
|
||||
* @param Iterator|string $dir The directory to search in or an iterator
|
||||
*
|
||||
* @return array A class map array
|
||||
*/
|
||||
public static function createMap($dir)
|
||||
{
|
||||
if (is_string($dir)) {
|
||||
$dir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
|
||||
}
|
||||
|
||||
$map = array();
|
||||
|
||||
foreach ($dir as $file) {
|
||||
if (!$file->isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $file->getRealPath();
|
||||
|
||||
if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classes = self::findClasses($path);
|
||||
|
||||
foreach ($classes as $class) {
|
||||
$map[$class] = $path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the classes in the given file
|
||||
*
|
||||
* @param string $path The file to check
|
||||
*
|
||||
* @return array The found classes
|
||||
*/
|
||||
private static function findClasses($path)
|
||||
{
|
||||
$contents = file_get_contents($path);
|
||||
$tokens = token_get_all($contents);
|
||||
$T_TRAIT = version_compare(PHP_VERSION, '5.4', '<') ? -1 : T_TRAIT;
|
||||
|
||||
$classes = array();
|
||||
|
||||
$namespace = '';
|
||||
for ($i = 0, $max = count($tokens); $i < $max; $i++) {
|
||||
$token = $tokens[$i];
|
||||
|
||||
if (is_string($token)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = '';
|
||||
|
||||
switch ($token[0]) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
$namespace .= '\\';
|
||||
break;
|
||||
case T_CLASS:
|
||||
case T_INTERFACE:
|
||||
case $T_TRAIT:
|
||||
// Find the classname
|
||||
while (($t = $tokens[++$i]) && is_array($t)) {
|
||||
if (T_STRING === $t[0]) {
|
||||
$class .= $t[1];
|
||||
} elseif ($class !== '' && T_WHITESPACE == $t[0]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$classes[] = ltrim($namespace . $class, '\\');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* Autoloader checking if the class is really defined in the file found.
|
||||
*
|
||||
* The DebugClassLoader will wrap all registered autoloaders providing a
|
||||
* findFile method and will throw an exception if a file is found but does
|
||||
* not declare the class.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class DebugClassLoader
|
||||
{
|
||||
private $classFinder;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $classFinder
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($classFinder)
|
||||
{
|
||||
$this->classFinder = $classFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all autoloaders implementing a findFile method by a DebugClassLoader wrapper.
|
||||
*/
|
||||
public static function enable()
|
||||
{
|
||||
if (!is_array($functions = spl_autoload_functions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($functions as $function) {
|
||||
spl_autoload_unregister($function);
|
||||
}
|
||||
|
||||
foreach ($functions as $function) {
|
||||
if (is_array($function) && method_exists($function[0], 'findFile')) {
|
||||
$function = array(new static($function[0]), 'loadClass');
|
||||
}
|
||||
|
||||
spl_autoload_register($function);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return Boolean|null True, if loaded
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->classFinder->findFile($class)) {
|
||||
require $file;
|
||||
|
||||
if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) {
|
||||
throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* Checks that the class is actually declared in the included file.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DebugUniversalClassLoader extends UniversalClassLoader
|
||||
{
|
||||
/**
|
||||
* Replaces all regular UniversalClassLoader instances by a DebugUniversalClassLoader ones.
|
||||
*/
|
||||
public static function enable()
|
||||
{
|
||||
if (!is_array($functions = spl_autoload_functions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($functions as $function) {
|
||||
spl_autoload_unregister($function);
|
||||
}
|
||||
|
||||
foreach ($functions as $function) {
|
||||
if (is_array($function) && $function[0] instanceof UniversalClassLoader) {
|
||||
$loader = new static();
|
||||
$loader->registerNamespaceFallbacks($function[0]->getNamespaceFallbacks());
|
||||
$loader->registerPrefixFallbacks($function[0]->getPrefixFallbacks());
|
||||
$loader->registerNamespaces($function[0]->getNamespaces());
|
||||
$loader->registerPrefixes($function[0]->getPrefixes());
|
||||
$loader->useIncludePath($function[0]->getUseIncludePath());
|
||||
|
||||
$function[0] = $loader;
|
||||
}
|
||||
|
||||
spl_autoload_register($function);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
require $file;
|
||||
|
||||
if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) {
|
||||
throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2004-2012 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
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,76 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* A class loader that uses a mapping file to look up paths.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class MapClassLoader
|
||||
{
|
||||
private $map = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $map A map where keys are classes and values the absolute file path
|
||||
*/
|
||||
public function __construct(array $map)
|
||||
{
|
||||
$this->map = $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param Boolean $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ('\\' === $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
if (isset($this->map[$class])) {
|
||||
require $this->map[$class];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|null The path, if found
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
if ('\\' === $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
if (isset($this->map[$class])) {
|
||||
return $this->map[$class];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
ClassLoader Component
|
||||
=====================
|
||||
|
||||
ClassLoader loads your project classes automatically if they follow some
|
||||
standard PHP conventions.
|
||||
|
||||
The Universal ClassLoader is able to autoload classes that implement the PSR-0
|
||||
standard or the PEAR naming convention.
|
||||
|
||||
First, register the autoloader:
|
||||
|
||||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
|
||||
|
||||
use Symfony\Component\ClassLoader\UniversalClassLoader;
|
||||
|
||||
$loader = new UniversalClassLoader();
|
||||
$loader->register();
|
||||
|
||||
Then, register some namespaces with the `registerNamespace()` method:
|
||||
|
||||
$loader->registerNamespace('Symfony', __DIR__.'/src');
|
||||
$loader->registerNamespace('Monolog', __DIR__.'/vendor/monolog/src');
|
||||
|
||||
The `registerNamespace()` method takes a namespace prefix and a path where to
|
||||
look for the classes as arguments.
|
||||
|
||||
You can also register a sub-namespaces:
|
||||
|
||||
$loader->registerNamespace('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:
|
||||
|
||||
$loader->registerNamespace('Symfony', array(__DIR__.'/src', __DIR__.'/symfony/src'));
|
||||
|
||||
Alternatively, you can use the `registerNamespaces()` method to register more
|
||||
than one namespace at once:
|
||||
|
||||
$loader->registerNamespaces(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 based version of the universal
|
||||
class loader:
|
||||
|
||||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
|
||||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php';
|
||||
|
||||
use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
|
||||
|
||||
$loader = new ApcUniversalClassLoader('apc.prefix.');
|
||||
|
||||
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.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
phpunit
|
||||
|
||||
If you also want to run the unit tests that depend on other Symfony
|
||||
Components, install dev dependencies before running PHPUnit:
|
||||
|
||||
php composer.phar install --dev
|
||||
@@ -1,319 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* UniversalClassLoader implements a "universal" autoloader for PHP 5.3.
|
||||
*
|
||||
* It is able to load classes that use either:
|
||||
*
|
||||
* * The technical interoperability standards for PHP 5.3 namespaces and
|
||||
* class names (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md);
|
||||
*
|
||||
* * The PEAR naming convention for classes (http://pear.php.net/).
|
||||
*
|
||||
* Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
|
||||
* looked for in a list of locations to ease the vendoring of a sub-set of
|
||||
* classes for large projects.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* $loader = new UniversalClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->registerNamespaces(array(
|
||||
* 'Symfony\Component' => __DIR__.'/component',
|
||||
* 'Symfony' => __DIR__.'/framework',
|
||||
* 'Sensio' => array(__DIR__.'/src', __DIR__.'/vendor'),
|
||||
* ));
|
||||
*
|
||||
* // register a library using the PEAR naming convention
|
||||
* $loader->registerPrefixes(array(
|
||||
* 'Swift_' => __DIR__.'/Swift',
|
||||
* ));
|
||||
*
|
||||
*
|
||||
* // to enable searching the include path (e.g. for PEAR packages)
|
||||
* $loader->useIncludePath(true);
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class UniversalClassLoader
|
||||
{
|
||||
private $namespaces = array();
|
||||
private $prefixes = array();
|
||||
private $namespaceFallbacks = array();
|
||||
private $prefixFallbacks = array();
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* Turns on searching the include for class files. Allows easy loading
|
||||
* of installed PEAR packages
|
||||
*
|
||||
* @param Boolean $useIncludePath
|
||||
*/
|
||||
public function useIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured namespaces.
|
||||
*
|
||||
* @return array A hash with namespaces as keys and directories as values
|
||||
*/
|
||||
public function getNamespaces()
|
||||
{
|
||||
return $this->namespaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured class prefixes.
|
||||
*
|
||||
* @return array A hash with class prefixes as keys and directories as values
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
return $this->prefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the directory(ies) to use as a fallback for namespaces.
|
||||
*
|
||||
* @return array An array of directories
|
||||
*/
|
||||
public function getNamespaceFallbacks()
|
||||
{
|
||||
return $this->namespaceFallbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the directory(ies) to use as a fallback for class prefixes.
|
||||
*
|
||||
* @return array An array of directories
|
||||
*/
|
||||
public function getPrefixFallbacks()
|
||||
{
|
||||
return $this->prefixFallbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the directory to use as a fallback for namespaces.
|
||||
*
|
||||
* @param array $dirs An array of directories
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function registerNamespaceFallbacks(array $dirs)
|
||||
{
|
||||
$this->namespaceFallbacks = $dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a directory to use as a fallback for namespaces.
|
||||
*
|
||||
* @param string $dir A directory
|
||||
*/
|
||||
public function registerNamespaceFallback($dir)
|
||||
{
|
||||
$this->namespaceFallbacks[] = $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers directories to use as a fallback for class prefixes.
|
||||
*
|
||||
* @param array $dirs An array of directories
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function registerPrefixFallbacks(array $dirs)
|
||||
{
|
||||
$this->prefixFallbacks = $dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a directory to use as a fallback for class prefixes.
|
||||
*
|
||||
* @param string $dir A directory
|
||||
*/
|
||||
public function registerPrefixFallback($dir)
|
||||
{
|
||||
$this->prefixFallbacks[] = $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an array of namespaces
|
||||
*
|
||||
* @param array $namespaces An array of namespaces (namespaces as keys and locations as values)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function registerNamespaces(array $namespaces)
|
||||
{
|
||||
foreach ($namespaces as $namespace => $locations) {
|
||||
$this->namespaces[$namespace] = (array) $locations;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a namespace.
|
||||
*
|
||||
* @param string $namespace The namespace
|
||||
* @param array|string $paths The location(s) of the namespace
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function registerNamespace($namespace, $paths)
|
||||
{
|
||||
$this->namespaces[$namespace] = (array) $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an array of classes using the PEAR naming convention.
|
||||
*
|
||||
* @param array $classes An array of classes (prefixes as keys and locations as values)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function registerPrefixes(array $classes)
|
||||
{
|
||||
foreach ($classes as $prefix => $locations) {
|
||||
$this->prefixes[$prefix] = (array) $locations;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of classes using the PEAR naming convention.
|
||||
*
|
||||
* @param string $prefix The classes prefix
|
||||
* @param array|string $paths The location(s) of the classes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function registerPrefix($prefix, $paths)
|
||||
{
|
||||
$this->prefixes[$prefix] = (array) $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param Boolean $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|null The path, if found
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
if ('\\' == $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$namespace = substr($class, 0, $pos);
|
||||
$className = substr($class, $pos + 1);
|
||||
$normalizedClass = str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php';
|
||||
foreach ($this->namespaces as $ns => $dirs) {
|
||||
if (0 !== strpos($namespace, $ns)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
|
||||
if (is_file($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->namespaceFallbacks as $dir) {
|
||||
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
|
||||
if (is_file($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$normalizedClass = str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
|
||||
foreach ($this->prefixes as $prefix => $dirs) {
|
||||
if (0 !== strpos($class, $prefix)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
|
||||
if (is_file($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->prefixFallbacks as $dir) {
|
||||
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
|
||||
if (is_file($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($normalizedClass)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
<?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\ClassLoader;
|
||||
|
||||
/**
|
||||
* XcacheClassLoader implements a wrapping autoloader cached in Xcache for PHP 5.3.
|
||||
*
|
||||
* It expects an object implementing a findFile method to find the file. This
|
||||
* allows using it as a wrapper around the other loaders of the component (the
|
||||
* ClassLoader and the UniversalClassLoader for instance) but also around any
|
||||
* other autoloader following this convention (the Composer one for instance)
|
||||
*
|
||||
* $loader = new ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* $cachedLoader = new XcacheClassLoader('my_prefix', $loader);
|
||||
*
|
||||
* // activate the cached autoloader
|
||||
* $cachedLoader->register();
|
||||
*
|
||||
* // eventually deactivate the non-cached loader if it was registered previously
|
||||
* // to be sure to use the cached one.
|
||||
* $loader->unregister();
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Kris Wallsmith <kris@symfony.com>
|
||||
* @author Kim Hemsø Rasmussen <kimhemsoe@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class XcacheClassLoader
|
||||
{
|
||||
private $prefix;
|
||||
private $classFinder;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $prefix A prefix to create a namespace in Xcache
|
||||
* @param object $classFinder An object that implements findFile() method.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($prefix, $classFinder)
|
||||
{
|
||||
if (!extension_loaded('Xcache')) {
|
||||
throw new \RuntimeException('Unable to use XcacheClassLoader as Xcache is not enabled.');
|
||||
}
|
||||
|
||||
if (!method_exists($classFinder, 'findFile')) {
|
||||
throw new \InvalidArgumentException('The class finder must implement a "findFile" method.');
|
||||
}
|
||||
|
||||
$this->prefix = $prefix;
|
||||
$this->classFinder = $classFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param Boolean $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return Boolean|null True, if loaded
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
require $file;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a file by class name while caching lookups to Xcache.
|
||||
*
|
||||
* @param string $class A class name to resolve to file
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
if (xcache_isset($this->prefix.$class)) {
|
||||
$file = xcache_get($this->prefix.$class);
|
||||
} else {
|
||||
xcache_set($this->prefix.$class, $file = $this->classFinder->findFile($class));
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "symfony/class-loader",
|
||||
"type": "library",
|
||||
"description": "Symfony ClassLoader Component",
|
||||
"keywords": [],
|
||||
"homepage": "http://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/finder": "2.1.*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Symfony\\Component\\ClassLoader": "" }
|
||||
},
|
||||
"target-dir": "Symfony/Component/ClassLoader",
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
/Tests export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
@@ -1,10 +0,0 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added a way to add documentation on configuration
|
||||
* implemented `Serializable` on resources
|
||||
* LoaderResolverInterface is now used instead of LoaderResolver for type
|
||||
hinting
|
||||
@@ -1,117 +0,0 @@
|
||||
<?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\Config;
|
||||
|
||||
/**
|
||||
* ConfigCache manages PHP cache files.
|
||||
*
|
||||
* When debug is enabled, it knows when to flush the cache
|
||||
* thanks to an array of ResourceInterface instances.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ConfigCache
|
||||
{
|
||||
private $debug;
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $file The absolute cache path
|
||||
* @param Boolean $debug Whether debugging is enabled or not
|
||||
*/
|
||||
public function __construct($file, $debug)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->debug = (Boolean) $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache file path.
|
||||
*
|
||||
* @return string The cache file path
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cache is still fresh.
|
||||
*
|
||||
* This method always returns true when debug is off and the
|
||||
* cache file exists.
|
||||
*
|
||||
* @return Boolean true if the cache is fresh, false otherwise
|
||||
*/
|
||||
public function isFresh()
|
||||
{
|
||||
if (!is_file($this->file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->debug) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$metadata = $this->file.'.meta';
|
||||
if (!is_file($metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time = filemtime($this->file);
|
||||
$meta = unserialize(file_get_contents($metadata));
|
||||
foreach ($meta as $resource) {
|
||||
if (!$resource->isFresh($time)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes cache.
|
||||
*
|
||||
* @param string $content The content to write in the cache
|
||||
* @param array $metadata An array of ResourceInterface instances
|
||||
*
|
||||
* @throws \RuntimeException When cache file can't be wrote
|
||||
*/
|
||||
public function write($content, array $metadata = null)
|
||||
{
|
||||
$dir = dirname($this->file);
|
||||
if (!is_dir($dir)) {
|
||||
if (false === @mkdir($dir, 0777, true)) {
|
||||
throw new \RuntimeException(sprintf('Unable to create the %s directory', $dir));
|
||||
}
|
||||
} elseif (!is_writable($dir)) {
|
||||
throw new \RuntimeException(sprintf('Unable to write in the %s directory', $dir));
|
||||
}
|
||||
|
||||
$tmpFile = tempnam(dirname($this->file), basename($this->file));
|
||||
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $this->file)) {
|
||||
@chmod($this->file, 0666 & ~umask());
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $this->file));
|
||||
}
|
||||
|
||||
if (null !== $metadata && true === $this->debug) {
|
||||
$file = $this->file.'.meta';
|
||||
$tmpFile = tempnam(dirname($file), basename($file));
|
||||
if (false !== @file_put_contents($tmpFile, serialize($metadata)) && @rename($tmpFile, $file)) {
|
||||
@chmod($file, 0666 & ~umask());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,362 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
|
||||
|
||||
/**
|
||||
* Represents an Array node in the config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ArrayNode extends BaseNode implements PrototypeNodeInterface
|
||||
{
|
||||
protected $xmlRemappings;
|
||||
protected $children;
|
||||
protected $allowFalse;
|
||||
protected $allowNewKeys;
|
||||
protected $addIfNotSet;
|
||||
protected $performDeepMerging;
|
||||
protected $ignoreExtraKeys;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The Node's name
|
||||
* @param NodeInterface $parent The node parent
|
||||
*/
|
||||
public function __construct($name, NodeInterface $parent = null)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
|
||||
$this->children = array();
|
||||
$this->xmlRemappings = array();
|
||||
$this->removeKeyAttribute = true;
|
||||
$this->allowFalse = false;
|
||||
$this->addIfNotSet = false;
|
||||
$this->allowNewKeys = true;
|
||||
$this->performDeepMerging = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the children of this node.
|
||||
*
|
||||
* @return array The children
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the xml remappings that should be performed.
|
||||
*
|
||||
* @param array $remappings an array of the form array(array(string, string))
|
||||
*/
|
||||
public function setXmlRemappings(array $remappings)
|
||||
{
|
||||
$this->xmlRemappings = $remappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to add default values for this array if it has not been
|
||||
* defined in any of the configuration files.
|
||||
*
|
||||
* @param Boolean $boolean
|
||||
*/
|
||||
public function setAddIfNotSet($boolean)
|
||||
{
|
||||
$this->addIfNotSet = (Boolean) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether false is allowed as value indicating that the array should be unset.
|
||||
*
|
||||
* @param Boolean $allow
|
||||
*/
|
||||
public function setAllowFalse($allow)
|
||||
{
|
||||
$this->allowFalse = (Boolean) $allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether new keys can be defined in subsequent configurations.
|
||||
*
|
||||
* @param Boolean $allow
|
||||
*/
|
||||
public function setAllowNewKeys($allow)
|
||||
{
|
||||
$this->allowNewKeys = (Boolean) $allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if deep merging should occur.
|
||||
*
|
||||
* @param Boolean $boolean
|
||||
*/
|
||||
public function setPerformDeepMerging($boolean)
|
||||
{
|
||||
$this->performDeepMerging = (Boolean) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether extra keys should just be ignore without an exception.
|
||||
*
|
||||
* @param Boolean $boolean To allow extra keys
|
||||
*/
|
||||
public function setIgnoreExtraKeys($boolean)
|
||||
{
|
||||
$this->ignoreExtraKeys = (Boolean) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the node Name.
|
||||
*
|
||||
* @param string $name The node's name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node has a default value.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function hasDefaultValue()
|
||||
{
|
||||
return $this->addIfNotSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default value.
|
||||
*
|
||||
* @return array The default value
|
||||
*
|
||||
* @throws \RuntimeException if the node has no default value
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
if (!$this->hasDefaultValue()) {
|
||||
throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
|
||||
}
|
||||
|
||||
$defaults = array();
|
||||
foreach ($this->children as $name => $child) {
|
||||
if ($child->hasDefaultValue()) {
|
||||
$defaults[$name] = $child->getDefaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child node.
|
||||
*
|
||||
* @param NodeInterface $node The child node to add
|
||||
*
|
||||
* @throws \InvalidArgumentException when the child node has no name
|
||||
* @throws \InvalidArgumentException when the child node's name is not unique
|
||||
*/
|
||||
public function addChild(NodeInterface $node)
|
||||
{
|
||||
$name = $node->getName();
|
||||
if (empty($name)) {
|
||||
throw new \InvalidArgumentException('Child nodes must be named.');
|
||||
}
|
||||
if (isset($this->children[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name));
|
||||
}
|
||||
|
||||
$this->children[$name] = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the value of this node.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed The finalised value
|
||||
*
|
||||
* @throws UnsetKeyException
|
||||
* @throws InvalidConfigurationException if the node doesn't have enough children
|
||||
*/
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
$msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
|
||||
throw new UnsetKeyException($msg);
|
||||
}
|
||||
|
||||
foreach ($this->children as $name => $child) {
|
||||
if (!array_key_exists($name, $value)) {
|
||||
if ($child->isRequired()) {
|
||||
$msg = sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath());
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
if ($child->hasDefaultValue()) {
|
||||
$value[$name] = $child->getDefaultValue();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$value[$name] = $child->finalize($value[$name]);
|
||||
} catch (UnsetKeyException $unset) {
|
||||
unset($value[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the type of the value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @throws InvalidTypeException
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
if (!is_array($value) && (!$this->allowFalse || false !== $value)) {
|
||||
$ex = new InvalidTypeException(sprintf(
|
||||
'Invalid type for path "%s". Expected array, but got %s',
|
||||
$this->getPath(),
|
||||
gettype($value)
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the value.
|
||||
*
|
||||
* @param mixed $value The value to normalize
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = $this->remapXml($value);
|
||||
|
||||
$normalized = array();
|
||||
foreach ($this->children as $name => $child) {
|
||||
if (array_key_exists($name, $value)) {
|
||||
$normalized[$name] = $child->normalize($value[$name]);
|
||||
unset($value[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
// if extra fields are present, throw exception
|
||||
if (count($value) && !$this->ignoreExtraKeys) {
|
||||
$msg = sprintf('Unrecognized options "%s" under "%s"', implode(', ', array_keys($value)), $this->getPath());
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaps multiple singular values to a single plural value.
|
||||
*
|
||||
* @param array $value The source values
|
||||
*
|
||||
* @return array The remapped values
|
||||
*/
|
||||
protected function remapXml($value)
|
||||
{
|
||||
foreach ($this->xmlRemappings as $transformation) {
|
||||
list($singular, $plural) = $transformation;
|
||||
|
||||
if (!isset($value[$singular])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value[$plural] = Processor::normalizeConfig($value, $singular, $plural);
|
||||
unset($value[$singular]);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges values together.
|
||||
*
|
||||
* @param mixed $leftSide The left side to merge.
|
||||
* @param mixed $rightSide The right side to merge.
|
||||
*
|
||||
* @return mixed The merged values
|
||||
*
|
||||
* @throws InvalidConfigurationException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function mergeValues($leftSide, $rightSide)
|
||||
{
|
||||
if (false === $rightSide) {
|
||||
// if this is still false after the last config has been merged the
|
||||
// finalization pass will take care of removing this key entirely
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false === $leftSide || !$this->performDeepMerging) {
|
||||
return $rightSide;
|
||||
}
|
||||
|
||||
foreach ($rightSide as $k => $v) {
|
||||
// no conflict
|
||||
if (!array_key_exists($k, $leftSide)) {
|
||||
if (!$this->allowNewKeys) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'You are not allowed to define new elements for path "%s". '
|
||||
.'Please define all elements for this path in one config file. '
|
||||
.'If you are trying to overwrite an element, make sure you redefine it '
|
||||
.'with the same name.',
|
||||
$this->getPath()
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$leftSide[$k] = $v;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($this->children[$k])) {
|
||||
throw new \RuntimeException('merge() expects a normalized config array.');
|
||||
}
|
||||
|
||||
$leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v);
|
||||
}
|
||||
|
||||
return $leftSide;
|
||||
}
|
||||
}
|
||||
@@ -1,337 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\Exception;
|
||||
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
|
||||
/**
|
||||
* The base node class
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class BaseNode implements NodeInterface
|
||||
{
|
||||
protected $name;
|
||||
protected $parent;
|
||||
protected $normalizationClosures;
|
||||
protected $finalValidationClosures;
|
||||
protected $allowOverwrite;
|
||||
protected $required;
|
||||
protected $equivalentValues;
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
* @param NodeInterface $parent The parent of this node
|
||||
*
|
||||
* @throws \InvalidArgumentException if the name contains a period.
|
||||
*/
|
||||
public function __construct($name, NodeInterface $parent = null)
|
||||
{
|
||||
if (false !== strpos($name, '.')) {
|
||||
throw new \InvalidArgumentException('The name must not contain ".".');
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->parent = $parent;
|
||||
$this->normalizationClosures = array();
|
||||
$this->finalValidationClosures = array();
|
||||
$this->allowOverwrite = true;
|
||||
$this->required = false;
|
||||
$this->equivalentValues = array();
|
||||
}
|
||||
|
||||
public function setAttribute($key, $value)
|
||||
{
|
||||
$this->attributes[$key] = $value;
|
||||
}
|
||||
|
||||
public function getAttribute($key, $default = null)
|
||||
{
|
||||
return isset($this->attributes[$key]) ? $this->attributes[$key] : $default;
|
||||
}
|
||||
|
||||
public function hasAttribute($key)
|
||||
{
|
||||
return isset($this->attributes[$key]);
|
||||
}
|
||||
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function setAttributes(array $attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
public function removeAttribute($key)
|
||||
{
|
||||
unset($this->attributes[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an info message.
|
||||
*
|
||||
* @param string $info
|
||||
*/
|
||||
public function setInfo($info)
|
||||
{
|
||||
$this->setAttribute('info', $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns info message.
|
||||
*
|
||||
* @return string The info text
|
||||
*/
|
||||
public function getInfo()
|
||||
{
|
||||
return $this->getAttribute('info');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the example configuration for this node.
|
||||
*
|
||||
* @param string|array $example
|
||||
*/
|
||||
public function setExample($example)
|
||||
{
|
||||
$this->setAttribute('example', $example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the example configuration for this node.
|
||||
*
|
||||
* @return string|array The example
|
||||
*/
|
||||
public function getExample()
|
||||
{
|
||||
return $this->getAttribute('example');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an equivalent value.
|
||||
*
|
||||
* @param mixed $originalValue
|
||||
* @param mixed $equivalentValue
|
||||
*/
|
||||
public function addEquivalentValue($originalValue, $equivalentValue)
|
||||
{
|
||||
$this->equivalentValues[] = array($originalValue, $equivalentValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this node as required.
|
||||
*
|
||||
* @param Boolean $boolean Required node
|
||||
*/
|
||||
public function setRequired($boolean)
|
||||
{
|
||||
$this->required = (Boolean) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this node can be overridden.
|
||||
*
|
||||
* @param Boolean $allow
|
||||
*/
|
||||
public function setAllowOverwrite($allow)
|
||||
{
|
||||
$this->allowOverwrite = (Boolean) $allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the closures used for normalization.
|
||||
*
|
||||
* @param array $closures An array of Closures used for normalization
|
||||
*/
|
||||
public function setNormalizationClosures(array $closures)
|
||||
{
|
||||
$this->normalizationClosures = $closures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the closures used for final validation.
|
||||
*
|
||||
* @param array $closures An array of Closures used for final validation
|
||||
*/
|
||||
public function setFinalValidationClosures(array $closures)
|
||||
{
|
||||
$this->finalValidationClosures = $closures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this node is required.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this node
|
||||
*
|
||||
* @return string The Node's name.
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the path of this node.
|
||||
*
|
||||
* @return string The Node's path
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
$path = $this->name;
|
||||
|
||||
if (null !== $this->parent) {
|
||||
$path = $this->parent->getPath().'.'.$path;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two values together.
|
||||
*
|
||||
* @param mixed $leftSide
|
||||
* @param mixed $rightSide
|
||||
*
|
||||
* @return mixed The merged value
|
||||
*
|
||||
* @throws ForbiddenOverwriteException
|
||||
*/
|
||||
final public function merge($leftSide, $rightSide)
|
||||
{
|
||||
if (!$this->allowOverwrite) {
|
||||
throw new ForbiddenOverwriteException(sprintf(
|
||||
'Configuration path "%s" cannot be overwritten. You have to '
|
||||
.'define all options for this path, and any of its sub-paths in '
|
||||
.'one configuration section.',
|
||||
$this->getPath()
|
||||
));
|
||||
}
|
||||
|
||||
$this->validateType($leftSide);
|
||||
$this->validateType($rightSide);
|
||||
|
||||
return $this->mergeValues($leftSide, $rightSide);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a value, applying all normalization closures.
|
||||
*
|
||||
* @param mixed $value Value to normalize.
|
||||
*
|
||||
* @return mixed The normalized value.
|
||||
*/
|
||||
final public function normalize($value)
|
||||
{
|
||||
// run custom normalization closures
|
||||
foreach ($this->normalizationClosures as $closure) {
|
||||
$value = $closure($value);
|
||||
}
|
||||
|
||||
// replace value with their equivalent
|
||||
foreach ($this->equivalentValues as $data) {
|
||||
if ($data[0] === $value) {
|
||||
$value = $data[1];
|
||||
}
|
||||
}
|
||||
|
||||
// validate type
|
||||
$this->validateType($value);
|
||||
|
||||
// normalize value
|
||||
return $this->normalizeValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes a value, applying all finalization closures.
|
||||
*
|
||||
* @param mixed $value The value to finalize
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*/
|
||||
final public function finalize($value)
|
||||
{
|
||||
$this->validateType($value);
|
||||
|
||||
$value = $this->finalizeValue($value);
|
||||
|
||||
// Perform validation on the final value if a closure has been set.
|
||||
// The closure is also allowed to return another value.
|
||||
foreach ($this->finalValidationClosures as $closure) {
|
||||
try {
|
||||
$value = $closure($value);
|
||||
} catch (Exception $correctEx) {
|
||||
throw $correctEx;
|
||||
} catch (\Exception $invalid) {
|
||||
throw new InvalidConfigurationException(sprintf(
|
||||
'Invalid configuration for path "%s": %s',
|
||||
$this->getPath(),
|
||||
$invalid->getMessage()
|
||||
), $invalid->getCode(), $invalid);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the type of a Node.
|
||||
*
|
||||
* @param mixed $value The value to validate
|
||||
*
|
||||
* @throws InvalidTypeException when the value is invalid
|
||||
*/
|
||||
abstract protected function validateType($value);
|
||||
|
||||
/**
|
||||
* Normalizes the value.
|
||||
*
|
||||
* @param mixed $value The value to normalize.
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*/
|
||||
abstract protected function normalizeValue($value);
|
||||
|
||||
/**
|
||||
* Merges two values together.
|
||||
*
|
||||
* @param mixed $leftSide
|
||||
* @param mixed $rightSide
|
||||
*
|
||||
* @return mixed The merged value
|
||||
*/
|
||||
abstract protected function mergeValues($leftSide, $rightSide);
|
||||
|
||||
/**
|
||||
* Finalizes a value.
|
||||
*
|
||||
* @param mixed $value The value to finalize
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*/
|
||||
abstract protected function finalizeValue($value);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
|
||||
/**
|
||||
* This node represents a Boolean value in the config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class BooleanNode extends ScalarNode
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
if (!is_bool($value)) {
|
||||
$ex = new InvalidTypeException(sprintf(
|
||||
'Invalid type for path "%s". Expected boolean, but got %s.',
|
||||
$this->getPath(),
|
||||
gettype($value)
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,420 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\NodeInterface;
|
||||
use Symfony\Component\Config\Definition\ArrayNode;
|
||||
use Symfony\Component\Config\Definition\PrototypedArrayNode;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining an array node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
|
||||
{
|
||||
protected $performDeepMerging;
|
||||
protected $ignoreExtraKeys;
|
||||
protected $children;
|
||||
protected $prototype;
|
||||
protected $atLeastOne;
|
||||
protected $allowNewKeys;
|
||||
protected $key;
|
||||
protected $removeKeyItem;
|
||||
protected $addDefaults;
|
||||
protected $addDefaultChildren;
|
||||
protected $nodeBuilder;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct($name, NodeParentInterface $parent = null)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
|
||||
$this->children = array();
|
||||
$this->addDefaults = false;
|
||||
$this->addDefaultChildren = false;
|
||||
$this->allowNewKeys = true;
|
||||
$this->atLeastOne = false;
|
||||
$this->allowEmptyValue = true;
|
||||
$this->performDeepMerging = true;
|
||||
$this->nullEquivalent = array();
|
||||
$this->trueEquivalent = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom children builder.
|
||||
*
|
||||
* @param NodeBuilder $builder A custom NodeBuilder
|
||||
*/
|
||||
public function setBuilder(NodeBuilder $builder)
|
||||
{
|
||||
$this->nodeBuilder = $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a builder to add children nodes.
|
||||
*
|
||||
* @return NodeBuilder
|
||||
*/
|
||||
public function children()
|
||||
{
|
||||
return $this->getNodeBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a prototype for child nodes.
|
||||
*
|
||||
* @param string $type the type of node
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function prototype($type)
|
||||
{
|
||||
return $this->prototype = $this->getNodeBuilder()->node(null, $type)->setParent($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the default value if the node is not set in the configuration.
|
||||
*
|
||||
* This method is applicable to concrete nodes only (not to prototype nodes).
|
||||
* If this function has been called and the node is not set during the finalization
|
||||
* phase, it's default value will be derived from its children default values.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function addDefaultsIfNotSet()
|
||||
{
|
||||
$this->addDefaults = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds children with a default value when none are defined.
|
||||
*
|
||||
* @param integer|string|array|null $children The number of children|The child name|The children names to be added
|
||||
*
|
||||
* This method is applicable to prototype nodes only.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function addDefaultChildrenIfNoneSet($children = null)
|
||||
{
|
||||
$this->addDefaultChildren = $children;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the node to have at least one element.
|
||||
*
|
||||
* This method is applicable to prototype nodes only.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function requiresAtLeastOneElement()
|
||||
{
|
||||
$this->atLeastOne = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disallows adding news keys in a subsequent configuration.
|
||||
*
|
||||
* If used all keys have to be defined in the same configuration file.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function disallowNewKeysInSubsequentConfigs()
|
||||
{
|
||||
$this->allowNewKeys = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a normalization rule for XML configurations.
|
||||
*
|
||||
* @param string $singular The key to remap
|
||||
* @param string $plural The plural of the key for irregular plurals
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function fixXmlConfig($singular, $plural = null)
|
||||
{
|
||||
$this->normalization()->remap($singular, $plural);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attribute which value is to be used as key.
|
||||
*
|
||||
* This is useful when you have an indexed array that should be an
|
||||
* associative array. You can select an item from within the array
|
||||
* to be the key of the particular item. For example, if "id" is the
|
||||
* "key", then:
|
||||
*
|
||||
* array(
|
||||
* array('id' => 'my_name', 'foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* becomes
|
||||
*
|
||||
* array(
|
||||
* 'my_name' => array('foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* If you'd like "'id' => 'my_name'" to still be present in the resulting
|
||||
* array, then you can set the second argument of this method to false.
|
||||
*
|
||||
* This method is applicable to prototype nodes only.
|
||||
*
|
||||
* @param string $name The name of the key
|
||||
* @param Boolean $removeKeyItem Whether or not the key item should be removed.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function useAttributeAsKey($name, $removeKeyItem = true)
|
||||
{
|
||||
$this->key = $name;
|
||||
$this->removeKeyItem = $removeKeyItem;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be unset.
|
||||
*
|
||||
* @param Boolean $allow
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function canBeUnset($allow = true)
|
||||
{
|
||||
$this->merge()->allowUnset($allow);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the deep merging of the node.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function performNoDeepMerging()
|
||||
{
|
||||
$this->performDeepMerging = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows extra config keys to be specified under an array without
|
||||
* throwing an exception.
|
||||
*
|
||||
* Those config values are simply ignored. This should be used only
|
||||
* in special cases where you want to send an entire configuration
|
||||
* array through a special tree that processes only part of the array.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function ignoreExtraKeys()
|
||||
{
|
||||
$this->ignoreExtraKeys = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a node definition.
|
||||
*
|
||||
* $node = new ArrayNodeDefinition()
|
||||
* ->children()
|
||||
* ->scalarNode('foo')->end()
|
||||
* ->scalarNode('baz')->end()
|
||||
* ->end()
|
||||
* ->append($this->getBarNodeDefinition())
|
||||
* ;
|
||||
*
|
||||
* @param NodeDefinition $node A NodeDefinition instance
|
||||
*
|
||||
* @return ArrayNodeDefinition This node
|
||||
*/
|
||||
public function append(NodeDefinition $node)
|
||||
{
|
||||
$this->children[$node->name] = $node->setParent($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a node builder to be used to add children and prototype
|
||||
*
|
||||
* @return NodeBuilder The node builder
|
||||
*/
|
||||
protected function getNodeBuilder()
|
||||
{
|
||||
if (null === $this->nodeBuilder) {
|
||||
$this->nodeBuilder = new NodeBuilder();
|
||||
}
|
||||
|
||||
return $this->nodeBuilder->setParent($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function createNode()
|
||||
{
|
||||
if (null === $this->prototype) {
|
||||
$node = new ArrayNode($this->name, $this->parent);
|
||||
|
||||
$this->validateConcreteNode($node);
|
||||
|
||||
$node->setAddIfNotSet($this->addDefaults);
|
||||
|
||||
foreach ($this->children as $child) {
|
||||
$child->parent = $node;
|
||||
$node->addChild($child->getNode());
|
||||
}
|
||||
} else {
|
||||
$node = new PrototypedArrayNode($this->name, $this->parent);
|
||||
|
||||
$this->validatePrototypeNode($node);
|
||||
|
||||
if (null !== $this->key) {
|
||||
$node->setKeyAttribute($this->key, $this->removeKeyItem);
|
||||
}
|
||||
|
||||
if (true === $this->atLeastOne) {
|
||||
$node->setMinNumberOfElements(1);
|
||||
}
|
||||
|
||||
if ($this->default) {
|
||||
$node->setDefaultValue($this->defaultValue);
|
||||
}
|
||||
|
||||
if (false !== $this->addDefaultChildren) {
|
||||
$node->setAddChildrenIfNoneSet($this->addDefaultChildren);
|
||||
if ($this->prototype instanceof static && null === $this->prototype->prototype) {
|
||||
$this->prototype->addDefaultsIfNotSet();
|
||||
}
|
||||
}
|
||||
|
||||
$this->prototype->parent = $node;
|
||||
$node->setPrototype($this->prototype->getNode());
|
||||
}
|
||||
|
||||
$node->setAllowNewKeys($this->allowNewKeys);
|
||||
$node->addEquivalentValue(null, $this->nullEquivalent);
|
||||
$node->addEquivalentValue(true, $this->trueEquivalent);
|
||||
$node->addEquivalentValue(false, $this->falseEquivalent);
|
||||
$node->setPerformDeepMerging($this->performDeepMerging);
|
||||
$node->setRequired($this->required);
|
||||
$node->setIgnoreExtraKeys($this->ignoreExtraKeys);
|
||||
|
||||
if (null !== $this->normalization) {
|
||||
$node->setNormalizationClosures($this->normalization->before);
|
||||
$node->setXmlRemappings($this->normalization->remappings);
|
||||
}
|
||||
|
||||
if (null !== $this->merge) {
|
||||
$node->setAllowOverwrite($this->merge->allowOverwrite);
|
||||
$node->setAllowFalse($this->merge->allowFalse);
|
||||
}
|
||||
|
||||
if (null !== $this->validation) {
|
||||
$node->setFinalValidationClosures($this->validation->rules);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration of a concrete node.
|
||||
*
|
||||
* @param NodeInterface $node The related node
|
||||
*
|
||||
* @throws InvalidDefinitionException When an error is detected in the configuration
|
||||
*/
|
||||
protected function validateConcreteNode(ArrayNode $node)
|
||||
{
|
||||
$path = $node->getPath();
|
||||
|
||||
if (null !== $this->key) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (true === $this->atLeastOne) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->default) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->defaultValue() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (false !== $this->addDefaultChildren) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration of a prototype node.
|
||||
*
|
||||
* @param NodeInterface $node The related node
|
||||
*
|
||||
* @throws InvalidDefinitionException When an error is detected in the configuration
|
||||
*/
|
||||
protected function validatePrototypeNode(PrototypedArrayNode $node)
|
||||
{
|
||||
$path = $node->getPath();
|
||||
|
||||
if ($this->addDefaults) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (false !== $this->addDefaultChildren) {
|
||||
if ($this->default) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('A default value and default children might not be used together at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (null !== $this->key && (null === $this->addDefaultChildren || is_integer($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (null === $this->key && (is_string($this->addDefaultChildren) || is_array($this->addDefaultChildren))) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\BooleanNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class BooleanNodeDefinition extends ScalarNodeDefinition
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct($name, NodeParentInterface $parent = null)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
|
||||
$this->nullEquivalent = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a Node
|
||||
*
|
||||
* @return BooleanNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new BooleanNode($this->name, $this->parent);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\EnumNode;
|
||||
use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
|
||||
|
||||
/**
|
||||
* Enum Node Definition.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class EnumNodeDefinition extends ScalarNodeDefinition
|
||||
{
|
||||
private $values;
|
||||
|
||||
public function values(array $values)
|
||||
{
|
||||
$values = array_unique($values);
|
||||
|
||||
if (count($values) <= 1) {
|
||||
throw new \InvalidArgumentException('->values() must be called with at least two distinct values.');
|
||||
}
|
||||
|
||||
$this->values = $values;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a Node
|
||||
*
|
||||
* @return EnumNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
if (null === $this->values) {
|
||||
throw new \RuntimeException('You must call ->values() on enum nodes.');
|
||||
}
|
||||
|
||||
return new EnumNode($this->name, $this->parent, $this->values);
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
|
||||
|
||||
/**
|
||||
* This class builds an if expression.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class ExprBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $ifPart;
|
||||
public $thenPart;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the expression as being always used.
|
||||
*
|
||||
* @param \Closure $then
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function always(\Closure $then = null)
|
||||
{
|
||||
$this->ifPart = function($v) { return true; };
|
||||
|
||||
if (null !== $then) {
|
||||
$this->thenPart = $then;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure to use as tests.
|
||||
*
|
||||
* The default one tests if the value is true.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifTrue(\Closure $closure = null)
|
||||
{
|
||||
if (null === $closure) {
|
||||
$closure = function($v) { return true === $v; };
|
||||
}
|
||||
|
||||
$this->ifPart = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is a string.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifString()
|
||||
{
|
||||
$this->ifPart = function($v) { return is_string($v); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is null.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifNull()
|
||||
{
|
||||
$this->ifPart = function($v) { return null === $v; };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is an array.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifArray()
|
||||
{
|
||||
$this->ifPart = function($v) { return is_array($v); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is in an array.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifInArray(array $array)
|
||||
{
|
||||
$this->ifPart = function($v) use ($array) { return in_array($v, $array, true); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is not in an array.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifNotInArray(array $array)
|
||||
{
|
||||
$this->ifPart = function($v) use ($array) { return !in_array($v, $array, true); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the closure to run if the test pass.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function then(\Closure $closure)
|
||||
{
|
||||
$this->thenPart = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure returning an empty array.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function thenEmptyArray()
|
||||
{
|
||||
$this->thenPart = function($v) { return array(); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure marking the value as invalid at validation time.
|
||||
*
|
||||
* if you want to add the value of the node in your message just use a %s placeholder.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function thenInvalid($message)
|
||||
{
|
||||
$this->thenPart = function ($v) use ($message) {throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure unsetting this key of the array at validation time.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function thenUnset()
|
||||
{
|
||||
$this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the related node
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
if (null === $this->ifPart) {
|
||||
throw new \RuntimeException('You must specify an if part.');
|
||||
}
|
||||
if (null === $this->thenPart) {
|
||||
throw new \RuntimeException('You must specify a then part.');
|
||||
}
|
||||
|
||||
return $this->node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the expressions.
|
||||
*
|
||||
* @param array $expressions An array of ExprBuilder instances to build
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function buildExpressions(array $expressions)
|
||||
{
|
||||
foreach ($expressions as $k => $expr) {
|
||||
if ($expr instanceof ExprBuilder) {
|
||||
$expressions[$k] = function($v) use ($expr) {
|
||||
return call_user_func($expr->ifPart, $v) ? call_user_func($expr->thenPart, $v) : $v;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return $expressions;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class builds merge conditions.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class MergeBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $allowFalse;
|
||||
public $allowOverwrite;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
$this->allowFalse = false;
|
||||
$this->allowOverwrite = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be unset.
|
||||
*
|
||||
* @param Boolean $allow
|
||||
*
|
||||
* @return MergeBuilder
|
||||
*/
|
||||
public function allowUnset($allow = true)
|
||||
{
|
||||
$this->allowFalse = $allow;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be overwritten.
|
||||
*
|
||||
* @param Boolean $deny Whether the overwriting is forbidden or not
|
||||
*
|
||||
* @return MergeBuilder
|
||||
*/
|
||||
public function denyOverwrite($deny = true)
|
||||
{
|
||||
$this->allowOverwrite = !$deny;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the related node.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->node;
|
||||
}
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for building a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class NodeBuilder implements NodeParentInterface
|
||||
{
|
||||
protected $parent;
|
||||
protected $nodeMapping;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->nodeMapping = array(
|
||||
'variable' => __NAMESPACE__.'\\VariableNodeDefinition',
|
||||
'scalar' => __NAMESPACE__.'\\ScalarNodeDefinition',
|
||||
'boolean' => __NAMESPACE__.'\\BooleanNodeDefinition',
|
||||
'array' => __NAMESPACE__.'\\ArrayNodeDefinition',
|
||||
'enum' => __NAMESPACE__.'\\EnumNodeDefinition',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent node.
|
||||
*
|
||||
* @param ParentNodeDefinitionInterface $parent The parent node
|
||||
*
|
||||
* @return NodeBuilder This node builder
|
||||
*/
|
||||
public function setParent(ParentNodeDefinitionInterface $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child array node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*
|
||||
* @return ArrayNodeDefinition The child node
|
||||
*/
|
||||
public function arrayNode($name)
|
||||
{
|
||||
return $this->node($name, 'array');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child scalar node.
|
||||
*
|
||||
* @param string $name the name of the node
|
||||
*
|
||||
* @return ScalarNodeDefinition The child node
|
||||
*/
|
||||
public function scalarNode($name)
|
||||
{
|
||||
return $this->node($name, 'scalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child Boolean node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*
|
||||
* @return BooleanNodeDefinition The child node
|
||||
*/
|
||||
public function booleanNode($name)
|
||||
{
|
||||
return $this->node($name, 'boolean');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child EnumNode.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return EnumNodeDefinition
|
||||
*/
|
||||
public function enumNode($name)
|
||||
{
|
||||
return $this->node($name, 'enum');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child variable node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*
|
||||
* @return VariableNodeDefinition The builder of the child node
|
||||
*/
|
||||
public function variableNode($name)
|
||||
{
|
||||
return $this->node($name, 'variable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent node.
|
||||
*
|
||||
* @return ParentNodeDefinitionInterface The parent node
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
* @param string $type The type of the node
|
||||
*
|
||||
* @return NodeDefinition The child node
|
||||
*
|
||||
* @throws \RuntimeException When the node type is not registered
|
||||
* @throws \RuntimeException When the node class is not found
|
||||
*/
|
||||
public function node($name, $type)
|
||||
{
|
||||
$class = $this->getNodeClass($type);
|
||||
|
||||
$node = new $class($name);
|
||||
|
||||
$this->append($node);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a node definition.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $node = new ArrayNodeDefinition('name')
|
||||
* ->children()
|
||||
* ->scalarNode('foo')->end()
|
||||
* ->scalarNode('baz')->end()
|
||||
* ->append($this->getBarNodeDefinition())
|
||||
* ->end()
|
||||
* ;
|
||||
*
|
||||
* @return NodeBuilder This node builder
|
||||
*/
|
||||
public function append(NodeDefinition $node)
|
||||
{
|
||||
if ($node instanceof ParentNodeDefinitionInterface) {
|
||||
$builder = clone $this;
|
||||
$builder->setParent(null);
|
||||
$node->setBuilder($builder);
|
||||
}
|
||||
|
||||
if (null !== $this->parent) {
|
||||
$this->parent->append($node);
|
||||
// Make this builder the node parent to allow for a fluid interface
|
||||
$node->setParent($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or overrides a node Type.
|
||||
*
|
||||
* @param string $type The name of the type
|
||||
* @param string $class The fully qualified name the node definition class
|
||||
*
|
||||
* @return NodeBuilder This node builder
|
||||
*/
|
||||
public function setNodeClass($type, $class)
|
||||
{
|
||||
$this->nodeMapping[strtolower($type)] = $class;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name of the node definition.
|
||||
*
|
||||
* @param string $type The node type
|
||||
*
|
||||
* @return string The node definition class name
|
||||
*
|
||||
* @throws \RuntimeException When the node type is not registered
|
||||
* @throws \RuntimeException When the node class is not found
|
||||
*/
|
||||
protected function getNodeClass($type)
|
||||
{
|
||||
$type = strtolower($type);
|
||||
|
||||
if (!isset($this->nodeMapping[$type])) {
|
||||
throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
|
||||
}
|
||||
|
||||
$class = $this->nodeMapping[$type];
|
||||
|
||||
if (!class_exists($class)) {
|
||||
throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,343 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\NodeInterface;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class NodeDefinition implements NodeParentInterface
|
||||
{
|
||||
protected $name;
|
||||
protected $normalization;
|
||||
protected $validation;
|
||||
protected $defaultValue;
|
||||
protected $default;
|
||||
protected $required;
|
||||
protected $merge;
|
||||
protected $allowEmptyValue;
|
||||
protected $nullEquivalent;
|
||||
protected $trueEquivalent;
|
||||
protected $falseEquivalent;
|
||||
protected $parent;
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
* @param NodeParentInterface $parent The parent
|
||||
*/
|
||||
public function __construct($name, NodeParentInterface $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->name = $name;
|
||||
$this->default = false;
|
||||
$this->required = false;
|
||||
$this->trueEquivalent = true;
|
||||
$this->falseEquivalent = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent node.
|
||||
*
|
||||
* @param NodeParentInterface $parent The parent
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function setParent(NodeParentInterface $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets info message.
|
||||
*
|
||||
* @param string $info The info text
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function info($info)
|
||||
{
|
||||
return $this->attribute('info', $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets example configuration.
|
||||
*
|
||||
* @param string|array $example
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function example($example)
|
||||
{
|
||||
return $this->attribute('example', $example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute on the node.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function attribute($key, $value)
|
||||
{
|
||||
$this->attributes[$key] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent node.
|
||||
*
|
||||
* @return NodeParentInterface The builder of the parent node
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the node.
|
||||
*
|
||||
* @param Boolean $forceRootNode Whether to force this node as the root node
|
||||
*
|
||||
* @return NodeInterface
|
||||
*/
|
||||
public function getNode($forceRootNode = false)
|
||||
{
|
||||
if ($forceRootNode) {
|
||||
$this->parent = null;
|
||||
}
|
||||
|
||||
if (null !== $this->normalization) {
|
||||
$this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
|
||||
}
|
||||
|
||||
if (null !== $this->validation) {
|
||||
$this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules);
|
||||
}
|
||||
|
||||
$node = $this->createNode();
|
||||
$node->setAttributes($this->attributes);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $value The default value
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function defaultValue($value)
|
||||
{
|
||||
$this->default = true;
|
||||
$this->defaultValue = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the node as required.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
$this->required = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the equivalent value used when the node contains null.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function treatNullLike($value)
|
||||
{
|
||||
$this->nullEquivalent = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the equivalent value used when the node contains true.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function treatTrueLike($value)
|
||||
{
|
||||
$this->trueEquivalent = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the equivalent value used when the node contains false.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function treatFalseLike($value)
|
||||
{
|
||||
$this->falseEquivalent = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets null as the default value.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function defaultNull()
|
||||
{
|
||||
return $this->defaultValue(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets true as the default value.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function defaultTrue()
|
||||
{
|
||||
return $this->defaultValue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets false as the default value.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function defaultFalse()
|
||||
{
|
||||
return $this->defaultValue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an expression to run before the normalization.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function beforeNormalization()
|
||||
{
|
||||
return $this->normalization()->before();
|
||||
}
|
||||
|
||||
/**
|
||||
* Denies the node value being empty.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function cannotBeEmpty()
|
||||
{
|
||||
$this->allowEmptyValue = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an expression to run for the validation.
|
||||
*
|
||||
* The expression receives the value of the node and must return it. It can
|
||||
* modify it.
|
||||
* An exception should be thrown when the node is not valid.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
return $this->validation()->rule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be overwritten.
|
||||
*
|
||||
* @param Boolean $deny Whether the overwriting is forbidden or not
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function cannotBeOverwritten($deny = true)
|
||||
{
|
||||
$this->merge()->denyOverwrite($deny);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the builder for validation rules.
|
||||
*
|
||||
* @return ValidationBuilder
|
||||
*/
|
||||
protected function validation()
|
||||
{
|
||||
if (null === $this->validation) {
|
||||
$this->validation = new ValidationBuilder($this);
|
||||
}
|
||||
|
||||
return $this->validation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the builder for merging rules.
|
||||
*
|
||||
* @return MergeBuilder
|
||||
*/
|
||||
protected function merge()
|
||||
{
|
||||
if (null === $this->merge) {
|
||||
$this->merge = new MergeBuilder($this);
|
||||
}
|
||||
|
||||
return $this->merge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the builder for normalization rules.
|
||||
*
|
||||
* @return NormalizationBuilder
|
||||
*/
|
||||
protected function normalization()
|
||||
{
|
||||
if (null === $this->normalization) {
|
||||
$this->normalization = new NormalizationBuilder($this);
|
||||
}
|
||||
|
||||
return $this->normalization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate and configure the node according to this definition
|
||||
*
|
||||
* @return NodeInterface $node The node instance
|
||||
*
|
||||
* @throws Symfony\Component\Config\Definition\Exception\InvalidDefinitionException When the definition is invalid
|
||||
*/
|
||||
abstract protected function createNode();
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* An interface that must be implemented by all node parents
|
||||
*
|
||||
* @author Victor Berchet <victor@suumit.com>
|
||||
*/
|
||||
interface NodeParentInterface
|
||||
{
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class builds normalization conditions.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class NormalizationBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $before;
|
||||
public $remappings;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
$this->keys = false;
|
||||
$this->remappings = array();
|
||||
$this->before = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a key to remap to its plural form.
|
||||
*
|
||||
* @param string $key The key to remap
|
||||
* @param string $plural The plural of the key in case of irregular plural
|
||||
*
|
||||
* @return NormalizationBuilder
|
||||
*/
|
||||
public function remap($key, $plural = null)
|
||||
{
|
||||
$this->remappings[] = array($key, null === $plural ? $key.'s' : $plural);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a closure to run before the normalization or an expression builder to build it if null is provided.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder|NormalizationBuilder
|
||||
*/
|
||||
public function before(\Closure $closure = null)
|
||||
{
|
||||
if (null !== $closure) {
|
||||
$this->before[] = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->before[] = new ExprBuilder($this->node);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* An interface that must be implemented by nodes which can have children
|
||||
*
|
||||
* @author Victor Berchet <victor@suumit.com>
|
||||
*/
|
||||
interface ParentNodeDefinitionInterface
|
||||
{
|
||||
public function children();
|
||||
|
||||
public function append(NodeDefinition $node);
|
||||
|
||||
public function setBuilder(NodeBuilder $builder);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\ScalarNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ScalarNodeDefinition extends VariableNodeDefinition
|
||||
{
|
||||
/**
|
||||
* Instantiate a Node
|
||||
*
|
||||
* @return ScalarNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new ScalarNode($this->name, $this->parent);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This is the entry class for building a config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class TreeBuilder implements NodeParentInterface
|
||||
{
|
||||
protected $tree;
|
||||
protected $root;
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* Creates the root node.
|
||||
*
|
||||
* @param string $name The name of the root node
|
||||
* @param string $type The type of the root node
|
||||
* @param NodeBuilder $builder A custom node builder instance
|
||||
*
|
||||
* @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array')
|
||||
*
|
||||
* @throws \RuntimeException When the node type is not supported
|
||||
*/
|
||||
public function root($name, $type = 'array', NodeBuilder $builder = null)
|
||||
{
|
||||
$builder = $builder ?: new NodeBuilder();
|
||||
|
||||
return $this->root = $builder->node($name, $type)->setParent($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the tree.
|
||||
*
|
||||
* @return NodeInterface
|
||||
*/
|
||||
public function buildTree()
|
||||
{
|
||||
if (null === $this->root) {
|
||||
throw new \RuntimeException('The configuration tree has no root node.');
|
||||
}
|
||||
if (null !== $this->tree) {
|
||||
return $this->tree;
|
||||
}
|
||||
|
||||
return $this->tree = $this->root->getNode(true);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class builds validation conditions.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class ValidationBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $rules;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
|
||||
$this->rules = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a closure to run as normalization or an expression builder to build it if null is provided.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder|ValidationBuilder
|
||||
*/
|
||||
public function rule(\Closure $closure = null)
|
||||
{
|
||||
if (null !== $closure) {
|
||||
$this->rules[] = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->rules[] = new ExprBuilder($this->node);
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\VariableNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class VariableNodeDefinition extends NodeDefinition
|
||||
{
|
||||
/**
|
||||
* Instantiate a Node
|
||||
*
|
||||
* @return VariableNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new VariableNode($this->name, $this->parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function createNode()
|
||||
{
|
||||
$node = $this->instantiateNode();
|
||||
|
||||
if (null !== $this->normalization) {
|
||||
$node->setNormalizationClosures($this->normalization->before);
|
||||
}
|
||||
|
||||
if (null !== $this->merge) {
|
||||
$node->setAllowOverwrite($this->merge->allowOverwrite);
|
||||
}
|
||||
|
||||
if (true === $this->default) {
|
||||
$node->setDefaultValue($this->defaultValue);
|
||||
}
|
||||
|
||||
if (false === $this->allowEmptyValue) {
|
||||
$node->setAllowEmptyValue($this->allowEmptyValue);
|
||||
}
|
||||
|
||||
$node->addEquivalentValue(null, $this->nullEquivalent);
|
||||
$node->addEquivalentValue(true, $this->trueEquivalent);
|
||||
$node->addEquivalentValue(false, $this->falseEquivalent);
|
||||
$node->setRequired($this->required);
|
||||
|
||||
if (null !== $this->validation) {
|
||||
$node->setFinalValidationClosures($this->validation->rules);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
/**
|
||||
* Configuration interface
|
||||
*
|
||||
* @author Victor Berchet <victor@suumit.com>
|
||||
*/
|
||||
interface ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* Generates the configuration tree builder.
|
||||
*
|
||||
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
|
||||
*/
|
||||
public function getConfigTreeBuilder();
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Config\Definition\ScalarNode;
|
||||
|
||||
/**
|
||||
* Node which only allows a finite set of values.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class EnumNode extends ScalarNode
|
||||
{
|
||||
private $values;
|
||||
|
||||
public function __construct($name, NodeInterface $parent = null, array $values = array())
|
||||
{
|
||||
$values = array_unique($values);
|
||||
if (count($values) <= 1) {
|
||||
throw new \InvalidArgumentException('$values must contain at least two distinct elements.');
|
||||
}
|
||||
|
||||
parent::__construct($name, $parent);
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
$value = parent::finalizeValue($value);
|
||||
|
||||
if (!in_array($value, $this->values, true)) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'The value %s is not allowed for path "%s". Permissible values: %s',
|
||||
json_encode($value),
|
||||
$this->getPath(),
|
||||
implode(', ', array_map('json_encode', $this->values))));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown whenever the key of an array is not unique. This can
|
||||
* only be the case if the configuration is coming from an XML file.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class DuplicateKeyException extends InvalidConfigurationException
|
||||
{
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* Base exception for all configuration exceptions
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class Exception extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a configuration path is overwritten from a
|
||||
* subsequent configuration file, but the entry node specifically forbids this.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ForbiddenOverwriteException extends InvalidConfigurationException
|
||||
{
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* A very general exception which can be thrown whenever non of the more specific
|
||||
* exceptions is suitable.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class InvalidConfigurationException extends Exception
|
||||
{
|
||||
private $path;
|
||||
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when an error is detected in a node Definition.
|
||||
*
|
||||
* @author Victor Berchet <victor.berchet@suumit.com>
|
||||
*/
|
||||
class InvalidDefinitionException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown if an invalid type is encountered.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class InvalidTypeException extends InvalidConfigurationException
|
||||
{
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is usually not encountered by the end-user, but only used
|
||||
* internally to signal the parent scope to unset a key.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class UnsetKeyException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
/**
|
||||
* Common Interface among all nodes.
|
||||
*
|
||||
* In most cases, it is better to inherit from BaseNode instead of implementing
|
||||
* this interface yourself.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface NodeInterface
|
||||
{
|
||||
/**
|
||||
* Returns the name of the node.
|
||||
*
|
||||
* @return string The name of the node
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Returns the path of the node.
|
||||
*
|
||||
* @return string The node path
|
||||
*/
|
||||
public function getPath();
|
||||
|
||||
/**
|
||||
* Returns true when the node is required.
|
||||
*
|
||||
* @return Boolean If the node is required
|
||||
*/
|
||||
public function isRequired();
|
||||
|
||||
/**
|
||||
* Returns true when the node has a default value.
|
||||
*
|
||||
* @return Boolean If the node has a default value
|
||||
*/
|
||||
public function hasDefaultValue();
|
||||
|
||||
/**
|
||||
* Returns the default value of the node.
|
||||
*
|
||||
* @return mixed The default value
|
||||
* @throws \RuntimeException if the node has no default value
|
||||
*/
|
||||
public function getDefaultValue();
|
||||
|
||||
/**
|
||||
* Normalizes the supplied value.
|
||||
*
|
||||
* @param mixed $value The value to normalize
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*/
|
||||
public function normalize($value);
|
||||
|
||||
/**
|
||||
* Merges two values together.
|
||||
*
|
||||
* @param mixed $leftSide
|
||||
* @param mixed $rightSide
|
||||
*
|
||||
* @return mixed The merged values
|
||||
*/
|
||||
public function merge($leftSide, $rightSide);
|
||||
|
||||
/**
|
||||
* Finalizes a value.
|
||||
*
|
||||
* @param mixed $value The value to finalize
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*/
|
||||
public function finalize($value);
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
/**
|
||||
* This class is the entry point for config normalization/merging/finalization.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class Processor
|
||||
{
|
||||
/**
|
||||
* Processes an array of configurations.
|
||||
*
|
||||
* @param NodeInterface $configTree The node tree describing the configuration
|
||||
* @param array $configs An array of configuration items to process
|
||||
*
|
||||
* @return array The processed configuration
|
||||
*/
|
||||
public function process(NodeInterface $configTree, array $configs)
|
||||
{
|
||||
$configs = self::normalizeKeys($configs);
|
||||
|
||||
$currentConfig = array();
|
||||
foreach ($configs as $config) {
|
||||
$config = $configTree->normalize($config);
|
||||
$currentConfig = $configTree->merge($currentConfig, $config);
|
||||
}
|
||||
|
||||
return $configTree->finalize($currentConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an array of configurations.
|
||||
*
|
||||
* @param ConfigurationInterface $configuration The configuration class
|
||||
* @param array $configs An array of configuration items to process
|
||||
*
|
||||
* @return array The processed configuration
|
||||
*/
|
||||
public function processConfiguration(ConfigurationInterface $configuration, array $configs)
|
||||
{
|
||||
return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method normalizes keys between the different configuration formats
|
||||
*
|
||||
* Namely, you mostly have foo_bar in YAML while you have foo-bar in XML.
|
||||
* After running this method, all keys are normalized to foo_bar.
|
||||
*
|
||||
* If you have a mixed key like foo-bar_moo, it will not be altered.
|
||||
* The key will also not be altered if the target key already exists.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return array the config with normalized keys
|
||||
*/
|
||||
public static function normalizeKeys(array $config)
|
||||
{
|
||||
foreach ($config as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$config[$key] = self::normalizeKeys($value);
|
||||
}
|
||||
|
||||
if (false !== strpos($key, '-') && false === strpos($key, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $key), $config)) {
|
||||
$config[$normalizedKey] = $config[$key];
|
||||
unset($config[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a configuration entry.
|
||||
*
|
||||
* This method returns a normalize configuration array for a given key
|
||||
* to remove the differences due to the original format (YAML and XML mainly).
|
||||
*
|
||||
* Here is an example.
|
||||
*
|
||||
* The configuration in XML:
|
||||
*
|
||||
* <twig:extension>twig.extension.foo</twig:extension>
|
||||
* <twig:extension>twig.extension.bar</twig:extension>
|
||||
*
|
||||
* And the same configuration in YAML:
|
||||
*
|
||||
* extensions: ['twig.extension.foo', 'twig.extension.bar']
|
||||
*
|
||||
* @param array $config A config array
|
||||
* @param string $key The key to normalize
|
||||
* @param string $plural The plural form of the key if it is irregular
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeConfig($config, $key, $plural = null)
|
||||
{
|
||||
if (null === $plural) {
|
||||
$plural = $key.'s';
|
||||
}
|
||||
|
||||
$values = array();
|
||||
if (isset($config[$plural])) {
|
||||
$values = $config[$plural];
|
||||
} elseif (isset($config[$key])) {
|
||||
if (is_string($config[$key]) || !is_int(key($config[$key]))) {
|
||||
// only one
|
||||
$values = array($config[$key]);
|
||||
} else {
|
||||
$values = $config[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
/**
|
||||
* This interface must be implemented by nodes which can be used as prototypes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface PrototypeNodeInterface extends NodeInterface
|
||||
{
|
||||
/**
|
||||
* Sets the name of the node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*/
|
||||
public function setName($name);
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
|
||||
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
|
||||
use Symfony\Component\Config\Definition\Exception\Exception;
|
||||
|
||||
/**
|
||||
* Represents a prototyped Array node in the config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class PrototypedArrayNode extends ArrayNode
|
||||
{
|
||||
protected $prototype;
|
||||
protected $keyAttribute;
|
||||
protected $removeKeyAttribute;
|
||||
protected $minNumberOfElements;
|
||||
protected $defaultValue;
|
||||
protected $defaultChildren;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The Node's name
|
||||
* @param NodeInterface $parent The node parent
|
||||
*/
|
||||
public function __construct($name, NodeInterface $parent = null)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
|
||||
$this->minNumberOfElements = 0;
|
||||
$this->defaultValue = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum number of elements that a prototype based node must
|
||||
* contain. By default this is zero, meaning no elements.
|
||||
*
|
||||
* @param integer $number
|
||||
*/
|
||||
public function setMinNumberOfElements($number)
|
||||
{
|
||||
$this->minNumberOfElements = $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attribute which value is to be used as key.
|
||||
*
|
||||
* This is useful when you have an indexed array that should be an
|
||||
* associative array. You can select an item from within the array
|
||||
* to be the key of the particular item. For example, if "id" is the
|
||||
* "key", then:
|
||||
*
|
||||
* array(
|
||||
* array('id' => 'my_name', 'foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* becomes
|
||||
*
|
||||
* array(
|
||||
* 'my_name' => array('foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* If you'd like "'id' => 'my_name'" to still be present in the resulting
|
||||
* array, then you can set the second argument of this method to false.
|
||||
*
|
||||
* @param string $attribute The name of the attribute which value is to be used as a key
|
||||
* @param Boolean $remove Whether or not to remove the key
|
||||
*/
|
||||
public function setKeyAttribute($attribute, $remove = true)
|
||||
{
|
||||
$this->keyAttribute = $attribute;
|
||||
$this->removeKeyAttribute = $remove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the name of the attribute which value should be used as key.
|
||||
*
|
||||
* @return string The name of the attribute
|
||||
*/
|
||||
public function getKeyAttribute()
|
||||
{
|
||||
return $this->keyAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value of this node.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the default value is not an array
|
||||
*/
|
||||
public function setDefaultValue($value)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
|
||||
}
|
||||
|
||||
$this->defaultValue = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node has a default value.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function hasDefaultValue()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default children when none are set.
|
||||
*
|
||||
* @param integer|string|array|null $children The number of children|The child name|The children names to be added
|
||||
*/
|
||||
public function setAddChildrenIfNoneSet($children = array('defaults'))
|
||||
{
|
||||
if (null === $children) {
|
||||
$this->defaultChildren = array('defaults');
|
||||
} else {
|
||||
$this->defaultChildren = is_integer($children) && $children > 0 ? range(1, $children) : (array) $children;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default value.
|
||||
*
|
||||
* The default value could be either explicited or derived from the prototype
|
||||
* default value.
|
||||
*
|
||||
* @return array The default value
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
if (null !== $this->defaultChildren) {
|
||||
$default = $this->prototype->hasDefaultValue() ? $this->prototype->getDefaultValue() : array();
|
||||
$defaults = array();
|
||||
foreach (array_values($this->defaultChildren) as $i => $name) {
|
||||
$defaults[null === $this->keyAttribute ? $i : $name] = $default;
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the node prototype.
|
||||
*
|
||||
* @param PrototypeNodeInterface $node
|
||||
*/
|
||||
public function setPrototype(PrototypeNodeInterface $node)
|
||||
{
|
||||
$this->prototype = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the prototype
|
||||
*
|
||||
* @return PrototypeNodeInterface The prototype
|
||||
*/
|
||||
public function getPrototype()
|
||||
{
|
||||
return $this->prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable adding concrete children for prototyped nodes.
|
||||
*
|
||||
* @param NodeInterface $node The child node to add
|
||||
*
|
||||
* @throws \RuntimeException Prototyped array nodes can't have concrete children.
|
||||
*/
|
||||
public function addChild(NodeInterface $node)
|
||||
{
|
||||
throw new Exception('A prototyped array node can not have concrete children.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the value of this node.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*
|
||||
* @throws UnsetKeyException
|
||||
* @throws InvalidConfigurationException if the node doesn't have enough children
|
||||
*/
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
$msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
|
||||
throw new UnsetKeyException($msg);
|
||||
}
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
$this->prototype->setName($k);
|
||||
try {
|
||||
$value[$k] = $this->prototype->finalize($v);
|
||||
} catch (UnsetKeyException $unset) {
|
||||
unset($value[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($value) < $this->minNumberOfElements) {
|
||||
$msg = sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements);
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the value.
|
||||
*
|
||||
* @param mixed $value The value to normalize
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = $this->remapXml($value);
|
||||
|
||||
$isAssoc = array_keys($value) !== range(0, count($value) -1);
|
||||
$normalized = array();
|
||||
foreach ($value as $k => $v) {
|
||||
if (null !== $this->keyAttribute && is_array($v)) {
|
||||
if (!isset($v[$this->keyAttribute]) && is_int($k) && !$isAssoc) {
|
||||
$msg = sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath());
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
} elseif (isset($v[$this->keyAttribute])) {
|
||||
$k = $v[$this->keyAttribute];
|
||||
|
||||
// remove the key attribute when required
|
||||
if ($this->removeKeyAttribute) {
|
||||
unset($v[$this->keyAttribute]);
|
||||
}
|
||||
|
||||
// if only "value" is left
|
||||
if (1 == count($v) && isset($v['value'])) {
|
||||
$v = $v['value'];
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($k, $normalized)) {
|
||||
$msg = sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath());
|
||||
$ex = new DuplicateKeyException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
$this->prototype->setName($k);
|
||||
if (null !== $this->keyAttribute || $isAssoc) {
|
||||
$normalized[$k] = $this->prototype->normalize($v);
|
||||
} else {
|
||||
$normalized[] = $this->prototype->normalize($v);
|
||||
}
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges values together.
|
||||
*
|
||||
* @param mixed $leftSide The left side to merge.
|
||||
* @param mixed $rightSide The right side to merge.
|
||||
*
|
||||
* @return mixed The merged values
|
||||
*
|
||||
* @throws InvalidConfigurationException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function mergeValues($leftSide, $rightSide)
|
||||
{
|
||||
if (false === $rightSide) {
|
||||
// if this is still false after the last config has been merged the
|
||||
// finalization pass will take care of removing this key entirely
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false === $leftSide || !$this->performDeepMerging) {
|
||||
return $rightSide;
|
||||
}
|
||||
|
||||
foreach ($rightSide as $k => $v) {
|
||||
// prototype, and key is irrelevant, so simply append the element
|
||||
if (null === $this->keyAttribute) {
|
||||
$leftSide[] = $v;
|
||||
continue;
|
||||
}
|
||||
|
||||
// no conflict
|
||||
if (!array_key_exists($k, $leftSide)) {
|
||||
if (!$this->allowNewKeys) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'You are not allowed to define new elements for path "%s". ' .
|
||||
'Please define all elements for this path in one config file.',
|
||||
$this->getPath()
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$leftSide[$k] = $v;
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->prototype->setName($k);
|
||||
$leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
|
||||
}
|
||||
|
||||
return $leftSide;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\VariableNode;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
|
||||
/**
|
||||
* This node represents a scalar value in the config tree.
|
||||
*
|
||||
* The following values are considered scalars:
|
||||
* * booleans
|
||||
* * strings
|
||||
* * null
|
||||
* * integers
|
||||
* * floats
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ScalarNode extends VariableNode
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
if (!is_scalar($value) && null !== $value) {
|
||||
$ex = new InvalidTypeException(sprintf(
|
||||
'Invalid type for path "%s". Expected scalar, but got %s.',
|
||||
$this->getPath(),
|
||||
gettype($value)
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
|
||||
/**
|
||||
* This node represents a value of variable type in the config tree.
|
||||
*
|
||||
* This node is intended for values of arbitrary type.
|
||||
* Any PHP type is accepted as a value.
|
||||
*
|
||||
* @author Jeremy Mikola <jmikola@gmail.com>
|
||||
*/
|
||||
class VariableNode extends BaseNode implements PrototypeNodeInterface
|
||||
{
|
||||
protected $defaultValueSet = false;
|
||||
protected $defaultValue;
|
||||
protected $allowEmptyValue = true;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setDefaultValue($value)
|
||||
{
|
||||
$this->defaultValueSet = true;
|
||||
$this->defaultValue = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasDefaultValue()
|
||||
{
|
||||
return $this->defaultValueSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return $this->defaultValue instanceof \Closure ? call_user_func($this->defaultValue) : $this->defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this node is allowed to have an empty value.
|
||||
*
|
||||
* @param Boolean $boolean True if this entity will accept empty values.
|
||||
*/
|
||||
public function setAllowEmptyValue($boolean)
|
||||
{
|
||||
$this->allowEmptyValue = (Boolean) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
if (!$this->allowEmptyValue && empty($value)) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'The path "%s" cannot contain an empty value, but got %s.',
|
||||
$this->getPath(),
|
||||
json_encode($value)
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function mergeValues($leftSide, $rightSide)
|
||||
{
|
||||
return $rightSide;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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\Config\Exception;
|
||||
|
||||
/**
|
||||
* Exception class for when a circular reference is detected when importing resources.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FileLoaderImportCircularReferenceException extends FileLoaderLoadException
|
||||
{
|
||||
public function __construct(array $resources, $code = null, $previous = null)
|
||||
{
|
||||
$message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
|
||||
|
||||
call_user_func('Exception::__construct', $message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<?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\Config\Exception;
|
||||
|
||||
/**
|
||||
* Exception class for when a resource cannot be loaded or imported.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@thatsquality.com>
|
||||
*/
|
||||
class FileLoaderLoadException extends \Exception
|
||||
{
|
||||
/**
|
||||
* @param string $resource The resource that could not be imported
|
||||
* @param string $sourceResource The original resource importing the new resource
|
||||
* @param integer $code The error code
|
||||
* @param Exception $previous A previous exception
|
||||
*/
|
||||
public function __construct($resource, $sourceResource = null, $code = null, $previous = null)
|
||||
{
|
||||
if (null === $sourceResource) {
|
||||
$message = sprintf('Cannot load resource "%s".', $this->varToString($resource));
|
||||
} else {
|
||||
$message = sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource));
|
||||
}
|
||||
|
||||
// Is the resource located inside a bundle?
|
||||
if ('@' === $resource[0]) {
|
||||
$parts = explode(DIRECTORY_SEPARATOR, $resource);
|
||||
$bundle = substr($parts[0], 1);
|
||||
$message .= ' '.sprintf('Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
|
||||
}
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
protected function varToString($var)
|
||||
{
|
||||
if (is_object($var)) {
|
||||
return sprintf('Object(%s)', get_class($var));
|
||||
}
|
||||
|
||||
if (is_array($var)) {
|
||||
$a = array();
|
||||
foreach ($var as $k => $v) {
|
||||
$a[] = sprintf('%s => %s', $k, $this->varToString($v));
|
||||
}
|
||||
|
||||
return sprintf("Array(%s)", implode(', ', $a));
|
||||
}
|
||||
|
||||
if (is_resource($var)) {
|
||||
return sprintf('Resource(%s)', get_resource_type($var));
|
||||
}
|
||||
|
||||
if (null === $var) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (false === $var) {
|
||||
return 'false';
|
||||
}
|
||||
|
||||
if (true === $var) {
|
||||
return 'true';
|
||||
}
|
||||
|
||||
return (string) $var;
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<?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\Config;
|
||||
|
||||
/**
|
||||
* FileLocator uses an array of pre-defined paths to find files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FileLocator implements FileLocatorInterface
|
||||
{
|
||||
protected $paths;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|array $paths A path or an array of paths where to look for resources
|
||||
*/
|
||||
public function __construct($paths = array())
|
||||
{
|
||||
$this->paths = (array) $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full path for a given file name.
|
||||
*
|
||||
* @param mixed $name The file name to locate
|
||||
* @param string $currentPath The current path
|
||||
* @param Boolean $first Whether to return the first occurrence or an array of filenames
|
||||
*
|
||||
* @return string|array The full path to the file|An array of file paths
|
||||
*
|
||||
* @throws \InvalidArgumentException When file is not found
|
||||
*/
|
||||
public function locate($name, $currentPath = null, $first = true)
|
||||
{
|
||||
if ($this->isAbsolutePath($name)) {
|
||||
if (!file_exists($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
$filepaths = array();
|
||||
if (null !== $currentPath && file_exists($file = $currentPath.DIRECTORY_SEPARATOR.$name)) {
|
||||
if (true === $first) {
|
||||
return $file;
|
||||
}
|
||||
$filepaths[] = $file;
|
||||
}
|
||||
|
||||
foreach ($this->paths as $path) {
|
||||
if (file_exists($file = $path.DIRECTORY_SEPARATOR.$name)) {
|
||||
if (true === $first) {
|
||||
return $file;
|
||||
}
|
||||
$filepaths[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$filepaths) {
|
||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist (in: %s%s).', $name, null !== $currentPath ? $currentPath.', ' : '', implode(', ', $this->paths)));
|
||||
}
|
||||
|
||||
return array_values(array_unique($filepaths));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the file path is an absolute path.
|
||||
*
|
||||
* @param string $file A file path
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
private function isAbsolutePath($file)
|
||||
{
|
||||
if ($file[0] == '/' || $file[0] == '\\'
|
||||
|| (strlen($file) > 3 && ctype_alpha($file[0])
|
||||
&& $file[1] == ':'
|
||||
&& ($file[2] == '\\' || $file[2] == '/')
|
||||
)
|
||||
|| null !== parse_url($file, PHP_URL_SCHEME)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?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\Config;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface FileLocatorInterface
|
||||
{
|
||||
/**
|
||||
* Returns a full path for a given file name.
|
||||
*
|
||||
* @param mixed $name The file name to locate
|
||||
* @param string $currentPath The current path
|
||||
* @param Boolean $first Whether to return the first occurrence or an array of filenames
|
||||
*
|
||||
* @return string|array The full path to the file|An array of file paths
|
||||
*
|
||||
* @throws \InvalidArgumentException When file is not found
|
||||
*/
|
||||
public function locate($name, $currentPath = null, $first = true);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2004-2012 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
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,62 +0,0 @@
|
||||
<?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\Config\Loader;
|
||||
|
||||
use Symfony\Component\Config\Exception\FileLoaderLoadException;
|
||||
|
||||
/**
|
||||
* DelegatingLoader delegates loading to other loaders using a loader resolver.
|
||||
*
|
||||
* This loader acts as an array of LoaderInterface objects - each having
|
||||
* a chance to load a given resource (handled by the resolver)
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DelegatingLoader extends Loader
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
|
||||
*/
|
||||
public function __construct(LoaderResolverInterface $resolver)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws FileLoaderLoadException if no loader is found.
|
||||
*/
|
||||
public function load($resource, $type = null)
|
||||
{
|
||||
if (false === $loader = $this->resolver->resolve($resource, $type)) {
|
||||
throw new FileLoaderLoadException($resource);
|
||||
}
|
||||
|
||||
return $loader->load($resource, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return false === $this->resolver->resolve($resource, $type) ? false : true;
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
<?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\Config\Loader;
|
||||
|
||||
use Symfony\Component\Config\FileLocatorInterface;
|
||||
use Symfony\Component\Config\Exception\FileLoaderLoadException;
|
||||
use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;
|
||||
|
||||
/**
|
||||
* FileLoader is the abstract class used by all built-in loaders that are file based.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class FileLoader extends Loader
|
||||
{
|
||||
protected static $loading = array();
|
||||
|
||||
protected $locator;
|
||||
|
||||
private $currentDir;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param FileLocatorInterface $locator A FileLocatorInterface instance
|
||||
*/
|
||||
public function __construct(FileLocatorInterface $locator)
|
||||
{
|
||||
$this->locator = $locator;
|
||||
}
|
||||
|
||||
public function setCurrentDir($dir)
|
||||
{
|
||||
$this->currentDir = $dir;
|
||||
}
|
||||
|
||||
public function getLocator()
|
||||
{
|
||||
return $this->locator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a resource.
|
||||
*
|
||||
* @param mixed $resource A Resource
|
||||
* @param string $type The resource type
|
||||
* @param Boolean $ignoreErrors Whether to ignore import errors or not
|
||||
* @param string $sourceResource The original resource importing the new resource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
|
||||
{
|
||||
try {
|
||||
$loader = $this->resolve($resource, $type);
|
||||
|
||||
if ($loader instanceof FileLoader && null !== $this->currentDir) {
|
||||
$resource = $this->locator->locate($resource, $this->currentDir);
|
||||
}
|
||||
|
||||
if (isset(self::$loading[$resource])) {
|
||||
throw new FileLoaderImportCircularReferenceException(array_keys(self::$loading));
|
||||
}
|
||||
self::$loading[$resource] = true;
|
||||
|
||||
$ret = $loader->load($resource, $type);
|
||||
|
||||
unset(self::$loading[$resource]);
|
||||
|
||||
return $ret;
|
||||
} catch (FileLoaderImportCircularReferenceException $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
if (!$ignoreErrors) {
|
||||
// prevent embedded imports from nesting multiple exceptions
|
||||
if ($e instanceof FileLoaderLoadException) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
throw new FileLoaderLoadException($resource, $sourceResource, null, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?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\Config\Loader;
|
||||
|
||||
use Symfony\Component\Config\Exception\FileLoaderLoadException;
|
||||
|
||||
/**
|
||||
* Loader is the abstract class used by all built-in loaders.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Loader implements LoaderInterface
|
||||
{
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* Gets the loader resolver.
|
||||
*
|
||||
* @return LoaderResolverInterface A LoaderResolverInterface instance
|
||||
*/
|
||||
public function getResolver()
|
||||
{
|
||||
return $this->resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the loader resolver.
|
||||
*
|
||||
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
|
||||
*/
|
||||
public function setResolver(LoaderResolverInterface $resolver)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a resource.
|
||||
*
|
||||
* @param mixed $resource A Resource
|
||||
* @param string $type The resource type
|
||||
*/
|
||||
public function import($resource, $type = null)
|
||||
{
|
||||
$this->resolve($resource)->load($resource, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a loader able to load an imported resource.
|
||||
*
|
||||
* @param mixed $resource A Resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return LoaderInterface A LoaderInterface instance
|
||||
*
|
||||
* @throws FileLoaderLoadException if no loader is found
|
||||
*/
|
||||
public function resolve($resource, $type = null)
|
||||
{
|
||||
if ($this->supports($resource, $type)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$loader = null === $this->resolver ? false : $this->resolver->resolve($resource, $type);
|
||||
|
||||
if (false === $loader) {
|
||||
throw new FileLoaderLoadException($resource);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?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\Config\Loader;
|
||||
|
||||
/**
|
||||
* LoaderInterface is the interface implemented by all loader classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface LoaderInterface
|
||||
{
|
||||
/**
|
||||
* Loads a resource.
|
||||
*
|
||||
* @param mixed $resource The resource
|
||||
* @param string $type The resource type
|
||||
*/
|
||||
public function load($resource, $type = null);
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean true if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null);
|
||||
|
||||
/**
|
||||
* Gets the loader resolver.
|
||||
*
|
||||
* @return LoaderResolverInterface A LoaderResolverInterface instance
|
||||
*/
|
||||
public function getResolver();
|
||||
|
||||
/**
|
||||
* Sets the loader resolver.
|
||||
*
|
||||
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
|
||||
*/
|
||||
public function setResolver(LoaderResolverInterface $resolver);
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
<?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\Config\Loader;
|
||||
|
||||
/**
|
||||
* LoaderResolver selects a loader for a given resource.
|
||||
*
|
||||
* A resource can be anything (e.g. a full path to a config file or a Closure).
|
||||
* Each loader determines whether it can load a resource and how.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class LoaderResolver implements LoaderResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var LoaderInterface[] An array of LoaderInterface objects
|
||||
*/
|
||||
private $loaders;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param LoaderInterface[] $loaders An array of loaders
|
||||
*/
|
||||
public function __construct(array $loaders = array())
|
||||
{
|
||||
$this->loaders = array();
|
||||
foreach ($loaders as $loader) {
|
||||
$this->addLoader($loader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a loader able to load the resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return LoaderInterface|false A LoaderInterface instance
|
||||
*/
|
||||
public function resolve($resource, $type = null)
|
||||
{
|
||||
foreach ($this->loaders as $loader) {
|
||||
if ($loader->supports($resource, $type)) {
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a loader.
|
||||
*
|
||||
* @param LoaderInterface $loader A LoaderInterface instance
|
||||
*/
|
||||
public function addLoader(LoaderInterface $loader)
|
||||
{
|
||||
$this->loaders[] = $loader;
|
||||
$loader->setResolver($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered loaders.
|
||||
*
|
||||
* @return LoaderInterface[] An array of LoaderInterface instances
|
||||
*/
|
||||
public function getLoaders()
|
||||
{
|
||||
return $this->loaders;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?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\Config\Loader;
|
||||
|
||||
/**
|
||||
* LoaderResolverInterface selects a loader for a given resource.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface LoaderResolverInterface
|
||||
{
|
||||
/**
|
||||
* Returns a loader able to load the resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return LoaderInterface A LoaderInterface instance
|
||||
*/
|
||||
public function resolve($resource, $type = null);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
Config Component
|
||||
================
|
||||
|
||||
Config provides the infrastructure for loading configurations from different
|
||||
data sources and optionally monitoring these data sources for changes. There
|
||||
are additional tools for validating, normalizing and handling of defaults that
|
||||
can optionally be used to convert from different formats to arrays.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
phpunit
|
||||
@@ -1,102 +0,0 @@
|
||||
<?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\Config\Resource;
|
||||
|
||||
/**
|
||||
* DirectoryResource represents a resources stored in a subdirectory tree.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DirectoryResource implements ResourceInterface, \Serializable
|
||||
{
|
||||
private $resource;
|
||||
private $pattern;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $resource The file path to the resource
|
||||
* @param string $pattern A pattern to restrict monitored files
|
||||
*/
|
||||
public function __construct($resource, $pattern = null)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
$this->pattern = $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the Resource.
|
||||
*
|
||||
* @return string A string representation of the Resource
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource tied to this Resource.
|
||||
*
|
||||
* @return mixed The resource
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
public function getPattern()
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the resource has not been updated since the given timestamp.
|
||||
*
|
||||
* @param integer $timestamp The last time the resource was loaded
|
||||
*
|
||||
* @return Boolean true if the resource has not been updated, false otherwise
|
||||
*/
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
if (!is_dir($this->resource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$newestMTime = filemtime($this->resource);
|
||||
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
|
||||
// if regex filtering is enabled only check matching files
|
||||
if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// always monitor directories for changes, except the .. entries
|
||||
// (otherwise deleted files wouldn't get detected)
|
||||
if ($file->isDir() && '/..' === substr($file, -3)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newestMTime = max($file->getMTime(), $newestMTime);
|
||||
}
|
||||
|
||||
return $newestMTime < $timestamp;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array($this->resource, $this->pattern));
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list($this->resource, $this->pattern) = unserialize($serialized);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?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\Config\Resource;
|
||||
|
||||
/**
|
||||
* FileResource represents a resource stored on the filesystem.
|
||||
*
|
||||
* The resource can be a file or a directory.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FileResource implements ResourceInterface, \Serializable
|
||||
{
|
||||
private $resource;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $resource The file path to the resource
|
||||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = realpath($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the Resource.
|
||||
*
|
||||
* @return string A string representation of the Resource
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource tied to this Resource.
|
||||
*
|
||||
* @return mixed The resource
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the resource has not been updated since the given timestamp.
|
||||
*
|
||||
* @param integer $timestamp The last time the resource was loaded
|
||||
*
|
||||
* @return Boolean true if the resource has not been updated, false otherwise
|
||||
*/
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
if (!file_exists($this->resource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return filemtime($this->resource) < $timestamp;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->resource);
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$this->resource = unserialize($serialized);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?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\Config\Resource;
|
||||
|
||||
/**
|
||||
* ResourceInterface is the interface that must be implemented by all Resource classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface ResourceInterface
|
||||
{
|
||||
/**
|
||||
* Returns a string representation of the Resource.
|
||||
*
|
||||
* @return string A string representation of the Resource
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Returns true if the resource has not been updated since the given timestamp.
|
||||
*
|
||||
* @param integer $timestamp The last time the resource was loaded
|
||||
*
|
||||
* @return Boolean true if the resource has not been updated, false otherwise
|
||||
*/
|
||||
public function isFresh($timestamp);
|
||||
|
||||
/**
|
||||
* Returns the resource tied to this Resource.
|
||||
*
|
||||
* @return mixed The resource
|
||||
*/
|
||||
public function getResource();
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"type": "library",
|
||||
"description": "Symfony Config Component",
|
||||
"keywords": [],
|
||||
"homepage": "http://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Symfony\\Component\\Config": "" }
|
||||
},
|
||||
"target-dir": "Symfony/Component/Config",
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
/Tests export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added ConsoleOutputInterface
|
||||
* added the possibility to disable a command (Command::isEnabled())
|
||||
* added suggestions when a command does not exist
|
||||
* added a --raw option to the list command
|
||||
* added support for STDERR in the console output class (errors are now sent
|
||||
to STDERR)
|
||||
* made the defaults (helper set, commands, input definition) in Application
|
||||
more easily customizable
|
||||
* added support for the shell even if readline is not available
|
||||
* added support for process isolation in Symfony shell via
|
||||
`--process-isolation` switch
|
||||
* added support for `--`, which disables options parsing after that point
|
||||
(tokens will be parsed as arguments)
|
||||
@@ -1,616 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
|
||||
/**
|
||||
* Base class for all commands.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Command
|
||||
{
|
||||
private $application;
|
||||
private $name;
|
||||
private $aliases;
|
||||
private $definition;
|
||||
private $help;
|
||||
private $description;
|
||||
private $ignoreValidationErrors;
|
||||
private $applicationDefinitionMerged;
|
||||
private $code;
|
||||
private $synopsis;
|
||||
private $helperSet;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the command
|
||||
*
|
||||
* @throws \LogicException When the command name is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
$this->definition = new InputDefinition();
|
||||
$this->ignoreValidationErrors = false;
|
||||
$this->applicationDefinitionMerged = false;
|
||||
$this->aliases = array();
|
||||
|
||||
if (null !== $name) {
|
||||
$this->setName($name);
|
||||
}
|
||||
|
||||
$this->configure();
|
||||
|
||||
if (!$this->name) {
|
||||
throw new \LogicException('The command name cannot be empty.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignores validation errors.
|
||||
*
|
||||
* This is mainly useful for the help command.
|
||||
*/
|
||||
public function ignoreValidationErrors()
|
||||
{
|
||||
$this->ignoreValidationErrors = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the application instance for this command.
|
||||
*
|
||||
* @param Application $application An Application instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setApplication(Application $application = null)
|
||||
{
|
||||
$this->application = $application;
|
||||
if ($application) {
|
||||
$this->setHelperSet($application->getHelperSet());
|
||||
} else {
|
||||
$this->helperSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the helper set.
|
||||
*
|
||||
* @param HelperSet $helperSet A HelperSet instance
|
||||
*/
|
||||
public function setHelperSet(HelperSet $helperSet)
|
||||
{
|
||||
$this->helperSet = $helperSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the helper set.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*/
|
||||
public function getHelperSet()
|
||||
{
|
||||
return $this->helperSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the application instance for this command.
|
||||
*
|
||||
* @return Application An Application instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
return $this->application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the command is enabled or not in the current environment
|
||||
*
|
||||
* Override this to check for x or y and return false if the command can not
|
||||
* run properly under the current conditions.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the current command.
|
||||
*
|
||||
* This method is not abstract because you can use this class
|
||||
* as a concrete class. In this case, instead of defining the
|
||||
* execute() method, you set the code to execute by passing
|
||||
* a Closure to the setCode() method.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return null|integer null or 0 if everything went fine, or an error code
|
||||
*
|
||||
* @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.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Interacts with the user.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the command just after the input has been validated.
|
||||
*
|
||||
* This is mainly useful when a lot of commands extends one main command
|
||||
* where some things need to be initialized based on the input arguments and options.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command.
|
||||
*
|
||||
* The code to execute is either defined directly with the
|
||||
* setCode() method or by overriding the execute() method
|
||||
* in a sub-class.
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*
|
||||
* @return integer The command exit code
|
||||
*
|
||||
* @see setCode()
|
||||
* @see execute()
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function run(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// force the creation of the synopsis before the merge with the app definition
|
||||
$this->getSynopsis();
|
||||
|
||||
// add the application arguments and options
|
||||
$this->mergeApplicationDefinition();
|
||||
|
||||
// bind the input against the command specific arguments/options
|
||||
try {
|
||||
$input->bind($this->definition);
|
||||
} catch (\Exception $e) {
|
||||
if (!$this->ignoreValidationErrors) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$this->initialize($input, $output);
|
||||
|
||||
if ($input->isInteractive()) {
|
||||
$this->interact($input, $output);
|
||||
}
|
||||
|
||||
$input->validate();
|
||||
|
||||
if ($this->code) {
|
||||
$statusCode = call_user_func($this->code, $input, $output);
|
||||
} else {
|
||||
$statusCode = $this->execute($input, $output);
|
||||
}
|
||||
|
||||
return is_numeric($statusCode) ? $statusCode : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the code to execute when running this command.
|
||||
*
|
||||
* If this method is used, it overrides the code defined
|
||||
* in the execute() method.
|
||||
*
|
||||
* @param \Closure $code A \Closure
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @see execute()
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setCode(\Closure $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the application definition with the command definition.
|
||||
*/
|
||||
private function mergeApplicationDefinition()
|
||||
{
|
||||
if (null === $this->application || true === $this->applicationDefinitionMerged) {
|
||||
return;
|
||||
}
|
||||
|
||||
$currentArguments = $this->definition->getArguments();
|
||||
$this->definition->setArguments($this->application->getDefinition()->getArguments());
|
||||
$this->definition->addArguments($currentArguments);
|
||||
|
||||
$this->definition->addOptions($this->application->getDefinition()->getOptions());
|
||||
|
||||
$this->applicationDefinitionMerged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an array of argument and option instances.
|
||||
*
|
||||
* @param array|InputDefinition $definition An array of argument and option instances or a definition instance
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDefinition($definition)
|
||||
{
|
||||
if ($definition instanceof InputDefinition) {
|
||||
$this->definition = $definition;
|
||||
} else {
|
||||
$this->definition->setDefinition($definition);
|
||||
}
|
||||
|
||||
$this->applicationDefinitionMerged = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the InputDefinition attached to this Command.
|
||||
*
|
||||
* @return InputDefinition An InputDefinition instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getDefinition()
|
||||
{
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the InputDefinition to be used to create XML and Text representations of this Command.
|
||||
*
|
||||
* Can be overridden to provide the original command representation when it would otherwise
|
||||
* be changed by merging with the application InputDefinition.
|
||||
*
|
||||
* @return InputDefinition An InputDefinition instance
|
||||
*/
|
||||
protected function getNativeDefinition()
|
||||
{
|
||||
return $this->getDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addArgument($name, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an option.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $shortcut The shortcut (can be null)
|
||||
* @param integer $mode The option mode: 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)
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the command.
|
||||
*
|
||||
* This method can set both the namespace and the name if
|
||||
* you separate them by a colon (:)
|
||||
*
|
||||
* $command->setName('foo:bar');
|
||||
*
|
||||
* @param string $name The command name
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @throws \InvalidArgumentException When command name given is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->validateName($name);
|
||||
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command name.
|
||||
*
|
||||
* @return string The command name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description for the command.
|
||||
*
|
||||
* @param string $description The description for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description for the command.
|
||||
*
|
||||
* @return string The description for the command
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the help for the command.
|
||||
*
|
||||
* @param string $help The help for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setHelp($help)
|
||||
{
|
||||
$this->help = $help;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the help for the command.
|
||||
*
|
||||
* @return string The help for the command
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getHelp()
|
||||
{
|
||||
return $this->help;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processed help for the command replacing the %command.name% and
|
||||
* %command.full_name% patterns with the real values dynamically.
|
||||
*
|
||||
* @return string The processed help for the command
|
||||
*/
|
||||
public function getProcessedHelp()
|
||||
{
|
||||
$name = $this->name;
|
||||
|
||||
$placeholders = array(
|
||||
'%command.name%',
|
||||
'%command.full_name%'
|
||||
);
|
||||
$replacements = array(
|
||||
$name,
|
||||
$_SERVER['PHP_SELF'].' '.$name
|
||||
);
|
||||
|
||||
return str_replace($placeholders, $replacements, $this->getHelp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases for the command.
|
||||
*
|
||||
* @param array $aliases An array of aliases for the command
|
||||
*
|
||||
* @return Command The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
foreach ($aliases as $alias) {
|
||||
$this->validateName($alias);
|
||||
}
|
||||
|
||||
$this->aliases = $aliases;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aliases for the command.
|
||||
*
|
||||
* @return array An array of aliases for the command
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the synopsis for the command.
|
||||
*
|
||||
* @return string The synopsis
|
||||
*/
|
||||
public function getSynopsis()
|
||||
{
|
||||
if (null === $this->synopsis) {
|
||||
$this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
|
||||
}
|
||||
|
||||
return $this->synopsis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper instance by name.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return mixed The helper value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getHelper($name)
|
||||
{
|
||||
return $this->helperSet->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a text representation of the command.
|
||||
*
|
||||
* @return string A string representing the command
|
||||
*/
|
||||
public function asText()
|
||||
{
|
||||
$messages = array(
|
||||
'<comment>Usage:</comment>',
|
||||
' '.$this->getSynopsis(),
|
||||
'',
|
||||
);
|
||||
|
||||
if ($this->getAliases()) {
|
||||
$messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
|
||||
}
|
||||
|
||||
$messages[] = $this->getNativeDefinition()->asText();
|
||||
|
||||
if ($help = $this->getProcessedHelp()) {
|
||||
$messages[] = '<comment>Help:</comment>';
|
||||
$messages[] = ' '.str_replace("\n", "\n ", $help)."\n";
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML representation of the command.
|
||||
*
|
||||
* @param Boolean $asDom Whether to return a DOM or an XML string
|
||||
*
|
||||
* @return string|DOMDocument An XML string representing the command
|
||||
*/
|
||||
public function asXml($asDom = false)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
$dom->appendChild($commandXML = $dom->createElement('command'));
|
||||
$commandXML->setAttribute('id', $this->name);
|
||||
$commandXML->setAttribute('name', $this->name);
|
||||
|
||||
$commandXML->appendChild($usageXML = $dom->createElement('usage'));
|
||||
$usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
|
||||
|
||||
$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getDescription())));
|
||||
|
||||
$commandXML->appendChild($helpXML = $dom->createElement('help'));
|
||||
$helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getProcessedHelp())));
|
||||
|
||||
$commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
|
||||
foreach ($this->getAliases() as $alias) {
|
||||
$aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
|
||||
$aliasXML->appendChild($dom->createTextNode($alias));
|
||||
}
|
||||
|
||||
$definition = $this->getNativeDefinition()->asXml(true);
|
||||
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
|
||||
$commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
|
||||
|
||||
return $asDom ? $dom : $dom->saveXml();
|
||||
}
|
||||
|
||||
private function validateName($name)
|
||||
{
|
||||
if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) {
|
||||
throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
/**
|
||||
* HelpCommand displays the help for a given command.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class HelpCommand extends Command
|
||||
{
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->ignoreValidationErrors();
|
||||
|
||||
$this
|
||||
->setName('help')
|
||||
->setDefinition(array(
|
||||
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
|
||||
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
|
||||
))
|
||||
->setDescription('Displays help for a command')
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command displays help for a given command:
|
||||
|
||||
<info>php %command.full_name% list</info>
|
||||
|
||||
You can also output the help as XML by using the <comment>--xml</comment> option:
|
||||
|
||||
<info>php %command.full_name% --xml list</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command
|
||||
*
|
||||
* @param Command $command The command to set
|
||||
*/
|
||||
public function setCommand(Command $command)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (null === $this->command) {
|
||||
$this->command = $this->getApplication()->get($input->getArgument('command_name'));
|
||||
}
|
||||
|
||||
if ($input->getOption('xml')) {
|
||||
$output->writeln($this->command->asXml(), OutputInterface::OUTPUT_RAW);
|
||||
} else {
|
||||
$output->writeln($this->command->asText());
|
||||
}
|
||||
|
||||
$this->command = null;
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
|
||||
/**
|
||||
* ListCommand displays the list of all available commands for the application.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ListCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('list')
|
||||
->setDefinition($this->createDefinition())
|
||||
->setDescription('Lists commands')
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command lists all commands:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
You can also display the commands for a specific namespace:
|
||||
|
||||
<info>php %command.full_name% test</info>
|
||||
|
||||
You can also output the information as XML by using the <comment>--xml</comment> option:
|
||||
|
||||
<info>php %command.full_name% --xml</info>
|
||||
|
||||
It's also possible to get raw list of commands (useful for embedding command runner):
|
||||
|
||||
<info>php %command.full_name% --raw</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNativeDefinition()
|
||||
{
|
||||
return $this->createDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('xml')) {
|
||||
$output->writeln($this->getApplication()->asXml($input->getArgument('namespace')), OutputInterface::OUTPUT_RAW);
|
||||
} else {
|
||||
$output->writeln($this->getApplication()->asText($input->getArgument('namespace'), $input->getOption('raw')));
|
||||
}
|
||||
}
|
||||
|
||||
private function createDefinition()
|
||||
{
|
||||
return new InputDefinition(array(
|
||||
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
|
||||
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
/**
|
||||
* Formatter class for console output.
|
||||
*
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class OutputFormatter implements OutputFormatterInterface
|
||||
{
|
||||
/**
|
||||
* The pattern to phrase the format.
|
||||
*/
|
||||
const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>((?:(?!\\\\?<).)*)#is';
|
||||
|
||||
private $decorated;
|
||||
private $styles = array();
|
||||
private $styleStack;
|
||||
|
||||
/**
|
||||
* Escapes "<" special char in given text.
|
||||
*
|
||||
* @param string $text Text to escape
|
||||
*
|
||||
* @return string Escaped text
|
||||
*/
|
||||
public static function escape($text)
|
||||
{
|
||||
return preg_replace('/([^\\\\]?)</is', '$1\\<', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes console output formatter.
|
||||
*
|
||||
* @param Boolean $decorated Whether this formatter should actually decorate strings
|
||||
* @param array $styles Array of "name => FormatterStyle" instances
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($decorated = null, array $styles = array())
|
||||
{
|
||||
$this->decorated = (Boolean) $decorated;
|
||||
|
||||
$this->setStyle('error', new OutputFormatterStyle('white', 'red'));
|
||||
$this->setStyle('info', new OutputFormatterStyle('green'));
|
||||
$this->setStyle('comment', new OutputFormatterStyle('yellow'));
|
||||
$this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
|
||||
|
||||
foreach ($styles as $name => $style) {
|
||||
$this->setStyle($name, $style);
|
||||
}
|
||||
|
||||
$this->styleStack = new OutputFormatterStyleStack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorate the messages or not
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDecorated($decorated)
|
||||
{
|
||||
$this->decorated = (Boolean) $decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the decorated flag.
|
||||
*
|
||||
* @return Boolean true if the output will decorate messages, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isDecorated()
|
||||
{
|
||||
return $this->decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new style.
|
||||
*
|
||||
* @param string $name The style name
|
||||
* @param OutputFormatterStyleInterface $style The style instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setStyle($name, OutputFormatterStyleInterface $style)
|
||||
{
|
||||
$this->styles[strtolower($name)] = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if output formatter has style with specified name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasStyle($name)
|
||||
{
|
||||
return isset($this->styles[strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets style options from style with specified name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return OutputFormatterStyleInterface
|
||||
*
|
||||
* @throws \InvalidArgumentException When style isn't defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getStyle($name)
|
||||
{
|
||||
if (!$this->hasStyle($name)) {
|
||||
throw new \InvalidArgumentException('Undefined style: '.$name);
|
||||
}
|
||||
|
||||
return $this->styles[strtolower($name)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a message according to the given styles.
|
||||
*
|
||||
* @param string $message The message to style
|
||||
*
|
||||
* @return string The styled message
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function format($message)
|
||||
{
|
||||
$message = preg_replace_callback(self::FORMAT_PATTERN, array($this, 'replaceStyle'), $message);
|
||||
|
||||
return str_replace('\\<', '<', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OutputFormatterStyleStack
|
||||
*/
|
||||
public function getStyleStack()
|
||||
{
|
||||
return $this->styleStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces style of the output.
|
||||
*
|
||||
* @param array $match
|
||||
*
|
||||
* @return string The replaced style
|
||||
*/
|
||||
private function replaceStyle($match)
|
||||
{
|
||||
// we got "\<" escaped char
|
||||
if ('\\' === $match[1]) {
|
||||
return $this->applyCurrentStyle($match[0]);
|
||||
}
|
||||
|
||||
if ('' === $match[3]) {
|
||||
if ('/' === $match[2]) {
|
||||
// we got "</>" tag
|
||||
$this->styleStack->pop();
|
||||
|
||||
return $this->applyCurrentStyle($match[4]);
|
||||
}
|
||||
|
||||
// we got "<>" tag
|
||||
return '<>'.$this->applyCurrentStyle($match[4]);
|
||||
}
|
||||
|
||||
if (isset($this->styles[strtolower($match[3])])) {
|
||||
$style = $this->styles[strtolower($match[3])];
|
||||
} else {
|
||||
$style = $this->createStyleFromString($match[3]);
|
||||
|
||||
if (false === $style) {
|
||||
return $this->applyCurrentStyle($match[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if ('/' === $match[2]) {
|
||||
$this->styleStack->pop($style);
|
||||
} else {
|
||||
$this->styleStack->push($style);
|
||||
}
|
||||
|
||||
return $this->applyCurrentStyle($match[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to create new style instance from string.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return OutputFormatterStyle|Boolean false if string is not format string
|
||||
*/
|
||||
private function createStyleFromString($string)
|
||||
{
|
||||
if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$style = new OutputFormatterStyle();
|
||||
foreach ($matches as $match) {
|
||||
array_shift($match);
|
||||
|
||||
if ('fg' == $match[0]) {
|
||||
$style->setForeground($match[1]);
|
||||
} elseif ('bg' == $match[0]) {
|
||||
$style->setBackground($match[1]);
|
||||
} else {
|
||||
$style->setOption($match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies current style from stack to text, if must be applied.
|
||||
*
|
||||
* @param string $text Input text
|
||||
*
|
||||
* @return string string Styled text
|
||||
*/
|
||||
private function applyCurrentStyle($text)
|
||||
{
|
||||
return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
/**
|
||||
* Formatter interface for console output.
|
||||
*
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface OutputFormatterInterface
|
||||
{
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorate the messages or not
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDecorated($decorated);
|
||||
|
||||
/**
|
||||
* Gets the decorated flag.
|
||||
*
|
||||
* @return Boolean true if the output will decorate messages, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isDecorated();
|
||||
|
||||
/**
|
||||
* Sets a new style.
|
||||
*
|
||||
* @param string $name The style name
|
||||
* @param OutputFormatterStyleInterface $style The style instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setStyle($name, OutputFormatterStyleInterface $style);
|
||||
|
||||
/**
|
||||
* Checks if output formatter has style with specified name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasStyle($name);
|
||||
|
||||
/**
|
||||
* Gets style options from style with specified name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return OutputFormatterStyleInterface
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getStyle($name);
|
||||
|
||||
/**
|
||||
* Formats a message according to the given styles.
|
||||
*
|
||||
* @param string $message The message to style
|
||||
*
|
||||
* @return string The styled message
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function format($message);
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
/**
|
||||
* Formatter style class for defining styles.
|
||||
*
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
{
|
||||
private static $availableForegroundColors = array(
|
||||
'black' => 30,
|
||||
'red' => 31,
|
||||
'green' => 32,
|
||||
'yellow' => 33,
|
||||
'blue' => 34,
|
||||
'magenta' => 35,
|
||||
'cyan' => 36,
|
||||
'white' => 37
|
||||
);
|
||||
private static $availableBackgroundColors = array(
|
||||
'black' => 40,
|
||||
'red' => 41,
|
||||
'green' => 42,
|
||||
'yellow' => 43,
|
||||
'blue' => 44,
|
||||
'magenta' => 45,
|
||||
'cyan' => 46,
|
||||
'white' => 47
|
||||
);
|
||||
private static $availableOptions = array(
|
||||
'bold' => 1,
|
||||
'underscore' => 4,
|
||||
'blink' => 5,
|
||||
'reverse' => 7,
|
||||
'conceal' => 8
|
||||
);
|
||||
|
||||
private $foreground;
|
||||
private $background;
|
||||
private $options = array();
|
||||
|
||||
/**
|
||||
* Initializes output formatter style.
|
||||
*
|
||||
* @param string $foreground The style foreground color name
|
||||
* @param string $background The style background color name
|
||||
* @param array $options The style options
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($foreground = null, $background = null, array $options = array())
|
||||
{
|
||||
if (null !== $foreground) {
|
||||
$this->setForeground($foreground);
|
||||
}
|
||||
if (null !== $background) {
|
||||
$this->setBackground($background);
|
||||
}
|
||||
if (count($options)) {
|
||||
$this->setOptions($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets style foreground color.
|
||||
*
|
||||
* @param string $color The color name
|
||||
*
|
||||
* @throws \InvalidArgumentException When the color name isn't defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setForeground($color = null)
|
||||
{
|
||||
if (null === $color) {
|
||||
$this->foreground = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset(static::$availableForegroundColors[$color])) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid foreground color specified: "%s". Expected one of (%s)',
|
||||
$color,
|
||||
implode(', ', array_keys(static::$availableForegroundColors))
|
||||
));
|
||||
}
|
||||
|
||||
$this->foreground = static::$availableForegroundColors[$color];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets style background color.
|
||||
*
|
||||
* @param string $color The color name
|
||||
*
|
||||
* @throws \InvalidArgumentException When the color name isn't defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setBackground($color = null)
|
||||
{
|
||||
if (null === $color) {
|
||||
$this->background = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset(static::$availableBackgroundColors[$color])) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid background color specified: "%s". Expected one of (%s)',
|
||||
$color,
|
||||
implode(', ', array_keys(static::$availableBackgroundColors))
|
||||
));
|
||||
}
|
||||
|
||||
$this->background = static::$availableBackgroundColors[$color];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*
|
||||
* @throws \InvalidArgumentException When the option name isn't defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setOption($option)
|
||||
{
|
||||
if (!isset(static::$availableOptions[$option])) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid option specified: "%s". Expected one of (%s)',
|
||||
$option,
|
||||
implode(', ', array_keys(static::$availableOptions))
|
||||
));
|
||||
}
|
||||
|
||||
if (false === array_search(static::$availableOptions[$option], $this->options)) {
|
||||
$this->options[] = static::$availableOptions[$option];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*
|
||||
* @throws \InvalidArgumentException When the option name isn't defined
|
||||
*
|
||||
*/
|
||||
public function unsetOption($option)
|
||||
{
|
||||
if (!isset(static::$availableOptions[$option])) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Invalid option specified: "%s". Expected one of (%s)',
|
||||
$option,
|
||||
implode(', ', array_keys(static::$availableOptions))
|
||||
));
|
||||
}
|
||||
|
||||
$pos = array_search(static::$availableOptions[$option], $this->options);
|
||||
if (false !== $pos) {
|
||||
unset($this->options[$pos]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets multiple style options at once.
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
$this->options = array();
|
||||
|
||||
foreach ($options as $option) {
|
||||
$this->setOption($option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the style to a given text.
|
||||
*
|
||||
* @param string $text The text to style
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function apply($text)
|
||||
{
|
||||
$codes = array();
|
||||
|
||||
if (null !== $this->foreground) {
|
||||
$codes[] = $this->foreground;
|
||||
}
|
||||
if (null !== $this->background) {
|
||||
$codes[] = $this->background;
|
||||
}
|
||||
if (count($this->options)) {
|
||||
$codes = array_merge($codes, $this->options);
|
||||
}
|
||||
|
||||
if (0 === count($codes)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
return sprintf("\033[%sm%s\033[0m", implode(';', $codes), $text);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
/**
|
||||
* Formatter style interface for defining styles.
|
||||
*
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface OutputFormatterStyleInterface
|
||||
{
|
||||
/**
|
||||
* Sets style foreground color.
|
||||
*
|
||||
* @param string $color The color name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setForeground($color = null);
|
||||
|
||||
/**
|
||||
* Sets style background color.
|
||||
*
|
||||
* @param string $color The color name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setBackground($color = null);
|
||||
|
||||
/**
|
||||
* Sets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setOption($option);
|
||||
|
||||
/**
|
||||
* Unsets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*/
|
||||
public function unsetOption($option);
|
||||
|
||||
/**
|
||||
* Sets multiple style options at once.
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function setOptions(array $options);
|
||||
|
||||
/**
|
||||
* Applies the style to a given text.
|
||||
*
|
||||
* @param string $text The text to style
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function apply($text);
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||
*/
|
||||
class OutputFormatterStyleStack
|
||||
{
|
||||
/**
|
||||
* @var OutputFormatterStyleInterface[]
|
||||
*/
|
||||
private $styles;
|
||||
|
||||
/**
|
||||
* @var OutputFormatterStyleInterface
|
||||
*/
|
||||
private $emptyStyle;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param OutputFormatterStyleInterface $emptyStyle
|
||||
*/
|
||||
public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
|
||||
{
|
||||
$this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets stack (ie. empty internal arrays).
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->styles = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a style in the stack.
|
||||
*
|
||||
* @param OutputFormatterStyleInterface $style
|
||||
*/
|
||||
public function push(OutputFormatterStyleInterface $style)
|
||||
{
|
||||
$this->styles[] = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops a style from the stack.
|
||||
*
|
||||
* @param OutputFormatterStyleInterface $style
|
||||
*
|
||||
* @return OutputFormatterStyleInterface
|
||||
*
|
||||
* @throws \InvalidArgumentException When style tags incorrectly nested
|
||||
*/
|
||||
public function pop(OutputFormatterStyleInterface $style = null)
|
||||
{
|
||||
if (empty($this->styles)) {
|
||||
return $this->emptyStyle;
|
||||
}
|
||||
|
||||
if (null === $style) {
|
||||
return array_pop($this->styles);
|
||||
}
|
||||
|
||||
foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
|
||||
if ($style->apply('') === $stackedStyle->apply('')) {
|
||||
$this->styles = array_slice($this->styles, 0, $index);
|
||||
|
||||
return $stackedStyle;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Incorrectly nested style tag found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes current style with stacks top codes.
|
||||
*
|
||||
* @return OutputFormatterStyle
|
||||
*/
|
||||
public function getCurrent()
|
||||
{
|
||||
if (empty($this->styles)) {
|
||||
return $this->emptyStyle;
|
||||
}
|
||||
|
||||
return $this->styles[count($this->styles)-1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormatterStyleInterface $emptyStyle
|
||||
*
|
||||
* @return OutputFormatterStyleStack
|
||||
*/
|
||||
public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
|
||||
{
|
||||
$this->emptyStyle = $emptyStyle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OutputFormatterStyleInterface
|
||||
*/
|
||||
public function getEmptyStyle()
|
||||
{
|
||||
return $this->emptyStyle;
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* The Dialog class provides helpers to interact with the user.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DialogHelper extends Helper
|
||||
{
|
||||
private $inputStream;
|
||||
|
||||
/**
|
||||
* Asks a question to the user.
|
||||
*
|
||||
* @param OutputInterface $output An Output instance
|
||||
* @param string|array $question The question to ask
|
||||
* @param string $default The default answer if none is given by the user
|
||||
*
|
||||
* @return string The user answer
|
||||
*
|
||||
* @throws \RuntimeException If there is no data to read in the input stream
|
||||
*/
|
||||
public function ask(OutputInterface $output, $question, $default = null)
|
||||
{
|
||||
$output->write($question);
|
||||
|
||||
$ret = fgets($this->inputStream ?: STDIN, 4096);
|
||||
if (false === $ret) {
|
||||
throw new \RuntimeException('Aborted');
|
||||
}
|
||||
$ret = trim($ret);
|
||||
|
||||
return strlen($ret) > 0 ? $ret : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks a confirmation to the user.
|
||||
*
|
||||
* The question will be asked until the user answers by nothing, yes, or no.
|
||||
*
|
||||
* @param OutputInterface $output An Output instance
|
||||
* @param string|array $question The question to ask
|
||||
* @param Boolean $default The default answer if the user enters nothing
|
||||
*
|
||||
* @return Boolean true if the user has confirmed, false otherwise
|
||||
*/
|
||||
public function askConfirmation(OutputInterface $output, $question, $default = true)
|
||||
{
|
||||
$answer = 'z';
|
||||
while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) {
|
||||
$answer = $this->ask($output, $question);
|
||||
}
|
||||
|
||||
if (false === $default) {
|
||||
return $answer && 'y' == strtolower($answer[0]);
|
||||
}
|
||||
|
||||
return !$answer || 'y' == strtolower($answer[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks for a value and validates the response.
|
||||
*
|
||||
* The validator receives the data to validate. It must return the
|
||||
* validated data when the data is valid and throw an exception
|
||||
* otherwise.
|
||||
*
|
||||
* @param OutputInterface $output An Output instance
|
||||
* @param string|array $question The question to ask
|
||||
* @param callback $validator A PHP callback
|
||||
* @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
|
||||
* @param string $default The default answer if none is given by the user
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception When any of the validators return an error
|
||||
*/
|
||||
public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null)
|
||||
{
|
||||
$error = null;
|
||||
while (false === $attempts || $attempts--) {
|
||||
if (null !== $error) {
|
||||
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
|
||||
}
|
||||
|
||||
$value = $this->ask($output, $question, $default);
|
||||
|
||||
try {
|
||||
return call_user_func($validator, $value);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
}
|
||||
|
||||
throw $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input stream to read from when interacting with the user.
|
||||
*
|
||||
* This is mainly useful for testing purpose.
|
||||
*
|
||||
* @param resource $stream The input stream
|
||||
*/
|
||||
public function setInputStream($stream)
|
||||
{
|
||||
$this->inputStream = $stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the helper's input stream
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInputStream()
|
||||
{
|
||||
return $this->inputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the helper's canonical name.
|
||||
*
|
||||
* @return string The helper name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'dialog';
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
<?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\Formatter\OutputFormatter;
|
||||
|
||||
/**
|
||||
* The Formatter class provides helpers to format messages.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FormatterHelper extends Helper
|
||||
{
|
||||
/**
|
||||
* Formats a message within a section.
|
||||
*
|
||||
* @param string $section The section name
|
||||
* @param string $message The message
|
||||
* @param string $style The style to apply to the section
|
||||
*
|
||||
* @return string The format section
|
||||
*/
|
||||
public function formatSection($section, $message, $style = 'info')
|
||||
{
|
||||
return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a message as a block of text.
|
||||
*
|
||||
* @param string|array $messages The message to write in the block
|
||||
* @param string $style The style to apply to the whole block
|
||||
* @param Boolean $large Whether to return a large block
|
||||
*
|
||||
* @return string The formatter message
|
||||
*/
|
||||
public function formatBlock($messages, $style, $large = false)
|
||||
{
|
||||
$messages = (array) $messages;
|
||||
|
||||
$len = 0;
|
||||
$lines = array();
|
||||
foreach ($messages as $message) {
|
||||
$message = OutputFormatter::escape($message);
|
||||
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
|
||||
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
|
||||
}
|
||||
|
||||
$messages = $large ? array(str_repeat(' ', $len)) : array();
|
||||
foreach ($lines as $line) {
|
||||
$messages[] = $line.str_repeat(' ', $len - $this->strlen($line));
|
||||
}
|
||||
if ($large) {
|
||||
$messages[] = str_repeat(' ', $len);
|
||||
}
|
||||
|
||||
foreach ($messages as &$message) {
|
||||
$message = sprintf('<%s>%s</%s>', $style, $message, $style);
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of a string, using mb_strlen if it is available.
|
||||
*
|
||||
* @param string $string The string to check its length
|
||||
*
|
||||
* @return integer The length of the string
|
||||
*/
|
||||
private function strlen($string)
|
||||
{
|
||||
if (!function_exists('mb_strlen')) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string)) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
return mb_strlen($string, $encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the helper's canonical name.
|
||||
*
|
||||
* @return string The canonical name of the helper
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'formatter';
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Helper is the base class for all helper classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Helper implements HelperInterface
|
||||
{
|
||||
protected $helperSet = null;
|
||||
|
||||
/**
|
||||
* Sets the helper set associated with this helper.
|
||||
*
|
||||
* @param HelperSet $helperSet A HelperSet instance
|
||||
*/
|
||||
public function setHelperSet(HelperSet $helperSet = null)
|
||||
{
|
||||
$this->helperSet = $helperSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the helper set associated with this helper.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*/
|
||||
public function getHelperSet()
|
||||
{
|
||||
return $this->helperSet;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* HelperInterface is the interface all helpers must implement.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface HelperInterface
|
||||
{
|
||||
/**
|
||||
* Sets the helper set associated with this helper.
|
||||
*
|
||||
* @param HelperSet $helperSet A HelperSet instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setHelperSet(HelperSet $helperSet = null);
|
||||
|
||||
/**
|
||||
* Gets the helper set associated with this helper.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getHelperSet();
|
||||
|
||||
/**
|
||||
* Returns the canonical name of this helper.
|
||||
*
|
||||
* @return string The canonical name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getName();
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
<?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\Command\Command;
|
||||
|
||||
/**
|
||||
* HelperSet represents a set of helpers to be used with a command.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class HelperSet
|
||||
{
|
||||
private $helpers;
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Helper[] $helpers An array of helper.
|
||||
*/
|
||||
public function __construct(array $helpers = array())
|
||||
{
|
||||
$this->helpers = array();
|
||||
foreach ($helpers as $alias => $helper) {
|
||||
$this->set($helper, is_int($alias) ? null : $alias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a helper.
|
||||
*
|
||||
* @param HelperInterface $helper The helper instance
|
||||
* @param string $alias An alias
|
||||
*/
|
||||
public function set(HelperInterface $helper, $alias = null)
|
||||
{
|
||||
$this->helpers[$helper->getName()] = $helper;
|
||||
if (null !== $alias) {
|
||||
$this->helpers[$alias] = $helper;
|
||||
}
|
||||
|
||||
$helper->setHelperSet($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the helper if defined.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return Boolean true if the helper is defined, false otherwise
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->helpers[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a helper value.
|
||||
*
|
||||
* @param string $name The helper name
|
||||
*
|
||||
* @return HelperInterface The helper instance
|
||||
*
|
||||
* @throws \InvalidArgumentException if the helper is not defined
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
|
||||
}
|
||||
|
||||
return $this->helpers[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command associated with this helper set.
|
||||
*
|
||||
* @param Command $command A Command instance
|
||||
*/
|
||||
public function setCommand(Command $command = null)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command associated with this helper set.
|
||||
*
|
||||
* @return Command A Command instance
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
}
|
||||
@@ -1,313 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* ArgvInput represents an input coming from the CLI arguments.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $input = new ArgvInput();
|
||||
*
|
||||
* By default, the `$_SERVER['argv']` array is used for the input values.
|
||||
*
|
||||
* This can be overridden by explicitly passing the input values in the constructor:
|
||||
*
|
||||
* $input = new ArgvInput($_SERVER['argv']);
|
||||
*
|
||||
* If you pass it yourself, don't forget that the first element of the array
|
||||
* is the name of the running application.
|
||||
*
|
||||
* When passing an argument to the constructor, be sure that it respects
|
||||
* the same rules as the argv one. It's almost always better to use the
|
||||
* `StringInput` when you want to provide your own input.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
||||
* @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ArgvInput extends Input
|
||||
{
|
||||
private $tokens;
|
||||
private $parsed;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $argv An array of parameters from the CLI (in the argv format)
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(array $argv = null, InputDefinition $definition = null)
|
||||
{
|
||||
if (null === $argv) {
|
||||
$argv = $_SERVER['argv'];
|
||||
}
|
||||
|
||||
// strip the application name
|
||||
array_shift($argv);
|
||||
|
||||
$this->tokens = $argv;
|
||||
|
||||
parent::__construct($definition);
|
||||
}
|
||||
|
||||
protected function setTokens(array $tokens)
|
||||
{
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
protected function parse()
|
||||
{
|
||||
$parseOptions = true;
|
||||
$this->parsed = $this->tokens;
|
||||
while (null !== $token = array_shift($this->parsed)) {
|
||||
if ($parseOptions && '' == $token) {
|
||||
$this->parseArgument($token);
|
||||
} elseif ($parseOptions && '--' == $token) {
|
||||
$parseOptions = false;
|
||||
} elseif ($parseOptions && 0 === strpos($token, '--')) {
|
||||
$this->parseLongOption($token);
|
||||
} elseif ($parseOptions && '-' === $token[0]) {
|
||||
$this->parseShortOption($token);
|
||||
} else {
|
||||
$this->parseArgument($token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short option.
|
||||
*
|
||||
* @param string $token The current token.
|
||||
*/
|
||||
private function parseShortOption($token)
|
||||
{
|
||||
$name = substr($token, 1);
|
||||
|
||||
if (strlen($name) > 1) {
|
||||
if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
|
||||
// an option with a value (with no space)
|
||||
$this->addShortOption($name[0], substr($name, 1));
|
||||
} else {
|
||||
$this->parseShortOptionSet($name);
|
||||
}
|
||||
} else {
|
||||
$this->addShortOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a short option set.
|
||||
*
|
||||
* @param string $name The current token
|
||||
*
|
||||
* @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]));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOptionForShortcut($name[$i]);
|
||||
if ($option->acceptValue()) {
|
||||
$this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
|
||||
|
||||
break;
|
||||
} else {
|
||||
$this->addLongOption($option->getName(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a long option.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
private function parseLongOption($token)
|
||||
{
|
||||
$name = substr($token, 2);
|
||||
|
||||
if (false !== $pos = strpos($name, '=')) {
|
||||
$this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
|
||||
} else {
|
||||
$this->addLongOption($name, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an argument.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*
|
||||
* @throws \RuntimeException When too many arguments are given
|
||||
*/
|
||||
private function parseArgument($token)
|
||||
{
|
||||
$c = count($this->arguments);
|
||||
|
||||
// if input is expecting another argument, add it
|
||||
if ($this->definition->hasArgument($c)) {
|
||||
$arg = $this->definition->getArgument($c);
|
||||
$this->arguments[$arg->getName()] = $arg->isArray()? array($token) : $token;
|
||||
|
||||
// if last argument isArray(), append token to last argument
|
||||
} elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
|
||||
$arg = $this->definition->getArgument($c - 1);
|
||||
$this->arguments[$arg->getName()][] = $token;
|
||||
|
||||
// unexpected argument
|
||||
} else {
|
||||
throw new \RuntimeException('Too many arguments.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOption($name);
|
||||
|
||||
if (null === $value && $option->acceptValue()) {
|
||||
// if option accepts an optional or mandatory argument
|
||||
// let's see if there is one provided
|
||||
$next = array_shift($this->parsed);
|
||||
if ('-' !== $next[0]) {
|
||||
$value = $next;
|
||||
} else {
|
||||
array_unshift($this->parsed, $next);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
if ($option->isValueRequired()) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
|
||||
}
|
||||
|
||||
$value = $option->isValueOptional() ? $option->getDefault() : true;
|
||||
}
|
||||
|
||||
if ($option->isArray()) {
|
||||
$this->options[$name][] = $value;
|
||||
} else {
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->tokens as $token) {
|
||||
if ($token && '-' === $token[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contain a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before they have been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
public function hasParameterOption($values)
|
||||
{
|
||||
$values = (array) $values;
|
||||
|
||||
foreach ($this->tokens as $v) {
|
||||
if (in_array($v, $values)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a raw option (not parsed).
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before they have been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
* @param mixed $default The default value to return if no result is found
|
||||
*
|
||||
* @return mixed The option value
|
||||
*/
|
||||
public function getParameterOption($values, $default = false)
|
||||
{
|
||||
$values = (array) $values;
|
||||
|
||||
$tokens = $this->tokens;
|
||||
while ($token = array_shift($tokens)) {
|
||||
foreach ($values as $value) {
|
||||
if (0 === strpos($token, $value)) {
|
||||
if (false !== $pos = strpos($token, '=')) {
|
||||
return substr($token, $pos + 1);
|
||||
}
|
||||
|
||||
return array_shift($tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* ArrayInput represents an input provided as an array.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar'));
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ArrayInput extends Input
|
||||
{
|
||||
private $parameters;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $parameters An array of parameters
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(array $parameters, InputDefinition $definition = null)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
|
||||
parent::__construct($definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
if ($key && '-' === $key[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contain a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before they have been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The values to look for in the raw parameters (can be an array)
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
public function hasParameterOption($values)
|
||||
{
|
||||
$values = (array) $values;
|
||||
|
||||
foreach ($this->parameters as $k => $v) {
|
||||
if (!is_int($k)) {
|
||||
$v = $k;
|
||||
}
|
||||
|
||||
if (in_array($v, $values)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a raw option (not parsed).
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before they have been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
* @param mixed $default The default value to return if no result is found
|
||||
*
|
||||
* @return mixed The option value
|
||||
*/
|
||||
public function getParameterOption($values, $default = false)
|
||||
{
|
||||
$values = (array) $values;
|
||||
|
||||
foreach ($this->parameters as $k => $v) {
|
||||
if (is_int($k) && in_array($v, $values)) {
|
||||
return true;
|
||||
} elseif (in_array($k, $values)) {
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
protected function parse()
|
||||
{
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
if (0 === strpos($key, '--')) {
|
||||
$this->addLongOption(substr($key, 2), $value);
|
||||
} elseif ('-' === $key[0]) {
|
||||
$this->addShortOption(substr($key, 1), $value);
|
||||
} else {
|
||||
$this->addArgument($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws \InvalidArgumentException 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));
|
||||
}
|
||||
|
||||
$this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws \InvalidArgumentException When option given doesn't exist
|
||||
* @throws \InvalidArgumentException 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));
|
||||
}
|
||||
|
||||
$option = $this->definition->getOption($name);
|
||||
|
||||
if (null === $value) {
|
||||
if ($option->isValueRequired()) {
|
||||
throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name));
|
||||
}
|
||||
|
||||
$value = $option->isValueOptional() ? $option->getDefault() : true;
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument value.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param mixed $value The value for the argument
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
$this->arguments[$name] = $value;
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* Input is the base class for all concrete Input classes.
|
||||
*
|
||||
* Three concrete classes are provided by default:
|
||||
*
|
||||
* * `ArgvInput`: The input comes from the CLI arguments (argv)
|
||||
* * `StringInput`: The input is provided as a string
|
||||
* * `ArrayInput`: The input is provided as an array
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Input implements InputInterface
|
||||
{
|
||||
protected $definition;
|
||||
protected $options;
|
||||
protected $arguments;
|
||||
protected $interactive = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function __construct(InputDefinition $definition = null)
|
||||
{
|
||||
if (null === $definition) {
|
||||
$this->definition = new InputDefinition();
|
||||
} else {
|
||||
$this->bind($definition);
|
||||
$this->validate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the current Input instance with the given arguments and options.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function bind(InputDefinition $definition)
|
||||
{
|
||||
$this->arguments = array();
|
||||
$this->options = array();
|
||||
$this->definition = $definition;
|
||||
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes command line arguments.
|
||||
*/
|
||||
abstract protected function parse();
|
||||
|
||||
/**
|
||||
* Validates the input.
|
||||
*
|
||||
* @throws \RuntimeException When not enough arguments are given
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {
|
||||
throw new \RuntimeException('Not enough arguments.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the input is interactive.
|
||||
*
|
||||
* @return Boolean Returns true if the input is interactive
|
||||
*/
|
||||
public function isInteractive()
|
||||
{
|
||||
return $this->interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input interactivity.
|
||||
*
|
||||
* @param Boolean $interactive If the input should be interactive
|
||||
*/
|
||||
public function setInteractive($interactive)
|
||||
{
|
||||
$this->interactive = (Boolean) $interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument values.
|
||||
*
|
||||
* @return array An array of argument values
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument value for a given argument name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
*
|
||||
* @return mixed The argument value
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an argument value by name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param string $value The argument value
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
$this->arguments[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return Boolean true if the InputArgument object exists, false otherwise
|
||||
*/
|
||||
public function hasArgument($name)
|
||||
{
|
||||
return $this->definition->hasArgument($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options values.
|
||||
*
|
||||
* @return array An array of option values
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return array_merge($this->definition->getOptionDefaults(), $this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the option value for a given option name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
*
|
||||
* @return mixed The option value
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an option value by name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $value The option value
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasOption($name)
|
||||
{
|
||||
return $this->definition->hasOption($name);
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* Represents a command line argument.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class InputArgument
|
||||
{
|
||||
const REQUIRED = 1;
|
||||
const OPTIONAL = 2;
|
||||
const IS_ARRAY = 4;
|
||||
|
||||
private $name;
|
||||
private $mode;
|
||||
private $default;
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param integer $mode The argument mode: self::REQUIRED or self::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (for self::OPTIONAL mode only)
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument mode is not valid
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->mode = $mode;
|
||||
$this->description = $description;
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument name.
|
||||
*
|
||||
* @return string The argument name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the argument is required.
|
||||
*
|
||||
* @return Boolean true if parameter mode is self::REQUIRED, false otherwise
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
return self::REQUIRED === (self::REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the argument can take multiple values.
|
||||
*
|
||||
* @return Boolean true if mode is self::IS_ARRAY, false otherwise
|
||||
*/
|
||||
public function isArray()
|
||||
{
|
||||
return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $default The default value
|
||||
*
|
||||
* @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.');
|
||||
}
|
||||
|
||||
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.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return mixed The default value
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description text.
|
||||
*
|
||||
* @return string The description text
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
@@ -1,535 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* A InputDefinition represents a set of valid command line arguments and options.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $definition = new InputDefinition(array(
|
||||
* new InputArgument('name', InputArgument::REQUIRED),
|
||||
* new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),
|
||||
* ));
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class InputDefinition
|
||||
{
|
||||
private $arguments;
|
||||
private $requiredCount;
|
||||
private $hasAnArrayArgument = false;
|
||||
private $hasOptional;
|
||||
private $options;
|
||||
private $shortcuts;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $definition An array of InputArgument and InputOption instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(array $definition = array())
|
||||
{
|
||||
$this->setDefinition($definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the definition of the input.
|
||||
*
|
||||
* @param array $definition The definition array
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDefinition(array $definition)
|
||||
{
|
||||
$arguments = array();
|
||||
$options = array();
|
||||
foreach ($definition as $item) {
|
||||
if ($item instanceof InputOption) {
|
||||
$options[] = $item;
|
||||
} else {
|
||||
$arguments[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setArguments($arguments);
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the InputArgument objects.
|
||||
*
|
||||
* @param array $arguments An array of InputArgument objects
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setArguments($arguments = array())
|
||||
{
|
||||
$this->arguments = array();
|
||||
$this->requiredCount = 0;
|
||||
$this->hasOptional = false;
|
||||
$this->hasAnArrayArgument = false;
|
||||
$this->addArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an array of InputArgument objects.
|
||||
*
|
||||
* @param InputArgument[] $arguments An array of InputArgument objects
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addArguments($arguments = array())
|
||||
{
|
||||
if (null !== $arguments) {
|
||||
foreach ($arguments as $argument) {
|
||||
$this->addArgument($argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an InputArgument object.
|
||||
*
|
||||
* @param InputArgument $argument An InputArgument object
|
||||
*
|
||||
* @throws \LogicException When incorrect argument is given
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addArgument(InputArgument $argument)
|
||||
{
|
||||
if (isset($this->arguments[$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.');
|
||||
}
|
||||
|
||||
if ($argument->isRequired() && $this->hasOptional) {
|
||||
throw new \LogicException('Cannot add a required argument after an optional one.');
|
||||
}
|
||||
|
||||
if ($argument->isArray()) {
|
||||
$this->hasAnArrayArgument = true;
|
||||
}
|
||||
|
||||
if ($argument->isRequired()) {
|
||||
++$this->requiredCount;
|
||||
} else {
|
||||
$this->hasOptional = true;
|
||||
}
|
||||
|
||||
$this->arguments[$argument->getName()] = $argument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InputArgument by name or by position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return InputArgument An InputArgument object
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument given doesn't exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getArgument($name)
|
||||
{
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
if (!$this->hasArgument($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
return $arguments[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return Boolean true if the InputArgument object exists, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasArgument($name)
|
||||
{
|
||||
$arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
|
||||
|
||||
return isset($arguments[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of InputArgument objects.
|
||||
*
|
||||
* @return array An array of InputArgument objects
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of InputArguments.
|
||||
*
|
||||
* @return integer The number of InputArguments
|
||||
*/
|
||||
public function getArgumentCount()
|
||||
{
|
||||
return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of required InputArguments.
|
||||
*
|
||||
* @return integer The number of required InputArguments
|
||||
*/
|
||||
public function getArgumentRequiredCount()
|
||||
{
|
||||
return $this->requiredCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default values.
|
||||
*
|
||||
* @return array An array of default values
|
||||
*/
|
||||
public function getArgumentDefaults()
|
||||
{
|
||||
$values = array();
|
||||
foreach ($this->arguments as $argument) {
|
||||
$values[$argument->getName()] = $argument->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the InputOption objects.
|
||||
*
|
||||
* @param array $options An array of InputOption objects
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setOptions($options = array())
|
||||
{
|
||||
$this->options = array();
|
||||
$this->shortcuts = array();
|
||||
$this->addOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an array of InputOption objects.
|
||||
*
|
||||
* @param InputOption[] $options An array of InputOption objects
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addOptions($options = array())
|
||||
{
|
||||
foreach ($options as $option) {
|
||||
$this->addOption($option);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an InputOption object.
|
||||
*
|
||||
* @param InputOption $option An InputOption object
|
||||
*
|
||||
* @throws \LogicException When option given already exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
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()));
|
||||
} elseif (isset($this->shortcuts[$option->getShortcut()]) && !$option->equals($this->options[$this->shortcuts[$option->getShortcut()]])) {
|
||||
throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $option->getShortcut()));
|
||||
}
|
||||
|
||||
$this->options[$option->getName()] = $option;
|
||||
if ($option->getShortcut()) {
|
||||
$this->shortcuts[$option->getShortcut()] = $option->getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InputOption by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return InputOption A InputOption object
|
||||
*
|
||||
* @throws \InvalidArgumentException When option given doesn't exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getOption($name)
|
||||
{
|
||||
if (!$this->hasOption($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return $this->options[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasOption($name)
|
||||
{
|
||||
return isset($this->options[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of InputOption objects.
|
||||
*
|
||||
* @return array An array of InputOption objects
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by shortcut.
|
||||
*
|
||||
* @param string $name The InputOption shortcut
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasShortcut($name)
|
||||
{
|
||||
return isset($this->shortcuts[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an InputOption by shortcut.
|
||||
*
|
||||
* @param string $shortcut the Shortcut name
|
||||
*
|
||||
* @return InputOption An InputOption object
|
||||
*/
|
||||
public function getOptionForShortcut($shortcut)
|
||||
{
|
||||
return $this->getOption($this->shortcutToName($shortcut));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of default values.
|
||||
*
|
||||
* @return array An array of all default values
|
||||
*/
|
||||
public function getOptionDefaults()
|
||||
{
|
||||
$values = array();
|
||||
foreach ($this->options as $option) {
|
||||
$values[$option->getName()] = $option->getDefault();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the InputOption name given a shortcut.
|
||||
*
|
||||
* @param string $shortcut The shortcut
|
||||
*
|
||||
* @return string The InputOption name
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
return $this->shortcuts[$shortcut];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the synopsis.
|
||||
*
|
||||
* @return string The synopsis
|
||||
*/
|
||||
public function getSynopsis()
|
||||
{
|
||||
$elements = array();
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
|
||||
$elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
|
||||
}
|
||||
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
|
||||
|
||||
if ($argument->isArray()) {
|
||||
$elements[] = sprintf('... [%sN]', $argument->getName());
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', $elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual representation of the InputDefinition.
|
||||
*
|
||||
* @return string A string representing the InputDefinition
|
||||
*/
|
||||
public function asText()
|
||||
{
|
||||
// find the largest option or argument name
|
||||
$max = 0;
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$nameLength = strlen($option->getName()) + 2;
|
||||
if ($option->getShortcut()) {
|
||||
$nameLength += strlen($option->getShortcut()) + 3;
|
||||
}
|
||||
|
||||
$max = max($max, $nameLength);
|
||||
}
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$max = max($max, strlen($argument->getName()));
|
||||
}
|
||||
++$max;
|
||||
|
||||
$text = array();
|
||||
|
||||
if ($this->getArguments()) {
|
||||
$text[] = '<comment>Arguments:</comment>';
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
|
||||
$default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($argument->getDefault()));
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $argument->getDescription());
|
||||
|
||||
$text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $description, $default);
|
||||
}
|
||||
|
||||
$text[] = '';
|
||||
}
|
||||
|
||||
if ($this->getOptions()) {
|
||||
$text[] = '<comment>Options:</comment>';
|
||||
|
||||
foreach ($this->getOptions() as $option) {
|
||||
if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
|
||||
$default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($option->getDefault()));
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
|
||||
$description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $option->getDescription());
|
||||
|
||||
$optionMax = $max - strlen($option->getName()) - 2;
|
||||
$text[] = sprintf(" <info>%s</info> %-${optionMax}s%s%s%s",
|
||||
'--'.$option->getName(),
|
||||
$option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '',
|
||||
$description,
|
||||
$default,
|
||||
$multiple
|
||||
);
|
||||
}
|
||||
|
||||
$text[] = '';
|
||||
}
|
||||
|
||||
return implode("\n", $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML representation of the InputDefinition.
|
||||
*
|
||||
* @param Boolean $asDom Whether to return a DOM or an XML string
|
||||
*
|
||||
* @return string|DOMDocument An XML string representing the InputDefinition
|
||||
*/
|
||||
public function asXml($asDom = false)
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
$dom->appendChild($definitionXML = $dom->createElement('definition'));
|
||||
|
||||
$definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$argumentsXML->appendChild($argumentXML = $dom->createElement('argument'));
|
||||
$argumentXML->setAttribute('name', $argument->getName());
|
||||
$argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
|
||||
$argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
|
||||
$argumentXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
|
||||
|
||||
$argumentXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
$defaults = is_array($argument->getDefault()) ? $argument->getDefault() : (is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
|
||||
foreach ($defaults as $default) {
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->appendChild($dom->createTextNode($default));
|
||||
}
|
||||
}
|
||||
|
||||
$definitionXML->appendChild($optionsXML = $dom->createElement('options'));
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$optionsXML->appendChild($optionXML = $dom->createElement('option'));
|
||||
$optionXML->setAttribute('name', '--'.$option->getName());
|
||||
$optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
|
||||
$optionXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
|
||||
$optionXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
|
||||
$optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
|
||||
$optionXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
|
||||
|
||||
if ($option->acceptValue()) {
|
||||
$optionXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
$defaults = is_array($option->getDefault()) ? $option->getDefault() : (is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
|
||||
foreach ($defaults as $default) {
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->appendChild($dom->createTextNode($default));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $asDom ? $dom : $dom->saveXml();
|
||||
}
|
||||
|
||||
private function formatDefaultValue($default)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4', '<')) {
|
||||
return str_replace('\/', '/', json_encode($default));
|
||||
}
|
||||
|
||||
return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* InputInterface is the interface implemented by all input classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface InputInterface
|
||||
{
|
||||
/**
|
||||
* Returns the first argument from the raw parameters (not parsed).
|
||||
*
|
||||
* @return string The value of the first argument or null otherwise
|
||||
*/
|
||||
public function getFirstArgument();
|
||||
|
||||
/**
|
||||
* Returns true if the raw parameters (not parsed) contain a value.
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before they have been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The values to look for in the raw parameters (can be an array)
|
||||
*
|
||||
* @return Boolean true if the value is contained in the raw parameters
|
||||
*/
|
||||
public function hasParameterOption($values);
|
||||
|
||||
/**
|
||||
* Returns the value of a raw option (not parsed).
|
||||
*
|
||||
* This method is to be used to introspect the input parameters
|
||||
* before they have been validated. It must be used carefully.
|
||||
*
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
* @param mixed $default The default value to return if no result is found
|
||||
*
|
||||
* @return mixed The option value
|
||||
*/
|
||||
public function getParameterOption($values, $default = false);
|
||||
|
||||
/**
|
||||
* Binds the current Input instance with the given arguments and options.
|
||||
*
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*/
|
||||
public function bind(InputDefinition $definition);
|
||||
|
||||
/**
|
||||
* Validates if arguments given are correct.
|
||||
*
|
||||
* Throws an exception when not enough arguments are given.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function validate();
|
||||
|
||||
/**
|
||||
* Returns all the given arguments merged with the default values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArguments();
|
||||
|
||||
/**
|
||||
* Gets argument by name.
|
||||
*
|
||||
* @param string $name The name of the argument
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getArgument($name);
|
||||
|
||||
/**
|
||||
* Sets an argument value by name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param string $value The argument value
|
||||
*
|
||||
* @throws \InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
public function setArgument($name, $value);
|
||||
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|integer $name The InputArgument name or position
|
||||
*
|
||||
* @return Boolean true if the InputArgument object exists, false otherwise
|
||||
*/
|
||||
public function hasArgument($name);
|
||||
|
||||
/**
|
||||
* Returns all the given options merged with the default values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions();
|
||||
|
||||
/**
|
||||
* Gets an option by name.
|
||||
*
|
||||
* @param string $name The name of the option
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOption($name);
|
||||
|
||||
/**
|
||||
* Sets an option value by name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $value The option value
|
||||
*
|
||||
* @throws \InvalidArgumentException When option given doesn't exist
|
||||
*/
|
||||
public function setOption($name, $value);
|
||||
|
||||
/**
|
||||
* Returns true if an InputOption object exists by name.
|
||||
*
|
||||
* @param string $name The InputOption name
|
||||
*
|
||||
* @return Boolean true if the InputOption object exists, false otherwise
|
||||
*/
|
||||
public function hasOption($name);
|
||||
|
||||
/**
|
||||
* Is this input means interactive?
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isInteractive();
|
||||
|
||||
/**
|
||||
* Sets the input interactivity.
|
||||
*
|
||||
* @param Boolean $interactive If the input should be interactive
|
||||
*/
|
||||
public function setInteractive($interactive);
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* Represents a command line option.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class InputOption
|
||||
{
|
||||
const VALUE_NONE = 1;
|
||||
const VALUE_REQUIRED = 2;
|
||||
const VALUE_OPTIONAL = 4;
|
||||
const VALUE_IS_ARRAY = 8;
|
||||
|
||||
private $name;
|
||||
private $shortcut;
|
||||
private $mode;
|
||||
private $default;
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string $shortcut The shortcut (can be null)
|
||||
* @param integer $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)
|
||||
*
|
||||
* @throws \InvalidArgumentException If option mode is invalid or incompatible
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
|
||||
{
|
||||
if (0 === strpos($name, '--')) {
|
||||
$name = substr($name, 2);
|
||||
}
|
||||
|
||||
if (empty($name)) {
|
||||
throw new \InvalidArgumentException('An option name cannot be empty.');
|
||||
}
|
||||
|
||||
if (empty($shortcut)) {
|
||||
$shortcut = null;
|
||||
}
|
||||
|
||||
if (null !== $shortcut) {
|
||||
if ('-' === $shortcut[0]) {
|
||||
$shortcut = substr($shortcut, 1);
|
||||
}
|
||||
|
||||
if (empty($shortcut)) {
|
||||
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));
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->shortcut = $shortcut;
|
||||
$this->mode = $mode;
|
||||
$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.');
|
||||
}
|
||||
|
||||
$this->setDefault($default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the option shortcut.
|
||||
*
|
||||
* @return string The shortcut
|
||||
*/
|
||||
public function getShortcut()
|
||||
{
|
||||
return $this->shortcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the option name.
|
||||
*
|
||||
* @return string The name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option accepts a value.
|
||||
*
|
||||
* @return Boolean true if value mode is not self::VALUE_NONE, false otherwise
|
||||
*/
|
||||
public function acceptValue()
|
||||
{
|
||||
return $this->isValueRequired() || $this->isValueOptional();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option requires a value.
|
||||
*
|
||||
* @return Boolean true if value mode is self::VALUE_REQUIRED, false otherwise
|
||||
*/
|
||||
public function isValueRequired()
|
||||
{
|
||||
return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option takes an optional value.
|
||||
*
|
||||
* @return Boolean true if value mode is self::VALUE_OPTIONAL, false otherwise
|
||||
*/
|
||||
public function isValueOptional()
|
||||
{
|
||||
return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the option can take multiple values.
|
||||
*
|
||||
* @return Boolean true if mode is self::VALUE_IS_ARRAY, false otherwise
|
||||
*/
|
||||
public function isArray()
|
||||
{
|
||||
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $default The default value
|
||||
*
|
||||
* @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.');
|
||||
}
|
||||
|
||||
if ($this->isArray()) {
|
||||
if (null === $default) {
|
||||
$default = array();
|
||||
} elseif (!is_array($default)) {
|
||||
throw new \LogicException('A default value for an array option must be an array.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->default = $this->acceptValue() ? $default : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return mixed The default value
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description text.
|
||||
*
|
||||
* @return string The description text
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given option equals this one
|
||||
*
|
||||
* @param InputOption $option option to compare
|
||||
* @return Boolean
|
||||
*/
|
||||
public function equals(InputOption $option)
|
||||
{
|
||||
return $option->getName() === $this->getName()
|
||||
&& $option->getShortcut() === $this->getShortcut()
|
||||
&& $option->getDefault() === $this->getDefault()
|
||||
&& $option->isArray() === $this->isArray()
|
||||
&& $option->isValueRequired() === $this->isValueRequired()
|
||||
&& $option->isValueOptional() === $this->isValueOptional()
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
<?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\Input;
|
||||
|
||||
/**
|
||||
* StringInput represents an input provided as a string.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $input = new StringInput('foo --bar="foobar"');
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class StringInput extends ArgvInput
|
||||
{
|
||||
const REGEX_STRING = '([^ ]+?)(?: |(?<!\\\\)"|(?<!\\\\)\'|$)';
|
||||
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $input An array of parameters from the CLI (in the argv format)
|
||||
* @param InputDefinition $definition A InputDefinition instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($input, InputDefinition $definition = null)
|
||||
{
|
||||
parent::__construct(array(), $definition);
|
||||
|
||||
$this->setTokens($this->tokenize($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes a string.
|
||||
*
|
||||
* @param string $input The input to tokenize
|
||||
*
|
||||
* @return array An array of tokens
|
||||
*
|
||||
* @throws \InvalidArgumentException When unable to parse input (should never happen)
|
||||
*/
|
||||
private function tokenize($input)
|
||||
{
|
||||
$input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input);
|
||||
|
||||
$tokens = array();
|
||||
$length = strlen($input);
|
||||
$cursor = 0;
|
||||
while ($cursor < $length) {
|
||||
if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
|
||||
} elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
|
||||
} elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
|
||||
} elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = stripcslashes($match[1]);
|
||||
} else {
|
||||
// should never happen
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$cursor += strlen($match[0]);
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2004-2012 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
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,103 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
|
||||
/**
|
||||
* ConsoleOutput is the default class for all CLI output. It uses STDOUT.
|
||||
*
|
||||
* This class is a convenient wrapper around `StreamOutput`.
|
||||
*
|
||||
* $output = new ConsoleOutput();
|
||||
*
|
||||
* This is equivalent to:
|
||||
*
|
||||
* $output = new StreamOutput(fopen('php://stdout', 'w'));
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
||||
{
|
||||
private $stderr;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL,
|
||||
* self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
* @param OutputFormatterInterface $formatter Output formatter instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
|
||||
{
|
||||
$outputStream = 'php://stdout';
|
||||
if (!$this->hasStdoutSupport()) {
|
||||
$outputStream = 'php://output';
|
||||
}
|
||||
|
||||
parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter);
|
||||
|
||||
$this->stderr = new StreamOutput(fopen('php://stderr', 'w'), $verbosity, $decorated, $formatter);
|
||||
}
|
||||
|
||||
public function setDecorated($decorated)
|
||||
{
|
||||
parent::setDecorated($decorated);
|
||||
$this->stderr->setDecorated($decorated);
|
||||
}
|
||||
|
||||
public function setFormatter(OutputFormatterInterface $formatter)
|
||||
{
|
||||
parent::setFormatter($formatter);
|
||||
$this->stderr->setFormatter($formatter);
|
||||
}
|
||||
|
||||
public function setVerbosity($level)
|
||||
{
|
||||
parent::setVerbosity($level);
|
||||
$this->stderr->setVerbosity($level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OutputInterface
|
||||
*/
|
||||
public function getErrorOutput()
|
||||
{
|
||||
return $this->stderr;
|
||||
}
|
||||
|
||||
public function setErrorOutput(OutputInterface $error)
|
||||
{
|
||||
$this->stderr = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if current environment supports writing console output to
|
||||
* STDOUT.
|
||||
*
|
||||
* IBM iSeries (OS400) exhibits character-encoding issues when writing to
|
||||
* STDOUT and doesn't properly convert ASCII to EBCDIC, resulting in garbage
|
||||
* output.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function hasStdoutSupport()
|
||||
{
|
||||
return ('OS400' != php_uname('s'));
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* ConsoleOutputInterface is the interface implemented by ConsoleOutput class.
|
||||
* This adds information about stderr output stream.
|
||||
*
|
||||
* @author Dariusz Górecki <darek.krk@gmail.com>
|
||||
*/
|
||||
interface ConsoleOutputInterface extends OutputInterface
|
||||
{
|
||||
/**
|
||||
* @return OutputInterface
|
||||
*/
|
||||
public function getErrorOutput();
|
||||
|
||||
public function setErrorOutput(OutputInterface $error);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
/**
|
||||
* NullOutput suppresses all output.
|
||||
*
|
||||
* $output = new NullOutput();
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class NullOutput extends Output
|
||||
{
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*/
|
||||
protected function doWrite($message, $newline)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
|
||||
/**
|
||||
* Base class for output classes.
|
||||
*
|
||||
* There are three levels of verbosity:
|
||||
*
|
||||
* * normal: no option passed (normal output - information)
|
||||
* * verbose: -v (more output - debug)
|
||||
* * quiet: -q (no output)
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
abstract class Output implements OutputInterface
|
||||
{
|
||||
private $verbosity;
|
||||
private $formatter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
* @param OutputFormatterInterface $formatter Output formatter instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
|
||||
{
|
||||
$this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
|
||||
$this->formatter = null === $formatter ? new OutputFormatter() : $formatter;
|
||||
$this->formatter->setDecorated((Boolean) $decorated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets output formatter.
|
||||
*
|
||||
* @param OutputFormatterInterface $formatter
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFormatter(OutputFormatterInterface $formatter)
|
||||
{
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current output formatter instance.
|
||||
*
|
||||
* @return OutputFormatterInterface
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorate the messages or not
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDecorated($decorated)
|
||||
{
|
||||
$this->formatter->setDecorated((Boolean) $decorated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the decorated flag.
|
||||
*
|
||||
* @return Boolean true if the output will decorate messages, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isDecorated()
|
||||
{
|
||||
return $this->formatter->isDecorated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the verbosity of the output.
|
||||
*
|
||||
* @param integer $level The level of verbosity
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setVerbosity($level)
|
||||
{
|
||||
$this->verbosity = (int) $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current verbosity of the output.
|
||||
*
|
||||
* @return integer The current level of verbosity
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getVerbosity()
|
||||
{
|
||||
return $this->verbosity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output and adds a newline at the end.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param integer $type The type of output
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function writeln($messages, $type = 0)
|
||||
{
|
||||
$this->write($messages, true, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
* @param integer $type The type of output
|
||||
*
|
||||
* @throws \InvalidArgumentException When unknown output type is given
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function write($messages, $newline = false, $type = 0)
|
||||
{
|
||||
if (self::VERBOSITY_QUIET === $this->verbosity) {
|
||||
return;
|
||||
}
|
||||
|
||||
$messages = (array) $messages;
|
||||
|
||||
foreach ($messages as $message) {
|
||||
switch ($type) {
|
||||
case OutputInterface::OUTPUT_NORMAL:
|
||||
$message = $this->formatter->format($message);
|
||||
break;
|
||||
case OutputInterface::OUTPUT_RAW:
|
||||
break;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*/
|
||||
abstract protected function doWrite($message, $newline);
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
|
||||
/**
|
||||
* OutputInterface is the interface implemented by all Output classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface OutputInterface
|
||||
{
|
||||
const VERBOSITY_QUIET = 0;
|
||||
const VERBOSITY_NORMAL = 1;
|
||||
const VERBOSITY_VERBOSE = 2;
|
||||
|
||||
const OUTPUT_NORMAL = 0;
|
||||
const OUTPUT_RAW = 1;
|
||||
const OUTPUT_PLAIN = 2;
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines of a single string
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
* @param integer $type The type of output (0: normal, 1: raw, 2: plain)
|
||||
*
|
||||
* @throws \InvalidArgumentException When unknown output type is given
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function write($messages, $newline = false, $type = 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 of a single string
|
||||
* @param integer $type The type of output (0: normal, 1: raw, 2: plain)
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function writeln($messages, $type = 0);
|
||||
|
||||
/**
|
||||
* Sets the verbosity of the output.
|
||||
*
|
||||
* @param integer $level The level of verbosity
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setVerbosity($level);
|
||||
|
||||
/**
|
||||
* Gets the current verbosity of the output.
|
||||
*
|
||||
* @return integer The current level of verbosity
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getVerbosity();
|
||||
|
||||
/**
|
||||
* Sets the decorated flag.
|
||||
*
|
||||
* @param Boolean $decorated Whether to decorate the messages or not
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDecorated($decorated);
|
||||
|
||||
/**
|
||||
* Gets the decorated flag.
|
||||
*
|
||||
* @return Boolean true if the output will decorate messages, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isDecorated();
|
||||
|
||||
/**
|
||||
* Sets output formatter.
|
||||
*
|
||||
* @param OutputFormatterInterface $formatter
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFormatter(OutputFormatterInterface $formatter);
|
||||
|
||||
/**
|
||||
* Returns current output formatter instance.
|
||||
*
|
||||
* @return OutputFormatterInterface
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFormatter();
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
|
||||
/**
|
||||
* StreamOutput writes the output to a given stream.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $output = new StreamOutput(fopen('php://stdout', 'w'));
|
||||
*
|
||||
* As `StreamOutput` can use any stream, you can also use a file:
|
||||
*
|
||||
* $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class StreamOutput extends Output
|
||||
{
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param mixed $stream A stream resource
|
||||
* @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL,
|
||||
* self::VERBOSITY_VERBOSE)
|
||||
* @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
|
||||
* @param OutputFormatterInterface $formatter Output formatter instance
|
||||
*
|
||||
* @throws \InvalidArgumentException When first argument is not a real stream
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
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.');
|
||||
}
|
||||
|
||||
$this->stream = $stream;
|
||||
|
||||
if (null === $decorated) {
|
||||
$decorated = $this->hasColorSupport();
|
||||
}
|
||||
|
||||
parent::__construct($verbosity, $decorated, $formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stream attached to this StreamOutput instance.
|
||||
*
|
||||
* @return resource A stream resource
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @param string $message A message to write to the output
|
||||
* @param Boolean $newline Whether to add a newline or not
|
||||
*
|
||||
* @throws \RuntimeException When unable to write output (should never happen)
|
||||
*/
|
||||
protected function doWrite($message, $newline)
|
||||
{
|
||||
if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {
|
||||
// @codeCoverageIgnoreStart
|
||||
// should never happen
|
||||
throw new \RuntimeException('Unable to write output.');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
fflush($this->stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the stream supports colorization.
|
||||
*
|
||||
* Colorization is disabled if not supported by the stream:
|
||||
*
|
||||
* - windows without ansicon
|
||||
* - non tty consoles
|
||||
*
|
||||
* @return Boolean true if the stream supports colorization, false otherwise
|
||||
*/
|
||||
protected function hasColorSupport()
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (DIRECTORY_SEPARATOR == '\\') {
|
||||
return false !== getenv('ANSICON');
|
||||
}
|
||||
|
||||
return function_exists('posix_isatty') && @posix_isatty($this->stream);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
Console Component
|
||||
=================
|
||||
|
||||
Console eases the creation of beautiful and testable command line interfaces.
|
||||
|
||||
The Application object manages the CLI application:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
phpunit
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
[The Console Component](http://symfony.com/doc/current/components/console.html)
|
||||
|
||||
[How to create a Console Command](http://symfony.com/doc/current/cookbook/console/console_command.html)
|
||||
@@ -1,207 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
|
||||
/**
|
||||
* A Shell wraps an Application to add shell capabilities to it.
|
||||
*
|
||||
* Support for history and completion only works with a PHP compiled
|
||||
* with readline support (either --with-readline or --with-libedit)
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class Shell
|
||||
{
|
||||
private $application;
|
||||
private $history;
|
||||
private $output;
|
||||
private $hasReadline;
|
||||
private $prompt;
|
||||
private $processIsolation;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* If there is no readline support for the current PHP executable
|
||||
* a \RuntimeException exception is thrown.
|
||||
*
|
||||
* @param Application $application An application instance
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->hasReadline = function_exists('readline');
|
||||
$this->application = $application;
|
||||
$this->history = getenv('HOME').'/.history_'.$application->getName();
|
||||
$this->output = new ConsoleOutput();
|
||||
$this->prompt = $application->getName().' > ';
|
||||
$this->processIsolation = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the shell.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->application->setAutoExit(false);
|
||||
$this->application->setCatchExceptions(true);
|
||||
|
||||
if ($this->hasReadline) {
|
||||
readline_read_history($this->history);
|
||||
readline_completion_function(array($this, 'autocompleter'));
|
||||
}
|
||||
|
||||
$this->output->writeln($this->getHeader());
|
||||
$php = null;
|
||||
if ($this->processIsolation) {
|
||||
$finder = new PhpExecutableFinder();
|
||||
$php = $finder->find();
|
||||
$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,
|
||||
* commands output is not colorized.
|
||||
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
$command = $this->readline();
|
||||
|
||||
if (false === $command) {
|
||||
$this->output->writeln("\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->hasReadline) {
|
||||
readline_add_history($command);
|
||||
readline_write_history($this->history);
|
||||
}
|
||||
|
||||
if ($this->processIsolation) {
|
||||
$pb = new ProcessBuilder();
|
||||
|
||||
$process = $pb
|
||||
->add($php)
|
||||
->add($_SERVER['argv'][0])
|
||||
->add($command)
|
||||
->inheritEnvironmentVariables(true)
|
||||
->getProcess()
|
||||
;
|
||||
|
||||
$output = $this->output;
|
||||
$process->run(function($type, $data) use ($output) {
|
||||
$output->writeln($data);
|
||||
});
|
||||
|
||||
$ret = $process->getExitCode();
|
||||
} else {
|
||||
$ret = $this->application->run(new StringInput($command), $this->output);
|
||||
}
|
||||
|
||||
if (0 !== $ret) {
|
||||
$this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shell header.
|
||||
*
|
||||
* @return string The header string
|
||||
*/
|
||||
protected function getHeader()
|
||||
{
|
||||
return <<<EOF
|
||||
|
||||
Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
|
||||
|
||||
At the prompt, type <comment>help</comment> for some help,
|
||||
or <comment>list</comment> to get a list of available commands.
|
||||
|
||||
To exit the shell, type <comment>^D</comment>.
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to return autocompletion for the current entered text.
|
||||
*
|
||||
* @param string $text The last segment of the entered text
|
||||
*
|
||||
* @return Boolean|array A list of guessed strings or true
|
||||
*/
|
||||
private function autocompleter($text)
|
||||
{
|
||||
$info = readline_info();
|
||||
$text = substr($info['line_buffer'], 0, $info['end']);
|
||||
|
||||
if ($info['point'] !== $info['end']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// task name?
|
||||
if (false === strpos($text, ' ') || !$text) {
|
||||
return array_keys($this->application->all());
|
||||
}
|
||||
|
||||
// options and arguments?
|
||||
try {
|
||||
$command = $this->application->find(substr($text, 0, strpos($text, ' ')));
|
||||
} catch (\Exception $e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$list = array('--help');
|
||||
foreach ($command->getDefinition()->getOptions() as $option) {
|
||||
$list[] = '--'.$option->getName();
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single line from standard input.
|
||||
*
|
||||
* @return string The single line from standard input
|
||||
*/
|
||||
private function readline()
|
||||
{
|
||||
if ($this->hasReadline) {
|
||||
$line = readline($this->prompt);
|
||||
} else {
|
||||
$this->output->write($this->prompt);
|
||||
$line = fgets(STDIN, 1024);
|
||||
$line = (!$line && strlen($line) == 0) ? false : rtrim($line);
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
public function getProcessIsolation()
|
||||
{
|
||||
return $this->processIsolation;
|
||||
}
|
||||
|
||||
public function setProcessIsolation($processIsolation)
|
||||
{
|
||||
$this->processIsolation = (Boolean) $processIsolation;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user