Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
vendor/
composer.lock
phpunit.xml

View File

@@ -0,0 +1,133 @@
CHANGELOG
=========
3.0.0
-----
* removed `validator.api` parameter
* removed `alias` option of the `form.type` tag
2.8.0
-----
* Deprecated the `alias` option of the `form.type_extension` tag in favor of the
`extended_type`/`extended-type` option
* Deprecated the `alias` option of the `form.type` tag
* Deprecated the Shell
2.7.0
-----
* Added possibility to extract translation messages from a file or files besides extracting from a directory
* Added `TranslationsCacheWarmer` to create catalogues at warmup
2.6.0
-----
* Added helper commands (`server:start`, `server:stop` and `server:status`) to control the built-in web
server in the background
* Added `Controller::isCsrfTokenValid` helper
* Added configuration for the PropertyAccess component
* Added `Controller::redirectToRoute` helper
* Added `Controller::addFlash` helper
* Added `Controller::isGranted` helper
* Added `Controller::denyAccessUnlessGranted` helper
* Deprecated `app.security` in twig as `app.user` and `is_granted()` are already available
2.5.0
-----
* Added `translation:debug` command
* Added `--no-backup` option to `translation:update` command
* Added `config:debug` command
* Added `yaml:lint` command
* Deprecated the `RouterApacheDumperCommand` which will be removed in Symfony 3.0.
2.4.0
-----
* allowed multiple IP addresses in profiler matcher settings
* added stopwatch helper to time templates with the WebProfilerBundle
* added service definition for "security.secure_random" service
* added service definitions for the new Security CSRF sub-component
2.3.0
-----
* [BC BREAK] added a way to disable the profiler (when disabling the profiler, it is now completely removed)
To get the same "disabled" behavior as before, set `enabled` to `true` and `collect` to `false`
* [BC BREAK] the `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RegisterKernelListenersPass` was moved
to `Component\HttpKernel\DependencyInjection\RegisterListenersPass`
* added ControllerNameParser::build() which converts a controller short notation (a:b:c) to a class::method notation
* added possibility to run PHP built-in server in production environment
* added possibility to load the serializer component in the service container
* added route debug information when using the `router:match` command
* added `TimedPhpEngine`
* added `--clean` option to the `translation:update` command
* added `http_method_override` option
* added support for default templates per render tag
* added FormHelper::form(), FormHelper::start() and FormHelper::end()
* deprecated FormHelper::enctype() in favor of FormHelper::start()
* RedirectController actions now receive the Request instance via the method signature.
2.2.0
-----
* added a new `uri_signer` service to help sign URIs
* deprecated `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` and `Symfony\Bundle\FrameworkBundle\HttpKernel::forward()`
* deprecated the `Symfony\Bundle\FrameworkBundle\HttpKernel` class in favor of `Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel`
* added support for adding new HTTP content rendering strategies (like ESI and Hinclude)
in the DIC via the `kernel.fragment_renderer` tag
* [BC BREAK] restricted the `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` method to only accept URIs or ControllerReference instances
* `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` method signature changed and the first argument
must now be a URI or a ControllerReference instance (the `generateInternalUri()` method was removed)
* The internal routes (`Resources/config/routing/internal.xml`) have been removed and replaced with a listener (`Symfony\Component\HttpKernel\EventListener\FragmentListener`)
* The `render` method of the `actions` templating helper signature and arguments changed
* replaced Symfony\Bundle\FrameworkBundle\Controller\TraceableControllerResolver by Symfony\Component\HttpKernel\Controller\TraceableControllerResolver
* replaced Symfony\Component\HttpKernel\Debug\ContainerAwareTraceableEventDispatcher by Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher
* added Client::enableProfiler()
* a new parameter has been added to the DIC: `router.request_context.base_url`
You can customize it for your functional tests or for generating URLs with
the right base URL when your are in the CLI context.
* added support for default templates per render tag
2.1.0
-----
* moved the translation files to the Form and Validator components
* changed the default extension for XLIFF files from .xliff to .xlf
* moved Symfony\Bundle\FrameworkBundle\ContainerAwareEventDispatcher to Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
* moved Symfony\Bundle\FrameworkBundle\Debug\TraceableEventDispatcher to Symfony\Component\EventDispatcher\ContainerAwareTraceableEventDispatcher
* added a router:match command
* added a config:dump-reference command
* added a server:run command
* added kernel.event_subscriber tag
* added a way to create relative symlinks when running assets:install command (--relative option)
* added Controller::getUser()
* [BC BREAK] assets_base_urls and base_urls merging strategy has changed
* changed the default profiler storage to use the filesystem instead of SQLite
* added support for placeholders in route defaults and requirements (replaced
by the value set in the service container)
* added Filesystem component as a dependency
* added support for hinclude (use ``standalone: 'js'`` in render tag)
* session options: lifetime, path, domain, secure, httponly were deprecated.
Prefixed versions should now be used instead: cookie_lifetime, cookie_path,
cookie_domain, cookie_secure, cookie_httponly
* [BC BREAK] following session options: 'lifetime', 'path', 'domain', 'secure',
'httponly' are now prefixed with cookie_ when dumped to the container
* Added `handler_id` configuration under `session` key to represent `session.handler`
service, defaults to `session.handler.native_file`.
* Added `gc_maxlifetime`, `gc_probability`, and `gc_divisor` to session
configuration. This means session garbage collection has a
`gc_probability`/`gc_divisor` chance of being run. The `gc_maxlifetime` defines
how long a session can idle for. It is different from cookie lifetime which
declares how long a cookie can be stored on the remote client.
* Removed 'auto_start' configuration parameter from session config. The session will
start on demand.
* [BC BREAK] TemplateNameParser::parseFromFilename() has been moved to a dedicated
parser: TemplateFilenameParser::parse().
* [BC BREAK] Kernel parameters are replaced by their value wherever they appear
in Route patterns, requirements and defaults. Use '%%' as the escaped value for '%'.
* [BC BREAK] Switched behavior of flash messages to expire flash messages on retrieval
using Symfony\Component\HttpFoundation\Session\Flash\FlashBag as opposed to on
next pageload regardless of whether they are displayed or not.

View File

@@ -0,0 +1,53 @@
<?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\Bundle\FrameworkBundle\CacheWarmer;
use Symfony\Component\ClassLoader\ClassCollectionLoader;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
/**
* Generates the Class Cache (classes.php) file.
*
* @author Tugdual Saunier <tucksaun@gmail.com>
*/
class ClassCacheCacheWarmer implements CacheWarmerInterface
{
/**
* Warms up the cache.
*
* @param string $cacheDir The cache directory
*/
public function warmUp($cacheDir)
{
$classmap = $cacheDir.'/classes.map';
if (!is_file($classmap)) {
return;
}
if (file_exists($cacheDir.'/classes.php')) {
return;
}
ClassCollectionLoader::load(include($classmap), $cacheDir, 'classes', false);
}
/**
* Checks whether this warmer is optional or not.
*
* @return bool always true
*/
public function isOptional()
{
return true;
}
}

View File

@@ -0,0 +1,58 @@
<?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\Bundle\FrameworkBundle\CacheWarmer;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
use Symfony\Component\Routing\RouterInterface;
/**
* Generates the router matcher and generator classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RouterCacheWarmer implements CacheWarmerInterface
{
protected $router;
/**
* Constructor.
*
* @param RouterInterface $router A Router instance
*/
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
/**
* Warms up the cache.
*
* @param string $cacheDir The cache directory
*/
public function warmUp($cacheDir)
{
if ($this->router instanceof WarmableInterface) {
$this->router->warmUp($cacheDir);
}
}
/**
* Checks whether this warmer is optional or not.
*
* @return bool always true
*/
public function isOptional()
{
return true;
}
}

View File

@@ -0,0 +1,113 @@
<?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\Bundle\FrameworkBundle\CacheWarmer;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Templating\TemplateNameParserInterface;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
/**
* Finds all the templates.
*
* @author Victor Berchet <victor@suumit.com>
*/
class TemplateFinder implements TemplateFinderInterface
{
private $kernel;
private $parser;
private $rootDir;
private $templates;
/**
* Constructor.
*
* @param KernelInterface $kernel A KernelInterface instance
* @param TemplateNameParserInterface $parser A TemplateNameParserInterface instance
* @param string $rootDir The directory where global templates can be stored
*/
public function __construct(KernelInterface $kernel, TemplateNameParserInterface $parser, $rootDir)
{
$this->kernel = $kernel;
$this->parser = $parser;
$this->rootDir = $rootDir;
}
/**
* Find all the templates in the bundle and in the kernel Resources folder.
*
* @return TemplateReferenceInterface[]
*/
public function findAllTemplates()
{
if (null !== $this->templates) {
return $this->templates;
}
$templates = array();
foreach ($this->kernel->getBundles() as $bundle) {
$templates = array_merge($templates, $this->findTemplatesInBundle($bundle));
}
$templates = array_merge($templates, $this->findTemplatesInFolder($this->rootDir.'/views'));
return $this->templates = $templates;
}
/**
* Find templates in the given directory.
*
* @param string $dir The folder where to look for templates
*
* @return TemplateReferenceInterface[]
*/
private function findTemplatesInFolder($dir)
{
$templates = array();
if (is_dir($dir)) {
$finder = new Finder();
foreach ($finder->files()->followLinks()->in($dir) as $file) {
$template = $this->parser->parse($file->getRelativePathname());
if (false !== $template) {
$templates[] = $template;
}
}
}
return $templates;
}
/**
* Find templates in the given bundle.
*
* @param BundleInterface $bundle The bundle where to look for templates
*
* @return TemplateReferenceInterface[]
*/
private function findTemplatesInBundle(BundleInterface $bundle)
{
$name = $bundle->getName();
$templates = array_merge(
$this->findTemplatesInFolder($bundle->getPath().'/Resources/views'),
$this->findTemplatesInFolder($this->rootDir.'/'.$name.'/views')
);
$templates = array_unique($templates);
foreach ($templates as $i => $template) {
$templates[$i] = $template->set('bundle', $name);
}
return $templates;
}
}

View File

@@ -0,0 +1,27 @@
<?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\Bundle\FrameworkBundle\CacheWarmer;
/**
* Interface for finding all the templates.
*
* @author Victor Berchet <victor@suumit.com>
*/
interface TemplateFinderInterface
{
/**
* Find all the templates.
*
* @return array An array of templates of type TemplateReferenceInterface
*/
public function findAllTemplates();
}

View File

@@ -0,0 +1,64 @@
<?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\Bundle\FrameworkBundle\CacheWarmer;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmer;
use Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator;
/**
* Computes the association between template names and their paths on the disk.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TemplatePathsCacheWarmer extends CacheWarmer
{
protected $finder;
protected $locator;
/**
* Constructor.
*
* @param TemplateFinderInterface $finder A template finder
* @param TemplateLocator $locator The template locator
*/
public function __construct(TemplateFinderInterface $finder, TemplateLocator $locator)
{
$this->finder = $finder;
$this->locator = $locator;
}
/**
* Warms up the cache.
*
* @param string $cacheDir The cache directory
*/
public function warmUp($cacheDir)
{
$templates = array();
foreach ($this->finder->findAllTemplates() as $template) {
$templates[$template->getLogicalName()] = $this->locator->locate($template);
}
$this->writeCacheFile($cacheDir.'/templates.php', sprintf('<?php return %s;', var_export($templates, true)));
}
/**
* Checks whether this warmer is optional or not.
*
* @return bool always true
*/
public function isOptional()
{
return true;
}
}

View File

@@ -0,0 +1,49 @@
<?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\Bundle\FrameworkBundle\CacheWarmer;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
use Symfony\Component\Translation\TranslatorInterface;
/**
* Generates the catalogues for translations.
*
* @author Xavier Leune <xavier.leune@gmail.com>
*/
class TranslationsCacheWarmer implements CacheWarmerInterface
{
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**
* {@inheritdoc}
*/
public function warmUp($cacheDir)
{
if ($this->translator instanceof WarmableInterface) {
$this->translator->warmUp($cacheDir);
}
}
/**
* {@inheritdoc}
*/
public function isOptional()
{
return true;
}
}

View File

@@ -0,0 +1,204 @@
<?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\Bundle\FrameworkBundle;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\HttpKernel\Client as BaseClient;
use Symfony\Component\HttpKernel\Profiler\Profile as HttpProfile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\BrowserKit\History;
use Symfony\Component\BrowserKit\CookieJar;
/**
* Client simulates a browser and makes requests to a Kernel object.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Client extends BaseClient
{
private $hasPerformedRequest = false;
private $profiler = false;
private $reboot = true;
/**
* {@inheritdoc}
*/
public function __construct(KernelInterface $kernel, array $server = array(), History $history = null, CookieJar $cookieJar = null)
{
parent::__construct($kernel, $server, $history, $cookieJar);
}
/**
* Returns the container.
*
* @return ContainerInterface|null Returns null when the Kernel has been shutdown or not started yet
*/
public function getContainer()
{
return $this->kernel->getContainer();
}
/**
* Returns the kernel.
*
* @return KernelInterface
*/
public function getKernel()
{
return $this->kernel;
}
/**
* Gets the profile associated with the current Response.
*
* @return HttpProfile A Profile instance
*/
public function getProfile()
{
if (!$this->kernel->getContainer()->has('profiler')) {
return false;
}
return $this->kernel->getContainer()->get('profiler')->loadProfileFromResponse($this->response);
}
/**
* Enables the profiler for the very next request.
*
* If the profiler is not enabled, the call to this method does nothing.
*/
public function enableProfiler()
{
if ($this->kernel->getContainer()->has('profiler')) {
$this->profiler = true;
}
}
/**
* Disables kernel reboot between requests.
*
* By default, the Client reboots the Kernel for each request. This method
* allows to keep the same kernel across requests.
*/
public function disableReboot()
{
$this->reboot = false;
}
/**
* Enables kernel reboot between requests.
*/
public function enableReboot()
{
$this->reboot = true;
}
/**
* {@inheritdoc}
*
* @param Request $request A Request instance
*
* @return Response A Response instance
*/
protected function doRequest($request)
{
// avoid shutting down the Kernel if no request has been performed yet
// WebTestCase::createClient() boots the Kernel but do not handle a request
if ($this->hasPerformedRequest && $this->reboot) {
$this->kernel->shutdown();
} else {
$this->hasPerformedRequest = true;
}
if ($this->profiler) {
$this->profiler = false;
$this->kernel->boot();
$this->kernel->getContainer()->get('profiler')->enable();
}
return parent::doRequest($request);
}
/**
* {@inheritdoc}
*
* @param Request $request A Request instance
*
* @return Response A Response instance
*/
protected function doRequestInProcess($request)
{
$response = parent::doRequestInProcess($request);
$this->profiler = false;
return $response;
}
/**
* Returns the script to execute when the request must be insulated.
*
* It assumes that the autoloader is named 'autoload.php' and that it is
* stored in the same directory as the kernel (this is the case for the
* Symfony Standard Edition). If this is not your case, create your own
* client and override this method.
*
* @param Request $request A Request instance
*
* @return string The script content
*/
protected function getScript($request)
{
$kernel = str_replace("'", "\\'", serialize($this->kernel));
$request = str_replace("'", "\\'", serialize($request));
$r = new \ReflectionObject($this->kernel);
$autoloader = dirname($r->getFileName()).'/autoload.php';
if (is_file($autoloader)) {
$autoloader = str_replace("'", "\\'", $autoloader);
} else {
$autoloader = '';
}
$path = str_replace("'", "\\'", $r->getFileName());
$profilerCode = '';
if ($this->profiler) {
$profilerCode = '$kernel->getContainer()->get(\'profiler\')->enable();';
}
$errorReporting = error_reporting();
$code = <<<EOF
<?php
error_reporting($errorReporting);
if ('$autoloader') {
require_once '$autoloader';
}
require_once '$path';
\$kernel = unserialize('$kernel');
\$kernel->boot();
$profilerCode
\$request = unserialize('$request');
EOF;
return $code.$this->getHandleScript();
}
}

View File

@@ -0,0 +1,108 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Style\StyleInterface;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
/**
* A console command for dumping available configuration reference.
*
* @author Kevin Bond <kevinbond@gmail.com>
* @author Wouter J <waldio.webdesign@gmail.com>
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
abstract class AbstractConfigCommand extends ContainerDebugCommand
{
protected function listBundles($output)
{
$headers = array('Bundle name', 'Extension alias');
$rows = array();
$bundles = $this->getContainer()->get('kernel')->getBundles();
usort($bundles, function ($bundleA, $bundleB) {
return strcmp($bundleA->getName(), $bundleB->getName());
});
foreach ($bundles as $bundle) {
$extension = $bundle->getContainerExtension();
$rows[] = array($bundle->getName(), $extension ? $extension->getAlias() : '');
}
if ($output instanceof StyleInterface) {
$output->table($headers, $rows);
} else {
$output->writeln('Available registered bundles with their extension alias if available:');
$table = new Table($output);
$table->setHeaders($headers)->setRows($rows)->render();
}
}
protected function findExtension($name)
{
$bundles = $this->initializeBundles();
foreach ($bundles as $bundle) {
if ($name === $bundle->getName()) {
if (!$bundle->getContainerExtension()) {
throw new \LogicException(sprintf('Bundle "%s" does not have a container extension.', $name));
}
return $bundle->getContainerExtension();
}
$extension = $bundle->getContainerExtension();
if ($extension && $name === $extension->getAlias()) {
return $extension;
}
}
if ('Bundle' !== substr($name, -6)) {
$message = sprintf('No extensions with configuration available for "%s"', $name);
} else {
$message = sprintf('No extension with alias "%s" is enabled', $name);
}
throw new \LogicException($message);
}
public function validateConfiguration(ExtensionInterface $extension, $configuration)
{
if (!$configuration) {
throw new \LogicException(sprintf('The extension with alias "%s" does not have its getConfiguration() method setup', $extension->getAlias()));
}
if (!$configuration instanceof ConfigurationInterface) {
throw new \LogicException(sprintf('Configuration class "%s" should implement ConfigurationInterface in order to be dumpable', get_class($configuration)));
}
}
private function initializeBundles()
{
// Re-build bundle manually to initialize DI extensions that can be extended by other bundles in their build() method
// as this method is not called when the container is loaded from the cache.
$container = $this->getContainerBuilder();
$bundles = $this->getContainer()->get('kernel')->registerBundles();
foreach ($bundles as $bundle) {
if ($extension = $bundle->getContainerExtension()) {
$container->registerExtension($extension);
}
}
foreach ($bundles as $bundle) {
$bundle->build($container);
}
return $bundles;
}
}

View File

@@ -0,0 +1,248 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
/**
* Command that places bundle web assets into a given directory.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Gábor Egyed <gabor.egyed@gmail.com>
*/
class AssetsInstallCommand extends ContainerAwareCommand
{
const METHOD_COPY = 'copy';
const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink';
const METHOD_RELATIVE_SYMLINK = 'relative symlink';
/**
* @var Filesystem
*/
private $filesystem;
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('assets:install')
->setDefinition(array(
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', 'web'),
))
->addOption('symlink', null, InputOption::VALUE_NONE, 'Symlinks the assets instead of copying it')
->addOption('relative', null, InputOption::VALUE_NONE, 'Make relative symlinks')
->setDescription('Installs bundles web assets under a public web directory')
->setHelp(<<<'EOT'
The <info>%command.name%</info> command installs bundle assets into a given
directory (e.g. the <comment>web</comment> directory).
<info>php %command.full_name% web</info>
A "bundles" directory will be created inside the target directory and the
"Resources/public" directory of each bundle will be copied into it.
To create a symlink to each bundle instead of copying its assets, use the
<info>--symlink</info> option (will fall back to hard copies when symbolic links aren't possible:
<info>php %command.full_name% web --symlink</info>
To make symlink relative, add the <info>--relative</info> option:
<info>php %command.full_name% web --symlink --relative</info>
EOT
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$targetArg = rtrim($input->getArgument('target'), '/');
if (!is_dir($targetArg)) {
throw new \InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $input->getArgument('target')));
}
$this->filesystem = $this->getContainer()->get('filesystem');
// Create the bundles directory otherwise symlink will fail.
$bundlesDir = $targetArg.'/bundles/';
$this->filesystem->mkdir($bundlesDir, 0777);
$io = new SymfonyStyle($input, $output);
$io->newLine();
if ($input->getOption('relative')) {
$expectedMethod = self::METHOD_RELATIVE_SYMLINK;
$io->text('Trying to install assets as <info>relative symbolic links</info>.');
} elseif ($input->getOption('symlink')) {
$expectedMethod = self::METHOD_ABSOLUTE_SYMLINK;
$io->text('Trying to install assets as <info>absolute symbolic links</info>.');
} else {
$expectedMethod = self::METHOD_COPY;
$io->text('Installing assets as <info>hard copies</info>.');
}
$io->newLine();
$rows = array();
$copyUsed = false;
$exitCode = 0;
/** @var BundleInterface $bundle */
foreach ($this->getContainer()->get('kernel')->getBundles() as $bundle) {
if (!is_dir($originDir = $bundle->getPath().'/Resources/public')) {
continue;
}
$targetDir = $bundlesDir.preg_replace('/bundle$/', '', strtolower($bundle->getName()));
if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$message = sprintf("%s\n-> %s", $bundle->getName(), $targetDir);
} else {
$message = $bundle->getName();
}
try {
$this->filesystem->remove($targetDir);
if (self::METHOD_RELATIVE_SYMLINK === $expectedMethod) {
$method = $this->relativeSymlinkWithFallback($originDir, $targetDir);
} elseif (self::METHOD_ABSOLUTE_SYMLINK === $expectedMethod) {
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
} else {
$method = $this->hardCopy($originDir, $targetDir);
}
if (self::METHOD_COPY === $method) {
$copyUsed = true;
}
if ($method === $expectedMethod) {
$rows[] = array(sprintf('<fg=green;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'OK' : "\xE2\x9C\x94" /* HEAVY CHECK MARK (U+2714) */), $message, $method);
} else {
$rows[] = array(sprintf('<fg=yellow;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'WARNING' : '!'), $message, $method);
}
} catch (\Exception $e) {
$exitCode = 1;
$rows[] = array(sprintf('<fg=red;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'ERROR' : "\xE2\x9C\x98" /* HEAVY BALLOT X (U+2718) */), $message, $e->getMessage());
}
}
$io->table(array('', 'Bundle', 'Method / Error'), $rows);
if (0 !== $exitCode) {
$io->error('Some errors occurred while installing assets.');
} else {
if ($copyUsed) {
$io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.');
}
$io->success('All assets were successfully installed.');
}
return $exitCode;
}
/**
* Try to create relative symlink.
*
* Falling back to absolute symlink and finally hard copy.
*
* @param string $originDir
* @param string $targetDir
*
* @return string
*/
private function relativeSymlinkWithFallback($originDir, $targetDir)
{
try {
$this->symlink($originDir, $targetDir, true);
$method = self::METHOD_RELATIVE_SYMLINK;
} catch (IOException $e) {
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
}
return $method;
}
/**
* Try to create absolute symlink.
*
* Falling back to hard copy.
*
* @param string $originDir
* @param string $targetDir
*
* @return string
*/
private function absoluteSymlinkWithFallback($originDir, $targetDir)
{
try {
$this->symlink($originDir, $targetDir);
$method = self::METHOD_ABSOLUTE_SYMLINK;
} catch (IOException $e) {
// fall back to copy
$method = $this->hardCopy($originDir, $targetDir);
}
return $method;
}
/**
* Creates symbolic link.
*
* @param string $originDir
* @param string $targetDir
* @param bool $relative
*
* @throws IOException If link can not be created.
*/
private function symlink($originDir, $targetDir, $relative = false)
{
if ($relative) {
$originDir = $this->filesystem->makePathRelative($originDir, realpath(dirname($targetDir)));
}
$this->filesystem->symlink($originDir, $targetDir);
if (!file_exists($targetDir)) {
throw new IOException(sprintf('Symbolic link "%s" was created but appears to be broken.', $targetDir), 0, null, $targetDir);
}
}
/**
* Copies origin to target.
*
* @param string $originDir
* @param string $targetDir
*
* @return string
*/
private function hardCopy($originDir, $targetDir)
{
$this->filesystem->mkdir($targetDir, 0777);
// We use a custom iterator to ignore VCS files
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
return self::METHOD_COPY;
}
}

View File

@@ -0,0 +1,260 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Finder\Finder;
/**
* Clear and Warmup the cache.
*
* @author Francis Besset <francis.besset@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class CacheClearCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('cache:clear')
->setDefinition(array(
new InputOption('no-warmup', '', InputOption::VALUE_NONE, 'Do not warm up the cache'),
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
))
->setDescription('Clears the cache')
->setHelp(<<<'EOF'
The <info>%command.name%</info> command clears the application cache for a given environment
and debug mode:
<info>php %command.full_name% --env=dev</info>
<info>php %command.full_name% --env=prod --no-debug</info>
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$outputIsVerbose = $output->isVerbose();
$io = new SymfonyStyle($input, $output);
$realCacheDir = $this->getContainer()->getParameter('kernel.cache_dir');
// the old cache dir name must not be longer than the real one to avoid exceeding
// the maximum length of a directory or file path within it (esp. Windows MAX_PATH)
$oldCacheDir = substr($realCacheDir, 0, -1).('~' === substr($realCacheDir, -1) ? '+' : '~');
$filesystem = $this->getContainer()->get('filesystem');
if (!is_writable($realCacheDir)) {
throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $realCacheDir));
}
if ($filesystem->exists($oldCacheDir)) {
$filesystem->remove($oldCacheDir);
}
$kernel = $this->getContainer()->get('kernel');
$io->comment(sprintf('Clearing the cache for the <info>%s</info> environment with debug <info>%s</info>', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
$this->getContainer()->get('cache_clearer')->clear($realCacheDir);
if ($input->getOption('no-warmup')) {
$filesystem->rename($realCacheDir, $oldCacheDir);
} else {
// the warmup cache dir name must have the same length than the real one
// to avoid the many problems in serialized resources files
$realCacheDir = realpath($realCacheDir);
$warmupDir = substr($realCacheDir, 0, -1).('_' === substr($realCacheDir, -1) ? '-' : '_');
if ($filesystem->exists($warmupDir)) {
if ($outputIsVerbose) {
$io->comment('Clearing outdated warmup directory...');
}
$filesystem->remove($warmupDir);
}
if ($outputIsVerbose) {
$io->comment('Warming up cache...');
}
$this->warmup($warmupDir, $realCacheDir, !$input->getOption('no-optional-warmers'));
$filesystem->rename($realCacheDir, $oldCacheDir);
if ('\\' === DIRECTORY_SEPARATOR) {
sleep(1); // workaround for Windows PHP rename bug
}
$filesystem->rename($warmupDir, $realCacheDir);
}
if ($outputIsVerbose) {
$io->comment('Removing old cache directory...');
}
$filesystem->remove($oldCacheDir);
if ($outputIsVerbose) {
$io->comment('Finished');
}
$io->success(sprintf('Cache for the "%s" environment (debug=%s) was successfully cleared.', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
}
/**
* @param string $warmupDir
* @param string $realCacheDir
* @param bool $enableOptionalWarmers
*/
protected function warmup($warmupDir, $realCacheDir, $enableOptionalWarmers = true)
{
// create a temporary kernel
$realKernel = $this->getContainer()->get('kernel');
$realKernelClass = get_class($realKernel);
$namespace = '';
if (false !== $pos = strrpos($realKernelClass, '\\')) {
$namespace = substr($realKernelClass, 0, $pos);
$realKernelClass = substr($realKernelClass, $pos + 1);
}
$tempKernel = $this->getTempKernel($realKernel, $namespace, $realKernelClass, $warmupDir);
$tempKernel->boot();
$tempKernelReflection = new \ReflectionObject($tempKernel);
$tempKernelFile = $tempKernelReflection->getFileName();
// warmup temporary dir
$warmer = $tempKernel->getContainer()->get('cache_warmer');
if ($enableOptionalWarmers) {
$warmer->enableOptionalWarmers();
}
$warmer->warmUp($warmupDir);
// fix references to the Kernel in .meta files
$safeTempKernel = str_replace('\\', '\\\\', get_class($tempKernel));
$realKernelFQN = get_class($realKernel);
foreach (Finder::create()->files()->name('*.meta')->in($warmupDir) as $file) {
file_put_contents($file, preg_replace(
'/(C\:\d+\:)"'.$safeTempKernel.'"/',
sprintf('$1"%s"', $realKernelFQN),
file_get_contents($file)
));
}
// fix references to cached files with the real cache directory name
$search = array($warmupDir, str_replace('\\', '\\\\', $warmupDir));
$replace = str_replace('\\', '/', $realCacheDir);
foreach (Finder::create()->files()->in($warmupDir) as $file) {
$content = str_replace($search, $replace, file_get_contents($file));
file_put_contents($file, $content);
}
// fix references to kernel/container related classes
$fileSearch = $tempKernel->getName().ucfirst($tempKernel->getEnvironment()).'*';
$search = array(
$tempKernel->getName().ucfirst($tempKernel->getEnvironment()),
sprintf('\'kernel.name\' => \'%s\'', $tempKernel->getName()),
sprintf('key="kernel.name">%s<', $tempKernel->getName()),
);
$replace = array(
$realKernel->getName().ucfirst($realKernel->getEnvironment()),
sprintf('\'kernel.name\' => \'%s\'', $realKernel->getName()),
sprintf('key="kernel.name">%s<', $realKernel->getName()),
);
foreach (Finder::create()->files()->name($fileSearch)->in($warmupDir) as $file) {
$content = str_replace($search, $replace, file_get_contents($file));
file_put_contents(str_replace($search, $replace, $file), $content);
unlink($file);
}
// remove temp kernel file after cache warmed up
@unlink($tempKernelFile);
}
/**
* @param KernelInterface $parent
* @param string $namespace
* @param string $parentClass
* @param string $warmupDir
*
* @return KernelInterface
*/
protected function getTempKernel(KernelInterface $parent, $namespace, $parentClass, $warmupDir)
{
$cacheDir = var_export($warmupDir, true);
$rootDir = var_export(realpath($parent->getRootDir()), true);
$logDir = var_export(realpath($parent->getLogDir()), true);
// the temp kernel class name must have the same length than the real one
// to avoid the many problems in serialized resources files
$class = substr($parentClass, 0, -1).'_';
// the temp kernel name must be changed too
$name = var_export(substr($parent->getName(), 0, -1).'_', true);
$code = <<<EOF
<?php
namespace $namespace
{
class $class extends $parentClass
{
public function getCacheDir()
{
return $cacheDir;
}
public function getName()
{
return $name;
}
public function getRootDir()
{
return $rootDir;
}
public function getLogDir()
{
return $logDir;
}
protected function buildContainer()
{
\$container = parent::buildContainer();
// filter container's resources, removing reference to temp kernel file
\$resources = \$container->getResources();
\$filteredResources = array();
foreach (\$resources as \$resource) {
if ((string) \$resource !== __FILE__) {
\$filteredResources[] = \$resource;
}
}
\$container->setResources(\$filteredResources);
return \$container;
}
}
}
EOF;
$this->getContainer()->get('filesystem')->mkdir($warmupDir);
file_put_contents($file = $warmupDir.'/kernel.tmp', $code);
require_once $file;
$class = "$namespace\\$class";
return new $class($parent->getEnvironment(), $parent->isDebug());
}
}

View File

@@ -0,0 +1,72 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Warmup the cache.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CacheWarmupCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('cache:warmup')
->setDefinition(array(
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
))
->setDescription('Warms up an empty cache')
->setHelp(<<<'EOF'
The <info>%command.name%</info> command warms up the cache.
Before running this command, the cache must be empty.
This command does not generate the classes cache (as when executing this
command, too many classes that should be part of the cache are already loaded
in memory). Use <comment>curl</comment> or any other similar tool to warm up
the classes cache if you want.
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$kernel = $this->getContainer()->get('kernel');
$io->comment(sprintf('Warming up the cache for the <info>%s</info> environment with debug <info>%s</info>', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
$warmer = $this->getContainer()->get('cache_warmer');
if (!$input->getOption('no-optional-warmers')) {
$warmer->enableOptionalWarmers();
}
$warmer->warmUp($this->getContainer()->getParameter('kernel.cache_dir'));
$io->success(sprintf('Cache for the "%s" environment (debug=%s) was successfully warmed.', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
}
}

View File

@@ -0,0 +1,103 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Yaml\Yaml;
/**
* A console command for dumping available configuration reference.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class ConfigDebugCommand extends AbstractConfigCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('debug:config')
->setDefinition(array(
new InputArgument('name', InputArgument::OPTIONAL, 'The bundle name or the extension alias'),
))
->setDescription('Dumps the current configuration for an extension')
->setHelp(<<<EOF
The <info>%command.name%</info> command dumps the current configuration for an
extension/bundle.
Either the extension alias or bundle name can be used:
<info>php %command.full_name% framework</info>
<info>php %command.full_name% FrameworkBundle</info>
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
if (empty($name)) {
$io->comment('Provide the name of a bundle as the first argument of this command to dump its configuration.');
$io->newLine();
$this->listBundles($output);
return;
}
$extension = $this->findExtension($name);
$container = $this->compileContainer();
$configs = $container->getExtensionConfig($extension->getAlias());
$configuration = $extension->getConfiguration($configs, $container);
$this->validateConfiguration($extension, $configuration);
$configs = $container->getParameterBag()->resolveValue($configs);
$processor = new Processor();
$config = $processor->processConfiguration($configuration, $configs);
if ($name === $extension->getAlias()) {
$io->title(sprintf('Current configuration for extension with alias "%s"', $name));
} else {
$io->title(sprintf('Current configuration for "%s"', $name));
}
$io->writeln(Yaml::dump(array($extension->getAlias() => $config), 10));
}
private function compileContainer()
{
$kernel = clone $this->getContainer()->get('kernel');
$kernel->boot();
$method = new \ReflectionMethod($kernel, 'buildContainer');
$method->setAccessible(true);
$container = $method->invoke($kernel);
$container->getCompiler()->compile($container);
return $container;
}
}

View File

@@ -0,0 +1,109 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper;
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\Style\SymfonyStyle;
/**
* A console command for dumping available configuration reference.
*
* @author Kevin Bond <kevinbond@gmail.com>
* @author Wouter J <waldio.webdesign@gmail.com>
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class ConfigDumpReferenceCommand extends AbstractConfigCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('config:dump-reference')
->setDefinition(array(
new InputArgument('name', InputArgument::OPTIONAL, 'The Bundle name or the extension alias'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (yaml or xml)', 'yaml'),
))
->setDescription('Dumps the default configuration for an extension')
->setHelp(<<<'EOF'
The <info>%command.name%</info> command dumps the default configuration for an
extension/bundle.
Either the extension alias or bundle name can be used:
<info>php %command.full_name% framework</info>
<info>php %command.full_name% FrameworkBundle</info>
With the <info>--format</info> option specifies the format of the configuration,
this is either <comment>yaml</comment> or <comment>xml</comment>.
When the option is not provided, <comment>yaml</comment> is used.
<info>php %command.full_name% FrameworkBundle --format=xml</info>
EOF
)
;
}
/**
* {@inheritdoc}
*
* @throws \LogicException
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
if (empty($name)) {
$io->comment('Provide the name of a bundle as the first argument of this command to dump its default configuration.');
$io->newLine();
$this->listBundles($output);
return;
}
$extension = $this->findExtension($name);
$configuration = $extension->getConfiguration(array(), $this->getContainerBuilder());
$this->validateConfiguration($extension, $configuration);
if ($name === $extension->getAlias()) {
$message = sprintf('Default configuration for extension with alias: "%s"', $name);
} else {
$message = sprintf('Default configuration for "%s"', $name);
}
switch ($input->getOption('format')) {
case 'yaml':
$io->writeln(sprintf('# %s', $message));
$dumper = new YamlReferenceDumper();
break;
case 'xml':
$io->writeln(sprintf('<!-- %s -->', $message));
$dumper = new XmlReferenceDumper();
break;
default:
$io->writeln($message);
throw new \InvalidArgumentException('Only the yaml and xml formats are supported.');
}
$io->writeln($dumper->dump($configuration, $extension->getNamespace()));
}
}

View File

@@ -0,0 +1,56 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/**
* Command.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class ContainerAwareCommand extends Command implements ContainerAwareInterface
{
/**
* @var ContainerInterface|null
*/
private $container;
/**
* @return ContainerInterface
*
* @throws \LogicException
*/
protected function getContainer()
{
if (null === $this->container) {
$application = $this->getApplication();
if (null === $application) {
throw new \LogicException('The container cannot be retrieved as the application instance is not yet set.');
}
$this->container = $application->getKernel()->getContainer();
}
return $this->container;
}
/**
* {@inheritdoc}
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
}

View File

@@ -0,0 +1,214 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
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\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
/**
* A console command for retrieving information about services.
*
* @author Ryan Weaver <ryan@thatsquality.com>
*/
class ContainerDebugCommand extends ContainerAwareCommand
{
/**
* @var ContainerBuilder|null
*/
protected $containerBuilder;
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('debug:container')
->setDefinition(array(
new InputArgument('name', InputArgument::OPTIONAL, 'A service name (foo)'),
new InputOption('show-private', null, InputOption::VALUE_NONE, 'Used to show public *and* private services'),
new InputOption('tag', null, InputOption::VALUE_REQUIRED, 'Shows all services with a specific tag'),
new InputOption('tags', null, InputOption::VALUE_NONE, 'Displays tagged services for an application'),
new InputOption('parameter', null, InputOption::VALUE_REQUIRED, 'Displays a specific parameter for an application'),
new InputOption('parameters', null, InputOption::VALUE_NONE, 'Displays parameters for an application'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
))
->setDescription('Displays current services for an application')
->setHelp(<<<'EOF'
The <info>%command.name%</info> command displays all configured <comment>public</comment> services:
<info>php %command.full_name%</info>
To get specific information about a service, specify its name:
<info>php %command.full_name% validator</info>
By default, private services are hidden. You can display all services by
using the <info>--show-private</info> flag:
<info>php %command.full_name% --show-private</info>
Use the --tags option to display tagged <comment>public</comment> services grouped by tag:
<info>php %command.full_name% --tags</info>
Find all services with a specific tag by specifying the tag name with the <info>--tag</info> option:
<info>php %command.full_name% --tag=form.type</info>
Use the <info>--parameters</info> option to display all parameters:
<info>php %command.full_name% --parameters</info>
Display a specific parameter by specifying its name with the <info>--parameter</info> option:
<info>php %command.full_name% --parameter=kernel.debug</info>
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$this->validateInput($input);
$object = $this->getContainerBuilder();
if ($input->getOption('parameters')) {
$object = $object->getParameterBag();
$options = array();
} elseif ($parameter = $input->getOption('parameter')) {
$options = array('parameter' => $parameter);
} elseif ($input->getOption('tags')) {
$options = array('group_by' => 'tags', 'show_private' => $input->getOption('show-private'));
} elseif ($tag = $input->getOption('tag')) {
$options = array('tag' => $tag, 'show_private' => $input->getOption('show-private'));
} elseif ($name = $input->getArgument('name')) {
$name = $this->findProperServiceName($input, $io, $object, $name);
$options = array('id' => $name);
} else {
$options = array('show_private' => $input->getOption('show-private'));
}
$helper = new DescriptorHelper();
$options['format'] = $input->getOption('format');
$options['raw_text'] = $input->getOption('raw');
$options['output'] = $io;
$helper->describe($output, $object, $options);
if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && $input->isInteractive()) {
if ($input->getOption('tags')) {
$io->comment('To search for a specific tag, re-run this command with a search term. (e.g. <comment>debug:container --tag=form.type</comment>)');
} elseif ($input->getOption('parameters')) {
$io->comment('To search for a specific parameter, re-run this command with a search term. (e.g. <comment>debug:container --parameter=kernel.debug</comment>)');
} else {
$io->comment('To search for a specific service, re-run this command with a search term. (e.g. <comment>debug:container log</comment>)');
}
}
}
/**
* Validates input arguments and options.
*
* @param InputInterface $input
*
* @throws \InvalidArgumentException
*/
protected function validateInput(InputInterface $input)
{
$options = array('tags', 'tag', 'parameters', 'parameter');
$optionsCount = 0;
foreach ($options as $option) {
if ($input->getOption($option)) {
++$optionsCount;
}
}
$name = $input->getArgument('name');
if ((null !== $name) && ($optionsCount > 0)) {
throw new \InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined with the service name argument.');
} elseif ((null === $name) && $optionsCount > 1) {
throw new \InvalidArgumentException('The options tags, tag, parameters & parameter can not be combined together.');
}
}
/**
* Loads the ContainerBuilder from the cache.
*
* @return ContainerBuilder
*
* @throws \LogicException
*/
protected function getContainerBuilder()
{
if ($this->containerBuilder) {
return $this->containerBuilder;
}
if (!$this->getApplication()->getKernel()->isDebug()) {
throw new \LogicException(sprintf('Debug information about the container is only available in debug mode.'));
}
if (!is_file($cachedFile = $this->getContainer()->getParameter('debug.container.dump'))) {
throw new \LogicException(sprintf('Debug information about the container could not be found. Please clear the cache and try again.'));
}
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator());
$loader->load($cachedFile);
return $this->containerBuilder = $container;
}
private function findProperServiceName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $builder, $name)
{
if ($builder->has($name) || !$input->isInteractive()) {
return $name;
}
$matchingServices = $this->findServiceIdsContaining($builder, $name);
if (empty($matchingServices)) {
throw new \InvalidArgumentException(sprintf('No services found that match "%s".', $name));
}
return $io->choice('Select one of the following services to display its information', $matchingServices);
}
private function findServiceIdsContaining(ContainerBuilder $builder, $name)
{
$serviceIds = $builder->getServiceIds();
$foundServiceIds = array();
$name = strtolower($name);
foreach ($serviceIds as $serviceId) {
if (false === strpos($serviceId, $name)) {
continue;
}
$foundServiceIds[] = $serviceId;
}
return $foundServiceIds;
}
}

View File

@@ -0,0 +1,92 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
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\Style\SymfonyStyle;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* A console command for retrieving information about event dispatcher.
*
* @author Matthieu Auger <mail@matthieuauger.com>
*/
class EventDispatcherDebugCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('debug:event-dispatcher')
->setDefinition(array(
new InputArgument('event', InputArgument::OPTIONAL, 'An event name'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
))
->setDescription('Displays configured listeners for an application')
->setHelp(<<<EOF
The <info>%command.name%</info> command displays all configured listeners:
<info>php %command.full_name%</info>
To get specific listeners for an event, specify its name:
<info>php %command.full_name% kernel.request</info>
EOF
)
;
}
/**
* {@inheritdoc}
*
* @throws \LogicException
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$dispatcher = $this->getEventDispatcher();
$options = array();
if ($event = $input->getArgument('event')) {
if (!$dispatcher->hasListeners($event)) {
$io->warning(sprintf('The event "%s" does not have any registered listeners.', $event));
return;
}
$options = array('event' => $event);
}
$helper = new DescriptorHelper();
$options['format'] = $input->getOption('format');
$options['raw_text'] = $input->getOption('raw');
$options['output'] = $io;
$helper->describe($io, $dispatcher, $options);
}
/**
* Loads the Event Dispatcher from the container.
*
* @return EventDispatcherInterface
*/
protected function getEventDispatcher()
{
return $this->getContainer()->get('event_dispatcher');
}
}

View File

@@ -0,0 +1,122 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\Route;
/**
* A console command for retrieving information about routes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Tobias Schultze <http://tobion.de>
*/
class RouterDebugCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
public function isEnabled()
{
if (!$this->getContainer()->has('router')) {
return false;
}
$router = $this->getContainer()->get('router');
if (!$router instanceof RouterInterface) {
return false;
}
return parent::isEnabled();
}
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('debug:router')
->setDefinition(array(
new InputArgument('name', InputArgument::OPTIONAL, 'A route name'),
new InputOption('show-controllers', null, InputOption::VALUE_NONE, 'Show assigned controllers in overview'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw route(s)'),
))
->setDescription('Displays current routes for an application')
->setHelp(<<<'EOF'
The <info>%command.name%</info> displays the configured routes:
<info>php %command.full_name%</info>
EOF
)
;
}
/**
* {@inheritdoc}
*
* @throws \InvalidArgumentException When route does not exist
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
$helper = new DescriptorHelper();
if ($name) {
$route = $this->getContainer()->get('router')->getRouteCollection()->get($name);
if (!$route) {
throw new \InvalidArgumentException(sprintf('The route "%s" does not exist.', $name));
}
$this->convertController($route);
$helper->describe($io, $route, array(
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
'name' => $name,
'output' => $io,
));
} else {
$routes = $this->getContainer()->get('router')->getRouteCollection();
foreach ($routes as $route) {
$this->convertController($route);
}
$helper->describe($io, $routes, array(
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
'show_controllers' => $input->getOption('show-controllers'),
'output' => $io,
));
}
}
private function convertController(Route $route)
{
$nameParser = $this->getContainer()->get('controller_name_converter');
if ($route->hasDefault('_controller')) {
try {
$route->setDefault('_controller', $nameParser->build($route->getDefault('_controller')));
} catch (\InvalidArgumentException $e) {
}
}
}
}

View File

@@ -0,0 +1,121 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\Matcher\TraceableUrlMatcher;
/**
* A console command to test route matching.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RouterMatchCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
public function isEnabled()
{
if (!$this->getContainer()->has('router')) {
return false;
}
$router = $this->getContainer()->get('router');
if (!$router instanceof RouterInterface) {
return false;
}
return parent::isEnabled();
}
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('router:match')
->setDefinition(array(
new InputArgument('path_info', InputArgument::REQUIRED, 'A path info'),
new InputOption('method', null, InputOption::VALUE_REQUIRED, 'Sets the HTTP method'),
new InputOption('scheme', null, InputOption::VALUE_REQUIRED, 'Sets the URI scheme (usually http or https)'),
new InputOption('host', null, InputOption::VALUE_REQUIRED, 'Sets the URI host'),
))
->setDescription('Helps debug routes by simulating a path info match')
->setHelp(<<<'EOF'
The <info>%command.name%</info> shows which routes match a given request and which don't and for what reason:
<info>php %command.full_name% /foo</info>
or
<info>php %command.full_name% /foo --method POST --scheme https --host symfony.com --verbose</info>
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$router = $this->getContainer()->get('router');
$context = $router->getContext();
if (null !== $method = $input->getOption('method')) {
$context->setMethod($method);
}
if (null !== $scheme = $input->getOption('scheme')) {
$context->setScheme($scheme);
}
if (null !== $host = $input->getOption('host')) {
$context->setHost($host);
}
$matcher = new TraceableUrlMatcher($router->getRouteCollection(), $context);
$traces = $matcher->getTraces($input->getArgument('path_info'));
$io->newLine();
$matches = false;
foreach ($traces as $trace) {
if (TraceableUrlMatcher::ROUTE_ALMOST_MATCHES == $trace['level']) {
$io->text(sprintf('Route <info>"%s"</> almost matches but %s', $trace['name'], lcfirst($trace['log'])));
} elseif (TraceableUrlMatcher::ROUTE_MATCHES == $trace['level']) {
$io->success(sprintf('Route "%s" matches', $trace['name']));
$routerDebugCommand = $this->getApplication()->find('debug:router');
$routerDebugCommand->run(new ArrayInput(array('name' => $trace['name'])), $output);
$matches = true;
} elseif ($input->getOption('verbose')) {
$io->text(sprintf('Route "%s" does not match: %s', $trace['name'], $trace['log']));
}
}
if (!$matches) {
$io->error(sprintf('None of the routes match the path "%s"', $input->getArgument('path_info')));
return 1;
}
}
}

View File

@@ -0,0 +1,69 @@
<?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\Bundle\FrameworkBundle\Command;
/**
* Base methods for commands related to PHP's built-in web server.
*
* @author Christian Flothmann <christian.flothmann@xabbuh.de>
*/
abstract class ServerCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
public function isEnabled()
{
if (defined('HHVM_VERSION')) {
return false;
}
if (!class_exists('Symfony\Component\Process\Process')) {
return false;
}
return parent::isEnabled();
}
/**
* Determines the name of the lock file for a particular PHP web server process.
*
* @param string $address An address/port tuple
*
* @return string The filename
*/
protected function getLockFile($address)
{
return sys_get_temp_dir().'/'.strtr($address, '.:', '--').'.pid';
}
protected function isOtherServerProcessRunning($address)
{
$lockFile = $this->getLockFile($address);
if (file_exists($lockFile)) {
return true;
}
list($hostname, $port) = explode(':', $address);
$fp = @fsockopen($hostname, $port, $errno, $errstr, 5);
if (false !== $fp) {
fclose($fp);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,163 @@
<?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\Bundle\FrameworkBundle\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\Style\SymfonyStyle;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\ProcessBuilder;
/**
* Runs Symfony application using PHP built-in web server.
*
* @author Michał Pipa <michal.pipa.xsolve@gmail.com>
*/
class ServerRunCommand extends ServerCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'),
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null),
new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'),
))
->setName('server:run')
->setDescription('Runs PHP built-in web server')
->setHelp(<<<'EOF'
The <info>%command.name%</info> runs PHP built-in web server:
<info>%command.full_name%</info>
To change default bind address and port use the <info>address</info> argument:
<info>%command.full_name% 127.0.0.1:8080</info>
To change default docroot directory use the <info>--docroot</info> option:
<info>%command.full_name% --docroot=htdocs/</info>
If you have custom docroot directory layout, you can specify your own
router script using <info>--router</info> option:
<info>%command.full_name% --router=app/config/router.php</info>
Specifing a router script is required when the used environment is not "dev",
"prod", or "test".
See also: http://www.php.net/manual/en/features.commandline.webserver.php
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$documentRoot = $input->getOption('docroot');
if (null === $documentRoot) {
$documentRoot = $this->getContainer()->getParameter('kernel.root_dir').'/../web';
}
if (!is_dir($documentRoot)) {
$io->error(sprintf('The given document root directory "%s" does not exist', $documentRoot));
return 1;
}
$env = $this->getContainer()->getParameter('kernel.environment');
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$address = $address.':'.$input->getOption('port');
}
if ($this->isOtherServerProcessRunning($address)) {
$io->error(sprintf('A process is already listening on http://%s.', $address));
return 1;
}
if ('prod' === $env) {
$io->error('Running PHP built-in server in production environment is NOT recommended!');
}
$io->success(sprintf('Server running on http://%s', $address));
$io->comment('Quit the server with CONTROL-C.');
if (null === $builder = $this->createPhpProcessBuilder($io, $address, $input->getOption('router'), $env)) {
return 1;
}
$builder->setWorkingDirectory($documentRoot);
$builder->setTimeout(null);
$process = $builder->getProcess();
if (OutputInterface::VERBOSITY_VERBOSE > $output->getVerbosity()) {
$process->disableOutput();
}
$this
->getHelper('process')
->run($output, $process, null, null, OutputInterface::VERBOSITY_VERBOSE);
if (!$process->isSuccessful()) {
$errorMessages = array('Built-in server terminated unexpectedly.');
if ($process->isOutputDisabled()) {
$errorMessages[] = 'Run the command again with -v option for more details.';
}
$io->error($errorMessages);
}
return $process->getExitCode();
}
private function createPhpProcessBuilder(SymfonyStyle $io, $address, $router, $env)
{
$router = $router ?: $this
->getContainer()
->get('kernel')
->locateResource(sprintf('@FrameworkBundle/Resources/config/router_%s.php', $env))
;
if (!file_exists($router)) {
$io->error(sprintf('The given router script "%s" does not exist.', $router));
return;
}
$router = realpath($router);
$finder = new PhpExecutableFinder();
if (false === $binary = $finder->find()) {
$io->error('Unable to find PHP binary to run server.');
return;
}
return new ProcessBuilder(array($binary, '-S', $address, $router));
}
}

View File

@@ -0,0 +1,234 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;
/**
* Runs PHP's built-in web server in a background process.
*
* @author Christian Flothmann <christian.flothmann@xabbuh.de>
*/
class ServerStartCommand extends ServerCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'),
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null),
new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'),
new InputOption('force', 'f', InputOption::VALUE_NONE, 'Force web server startup'),
))
->setName('server:start')
->setDescription('Starts PHP built-in web server in the background')
->setHelp(<<<EOF
The <info>%command.name%</info> runs PHP's built-in web server:
<info>php %command.full_name%</info>
To change the default bind address and the default port use the <info>address</info> argument:
<info>php %command.full_name% 127.0.0.1:8080</info>
To change the default document root directory use the <info>--docroot</info> option:
<info>php %command.full_name% --docroot=htdocs/</info>
If you have a custom document root directory layout, you can specify your own
router script using the <info>--router</info> option:
<info>php %command.full_name% --router=app/config/router.php</info>
Specifying a router script is required when the used environment is not <comment>"dev"</comment> or
<comment>"prod"</comment>.
See also: http://www.php.net/manual/en/features.commandline.webserver.php
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $cliOutput = $output);
if (!extension_loaded('pcntl')) {
$io->error(array(
'This command needs the pcntl extension to run.',
'You can either install it or use the "server:run" command instead to run the built-in web server.',
));
if ($io->ask('Do you want to execute <info>server:run</info> immediately? [Yn] ', true)) {
$command = $this->getApplication()->find('server:run');
return $command->run($input, $cliOutput);
}
return 1;
}
$documentRoot = $input->getOption('docroot');
if (null === $documentRoot) {
$documentRoot = $this->getContainer()->getParameter('kernel.root_dir').'/../web';
}
if (!is_dir($documentRoot)) {
$io->error(sprintf('The given document root directory "%s" does not exist.', $documentRoot));
return 1;
}
$env = $this->getContainer()->getParameter('kernel.environment');
if (false === $router = $this->determineRouterScript($input->getOption('router'), $env, $io)) {
return 1;
}
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$address = $address.':'.$input->getOption('port');
}
if (!$input->getOption('force') && $this->isOtherServerProcessRunning($address)) {
$io->error(array(
sprintf('A process is already listening on http://%s.', $address),
'Use the --force option if the server process terminated unexpectedly to start a new web server process.',
));
return 1;
}
if ('prod' === $env) {
$io->error('Running PHP built-in server in production environment is NOT recommended!');
}
$pid = pcntl_fork();
if ($pid < 0) {
$io->error('Unable to start the server process.');
return 1;
}
if ($pid > 0) {
$io->success(sprintf('Web server listening on http://%s', $address));
return;
}
if (posix_setsid() < 0) {
$io->error('Unable to set the child process as session leader');
return 1;
}
if (null === $process = $this->createServerProcess($io, $address, $documentRoot, $router)) {
return 1;
}
$process->disableOutput();
$process->start();
$lockFile = $this->getLockFile($address);
touch($lockFile);
if (!$process->isRunning()) {
$io->error('Unable to start the server process');
unlink($lockFile);
return 1;
}
// stop the web server when the lock file is removed
while ($process->isRunning()) {
if (!file_exists($lockFile)) {
$process->stop();
}
sleep(1);
}
}
/**
* Determine the absolute file path for the router script, using the environment to choose a standard script
* if no custom router script is specified.
*
* @param string|null $router File path of the custom router script, if set by the user; otherwise null
* @param string $env The application environment
* @param SymfonyStyle $io An SymfonyStyle instance
*
* @return string|bool The absolute file path of the router script, or false on failure
*/
private function determineRouterScript($router, $env, SymfonyStyle $io)
{
if (null === $router) {
$router = $this
->getContainer()
->get('kernel')
->locateResource(sprintf('@FrameworkBundle/Resources/config/router_%s.php', $env))
;
}
if (false === $path = realpath($router)) {
$io->error(sprintf('The given router script "%s" does not exist.', $router));
return false;
}
return $path;
}
/**
* Creates a process to start PHP's built-in web server.
*
* @param SymfonyStyle $io A SymfonyStyle instance
* @param string $address IP address and port to listen to
* @param string $documentRoot The application's document root
* @param string $router The router filename
*
* @return Process The process
*/
private function createServerProcess(SymfonyStyle $io, $address, $documentRoot, $router)
{
$finder = new PhpExecutableFinder();
if (false === $binary = $finder->find()) {
$io->error('Unable to find PHP binary to start server.');
return;
}
$script = implode(' ', array_map(array('Symfony\Component\Process\ProcessUtils', 'escapeArgument'), array(
$binary,
'-S',
$address,
$router,
)));
return new Process('exec '.$script, $documentRoot, null, null, null);
}
}

View File

@@ -0,0 +1,79 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Shows the status of a process that is running PHP's built-in web server in
* the background.
*
* @author Christian Flothmann <christian.flothmann@xabbuh.de>
*/
class ServerStatusCommand extends ServerCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'),
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
))
->setName('server:status')
->setDescription('Outputs the status of the built-in web server for the given address')
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$address = $address.':'.$input->getOption('port');
}
// remove an orphaned lock file
if (file_exists($this->getLockFile($address)) && !$this->isServerRunning($address)) {
unlink($this->getLockFile($address));
}
if (file_exists($this->getLockFile($address))) {
$io->success(sprintf('Web server still listening on http://%s', $address));
} else {
$io->warning(sprintf('No web server is listening on http://%s', $address));
}
}
private function isServerRunning($address)
{
list($hostname, $port) = explode(':', $address);
if (false !== $fp = @fsockopen($hostname, $port, $errno, $errstr, 1)) {
fclose($fp);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,76 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Stops a background process running PHP's built-in web server.
*
* @author Christian Flothmann <christian.flothmann@xabbuh.de>
*/
class ServerStopCommand extends ServerCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'),
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
))
->setName('server:stop')
->setDescription('Stops PHP\'s built-in web server that was started with the server:start command')
->setHelp(<<<EOF
The <info>%command.name%</info> stops PHP's built-in web server:
<info>php %command.full_name%</info>
To change the default bind address and the default port use the <info>address</info> argument:
<info>php %command.full_name% 127.0.0.1:8080</info>
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$address = $address.':'.$input->getOption('port');
}
$lockFile = $this->getLockFile($address);
if (!file_exists($lockFile)) {
$io->error(sprintf('No web server is listening on http://%s', $address));
return 1;
}
unlink($lockFile);
$io->success(sprintf('Stopped the web server listening on http://%s', $address));
}
}

View File

@@ -0,0 +1,317 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Translation\Catalogue\MergeOperation;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Translator;
/**
* Helps finding unused or missing translation messages in a given locale
* and comparing them with the fallback ones.
*
* @author Florian Voutzinos <florian@voutzinos.com>
*/
class TranslationDebugCommand extends ContainerAwareCommand
{
const MESSAGE_MISSING = 0;
const MESSAGE_UNUSED = 1;
const MESSAGE_EQUALS_FALLBACK = 2;
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('debug:translation')
->setDefinition(array(
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages, defaults to app/Resources folder'),
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'The messages domain'),
new InputOption('only-missing', null, InputOption::VALUE_NONE, 'Displays only missing messages'),
new InputOption('only-unused', null, InputOption::VALUE_NONE, 'Displays only unused messages'),
new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'),
))
->setDescription('Displays translation messages information')
->setHelp(<<<EOF
The <info>%command.name%</info> command helps finding unused or missing translation
messages and comparing them with the fallback ones by inspecting the
templates and translation files of a given bundle or the app folder.
You can display information about bundle translations in a specific locale:
<info>php %command.full_name% en AcmeDemoBundle</info>
You can also specify a translation domain for the search:
<info>php %command.full_name% --domain=messages en AcmeDemoBundle</info>
You can only display missing messages:
<info>php %command.full_name% --only-missing en AcmeDemoBundle</info>
You can only display unused messages:
<info>php %command.full_name% --only-unused en AcmeDemoBundle</info>
You can display information about app translations in a specific locale:
<info>php %command.full_name% en</info>
You can display information about translations in all registered bundles in a specific locale:
<info>php %command.full_name% --all en</info>
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$locale = $input->getArgument('locale');
$domain = $input->getOption('domain');
/** @var TranslationLoader $loader */
$loader = $this->getContainer()->get('translation.loader');
/** @var Kernel $kernel */
$kernel = $this->getContainer()->get('kernel');
// Define Root Path to App folder
$transPaths = array($kernel->getRootDir().'/Resources/');
// Override with provided Bundle info
if (null !== $input->getArgument('bundle')) {
try {
$bundle = $kernel->getBundle($input->getArgument('bundle'));
$transPaths = array(
$bundle->getPath().'/Resources/',
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName()),
);
} catch (\InvalidArgumentException $e) {
// such a bundle does not exist, so treat the argument as path
$transPaths = array($input->getArgument('bundle').'/Resources/');
if (!is_dir($transPaths[0])) {
throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
}
}
} elseif ($input->getOption('all')) {
foreach ($kernel->getBundles() as $bundle) {
$transPaths[] = $bundle->getPath().'/Resources/';
$transPaths[] = sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName());
}
}
// Extract used messages
$extractedCatalogue = $this->extractMessages($locale, $transPaths);
// Load defined messages
$currentCatalogue = $this->loadCurrentMessages($locale, $transPaths, $loader);
// Merge defined and extracted messages to get all message ids
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
$allMessages = $mergeOperation->getResult()->all($domain);
if (null !== $domain) {
$allMessages = array($domain => $allMessages);
}
// No defined or extracted messages
if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
$outputMessage = sprintf('No defined or extracted messages for locale "%s"', $locale);
if (null !== $domain) {
$outputMessage .= sprintf(' and domain "%s"', $domain);
}
$io->warning($outputMessage);
return;
}
// Load the fallback catalogues
$fallbackCatalogues = $this->loadFallbackCatalogues($locale, $transPaths, $loader);
// Display header line
$headers = array('State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale));
foreach ($fallbackCatalogues as $fallbackCatalogue) {
$headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale());
}
$rows = array();
// Iterate all message ids and determine their state
foreach ($allMessages as $domain => $messages) {
foreach (array_keys($messages) as $messageId) {
$value = $currentCatalogue->get($messageId, $domain);
$states = array();
if ($extractedCatalogue->defines($messageId, $domain)) {
if (!$currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_MISSING;
}
} elseif ($currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_UNUSED;
}
if (!in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused')
|| !in_array(self::MESSAGE_MISSING, $states) && true === $input->getOption('only-missing')) {
continue;
}
foreach ($fallbackCatalogues as $fallbackCatalogue) {
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
$states[] = self::MESSAGE_EQUALS_FALLBACK;
break;
}
}
$row = array($this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value));
foreach ($fallbackCatalogues as $fallbackCatalogue) {
$row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain));
}
$rows[] = $row;
}
}
$io->table($headers, $rows);
}
private function formatState($state)
{
if (self::MESSAGE_MISSING === $state) {
return '<error> missing </error>';
}
if (self::MESSAGE_UNUSED === $state) {
return '<comment> unused </comment>';
}
if (self::MESSAGE_EQUALS_FALLBACK === $state) {
return '<info> fallback </info>';
}
return $state;
}
private function formatStates(array $states)
{
$result = array();
foreach ($states as $state) {
$result[] = $this->formatState($state);
}
return implode(' ', $result);
}
private function formatId($id)
{
return sprintf('<fg=cyan;options=bold>%s</>', $id);
}
private function sanitizeString($string, $length = 40)
{
$string = trim(preg_replace('/\s+/', ' ', $string));
if (false !== $encoding = mb_detect_encoding($string, null, true)) {
if (mb_strlen($string, $encoding) > $length) {
return mb_substr($string, 0, $length - 3, $encoding).'...';
}
} elseif (strlen($string) > $length) {
return substr($string, 0, $length - 3).'...';
}
return $string;
}
/**
* @param string $locale
* @param array $transPaths
*
* @return MessageCatalogue
*/
private function extractMessages($locale, $transPaths)
{
$extractedCatalogue = new MessageCatalogue($locale);
foreach ($transPaths as $path) {
$path = $path.'views';
if (is_dir($path)) {
$this->getContainer()->get('translation.extractor')->extract($path, $extractedCatalogue);
}
}
return $extractedCatalogue;
}
/**
* @param string $locale
* @param array $transPaths
* @param TranslationLoader $loader
*
* @return MessageCatalogue
*/
private function loadCurrentMessages($locale, $transPaths, TranslationLoader $loader)
{
$currentCatalogue = new MessageCatalogue($locale);
foreach ($transPaths as $path) {
$path = $path.'translations';
if (is_dir($path)) {
$loader->loadMessages($path, $currentCatalogue);
}
}
return $currentCatalogue;
}
/**
* @param string $locale
* @param array $transPaths
* @param TranslationLoader $loader
*
* @return MessageCatalogue[]
*/
private function loadFallbackCatalogues($locale, $transPaths, TranslationLoader $loader)
{
$fallbackCatalogues = array();
$translator = $this->getContainer()->get('translator');
if ($translator instanceof Translator) {
foreach ($translator->getFallbackLocales() as $fallbackLocale) {
if ($fallbackLocale === $locale) {
continue;
}
$fallbackCatalogue = new MessageCatalogue($fallbackLocale);
foreach ($transPaths as $path) {
$path = $path.'translations';
if (is_dir($path)) {
$loader->loadMessages($path, $fallbackCatalogue);
}
}
$fallbackCatalogues[] = $fallbackCatalogue;
}
}
return $fallbackCatalogues;
}
}

View File

@@ -0,0 +1,216 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Translation\Catalogue\TargetOperation;
use Symfony\Component\Translation\Catalogue\MergeOperation;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Translation\MessageCatalogue;
/**
* A command that parses templates to extract translation messages and adds them
* into the translation files.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
class TranslationUpdateCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('translation:update')
->setDefinition(array(
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages, defaults to app/Resources folder'),
new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'yml'),
new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'),
new InputOption('force', null, InputOption::VALUE_NONE, 'Should the update be done'),
new InputOption('no-backup', null, InputOption::VALUE_NONE, 'Should backup be disabled'),
new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'),
))
->setDescription('Updates the translation file')
->setHelp(<<<'EOF'
The <info>%command.name%</info> command extracts translation strings from templates
of a given bundle or the app folder. It can display them or merge the new ones into the translation files.
When new translation strings are found it can automatically add a prefix to the translation
message.
Example running against a Bundle (AcmeBundle)
<info>php %command.full_name% --dump-messages en AcmeBundle</info>
<info>php %command.full_name% --force --prefix="new_" fr AcmeBundle</info>
Example running against app messages (app/Resources folder)
<info>php %command.full_name% --dump-messages en</info>
<info>php %command.full_name% --force --prefix="new_" fr</info>
EOF
)
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
// check presence of force or dump-message
if ($input->getOption('force') !== true && $input->getOption('dump-messages') !== true) {
$io->error('You must choose one of --force or --dump-messages');
return 1;
}
// check format
$writer = $this->getContainer()->get('translation.writer');
$supportedFormats = $writer->getFormats();
if (!in_array($input->getOption('output-format'), $supportedFormats)) {
$io->error(array('Wrong output format', 'Supported formats are: '.implode(', ', $supportedFormats).'.'));
return 1;
}
$kernel = $this->getContainer()->get('kernel');
// Define Root Path to App folder
$transPaths = array($kernel->getRootDir().'/Resources/');
$currentName = 'app folder';
// Override with provided Bundle info
if (null !== $input->getArgument('bundle')) {
try {
$foundBundle = $kernel->getBundle($input->getArgument('bundle'));
$transPaths = array(
$foundBundle->getPath().'/Resources/',
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $foundBundle->getName()),
);
$currentName = $foundBundle->getName();
} catch (\InvalidArgumentException $e) {
// such a bundle does not exist, so treat the argument as path
$transPaths = array($input->getArgument('bundle').'/Resources/');
$currentName = $transPaths[0];
if (!is_dir($transPaths[0])) {
throw new \InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $transPaths[0]));
}
}
}
$io->title('Translation Messages Extractor and Dumper');
$io->comment(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
// load any messages from templates
$extractedCatalogue = new MessageCatalogue($input->getArgument('locale'));
$io->comment('Parsing templates...');
$extractor = $this->getContainer()->get('translation.extractor');
$extractor->setPrefix($input->getOption('prefix'));
foreach ($transPaths as $path) {
$path .= 'views';
if (is_dir($path)) {
$extractor->extract($path, $extractedCatalogue);
}
}
// load any existing messages from the translation files
$currentCatalogue = new MessageCatalogue($input->getArgument('locale'));
$io->comment('Loading translation files...');
$loader = $this->getContainer()->get('translation.loader');
foreach ($transPaths as $path) {
$path .= 'translations';
if (is_dir($path)) {
$loader->loadMessages($path, $currentCatalogue);
}
}
// process catalogues
$operation = $input->getOption('clean')
? new TargetOperation($currentCatalogue, $extractedCatalogue)
: new MergeOperation($currentCatalogue, $extractedCatalogue);
// Exit if no messages found.
if (!count($operation->getDomains())) {
$io->warning('No translation messages were found.');
return;
}
$resultMessage = 'Translation files were successfully updated';
// show compiled list of messages
if (true === $input->getOption('dump-messages')) {
$extractedMessagesCount = 0;
$io->newLine();
foreach ($operation->getDomains() as $domain) {
$newKeys = array_keys($operation->getNewMessages($domain));
$allKeys = array_keys($operation->getMessages($domain));
$domainMessagesCount = count($newKeys) + count($allKeys);
$io->section(sprintf('Messages extracted for domain "<info>%s</info>" (%d messages)', $domain, $domainMessagesCount));
$io->listing(array_merge(
array_diff($allKeys, $newKeys),
array_map(function ($id) {
return sprintf('<fg=green>%s</>', $id);
}, $newKeys),
array_map(function ($id) {
return sprintf('<fg=red>%s</>', $id);
}, array_keys($operation->getObsoleteMessages($domain)))
));
$extractedMessagesCount += $domainMessagesCount;
}
if ($input->getOption('output-format') == 'xlf') {
$io->comment('Xliff output version is <info>1.2</info>');
}
$resultMessage = sprintf('%d messages were successfully extracted', $extractedMessagesCount);
}
if ($input->getOption('no-backup') === true) {
$writer->disableBackup();
}
// save the files
if ($input->getOption('force') === true) {
$io->comment('Writing files...');
$bundleTransPath = false;
foreach ($transPaths as $path) {
$path .= 'translations';
if (is_dir($path)) {
$bundleTransPath = $path;
}
}
if (!$bundleTransPath) {
$bundleTransPath = end($transPaths).'translations';
}
$writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
if (true === $input->getOption('dump-messages')) {
$resultMessage .= ' and translation files were updated';
}
}
$io->success($resultMessage.'.');
}
}

View File

@@ -0,0 +1,165 @@
<?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\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser;
/**
* Validates YAML files syntax and outputs encountered errors.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class YamlLintCommand extends Command
{
protected function configure()
{
$this
->setName('lint:yaml')
->setDescription('Lints a file and outputs encountered errors')
->addArgument('filename', null, 'A file or a directory or STDIN')
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
->setHelp(<<<EOF
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
the first encountered syntax error.
You can validate the syntax of a file:
<info>php %command.full_name% filename</info>
Or of a whole directory:
<info>php %command.full_name% dirname</info>
<info>php %command.full_name% dirname --format=json</info>
Or all YAML files in a bundle:
<info>php %command.full_name% @AcmeDemoBundle</info>
You can also pass the YAML contents from STDIN:
<info>cat filename | php %command.full_name%</info>
EOF
)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$filename = $input->getArgument('filename');
if (!$filename) {
if (0 !== ftell(STDIN)) {
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
$content = '';
while (!feof(STDIN)) {
$content .= fread(STDIN, 1024);
}
return $this->display($input, $output, $io, array($this->validate($content)));
}
if (0 !== strpos($filename, '@') && !is_readable($filename)) {
throw new \RuntimeException(sprintf('File or directory "%s" is not readable', $filename));
}
$files = array();
if (is_file($filename)) {
$files = array($filename);
} elseif (is_dir($filename)) {
$files = Finder::create()->files()->in($filename)->name('*.yml');
} else {
$dir = $this->getApplication()->getKernel()->locateResource($filename);
$files = Finder::create()->files()->in($dir)->name('*.yml');
}
$filesInfo = array();
foreach ($files as $file) {
$filesInfo[] = $this->validate(file_get_contents($file), $file);
}
return $this->display($input, $output, $io, $filesInfo);
}
private function validate($content, $file = null)
{
$parser = new Parser();
try {
$parser->parse($content);
} catch (ParseException $e) {
return array('file' => $file, 'valid' => false, 'message' => $e->getMessage());
}
return array('file' => $file, 'valid' => true);
}
private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, $files)
{
switch ($input->getOption('format')) {
case 'txt':
return $this->displayTxt($output, $io, $files);
case 'json':
return $this->displayJson($io, $files);
default:
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
}
}
private function displayTxt(OutputInterface $output, SymfonyStyle $io, $filesInfo)
{
$errors = 0;
foreach ($filesInfo as $info) {
if ($info['valid'] && $output->isVerbose()) {
$io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
} elseif (!$info['valid']) {
++$errors;
$io->text(sprintf('<error> ERROR </error> in %s', $info['file']));
$io->text(sprintf('<error> >> %s</error>', $info['message']));
}
}
if ($errors === 0) {
$io->success(sprintf('All %d YAML files contain valid syntax.', count($filesInfo)));
} else {
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.', count($filesInfo) - $errors, $errors));
}
return min($errors, 1);
}
private function displayJson(OutputInterface $output, $filesInfo)
{
$errors = 0;
array_walk($filesInfo, function (&$v) use (&$errors) {
$v['file'] = (string) $v['file'];
if (!$v['valid']) {
++$errors;
}
});
$output->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT));
return min($errors, 1);
}
}

View File

@@ -0,0 +1,127 @@
<?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\Bundle\FrameworkBundle\Console;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* Application.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Application extends BaseApplication
{
private $kernel;
private $commandsRegistered = false;
/**
* Constructor.
*
* @param KernelInterface $kernel A KernelInterface instance
*/
public function __construct(KernelInterface $kernel)
{
$this->kernel = $kernel;
parent::__construct('Symfony', Kernel::VERSION.' - '.$kernel->getName().'/'.$kernel->getEnvironment().($kernel->isDebug() ? '/debug' : ''));
$this->getDefinition()->addOption(new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', $kernel->getEnvironment()));
$this->getDefinition()->addOption(new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switches off debug mode.'));
}
/**
* Gets the Kernel associated with this Console.
*
* @return KernelInterface A KernelInterface instance
*/
public function getKernel()
{
return $this->kernel;
}
/**
* Runs the current application.
*
* @param InputInterface $input An Input instance
* @param OutputInterface $output An Output instance
*
* @return int 0 if everything went fine, or an error code
*/
public function doRun(InputInterface $input, OutputInterface $output)
{
$this->kernel->boot();
$container = $this->kernel->getContainer();
foreach ($this->all() as $command) {
if ($command instanceof ContainerAwareInterface) {
$command->setContainer($container);
}
}
$this->setDispatcher($container->get('event_dispatcher'));
return parent::doRun($input, $output);
}
/**
* {@inheritdoc}
*/
public function get($name)
{
$this->registerCommands();
return parent::get($name);
}
/**
* {@inheritdoc}
*/
public function all($namespace = null)
{
$this->registerCommands();
return parent::all($namespace);
}
protected function registerCommands()
{
if ($this->commandsRegistered) {
return;
}
$this->commandsRegistered = true;
$this->kernel->boot();
$container = $this->kernel->getContainer();
foreach ($this->kernel->getBundles() as $bundle) {
if ($bundle instanceof Bundle) {
$bundle->registerCommands($this);
}
}
if ($container->hasParameter('console.command.ids')) {
foreach ($container->getParameter('console.command.ids') as $id) {
$this->add($container->get($id));
}
}
}
}

View File

@@ -0,0 +1,312 @@
<?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\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\Console\Descriptor\DescriptorInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
abstract class Descriptor implements DescriptorInterface
{
/**
* @var OutputInterface
*/
protected $output;
/**
* {@inheritdoc}
*/
public function describe(OutputInterface $output, $object, array $options = array())
{
$this->output = $output;
switch (true) {
case $object instanceof RouteCollection:
$this->describeRouteCollection($object, $options);
break;
case $object instanceof Route:
$this->describeRoute($object, $options);
break;
case $object instanceof ParameterBag:
$this->describeContainerParameters($object, $options);
break;
case $object instanceof ContainerBuilder && isset($options['group_by']) && 'tags' === $options['group_by']:
$this->describeContainerTags($object, $options);
break;
case $object instanceof ContainerBuilder && isset($options['id']):
$this->describeContainerService($this->resolveServiceDefinition($object, $options['id']), $options);
break;
case $object instanceof ContainerBuilder && isset($options['parameter']):
$this->describeContainerParameter($object->getParameter($options['parameter']), $options);
break;
case $object instanceof ContainerBuilder:
$this->describeContainerServices($object, $options);
break;
case $object instanceof Definition:
$this->describeContainerDefinition($object, $options);
break;
case $object instanceof Alias:
$this->describeContainerAlias($object, $options);
break;
case $object instanceof EventDispatcherInterface:
$this->describeEventDispatcherListeners($object, $options);
break;
case is_callable($object):
$this->describeCallable($object, $options);
break;
default:
throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object)));
}
}
/**
* Returns the output.
*
* @return OutputInterface The output
*/
protected function getOutput()
{
return $this->output;
}
/**
* Writes content to output.
*
* @param string $content
* @param bool $decorated
*/
protected function write($content, $decorated = false)
{
$this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
}
/**
* Describes an InputArgument instance.
*
* @param RouteCollection $routes
* @param array $options
*/
abstract protected function describeRouteCollection(RouteCollection $routes, array $options = array());
/**
* Describes an InputOption instance.
*
* @param Route $route
* @param array $options
*/
abstract protected function describeRoute(Route $route, array $options = array());
/**
* Describes container parameters.
*
* @param ParameterBag $parameters
* @param array $options
*/
abstract protected function describeContainerParameters(ParameterBag $parameters, array $options = array());
/**
* Describes container tags.
*
* @param ContainerBuilder $builder
* @param array $options
*/
abstract protected function describeContainerTags(ContainerBuilder $builder, array $options = array());
/**
* Describes a container service by its name.
*
* Common options are:
* * name: name of described service
*
* @param Definition|Alias|object $service
* @param array $options
*/
abstract protected function describeContainerService($service, array $options = array());
/**
* Describes container services.
*
* Common options are:
* * tag: filters described services by given tag
*
* @param ContainerBuilder $builder
* @param array $options
*/
abstract protected function describeContainerServices(ContainerBuilder $builder, array $options = array());
/**
* Describes a service definition.
*
* @param Definition $definition
* @param array $options
*/
abstract protected function describeContainerDefinition(Definition $definition, array $options = array());
/**
* Describes a service alias.
*
* @param Alias $alias
* @param array $options
*/
abstract protected function describeContainerAlias(Alias $alias, array $options = array());
/**
* Describes a container parameter.
*
* @param string $parameter
* @param array $options
*/
abstract protected function describeContainerParameter($parameter, array $options = array());
/**
* Describes event dispatcher listeners.
*
* Common options are:
* * name: name of listened event
*
* @param EventDispatcherInterface $eventDispatcher
* @param array $options
*/
abstract protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array());
/**
* Describes a callable.
*
* @param callable $callable
* @param array $options
*/
abstract protected function describeCallable($callable, array $options = array());
/**
* Formats a value as string.
*
* @param mixed $value
*
* @return string
*/
protected function formatValue($value)
{
if (is_object($value)) {
return sprintf('object(%s)', get_class($value));
}
if (is_string($value)) {
return $value;
}
return preg_replace("/\n\s*/s", '', var_export($value, true));
}
/**
* Formats a parameter.
*
* @param mixed $value
*
* @return string
*/
protected function formatParameter($value)
{
if (is_bool($value) || is_array($value) || (null === $value)) {
$jsonString = json_encode($value);
if (preg_match('/^(.{60})./us', $jsonString, $matches)) {
return $matches[1].'...';
}
return $jsonString;
}
return (string) $value;
}
/**
* @param ContainerBuilder $builder
* @param string $serviceId
*
* @return mixed
*/
protected function resolveServiceDefinition(ContainerBuilder $builder, $serviceId)
{
if ($builder->hasDefinition($serviceId)) {
return $builder->getDefinition($serviceId);
}
// Some service IDs don't have a Definition, they're simply an Alias
if ($builder->hasAlias($serviceId)) {
return $builder->getAlias($serviceId);
}
if ('service_container' === $serviceId) {
return $builder;
}
// the service has been injected in some special way, just return the service
return $builder->get($serviceId);
}
/**
* @param ContainerBuilder $builder
* @param bool $showPrivate
*
* @return array
*/
protected function findDefinitionsByTag(ContainerBuilder $builder, $showPrivate)
{
$definitions = array();
$tags = $builder->findTags();
asort($tags);
foreach ($tags as $tag) {
foreach ($builder->findTaggedServiceIds($tag) as $serviceId => $attributes) {
$definition = $this->resolveServiceDefinition($builder, $serviceId);
if (!$definition instanceof Definition || !$showPrivate && !$definition->isPublic()) {
continue;
}
if (!isset($definitions[$tag])) {
$definitions[$tag] = array();
}
$definitions[$tag][$serviceId] = $definition;
}
}
return $definitions;
}
protected function sortParameters(ParameterBag $parameters)
{
$parameters = $parameters->all();
ksort($parameters);
return $parameters;
}
protected function sortServiceIds(array $serviceIds)
{
asort($serviceIds);
return $serviceIds;
}
}

View File

@@ -0,0 +1,367 @@
<?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\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class JsonDescriptor extends Descriptor
{
/**
* {@inheritdoc}
*/
protected function describeRouteCollection(RouteCollection $routes, array $options = array())
{
$data = array();
foreach ($routes->all() as $name => $route) {
$data[$name] = $this->getRouteData($route);
}
$this->writeData($data, $options);
}
/**
* {@inheritdoc}
*/
protected function describeRoute(Route $route, array $options = array())
{
$this->writeData($this->getRouteData($route), $options);
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameters(ParameterBag $parameters, array $options = array())
{
$this->writeData($this->sortParameters($parameters), $options);
}
/**
* {@inheritdoc}
*/
protected function describeContainerTags(ContainerBuilder $builder, array $options = array())
{
$showPrivate = isset($options['show_private']) && $options['show_private'];
$data = array();
foreach ($this->findDefinitionsByTag($builder, $showPrivate) as $tag => $definitions) {
$data[$tag] = array();
foreach ($definitions as $definition) {
$data[$tag][] = $this->getContainerDefinitionData($definition, true);
}
}
$this->writeData($data, $options);
}
/**
* {@inheritdoc}
*/
protected function describeContainerService($service, array $options = array())
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
if ($service instanceof Alias) {
$this->writeData($this->getContainerAliasData($service), $options);
} elseif ($service instanceof Definition) {
$this->writeData($this->getContainerDefinitionData($service), $options);
} else {
$this->writeData(get_class($service), $options);
}
}
/**
* {@inheritdoc}
*/
protected function describeContainerServices(ContainerBuilder $builder, array $options = array())
{
$serviceIds = isset($options['tag']) && $options['tag'] ? array_keys($builder->findTaggedServiceIds($options['tag'])) : $builder->getServiceIds();
$showPrivate = isset($options['show_private']) && $options['show_private'];
$data = array('definitions' => array(), 'aliases' => array(), 'services' => array());
foreach ($this->sortServiceIds($serviceIds) as $serviceId) {
$service = $this->resolveServiceDefinition($builder, $serviceId);
if ($service instanceof Alias) {
$data['aliases'][$serviceId] = $this->getContainerAliasData($service);
} elseif ($service instanceof Definition) {
if (($showPrivate || $service->isPublic())) {
$data['definitions'][$serviceId] = $this->getContainerDefinitionData($service);
}
} else {
$data['services'][$serviceId] = get_class($service);
}
}
$this->writeData($data, $options);
}
/**
* {@inheritdoc}
*/
protected function describeContainerDefinition(Definition $definition, array $options = array())
{
$this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags']), $options);
}
/**
* {@inheritdoc}
*/
protected function describeContainerAlias(Alias $alias, array $options = array())
{
$this->writeData($this->getContainerAliasData($alias), $options);
}
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$this->writeData($this->getEventDispatcherListenersData($eventDispatcher, array_key_exists('event', $options) ? $options['event'] : null), $options);
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$this->writeData($this->getCallableData($callable, $options), $options);
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameter($parameter, array $options = array())
{
$key = isset($options['parameter']) ? $options['parameter'] : '';
$this->writeData(array($key => $parameter), $options);
}
/**
* Writes data as json.
*
* @param array $data
* @param array $options
*
* @return array|string
*/
private function writeData(array $data, array $options)
{
$flags = isset($options['json_encoding']) ? $options['json_encoding'] : 0;
$this->write(json_encode($data, $flags | JSON_PRETTY_PRINT)."\n");
}
/**
* @param Route $route
*
* @return array
*/
protected function getRouteData(Route $route)
{
return array(
'path' => $route->getPath(),
'pathRegex' => $route->compile()->getRegex(),
'host' => '' !== $route->getHost() ? $route->getHost() : 'ANY',
'hostRegex' => '' !== $route->getHost() ? $route->compile()->getHostRegex() : '',
'scheme' => $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY',
'method' => $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY',
'class' => get_class($route),
'defaults' => $route->getDefaults(),
'requirements' => $route->getRequirements() ?: 'NO CUSTOM',
'options' => $route->getOptions(),
);
}
/**
* @param Definition $definition
* @param bool $omitTags
*
* @return array
*/
private function getContainerDefinitionData(Definition $definition, $omitTags = false)
{
$data = array(
'class' => (string) $definition->getClass(),
'public' => $definition->isPublic(),
'synthetic' => $definition->isSynthetic(),
'lazy' => $definition->isLazy(),
);
if (method_exists($definition, 'isShared')) {
$data['shared'] = $definition->isShared();
}
$data['abstract'] = $definition->isAbstract();
if (method_exists($definition, 'isAutowired')) {
$data['autowire'] = $definition->isAutowired();
$data['autowiring_types'] = array();
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$data['autowiring_types'][] = $autowiringType;
}
}
$data['file'] = $definition->getFile();
if ($factory = $definition->getFactory()) {
if (is_array($factory)) {
if ($factory[0] instanceof Reference) {
$data['factory_service'] = (string) $factory[0];
} elseif ($factory[0] instanceof Definition) {
throw new \InvalidArgumentException('Factory is not describable.');
} else {
$data['factory_class'] = $factory[0];
}
$data['factory_method'] = $factory[1];
} else {
$data['factory_function'] = $factory;
}
}
if (!$omitTags) {
$data['tags'] = array();
if (count($definition->getTags())) {
foreach ($definition->getTags() as $tagName => $tagData) {
foreach ($tagData as $parameters) {
$data['tags'][] = array('name' => $tagName, 'parameters' => $parameters);
}
}
}
}
return $data;
}
/**
* @param Alias $alias
*
* @return array
*/
private function getContainerAliasData(Alias $alias)
{
return array(
'service' => (string) $alias,
'public' => $alias->isPublic(),
);
}
/**
* @param EventDispatcherInterface $eventDispatcher
* @param string|null $event
*
* @return array
*/
private function getEventDispatcherListenersData(EventDispatcherInterface $eventDispatcher, $event = null)
{
$data = array();
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
foreach ($registeredListeners as $listener) {
$l = $this->getCallableData($listener);
$l['priority'] = $eventDispatcher->getListenerPriority($event, $listener);
$data[] = $l;
}
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
foreach ($eventListeners as $eventListener) {
$l = $this->getCallableData($eventListener);
$l['priority'] = $eventDispatcher->getListenerPriority($eventListened, $eventListener);
$data[$eventListened][] = $l;
}
}
}
return $data;
}
/**
* @param callable $callable
* @param array $options
*
* @return array
*/
private function getCallableData($callable, array $options = array())
{
$data = array();
if (is_array($callable)) {
$data['type'] = 'function';
if (is_object($callable[0])) {
$data['name'] = $callable[1];
$data['class'] = get_class($callable[0]);
} else {
if (0 !== strpos($callable[1], 'parent::')) {
$data['name'] = $callable[1];
$data['class'] = $callable[0];
$data['static'] = true;
} else {
$data['name'] = substr($callable[1], 8);
$data['class'] = $callable[0];
$data['static'] = true;
$data['parent'] = true;
}
}
return $data;
}
if (is_string($callable)) {
$data['type'] = 'function';
if (false === strpos($callable, '::')) {
$data['name'] = $callable;
} else {
$callableParts = explode('::', $callable);
$data['name'] = $callableParts[1];
$data['class'] = $callableParts[0];
$data['static'] = true;
}
return $data;
}
if ($callable instanceof \Closure) {
$data['type'] = 'closure';
return $data;
}
if (method_exists($callable, '__invoke')) {
$data['type'] = 'object';
$data['name'] = get_class($callable);
return $data;
}
throw new \InvalidArgumentException('Callable is not describable.');
}
}

View File

@@ -0,0 +1,366 @@
<?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\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class MarkdownDescriptor extends Descriptor
{
/**
* {@inheritdoc}
*/
protected function describeRouteCollection(RouteCollection $routes, array $options = array())
{
$first = true;
foreach ($routes->all() as $name => $route) {
if ($first) {
$first = false;
} else {
$this->write("\n\n");
}
$this->describeRoute($route, array('name' => $name));
}
$this->write("\n");
}
/**
* {@inheritdoc}
*/
protected function describeRoute(Route $route, array $options = array())
{
$output = '- Path: '.$route->getPath()
."\n".'- Path Regex: '.$route->compile()->getRegex()
."\n".'- Host: '.('' !== $route->getHost() ? $route->getHost() : 'ANY')
."\n".'- Host Regex: '.('' !== $route->getHost() ? $route->compile()->getHostRegex() : '')
."\n".'- Scheme: '.($route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY')
."\n".'- Method: '.($route->getMethods() ? implode('|', $route->getMethods()) : 'ANY')
."\n".'- Class: '.get_class($route)
."\n".'- Defaults: '.$this->formatRouterConfig($route->getDefaults())
."\n".'- Requirements: '.($route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM')
."\n".'- Options: '.$this->formatRouterConfig($route->getOptions());
$this->write(isset($options['name'])
? $options['name']."\n".str_repeat('-', strlen($options['name']))."\n\n".$output
: $output);
$this->write("\n");
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameters(ParameterBag $parameters, array $options = array())
{
$this->write("Container parameters\n====================\n");
foreach ($this->sortParameters($parameters) as $key => $value) {
$this->write(sprintf("\n- `%s`: `%s`", $key, $this->formatParameter($value)));
}
}
/**
* {@inheritdoc}
*/
protected function describeContainerTags(ContainerBuilder $builder, array $options = array())
{
$showPrivate = isset($options['show_private']) && $options['show_private'];
$this->write("Container tags\n==============");
foreach ($this->findDefinitionsByTag($builder, $showPrivate) as $tag => $definitions) {
$this->write("\n\n".$tag."\n".str_repeat('-', strlen($tag)));
foreach ($definitions as $serviceId => $definition) {
$this->write("\n\n");
$this->describeContainerDefinition($definition, array('omit_tags' => true, 'id' => $serviceId));
}
}
}
/**
* {@inheritdoc}
*/
protected function describeContainerService($service, array $options = array())
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
$childOptions = array('id' => $options['id'], 'as_array' => true);
if ($service instanceof Alias) {
$this->describeContainerAlias($service, $childOptions);
} elseif ($service instanceof Definition) {
$this->describeContainerDefinition($service, $childOptions);
} else {
$this->write(sprintf('**`%s`:** `%s`', $options['id'], get_class($service)));
}
}
/**
* {@inheritdoc}
*/
protected function describeContainerServices(ContainerBuilder $builder, array $options = array())
{
$showPrivate = isset($options['show_private']) && $options['show_private'];
$title = $showPrivate ? 'Public and private services' : 'Public services';
if (isset($options['tag'])) {
$title .= ' with tag `'.$options['tag'].'`';
}
$this->write($title."\n".str_repeat('=', strlen($title)));
$serviceIds = isset($options['tag']) && $options['tag'] ? array_keys($builder->findTaggedServiceIds($options['tag'])) : $builder->getServiceIds();
$showPrivate = isset($options['show_private']) && $options['show_private'];
$services = array('definitions' => array(), 'aliases' => array(), 'services' => array());
foreach ($this->sortServiceIds($serviceIds) as $serviceId) {
$service = $this->resolveServiceDefinition($builder, $serviceId);
if ($service instanceof Alias) {
$services['aliases'][$serviceId] = $service;
} elseif ($service instanceof Definition) {
if (($showPrivate || $service->isPublic())) {
$services['definitions'][$serviceId] = $service;
}
} else {
$services['services'][$serviceId] = $service;
}
}
if (!empty($services['definitions'])) {
$this->write("\n\nDefinitions\n-----------\n");
foreach ($services['definitions'] as $id => $service) {
$this->write("\n");
$this->describeContainerDefinition($service, array('id' => $id));
}
}
if (!empty($services['aliases'])) {
$this->write("\n\nAliases\n-------\n");
foreach ($services['aliases'] as $id => $service) {
$this->write("\n");
$this->describeContainerAlias($service, array('id' => $id));
}
}
if (!empty($services['services'])) {
$this->write("\n\nServices\n--------\n");
foreach ($services['services'] as $id => $service) {
$this->write("\n");
$this->write(sprintf('- `%s`: `%s`', $id, get_class($service)));
}
}
}
/**
* {@inheritdoc}
*/
protected function describeContainerDefinition(Definition $definition, array $options = array())
{
$output = '- Class: `'.$definition->getClass().'`'
."\n".'- Public: '.($definition->isPublic() ? 'yes' : 'no')
."\n".'- Synthetic: '.($definition->isSynthetic() ? 'yes' : 'no')
."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no')
;
if (method_exists($definition, 'isShared')) {
$output .= "\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no');
}
$output .= "\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no');
if (method_exists($definition, 'isAutowired')) {
$output .= "\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no');
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$output .= "\n".'- Autowiring Type: `'.$autowiringType.'`';
}
}
if ($definition->getFile()) {
$output .= "\n".'- File: `'.$definition->getFile().'`';
}
if ($factory = $definition->getFactory()) {
if (is_array($factory)) {
if ($factory[0] instanceof Reference) {
$output .= "\n".'- Factory Service: `'.$factory[0].'`';
} elseif ($factory[0] instanceof Definition) {
throw new \InvalidArgumentException('Factory is not describable.');
} else {
$output .= "\n".'- Factory Class: `'.$factory[0].'`';
}
$output .= "\n".'- Factory Method: `'.$factory[1].'`';
} else {
$output .= "\n".'- Factory Function: `'.$factory.'`';
}
}
if (!(isset($options['omit_tags']) && $options['omit_tags'])) {
foreach ($definition->getTags() as $tagName => $tagData) {
foreach ($tagData as $parameters) {
$output .= "\n".'- Tag: `'.$tagName.'`';
foreach ($parameters as $name => $value) {
$output .= "\n".' - '.ucfirst($name).': '.$value;
}
}
}
}
$this->write(isset($options['id']) ? sprintf("%s\n%s\n\n%s\n", $options['id'], str_repeat('~', strlen($options['id'])), $output) : $output);
}
/**
* {@inheritdoc}
*/
protected function describeContainerAlias(Alias $alias, array $options = array())
{
$output = '- Service: `'.$alias.'`'
."\n".'- Public: '.($alias->isPublic() ? 'yes' : 'no');
$this->write(isset($options['id']) ? sprintf("%s\n%s\n\n%s\n", $options['id'], str_repeat('~', strlen($options['id'])), $output) : $output);
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameter($parameter, array $options = array())
{
$this->write(isset($options['parameter']) ? sprintf("%s\n%s\n\n%s", $options['parameter'], str_repeat('=', strlen($options['parameter'])), $this->formatParameter($parameter)) : $parameter);
}
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$event = array_key_exists('event', $options) ? $options['event'] : null;
$title = 'Registered listeners';
if (null !== $event) {
$title .= sprintf(' for event `%s` ordered by descending priority', $event);
}
$this->write(sprintf('# %s', $title)."\n");
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
foreach ($registeredListeners as $order => $listener) {
$this->write("\n".sprintf('## Listener %d', $order + 1)."\n");
$this->describeCallable($listener);
$this->write(sprintf('- Priority: `%d`', $eventDispatcher->getListenerPriority($event, $listener))."\n");
}
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
$this->write("\n".sprintf('## %s', $eventListened)."\n");
foreach ($eventListeners as $order => $eventListener) {
$this->write("\n".sprintf('### Listener %d', $order + 1)."\n");
$this->describeCallable($eventListener);
$this->write(sprintf('- Priority: `%d`', $eventDispatcher->getListenerPriority($eventListened, $eventListener))."\n");
}
}
}
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$string = '';
if (is_array($callable)) {
$string .= "\n- Type: `function`";
if (is_object($callable[0])) {
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
$string .= "\n".sprintf('- Class: `%s`', get_class($callable[0]));
} else {
if (0 !== strpos($callable[1], 'parent::')) {
$string .= "\n".sprintf('- Name: `%s`', $callable[1]);
$string .= "\n".sprintf('- Class: `%s`', $callable[0]);
$string .= "\n- Static: yes";
} else {
$string .= "\n".sprintf('- Name: `%s`', substr($callable[1], 8));
$string .= "\n".sprintf('- Class: `%s`', $callable[0]);
$string .= "\n- Static: yes";
$string .= "\n- Parent: yes";
}
}
return $this->write($string."\n");
}
if (is_string($callable)) {
$string .= "\n- Type: `function`";
if (false === strpos($callable, '::')) {
$string .= "\n".sprintf('- Name: `%s`', $callable);
} else {
$callableParts = explode('::', $callable);
$string .= "\n".sprintf('- Name: `%s`', $callableParts[1]);
$string .= "\n".sprintf('- Class: `%s`', $callableParts[0]);
$string .= "\n- Static: yes";
}
return $this->write($string."\n");
}
if ($callable instanceof \Closure) {
$string .= "\n- Type: `closure`";
return $this->write($string."\n");
}
if (method_exists($callable, '__invoke')) {
$string .= "\n- Type: `object`";
$string .= "\n".sprintf('- Name: `%s`', get_class($callable));
return $this->write($string."\n");
}
throw new \InvalidArgumentException('Callable is not describable.');
}
/**
* @param array $array
*
* @return string
*/
private function formatRouterConfig(array $array)
{
if (!count($array)) {
return 'NONE';
}
$string = '';
ksort($array);
foreach ($array as $name => $value) {
$string .= "\n".' - `'.$name.'`: '.$this->formatValue($value);
}
return $string;
}
}

View File

@@ -0,0 +1,454 @@
<?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\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class TextDescriptor extends Descriptor
{
/**
* {@inheritdoc}
*/
protected function describeRouteCollection(RouteCollection $routes, array $options = array())
{
$showControllers = isset($options['show_controllers']) && $options['show_controllers'];
$tableHeaders = array('Name', 'Method', 'Scheme', 'Host', 'Path');
if ($showControllers) {
$tableHeaders[] = 'Controller';
}
$tableRows = array();
foreach ($routes->all() as $name => $route) {
$row = array(
$name,
$route->getMethods() ? implode('|', $route->getMethods()) : 'ANY',
$route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY',
'' !== $route->getHost() ? $route->getHost() : 'ANY',
$route->getPath(),
);
if ($showControllers) {
$controller = $route->getDefault('_controller');
if ($controller instanceof \Closure) {
$controller = 'Closure';
} elseif (is_object($controller)) {
$controller = get_class($controller);
}
$row[] = $controller;
}
$tableRows[] = $row;
}
if (isset($options['output'])) {
$options['output']->table($tableHeaders, $tableRows);
} else {
$table = new Table($this->getOutput());
$table->setHeaders($tableHeaders)->setRows($tableRows);
$table->render();
}
}
/**
* {@inheritdoc}
*/
protected function describeRoute(Route $route, array $options = array())
{
$tableHeaders = array('Property', 'Value');
$tableRows = array(
array('Route Name', isset($options['name']) ? $options['name'] : ''),
array('Path', $route->getPath()),
array('Path Regex', $route->compile()->getRegex()),
array('Host', ('' !== $route->getHost() ? $route->getHost() : 'ANY')),
array('Host Regex', ('' !== $route->getHost() ? $route->compile()->getHostRegex() : '')),
array('Scheme', ($route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY')),
array('Method', ($route->getMethods() ? implode('|', $route->getMethods()) : 'ANY')),
array('Requirements', ($route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM')),
array('Class', get_class($route)),
array('Defaults', $this->formatRouterConfig($route->getDefaults())),
array('Options', $this->formatRouterConfig($route->getOptions())),
);
$table = new Table($this->getOutput());
$table->setHeaders($tableHeaders)->setRows($tableRows);
$table->render();
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameters(ParameterBag $parameters, array $options = array())
{
$tableHeaders = array('Parameter', 'Value');
$tableRows = array();
foreach ($this->sortParameters($parameters) as $parameter => $value) {
$tableRows[] = array($parameter, $this->formatParameter($value));
}
$options['output']->title('Symfony Container Parameters');
$options['output']->table($tableHeaders, $tableRows);
}
/**
* {@inheritdoc}
*/
protected function describeContainerTags(ContainerBuilder $builder, array $options = array())
{
$showPrivate = isset($options['show_private']) && $options['show_private'];
if ($showPrivate) {
$options['output']->title('Symfony Container Public and Private Tags');
} else {
$options['output']->title('Symfony Container Public Tags');
}
foreach ($this->findDefinitionsByTag($builder, $showPrivate) as $tag => $definitions) {
$options['output']->section(sprintf('"%s" tag', $tag));
$options['output']->listing(array_keys($definitions));
}
}
/**
* {@inheritdoc}
*/
protected function describeContainerService($service, array $options = array())
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
if ($service instanceof Alias) {
$this->describeContainerAlias($service, $options);
} elseif ($service instanceof Definition) {
$this->describeContainerDefinition($service, $options);
} else {
$options['output']->title(sprintf('Information for Service "<info>%s</info>"', $options['id']));
$options['output']->table(
array('Service ID', 'Class'),
array(
array(isset($options['id']) ? $options['id'] : '-', get_class($service)),
)
);
}
}
/**
* {@inheritdoc}
*/
protected function describeContainerServices(ContainerBuilder $builder, array $options = array())
{
$showPrivate = isset($options['show_private']) && $options['show_private'];
$showTag = isset($options['tag']) ? $options['tag'] : null;
if ($showPrivate) {
$title = 'Symfony Container Public and Private Services';
} else {
$title = 'Symfony Container Public Services';
}
if ($showTag) {
$title .= sprintf(' Tagged with "%s" Tag', $options['tag']);
}
$options['output']->title($title);
$serviceIds = isset($options['tag']) && $options['tag'] ? array_keys($builder->findTaggedServiceIds($options['tag'])) : $builder->getServiceIds();
$maxTags = array();
foreach ($serviceIds as $key => $serviceId) {
$definition = $this->resolveServiceDefinition($builder, $serviceId);
if ($definition instanceof Definition) {
// filter out private services unless shown explicitly
if (!$showPrivate && !$definition->isPublic()) {
unset($serviceIds[$key]);
continue;
}
if ($showTag) {
$tags = $definition->getTag($showTag);
foreach ($tags as $tag) {
foreach ($tag as $key => $value) {
if (!isset($maxTags[$key])) {
$maxTags[$key] = strlen($key);
}
if (strlen($value) > $maxTags[$key]) {
$maxTags[$key] = strlen($value);
}
}
}
}
}
}
$tagsCount = count($maxTags);
$tagsNames = array_keys($maxTags);
$tableHeaders = array_merge(array('Service ID'), $tagsNames, array('Class name'));
$tableRows = array();
foreach ($this->sortServiceIds($serviceIds) as $serviceId) {
$definition = $this->resolveServiceDefinition($builder, $serviceId);
if ($definition instanceof Definition) {
if ($showTag) {
foreach ($definition->getTag($showTag) as $key => $tag) {
$tagValues = array();
foreach ($tagsNames as $tagName) {
$tagValues[] = isset($tag[$tagName]) ? $tag[$tagName] : '';
}
if (0 === $key) {
$tableRows[] = array_merge(array($serviceId), $tagValues, array($definition->getClass()));
} else {
$tableRows[] = array_merge(array(' "'), $tagValues, array(''));
}
}
} else {
$tableRows[] = array($serviceId, $definition->getClass());
}
} elseif ($definition instanceof Alias) {
$alias = $definition;
$tableRows[] = array_merge(array($serviceId, sprintf('alias for "%s"', $alias)), $tagsCount ? array_fill(0, $tagsCount, '') : array());
} else {
$tableRows[] = array_merge(array($serviceId, get_class($definition)), $tagsCount ? array_fill(0, $tagsCount, '') : array());
}
}
$options['output']->table($tableHeaders, $tableRows);
}
/**
* {@inheritdoc}
*/
protected function describeContainerDefinition(Definition $definition, array $options = array())
{
if (isset($options['id'])) {
$options['output']->title(sprintf('Information for Service "<info>%s</info>"', $options['id']));
}
$tableHeaders = array('Option', 'Value');
$tableRows[] = array('Service ID', isset($options['id']) ? $options['id'] : '-');
$tableRows[] = array('Class', $definition->getClass() ?: '-');
$tags = $definition->getTags();
if (count($tags)) {
$tagInformation = '';
foreach ($tags as $tagName => $tagData) {
foreach ($tagData as $tagParameters) {
$parameters = array_map(function ($key, $value) {
return sprintf('<info>%s</info>: %s', $key, $value);
}, array_keys($tagParameters), array_values($tagParameters));
$parameters = implode(', ', $parameters);
if ('' === $parameters) {
$tagInformation .= sprintf('%s', $tagName);
} else {
$tagInformation .= sprintf('%s (%s)', $tagName, $parameters);
}
}
}
} else {
$tagInformation = '-';
}
$tableRows[] = array('Tags', $tagInformation);
$tableRows[] = array('Public', $definition->isPublic() ? 'yes' : 'no');
$tableRows[] = array('Synthetic', $definition->isSynthetic() ? 'yes' : 'no');
$tableRows[] = array('Lazy', $definition->isLazy() ? 'yes' : 'no');
if (method_exists($definition, 'isShared')) {
$tableRows[] = array('Shared', $definition->isShared() ? 'yes' : 'no');
}
$tableRows[] = array('Abstract', $definition->isAbstract() ? 'yes' : 'no');
if (method_exists($definition, 'isAutowired')) {
$tableRows[] = array('Autowired', $definition->isAutowired() ? 'yes' : 'no');
$autowiringTypes = $definition->getAutowiringTypes();
if (count($autowiringTypes)) {
$autowiringTypesInformation = implode(', ', $autowiringTypes);
} else {
$autowiringTypesInformation = '-';
}
$tableRows[] = array('Autowiring Types', $autowiringTypesInformation);
}
if ($definition->getFile()) {
$tableRows[] = array('Required File', $definition->getFile() ? $definition->getFile() : '-');
}
if ($factory = $definition->getFactory()) {
if (is_array($factory)) {
if ($factory[0] instanceof Reference) {
$tableRows[] = array('Factory Service', $factory[0]);
} elseif ($factory[0] instanceof Definition) {
throw new \InvalidArgumentException('Factory is not describable.');
} else {
$tableRows[] = array('Factory Class', $factory[0]);
}
$tableRows[] = array('Factory Method', $factory[1]);
} else {
$tableRows[] = array('Factory Function', $factory);
}
}
$options['output']->table($tableHeaders, $tableRows);
}
/**
* {@inheritdoc}
*/
protected function describeContainerAlias(Alias $alias, array $options = array())
{
$options['output']->comment(sprintf('This service is an alias for the service <info>%s</info>', (string) $alias));
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameter($parameter, array $options = array())
{
$options['output']->table(
array('Parameter', 'Value'),
array(
array($options['parameter'], $this->formatParameter($parameter),
),
));
}
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$event = array_key_exists('event', $options) ? $options['event'] : null;
if (null !== $event) {
$title = sprintf('Registered Listeners for "%s" Event', $event);
} else {
$title = 'Registered Listeners Grouped by Event';
}
$options['output']->title($title);
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
$this->renderEventListenerTable($eventDispatcher, $event, $registeredListeners, $options['output']);
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
$options['output']->section(sprintf('"%s" event', $eventListened));
$this->renderEventListenerTable($eventDispatcher, $eventListened, $eventListeners, $options['output']);
}
}
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$this->writeText($this->formatCallable($callable), $options);
}
/**
* @param array $array
*/
private function renderEventListenerTable(EventDispatcherInterface $eventDispatcher, $event, array $eventListeners, SymfonyStyle $io)
{
$tableHeaders = array('Order', 'Callable', 'Priority');
$tableRows = array();
$order = 1;
foreach ($eventListeners as $order => $listener) {
$tableRows[] = array(sprintf('#%d', $order + 1), $this->formatCallable($listener), $eventDispatcher->getListenerPriority($event, $listener));
}
$io->table($tableHeaders, $tableRows);
}
/**
* @param array $config
*
* @return string
*/
private function formatRouterConfig(array $config)
{
if (empty($config)) {
return 'NONE';
}
ksort($config);
$configAsString = '';
foreach ($config as $key => $value) {
$configAsString .= sprintf("\n%s: %s", $key, $this->formatValue($value));
}
return trim($configAsString);
}
/**
* @param callable $callable
*
* @return string
*/
private function formatCallable($callable)
{
if (is_array($callable)) {
if (is_object($callable[0])) {
return sprintf('%s::%s()', get_class($callable[0]), $callable[1]);
}
return sprintf('%s::%s()', $callable[0], $callable[1]);
}
if (is_string($callable)) {
return sprintf('%s()', $callable);
}
if ($callable instanceof \Closure) {
return '\Closure()';
}
if (method_exists($callable, '__invoke')) {
return sprintf('%s::__invoke()', get_class($callable));
}
throw new \InvalidArgumentException('Callable is not describable.');
}
/**
* @param string $content
* @param array $options
*/
private function writeText($content, array $options = array())
{
$this->write(
isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
isset($options['raw_output']) ? !$options['raw_output'] : true
);
}
}

View File

@@ -0,0 +1,531 @@
<?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\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class XmlDescriptor extends Descriptor
{
/**
* {@inheritdoc}
*/
protected function describeRouteCollection(RouteCollection $routes, array $options = array())
{
$this->writeDocument($this->getRouteCollectionDocument($routes));
}
/**
* {@inheritdoc}
*/
protected function describeRoute(Route $route, array $options = array())
{
$this->writeDocument($this->getRouteDocument($route, isset($options['name']) ? $options['name'] : null));
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameters(ParameterBag $parameters, array $options = array())
{
$this->writeDocument($this->getContainerParametersDocument($parameters));
}
/**
* {@inheritdoc}
*/
protected function describeContainerTags(ContainerBuilder $builder, array $options = array())
{
$this->writeDocument($this->getContainerTagsDocument($builder, isset($options['show_private']) && $options['show_private']));
}
/**
* {@inheritdoc}
*/
protected function describeContainerService($service, array $options = array())
{
if (!isset($options['id'])) {
throw new \InvalidArgumentException('An "id" option must be provided.');
}
$this->writeDocument($this->getContainerServiceDocument($service, $options['id']));
}
/**
* {@inheritdoc}
*/
protected function describeContainerServices(ContainerBuilder $builder, array $options = array())
{
$this->writeDocument($this->getContainerServicesDocument($builder, isset($options['tag']) ? $options['tag'] : null, isset($options['show_private']) && $options['show_private']));
}
/**
* {@inheritdoc}
*/
protected function describeContainerDefinition(Definition $definition, array $options = array())
{
$this->writeDocument($this->getContainerDefinitionDocument($definition, isset($options['id']) ? $options['id'] : null, isset($options['omit_tags']) && $options['omit_tags']));
}
/**
* {@inheritdoc}
*/
protected function describeContainerAlias(Alias $alias, array $options = array())
{
$this->writeDocument($this->getContainerAliasDocument($alias, isset($options['id']) ? $options['id'] : null));
}
/**
* {@inheritdoc}
*/
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = array())
{
$this->writeDocument($this->getEventDispatcherListenersDocument($eventDispatcher, array_key_exists('event', $options) ? $options['event'] : null));
}
/**
* {@inheritdoc}
*/
protected function describeCallable($callable, array $options = array())
{
$this->writeDocument($this->getCallableDocument($callable));
}
/**
* {@inheritdoc}
*/
protected function describeContainerParameter($parameter, array $options = array())
{
$this->writeDocument($this->getContainerParameterDocument($parameter, $options));
}
/**
* Writes DOM document.
*
* @param \DOMDocument $dom
*
* @return \DOMDocument|string
*/
private function writeDocument(\DOMDocument $dom)
{
$dom->formatOutput = true;
$this->write($dom->saveXML());
}
/**
* @param RouteCollection $routes
*
* @return \DOMDocument
*/
private function getRouteCollectionDocument(RouteCollection $routes)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($routesXML = $dom->createElement('routes'));
foreach ($routes->all() as $name => $route) {
$routeXML = $this->getRouteDocument($route, $name);
$routesXML->appendChild($routesXML->ownerDocument->importNode($routeXML->childNodes->item(0), true));
}
return $dom;
}
/**
* @param Route $route
* @param string|null $name
*
* @return \DOMDocument
*/
private function getRouteDocument(Route $route, $name = null)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($routeXML = $dom->createElement('route'));
if ($name) {
$routeXML->setAttribute('name', $name);
}
$routeXML->setAttribute('class', get_class($route));
$routeXML->appendChild($pathXML = $dom->createElement('path'));
$pathXML->setAttribute('regex', $route->compile()->getRegex());
$pathXML->appendChild(new \DOMText($route->getPath()));
if ('' !== $route->getHost()) {
$routeXML->appendChild($hostXML = $dom->createElement('host'));
$hostXML->setAttribute('regex', $route->compile()->getHostRegex());
$hostXML->appendChild(new \DOMText($route->getHost()));
}
foreach ($route->getSchemes() as $scheme) {
$routeXML->appendChild($schemeXML = $dom->createElement('scheme'));
$schemeXML->appendChild(new \DOMText($scheme));
}
foreach ($route->getMethods() as $method) {
$routeXML->appendChild($methodXML = $dom->createElement('method'));
$methodXML->appendChild(new \DOMText($method));
}
if (count($route->getDefaults())) {
$routeXML->appendChild($defaultsXML = $dom->createElement('defaults'));
foreach ($route->getDefaults() as $attribute => $value) {
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
$defaultXML->setAttribute('key', $attribute);
$defaultXML->appendChild(new \DOMText($this->formatValue($value)));
}
}
if (count($route->getRequirements())) {
$routeXML->appendChild($requirementsXML = $dom->createElement('requirements'));
foreach ($route->getRequirements() as $attribute => $pattern) {
$requirementsXML->appendChild($requirementXML = $dom->createElement('requirement'));
$requirementXML->setAttribute('key', $attribute);
$requirementXML->appendChild(new \DOMText($pattern));
}
}
if (count($route->getOptions())) {
$routeXML->appendChild($optionsXML = $dom->createElement('options'));
foreach ($route->getOptions() as $name => $value) {
$optionsXML->appendChild($optionXML = $dom->createElement('option'));
$optionXML->setAttribute('key', $name);
$optionXML->appendChild(new \DOMText($this->formatValue($value)));
}
}
return $dom;
}
/**
* @param ParameterBag $parameters
*
* @return \DOMDocument
*/
private function getContainerParametersDocument(ParameterBag $parameters)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($parametersXML = $dom->createElement('parameters'));
foreach ($this->sortParameters($parameters) as $key => $value) {
$parametersXML->appendChild($parameterXML = $dom->createElement('parameter'));
$parameterXML->setAttribute('key', $key);
$parameterXML->appendChild(new \DOMText($this->formatParameter($value)));
}
return $dom;
}
/**
* @param ContainerBuilder $builder
* @param bool $showPrivate
*
* @return \DOMDocument
*/
private function getContainerTagsDocument(ContainerBuilder $builder, $showPrivate = false)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($containerXML = $dom->createElement('container'));
foreach ($this->findDefinitionsByTag($builder, $showPrivate) as $tag => $definitions) {
$containerXML->appendChild($tagXML = $dom->createElement('tag'));
$tagXML->setAttribute('name', $tag);
foreach ($definitions as $serviceId => $definition) {
$definitionXML = $this->getContainerDefinitionDocument($definition, $serviceId, true);
$tagXML->appendChild($dom->importNode($definitionXML->childNodes->item(0), true));
}
}
return $dom;
}
/**
* @param mixed $service
* @param string $id
*
* @return \DOMDocument
*/
private function getContainerServiceDocument($service, $id)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
if ($service instanceof Alias) {
$dom->appendChild($dom->importNode($this->getContainerAliasDocument($service, $id)->childNodes->item(0), true));
} elseif ($service instanceof Definition) {
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id)->childNodes->item(0), true));
} else {
$dom->appendChild($serviceXML = $dom->createElement('service'));
$serviceXML->setAttribute('id', $id);
$serviceXML->setAttribute('class', get_class($service));
}
return $dom;
}
/**
* @param ContainerBuilder $builder
* @param string|null $tag
* @param bool $showPrivate
*
* @return \DOMDocument
*/
private function getContainerServicesDocument(ContainerBuilder $builder, $tag = null, $showPrivate = false)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($containerXML = $dom->createElement('container'));
$serviceIds = $tag ? array_keys($builder->findTaggedServiceIds($tag)) : $builder->getServiceIds();
foreach ($this->sortServiceIds($serviceIds) as $serviceId) {
$service = $this->resolveServiceDefinition($builder, $serviceId);
if ($service instanceof Definition && !($showPrivate || $service->isPublic())) {
continue;
}
$serviceXML = $this->getContainerServiceDocument($service, $serviceId);
$containerXML->appendChild($containerXML->ownerDocument->importNode($serviceXML->childNodes->item(0), true));
}
return $dom;
}
/**
* @param Definition $definition
* @param string|null $id
* @param bool $omitTags
*
* @return \DOMDocument
*/
private function getContainerDefinitionDocument(Definition $definition, $id = null, $omitTags = false)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($serviceXML = $dom->createElement('definition'));
if ($id) {
$serviceXML->setAttribute('id', $id);
}
$serviceXML->setAttribute('class', $definition->getClass());
if ($factory = $definition->getFactory()) {
$serviceXML->appendChild($factoryXML = $dom->createElement('factory'));
if (is_array($factory)) {
if ($factory[0] instanceof Reference) {
$factoryXML->setAttribute('service', (string) $factory[0]);
} elseif ($factory[0] instanceof Definition) {
throw new \InvalidArgumentException('Factory is not describable.');
} else {
$factoryXML->setAttribute('class', $factory[0]);
}
$factoryXML->setAttribute('method', $factory[1]);
} else {
$factoryXML->setAttribute('function', $factory);
}
}
$serviceXML->setAttribute('public', $definition->isPublic() ? 'true' : 'false');
$serviceXML->setAttribute('synthetic', $definition->isSynthetic() ? 'true' : 'false');
$serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false');
if (method_exists($definition, 'isShared')) {
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
}
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
if (method_exists($definition, 'isAutowired')) {
$serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false');
}
$serviceXML->setAttribute('file', $definition->getFile());
if (!$omitTags) {
$tags = $definition->getTags();
if (count($tags) > 0) {
$serviceXML->appendChild($tagsXML = $dom->createElement('tags'));
foreach ($tags as $tagName => $tagData) {
foreach ($tagData as $parameters) {
$tagsXML->appendChild($tagXML = $dom->createElement('tag'));
$tagXML->setAttribute('name', $tagName);
foreach ($parameters as $name => $value) {
$tagXML->appendChild($parameterXML = $dom->createElement('parameter'));
$parameterXML->setAttribute('name', $name);
$parameterXML->appendChild(new \DOMText($this->formatParameter($value)));
}
}
}
}
}
return $dom;
}
/**
* @param Alias $alias
* @param string|null $id
*
* @return \DOMDocument
*/
private function getContainerAliasDocument(Alias $alias, $id = null)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($aliasXML = $dom->createElement('alias'));
if ($id) {
$aliasXML->setAttribute('id', $id);
}
$aliasXML->setAttribute('service', (string) $alias);
$aliasXML->setAttribute('public', $alias->isPublic() ? 'true' : 'false');
return $dom;
}
/**
* @param string $parameter
* @param array $options
*
* @return \DOMDocument
*/
private function getContainerParameterDocument($parameter, $options = array())
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($parameterXML = $dom->createElement('parameter'));
if (isset($options['parameter'])) {
$parameterXML->setAttribute('key', $options['parameter']);
}
$parameterXML->appendChild(new \DOMText($this->formatParameter($parameter)));
return $dom;
}
/**
* @param EventDispatcherInterface $eventDispatcher
* @param string|null $event
*
* @return \DOMDocument
*/
private function getEventDispatcherListenersDocument(EventDispatcherInterface $eventDispatcher, $event = null)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($eventDispatcherXML = $dom->createElement('event-dispatcher'));
$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
$this->appendEventListenerDocument($eventDispatcher, $event, $eventDispatcherXML, $registeredListeners);
} else {
ksort($registeredListeners);
foreach ($registeredListeners as $eventListened => $eventListeners) {
$eventDispatcherXML->appendChild($eventXML = $dom->createElement('event'));
$eventXML->setAttribute('name', $eventListened);
$this->appendEventListenerDocument($eventDispatcher, $eventListened, $eventXML, $eventListeners);
}
}
return $dom;
}
/**
* @param \DOMElement $element
* @param array $eventListeners
*/
private function appendEventListenerDocument(EventDispatcherInterface $eventDispatcher, $event, \DOMElement $element, array $eventListeners)
{
foreach ($eventListeners as $listener) {
$callableXML = $this->getCallableDocument($listener);
$callableXML->childNodes->item(0)->setAttribute('priority', $eventDispatcher->getListenerPriority($event, $listener));
$element->appendChild($element->ownerDocument->importNode($callableXML->childNodes->item(0), true));
}
}
/**
* @param callable $callable
*
* @return \DOMDocument
*/
private function getCallableDocument($callable)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($callableXML = $dom->createElement('callable'));
if (is_array($callable)) {
$callableXML->setAttribute('type', 'function');
if (is_object($callable[0])) {
$callableXML->setAttribute('name', $callable[1]);
$callableXML->setAttribute('class', get_class($callable[0]));
} else {
if (0 !== strpos($callable[1], 'parent::')) {
$callableXML->setAttribute('name', $callable[1]);
$callableXML->setAttribute('class', $callable[0]);
$callableXML->setAttribute('static', 'true');
} else {
$callableXML->setAttribute('name', substr($callable[1], 8));
$callableXML->setAttribute('class', $callable[0]);
$callableXML->setAttribute('static', 'true');
$callableXML->setAttribute('parent', 'true');
}
}
return $dom;
}
if (is_string($callable)) {
$callableXML->setAttribute('type', 'function');
if (false === strpos($callable, '::')) {
$callableXML->setAttribute('name', $callable);
} else {
$callableParts = explode('::', $callable);
$callableXML->setAttribute('name', $callableParts[1]);
$callableXML->setAttribute('class', $callableParts[0]);
$callableXML->setAttribute('static', 'true');
}
return $dom;
}
if ($callable instanceof \Closure) {
$callableXML->setAttribute('type', 'closure');
return $dom;
}
if (method_exists($callable, '__invoke')) {
$callableXML->setAttribute('type', 'object');
$callableXML->setAttribute('name', get_class($callable));
return $dom;
}
throw new \InvalidArgumentException('Callable is not describable.');
}
}

View File

@@ -0,0 +1,39 @@
<?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\Bundle\FrameworkBundle\Console\Helper;
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\JsonDescriptor;
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\MarkdownDescriptor;
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\TextDescriptor;
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Helper\DescriptorHelper as BaseDescriptorHelper;
/**
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*
* @internal
*/
class DescriptorHelper extends BaseDescriptorHelper
{
/**
* Constructor.
*/
public function __construct()
{
$this
->register('txt', new TextDescriptor())
->register('xml', new XmlDescriptor())
->register('json', new JsonDescriptor())
->register('md', new MarkdownDescriptor())
;
}
}

View File

@@ -0,0 +1,394 @@
<?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\Bundle\FrameworkBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Doctrine\Bundle\DoctrineBundle\Registry;
/**
* Controller is a simple implementation of a Controller.
*
* It provides methods to common features needed in controllers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Controller implements ContainerAwareInterface
{
use ContainerAwareTrait;
/**
* Generates a URL from the given parameters.
*
* @param string $route The name of the route
* @param mixed $parameters An array of parameters
* @param int $referenceType The type of reference (one of the constants in UrlGeneratorInterface)
*
* @return string The generated URL
*
* @see UrlGeneratorInterface
*/
protected function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
{
return $this->container->get('router')->generate($route, $parameters, $referenceType);
}
/**
* Forwards the request to another controller.
*
* @param string $controller The controller name (a string like BlogBundle:Post:index)
* @param array $path An array of path parameters
* @param array $query An array of query parameters
*
* @return Response A Response instance
*/
protected function forward($controller, array $path = array(), array $query = array())
{
$path['_controller'] = $controller;
$subRequest = $this->container->get('request_stack')->getCurrentRequest()->duplicate($query, null, $path);
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
/**
* Returns a RedirectResponse to the given URL.
*
* @param string $url The URL to redirect to
* @param int $status The status code to use for the Response
*
* @return RedirectResponse
*/
protected function redirect($url, $status = 302)
{
return new RedirectResponse($url, $status);
}
/**
* Returns a RedirectResponse to the given route with the given parameters.
*
* @param string $route The name of the route
* @param array $parameters An array of parameters
* @param int $status The status code to use for the Response
*
* @return RedirectResponse
*/
protected function redirectToRoute($route, array $parameters = array(), $status = 302)
{
return $this->redirect($this->generateUrl($route, $parameters), $status);
}
/**
* Adds a flash message to the current session for type.
*
* @param string $type The type
* @param string $message The message
*
* @throws \LogicException
*/
protected function addFlash($type, $message)
{
if (!$this->container->has('session')) {
throw new \LogicException('You can not use the addFlash method if sessions are disabled.');
}
$this->container->get('session')->getFlashBag()->add($type, $message);
}
/**
* Checks if the attributes are granted against the current authentication token and optionally supplied object.
*
* @param mixed $attributes The attributes
* @param mixed $object The object
*
* @return bool
*
* @throws \LogicException
*/
protected function isGranted($attributes, $object = null)
{
if (!$this->container->has('security.authorization_checker')) {
throw new \LogicException('The SecurityBundle is not registered in your application.');
}
return $this->container->get('security.authorization_checker')->isGranted($attributes, $object);
}
/**
* Throws an exception unless the attributes are granted against the current authentication token and optionally
* supplied object.
*
* @param mixed $attributes The attributes
* @param mixed $object The object
* @param string $message The message passed to the exception
*
* @throws AccessDeniedException
*/
protected function denyAccessUnlessGranted($attributes, $object = null, $message = 'Access Denied.')
{
if (!$this->isGranted($attributes, $object)) {
throw $this->createAccessDeniedException($message);
}
}
/**
* Returns a rendered view.
*
* @param string $view The view name
* @param array $parameters An array of parameters to pass to the view
*
* @return string The rendered view
*/
protected function renderView($view, array $parameters = array())
{
if ($this->container->has('templating')) {
return $this->container->get('templating')->render($view, $parameters);
}
if (!$this->container->has('twig')) {
throw new \LogicException('You can not use the "renderView" method if the Templating Component or the Twig Bundle are not available.');
}
return $this->container->get('twig')->render($view, $parameters);
}
/**
* Renders a view.
*
* @param string $view The view name
* @param array $parameters An array of parameters to pass to the view
* @param Response $response A response instance
*
* @return Response A Response instance
*/
protected function render($view, array $parameters = array(), Response $response = null)
{
if ($this->container->has('templating')) {
return $this->container->get('templating')->renderResponse($view, $parameters, $response);
}
if (!$this->container->has('twig')) {
throw new \LogicException('You can not use the "render" method if the Templating Component or the Twig Bundle are not available.');
}
if (null === $response) {
$response = new Response();
}
$response->setContent($this->container->get('twig')->render($view, $parameters));
return $response;
}
/**
* Streams a view.
*
* @param string $view The view name
* @param array $parameters An array of parameters to pass to the view
* @param StreamedResponse $response A response instance
*
* @return StreamedResponse A StreamedResponse instance
*/
protected function stream($view, array $parameters = array(), StreamedResponse $response = null)
{
if ($this->container->has('templating')) {
$templating = $this->container->get('templating');
$callback = function () use ($templating, $view, $parameters) {
$templating->stream($view, $parameters);
};
} elseif ($this->container->has('twig')) {
$twig = $this->container->get('twig');
$callback = function () use ($twig, $view, $parameters) {
$twig->display($view, $parameters);
};
} else {
throw new \LogicException('You can not use the "stream" method if the Templating Component or the Twig Bundle are not available.');
}
if (null === $response) {
return new StreamedResponse($callback);
}
$response->setCallback($callback);
return $response;
}
/**
* Returns a NotFoundHttpException.
*
* This will result in a 404 response code. Usage example:
*
* throw $this->createNotFoundException('Page not found!');
*
* @param string $message A message
* @param \Exception|null $previous The previous exception
*
* @return NotFoundHttpException
*/
protected function createNotFoundException($message = 'Not Found', \Exception $previous = null)
{
return new NotFoundHttpException($message, $previous);
}
/**
* Returns an AccessDeniedException.
*
* This will result in a 403 response code. Usage example:
*
* throw $this->createAccessDeniedException('Unable to access this page!');
*
* @param string $message A message
* @param \Exception|null $previous The previous exception
*
* @return AccessDeniedException
*/
protected function createAccessDeniedException($message = 'Access Denied.', \Exception $previous = null)
{
return new AccessDeniedException($message, $previous);
}
/**
* Creates and returns a Form instance from the type of the form.
*
* @param string $type The fully qualified class name of the form type
* @param mixed $data The initial data for the form
* @param array $options Options for the form
*
* @return Form
*/
protected function createForm($type, $data = null, array $options = array())
{
return $this->container->get('form.factory')->create($type, $data, $options);
}
/**
* Creates and returns a form builder instance.
*
* @param mixed $data The initial data for the form
* @param array $options Options for the form
*
* @return FormBuilder
*/
protected function createFormBuilder($data = null, array $options = array())
{
return $this->container->get('form.factory')->createBuilder(FormType::class, $data, $options);
}
/**
* Shortcut to return the Doctrine Registry service.
*
* @return Registry
*
* @throws \LogicException If DoctrineBundle is not available
*/
protected function getDoctrine()
{
if (!$this->container->has('doctrine')) {
throw new \LogicException('The DoctrineBundle is not registered in your application.');
}
return $this->container->get('doctrine');
}
/**
* Get a user from the Security Token Storage.
*
* @return mixed
*
* @throws \LogicException If SecurityBundle is not available
*
* @see TokenInterface::getUser()
*/
protected function getUser()
{
if (!$this->container->has('security.token_storage')) {
throw new \LogicException('The SecurityBundle is not registered in your application.');
}
if (null === $token = $this->container->get('security.token_storage')->getToken()) {
return;
}
if (!is_object($user = $token->getUser())) {
// e.g. anonymous authentication
return;
}
return $user;
}
/**
* Returns true if the service id is defined.
*
* @param string $id The service id
*
* @return bool true if the service id is defined, false otherwise
*/
protected function has($id)
{
return $this->container->has($id);
}
/**
* Gets a container service by its id.
*
* @param string $id The service id
*
* @return object The service
*/
protected function get($id)
{
return $this->container->get($id);
}
/**
* Gets a container configuration parameter by its name.
*
* @param string $name The parameter name
*
* @return mixed
*/
protected function getParameter($name)
{
return $this->container->getParameter($name);
}
/**
* Checks the validity of a CSRF token.
*
* @param string $id The id used when generating the token
* @param string $token The actual token sent with the request that should be validated
*
* @return bool
*/
protected function isCsrfTokenValid($id, $token)
{
if (!$this->container->has('security.csrf.token_manager')) {
throw new \LogicException('CSRF protection is not enabled in your application.');
}
return $this->container->get('security.csrf.token_manager')->isTokenValid(new CsrfToken($id, $token));
}
}

View File

@@ -0,0 +1,151 @@
<?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\Bundle\FrameworkBundle\Controller;
use Symfony\Component\HttpKernel\KernelInterface;
/**
* ControllerNameParser converts controller from the short notation a:b:c
* (BlogBundle:Post:index) to a fully-qualified class::method string
* (Bundle\BlogBundle\Controller\PostController::indexAction).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ControllerNameParser
{
protected $kernel;
/**
* Constructor.
*
* @param KernelInterface $kernel A KernelInterface instance
*/
public function __construct(KernelInterface $kernel)
{
$this->kernel = $kernel;
}
/**
* Converts a short notation a:b:c to a class::method.
*
* @param string $controller A short notation controller (a:b:c)
*
* @return string A string in the class::method notation
*
* @throws \InvalidArgumentException when the specified bundle is not enabled
* or the controller cannot be found
*/
public function parse($controller)
{
$originalController = $controller;
if (3 !== count($parts = explode(':', $controller))) {
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "a:b:c" controller string.', $controller));
}
list($bundle, $controller, $action) = $parts;
$controller = str_replace('/', '\\', $controller);
$bundles = array();
try {
// this throws an exception if there is no such bundle
$allBundles = $this->kernel->getBundle($bundle, false);
} catch (\InvalidArgumentException $e) {
$message = sprintf(
'The "%s" (from the _controller value "%s") does not exist or is not enabled in your kernel!',
$bundle,
$originalController
);
if ($alternative = $this->findAlternative($bundle)) {
$message .= sprintf(' Did you mean "%s:%s:%s"?', $alternative, $controller, $action);
}
throw new \InvalidArgumentException($message, 0, $e);
}
foreach ($allBundles as $b) {
$try = $b->getNamespace().'\\Controller\\'.$controller.'Controller';
if (class_exists($try)) {
return $try.'::'.$action.'Action';
}
$bundles[] = $b->getName();
$msg = sprintf('The _controller value "%s:%s:%s" maps to a "%s" class, but this class was not found. Create this class or check the spelling of the class and its namespace.', $bundle, $controller, $action, $try);
}
if (count($bundles) > 1) {
$msg = sprintf('Unable to find controller "%s:%s" in bundles %s.', $bundle, $controller, implode(', ', $bundles));
}
throw new \InvalidArgumentException($msg);
}
/**
* Converts a class::method notation to a short one (a:b:c).
*
* @param string $controller A string in the class::method notation
*
* @return string A short notation controller (a:b:c)
*
* @throws \InvalidArgumentException when the controller is not valid or cannot be found in any bundle
*/
public function build($controller)
{
if (0 === preg_match('#^(.*?\\\\Controller\\\\(.+)Controller)::(.+)Action$#', $controller, $match)) {
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "class::method" string.', $controller));
}
$className = $match[1];
$controllerName = $match[2];
$actionName = $match[3];
foreach ($this->kernel->getBundles() as $name => $bundle) {
if (0 !== strpos($className, $bundle->getNamespace())) {
continue;
}
return sprintf('%s:%s:%s', $name, $controllerName, $actionName);
}
throw new \InvalidArgumentException(sprintf('Unable to find a bundle that defines controller "%s".', $controller));
}
/**
* Attempts to find a bundle that is *similar* to the given bundle name.
*
* @param string $nonExistentBundleName
*
* @return string
*/
private function findAlternative($nonExistentBundleName)
{
$bundleNames = array_map(function ($b) {
return $b->getName();
}, $this->kernel->getBundles());
$alternative = null;
$shortest = null;
foreach ($bundleNames as $bundleName) {
// if there's a partial match, return it immediately
if (false !== strpos($bundleName, $nonExistentBundleName)) {
return $bundleName;
}
$lev = levenshtein($nonExistentBundleName, $bundleName);
if ($lev <= strlen($nonExistentBundleName) / 3 && ($alternative === null || $lev < $shortest)) {
$alternative = $bundleName;
$shortest = $lev;
}
}
return $alternative;
}
}

View File

@@ -0,0 +1,93 @@
<?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\Bundle\FrameworkBundle\Controller;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/**
* ControllerResolver.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ControllerResolver extends BaseControllerResolver
{
protected $container;
protected $parser;
/**
* Constructor.
*
* @param ContainerInterface $container A ContainerInterface instance
* @param ControllerNameParser $parser A ControllerNameParser instance
* @param LoggerInterface $logger A LoggerInterface instance
*/
public function __construct(ContainerInterface $container, ControllerNameParser $parser, LoggerInterface $logger = null)
{
$this->container = $container;
$this->parser = $parser;
parent::__construct($logger);
}
/**
* Returns a callable for the given controller.
*
* @param string $controller A Controller string
*
* @return mixed A PHP callable
*
* @throws \LogicException When the name could not be parsed
* @throws \InvalidArgumentException When the controller class does not exist
*/
protected function createController($controller)
{
if (false === strpos($controller, '::')) {
$count = substr_count($controller, ':');
if (2 == $count) {
// controller in the a:b:c notation then
$controller = $this->parser->parse($controller);
} elseif (1 == $count) {
// controller in the service:method notation
list($service, $method) = explode(':', $controller, 2);
return array($this->container->get($service), $method);
} elseif ($this->container->has($controller) && method_exists($service = $this->container->get($controller), '__invoke')) {
return $service;
} else {
throw new \LogicException(sprintf('Unable to parse the controller name "%s".', $controller));
}
}
return parent::createController($controller);
}
/**
* {@inheritdoc}
*/
protected function instantiateController($class)
{
if ($this->container->has($class)) {
return $this->container->get($class);
}
$controller = parent::instantiateController($class);
if ($controller instanceof ContainerAwareInterface) {
$controller->setContainer($this->container);
}
return $controller;
}
}

View File

@@ -0,0 +1,144 @@
<?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\Bundle\FrameworkBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Redirects a request to another URL.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RedirectController implements ContainerAwareInterface
{
use ContainerAwareTrait;
/**
* Redirects to another route with the given name.
*
* The response status code is 302 if the permanent parameter is false (default),
* and 301 if the redirection is permanent.
*
* In case the route name is empty, the status code will be 404 when permanent is false
* and 410 otherwise.
*
* @param Request $request The request instance
* @param string $route The route name to redirect to
* @param bool $permanent Whether the redirection is permanent
* @param bool|array $ignoreAttributes Whether to ignore attributes or an array of attributes to ignore
*
* @return Response A Response instance
*
* @throws HttpException In case the route name is empty
*/
public function redirectAction(Request $request, $route, $permanent = false, $ignoreAttributes = false)
{
if ('' == $route) {
throw new HttpException($permanent ? 410 : 404);
}
$attributes = array();
if (false === $ignoreAttributes || is_array($ignoreAttributes)) {
$attributes = $request->attributes->get('_route_params');
unset($attributes['route'], $attributes['permanent'], $attributes['ignoreAttributes']);
if ($ignoreAttributes) {
$attributes = array_diff_key($attributes, array_flip($ignoreAttributes));
}
}
return new RedirectResponse($this->container->get('router')->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), $permanent ? 301 : 302);
}
/**
* Redirects to a URL.
*
* The response status code is 302 if the permanent parameter is false (default),
* and 301 if the redirection is permanent.
*
* In case the path is empty, the status code will be 404 when permanent is false
* and 410 otherwise.
*
* @param Request $request The request instance
* @param string $path The absolute path or URL to redirect to
* @param bool $permanent Whether the redirect is permanent or not
* @param string|null $scheme The URL scheme (null to keep the current one)
* @param int|null $httpPort The HTTP port (null to keep the current one for the same scheme or the configured port in the container)
* @param int|null $httpsPort The HTTPS port (null to keep the current one for the same scheme or the configured port in the container)
*
* @return Response A Response instance
*
* @throws HttpException In case the path is empty
*/
public function urlRedirectAction(Request $request, $path, $permanent = false, $scheme = null, $httpPort = null, $httpsPort = null)
{
if ('' == $path) {
throw new HttpException($permanent ? 410 : 404);
}
$statusCode = $permanent ? 301 : 302;
// redirect if the path is a full URL
if (parse_url($path, PHP_URL_SCHEME)) {
return new RedirectResponse($path, $statusCode);
}
if (null === $scheme) {
$scheme = $request->getScheme();
}
$qs = $request->getQueryString();
if ($qs) {
if (strpos($path, '?') === false) {
$qs = '?'.$qs;
} else {
$qs = '&'.$qs;
}
}
$port = '';
if ('http' === $scheme) {
if (null === $httpPort) {
if ('http' === $request->getScheme()) {
$httpPort = $request->getPort();
} elseif ($this->container->hasParameter('request_listener.http_port')) {
$httpPort = $this->container->getParameter('request_listener.http_port');
}
}
if (null !== $httpPort && 80 != $httpPort) {
$port = ":$httpPort";
}
} elseif ('https' === $scheme) {
if (null === $httpsPort) {
if ('https' === $request->getScheme()) {
$httpsPort = $request->getPort();
} elseif ($this->container->hasParameter('request_listener.https_port')) {
$httpsPort = $this->container->getParameter('request_listener.https_port');
}
}
if (null !== $httpsPort && 443 != $httpsPort) {
$port = ":$httpsPort";
}
}
$url = $scheme.'://'.$request->getHost().$port.$request->getBaseUrl().$path.$qs;
return new RedirectResponse($url, $statusCode);
}
}

View File

@@ -0,0 +1,58 @@
<?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\Bundle\FrameworkBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Response;
/**
* TemplateController.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TemplateController implements ContainerAwareInterface
{
use ContainerAwareTrait;
/**
* Renders a template.
*
* @param string $template The template name
* @param int|null $maxAge Max age for client caching
* @param int|null $sharedAge Max age for shared (proxy) caching
* @param bool|null $private Whether or not caching should apply for client caches only
*
* @return Response A Response instance
*/
public function templateAction($template, $maxAge = null, $sharedAge = null, $private = null)
{
/** @var $response \Symfony\Component\HttpFoundation\Response */
$response = $this->container->get('templating')->renderResponse($template);
if ($maxAge) {
$response->setMaxAge($maxAge);
}
if ($sharedAge) {
$response->setSharedMaxAge($sharedAge);
}
if ($private) {
$response->setPrivate();
} elseif ($private === false || (null === $private && ($maxAge || $sharedAge))) {
$response->setPublic();
}
return $response;
}
}

View File

@@ -0,0 +1,37 @@
<?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\Bundle\FrameworkBundle\DataCollector;
use Symfony\Component\HttpKernel\DataCollector\RouterDataCollector as BaseRouterDataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
/**
* RouterDataCollector.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RouterDataCollector extends BaseRouterDataCollector
{
public function guessRoute(Request $request, $controller)
{
if (is_array($controller)) {
$controller = $controller[0];
}
if ($controller instanceof RedirectController) {
return $request->attributes->get('_route');
}
return parent::guessRoute($request, $controller);
}
}

View File

@@ -0,0 +1,41 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers the cache clearers.
*
* @author Dustin Dobervich <ddobervich@gmail.com>
*/
class AddCacheClearerPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('cache_clearer')) {
return;
}
$clearers = array();
foreach ($container->findTaggedServiceIds('kernel.cache_clearer') as $id => $attributes) {
$clearers[] = new Reference($id);
}
$container->getDefinition('cache_clearer')->replaceArgument(0, $clearers);
}
}

View File

@@ -0,0 +1,50 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers the cache warmers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AddCacheWarmerPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('cache_warmer')) {
return;
}
$warmers = array();
foreach ($container->findTaggedServiceIds('kernel.cache_warmer') as $id => $attributes) {
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
$warmers[$priority][] = new Reference($id);
}
if (empty($warmers)) {
return;
}
// sort by priority and flatten
krsort($warmers);
$warmers = call_user_func_array('array_merge', $warmers);
$container->getDefinition('cache_warmer')->replaceArgument(0, $warmers);
}
}

View File

@@ -0,0 +1,48 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* AddConsoleCommandPass.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class AddConsoleCommandPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$commandServices = $container->findTaggedServiceIds('console.command');
foreach ($commandServices as $id => $tags) {
$definition = $container->getDefinition($id);
if (!$definition->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must be public.', $id));
}
if ($definition->isAbstract()) {
throw new \InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must not be abstract.', $id));
}
$class = $container->getParameterBag()->resolveValue($definition->getClass());
if (!is_subclass_of($class, 'Symfony\\Component\\Console\\Command\\Command')) {
throw new \InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must be a subclass of "Symfony\\Component\\Console\\Command\\Command".', $id));
}
$container->setAlias('console.command.'.strtolower(str_replace('\\', '_', $class)), $id);
}
$container->setParameter('console.command.ids', array_keys($commandServices));
}
}

View File

@@ -0,0 +1,36 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class AddConstraintValidatorsPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('validator.validator_factory')) {
return;
}
$validators = array();
foreach ($container->findTaggedServiceIds('validator.constraint_validator') as $id => $attributes) {
if (isset($attributes[0]['alias'])) {
$validators[$attributes[0]['alias']] = $id;
}
$validators[$container->getDefinition($id)->getClass()] = $id;
}
$container->getDefinition('validator.validator_factory')->replaceArgument(1, $validators);
}
}

View File

@@ -0,0 +1,46 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers the expression language providers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AddExpressionLanguageProvidersPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
// routing
if ($container->has('router')) {
$definition = $container->findDefinition('router');
foreach ($container->findTaggedServiceIds('routing.expression_language_provider') as $id => $attributes) {
$definition->addMethodCall('addExpressionLanguageProvider', array(new Reference($id)));
}
}
// security
if ($container->has('security.access.expression_voter')) {
$definition = $container->findDefinition('security.access.expression_voter');
foreach ($container->findTaggedServiceIds('security.expression_language_provider') as $id => $attributes) {
$definition->addMethodCall('addExpressionLanguageProvider', array(new Reference($id)));
}
}
}
}

View File

@@ -0,0 +1,35 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class AddValidatorInitializersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('validator.builder')) {
return;
}
$validatorBuilder = $container->getDefinition('validator.builder');
$initializers = array();
foreach ($container->findTaggedServiceIds('validator.initializer') as $id => $attributes) {
$initializers[] = new Reference($id);
}
$validatorBuilder->addMethodCall('addObjectInitializers', array($initializers));
}
}

View File

@@ -0,0 +1,41 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
class CompilerDebugDumpPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$filename = self::getCompilerLogFilename($container);
$filesystem = new Filesystem();
$filesystem->dumpFile($filename, implode("\n", $container->getCompiler()->getLog()), null);
try {
$filesystem->chmod($filename, 0666, umask());
} catch (IOException $e) {
// discard chmod failure (some filesystem may not support it)
}
}
public static function getCompilerLogFilename(ContainerInterface $container)
{
$class = $container->getParameter('kernel.container_class');
return $container->getParameter('kernel.cache_dir').'/'.$class.'Compiler.log';
}
}

View File

@@ -0,0 +1,45 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Adds services tagged config_cache.resource_checker to the config_cache_factory service, ordering them by priority.
*
* @author Matthias Pigulla <mp@webfactory.de>
* @author Benjamin Klotz <bk@webfactory.de>
*/
class ConfigCachePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$resourceCheckers = array();
foreach ($container->findTaggedServiceIds('config_cache.resource_checker') as $id => $tags) {
$priority = isset($tags[0]['priority']) ? $tags[0]['priority'] : 0;
$resourceCheckers[$priority][] = new Reference($id);
}
if (empty($resourceCheckers)) {
return;
}
// sort by priority and flatten
krsort($resourceCheckers);
$resourceCheckers = call_user_func_array('array_merge', $resourceCheckers);
$container->getDefinition('config_cache_factory')->replaceArgument(0, $resourceCheckers);
}
}

View File

@@ -0,0 +1,41 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
/**
* Dumps the ContainerBuilder to a cache file so that it can be used by
* debugging tools such as the debug:container console command.
*
* @author Ryan Weaver <ryan@thatsquality.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class ContainerBuilderDebugDumpPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$dumper = new XmlDumper($container);
$filename = $container->getParameter('debug.container.dump');
$filesystem = new Filesystem();
$filesystem->dumpFile($filename, $dumper->dump(), null);
try {
$filesystem->chmod($filename, 0666, umask());
} catch (IOException $e) {
// discard chmod failure (some filesystem may not support it)
}
}
}

View File

@@ -0,0 +1,78 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds all services with the tags "form.type" and "form.type_guesser" as
* arguments of the "form.extension" service.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('form.extension')) {
return;
}
$definition = $container->getDefinition('form.extension');
// Builds an array with fully-qualified type class names as keys and service IDs as values
$types = array();
foreach ($container->findTaggedServiceIds('form.type') as $serviceId => $tag) {
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as form types are lazy-loaded.', $serviceId));
}
// Support type access by FQCN
$types[$serviceDefinition->getClass()] = $serviceId;
}
$definition->replaceArgument(1, $types);
$typeExtensions = array();
foreach ($container->findTaggedServiceIds('form.type_extension') as $serviceId => $tag) {
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as form type extensions are lazy-loaded.', $serviceId));
}
if (isset($tag[0]['extended_type'])) {
$extendedType = $tag[0]['extended_type'];
} else {
throw new \InvalidArgumentException(sprintf('Tagged form type extension must have the extended type configured using the extended_type/extended-type attribute, none was configured for the "%s" service.', $serviceId));
}
$typeExtensions[$extendedType][] = $serviceId;
}
$definition->replaceArgument(2, $typeExtensions);
// Find all services annotated with "form.type_guesser"
$guessers = array_keys($container->findTaggedServiceIds('form.type_guesser'));
foreach ($guessers as $serviceId) {
$serviceDefinition = $container->getDefinition($serviceId);
if (!$serviceDefinition->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as form type guessers are lazy-loaded.', $serviceId));
}
}
$definition->replaceArgument(3, $guessers);
}
}

View File

@@ -0,0 +1,45 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
*/
class LoggingTranslatorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasAlias('logger') || !$container->hasAlias('translator')) {
return;
}
// skip if the symfony/translation version is lower than 2.6
if (!interface_exists('Symfony\Component\Translation\TranslatorBagInterface')) {
return;
}
if ($container->hasParameter('translator.logging') && $container->getParameter('translator.logging')) {
$translatorAlias = $container->getAlias('translator');
$definition = $container->getDefinition((string) $translatorAlias);
$class = $container->getParameterBag()->resolveValue($definition->getClass());
if (is_subclass_of($class, 'Symfony\Component\Translation\TranslatorInterface') && is_subclass_of($class, 'Symfony\Component\Translation\TranslatorBagInterface')) {
$container->getDefinition('translator.logging')->setDecoratedService('translator');
$container->getDefinition('translation.warmer')->replaceArgument(0, new Reference('translator.logging.inner'));
}
}
}
}

View File

@@ -0,0 +1,57 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds tagged data_collector services to profiler service.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ProfilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition('profiler')) {
return;
}
$definition = $container->getDefinition('profiler');
$collectors = new \SplPriorityQueue();
$order = PHP_INT_MAX;
foreach ($container->findTaggedServiceIds('data_collector') as $id => $attributes) {
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
$template = null;
if (isset($attributes[0]['template'])) {
if (!isset($attributes[0]['id'])) {
throw new \InvalidArgumentException(sprintf('Data collector service "%s" must have an id attribute in order to specify a template', $id));
}
$template = array($attributes[0]['id'], $attributes[0]['template']);
}
$collectors->insert(array($id, $template), array($priority, --$order));
}
$templates = array();
foreach ($collectors as $collector) {
$definition->addMethodCall('add', array(new Reference($collector[0])));
$templates[$collector[0]] = $collector[1];
}
$container->setParameter('data_collector.templates', $templates);
}
}

View File

@@ -0,0 +1,76 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Adds extractors to the property_info service.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class PropertyInfoPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('property_info')) {
return;
}
$listExtractors = $this->findAndSortTaggedServices('property_info.list_extractor', $container);
$container->getDefinition('property_info')->replaceArgument(0, $listExtractors);
$typeExtractors = $this->findAndSortTaggedServices('property_info.type_extractor', $container);
$container->getDefinition('property_info')->replaceArgument(1, $typeExtractors);
$descriptionExtractors = $this->findAndSortTaggedServices('property_info.description_extractor', $container);
$container->getDefinition('property_info')->replaceArgument(2, $descriptionExtractors);
$accessExtractors = $this->findAndSortTaggedServices('property_info.access_extractor', $container);
$container->getDefinition('property_info')->replaceArgument(3, $accessExtractors);
}
/**
* Finds all services with the given tag name and order them by their priority.
*
* @param string $tagName
* @param ContainerBuilder $container
*
* @return array
*/
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
{
$services = $container->findTaggedServiceIds($tagName);
$sortedServices = array();
foreach ($services as $serviceId => $tags) {
foreach ($tags as $attributes) {
$priority = isset($attributes['priority']) ? $attributes['priority'] : 0;
$sortedServices[$priority][] = new Reference($serviceId);
}
}
if (empty($sortedServices)) {
return array();
}
krsort($sortedServices);
// Flatten the array
return call_user_func_array('array_merge', $sortedServices);
}
}

View File

@@ -0,0 +1,37 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds tagged routing.loader services to routing.resolver service.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RoutingResolverPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition('routing.resolver')) {
return;
}
$definition = $container->getDefinition('routing.resolver');
foreach ($container->findTaggedServiceIds('routing.loader') as $id => $attributes) {
$definition->addMethodCall('addLoader', array(new Reference($id)));
}
}
}

View File

@@ -0,0 +1,72 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Adds all services with the tags "serializer.encoder" and "serializer.normalizer" as
* encoders and normalizers to the Serializer service.
*
* @author Javier Lopez <f12loalf@gmail.com>
*/
class SerializerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('serializer')) {
return;
}
// Looks for all the services tagged "serializer.normalizer" and adds them to the Serializer service
$normalizers = $this->findAndSortTaggedServices('serializer.normalizer', $container);
$container->getDefinition('serializer')->replaceArgument(0, $normalizers);
// Looks for all the services tagged "serializer.encoders" and adds them to the Serializer service
$encoders = $this->findAndSortTaggedServices('serializer.encoder', $container);
$container->getDefinition('serializer')->replaceArgument(1, $encoders);
}
/**
* Finds all services with the given tag name and order them by their priority.
*
* @param string $tagName
* @param ContainerBuilder $container
*
* @return array
*
* @throws \RuntimeException
*/
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
{
$services = $container->findTaggedServiceIds($tagName);
if (empty($services)) {
throw new \RuntimeException(sprintf('You must tag at least one service as "%s" to use the Serializer service', $tagName));
}
$sortedServices = array();
foreach ($services as $serviceId => $tags) {
foreach ($tags as $attributes) {
$priority = isset($attributes['priority']) ? $attributes['priority'] : 0;
$sortedServices[$priority][] = new Reference($serviceId);
}
}
krsort($sortedServices);
// Flatten the array
return call_user_func_array('array_merge', $sortedServices);
}
}

View File

@@ -0,0 +1,39 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class TemplatingPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if ($container->hasDefinition('templating')) {
return;
}
if ($container->hasDefinition('templating.engine.php')) {
$helpers = array();
foreach ($container->findTaggedServiceIds('templating.helper') as $id => $attributes) {
if (isset($attributes[0]['alias'])) {
$helpers[$attributes[0]['alias']] = $id;
}
}
if (count($helpers) > 0) {
$definition = $container->getDefinition('templating.engine.php');
$definition->addMethodCall('setHelpers', array($helpers));
}
}
}
}

View File

@@ -0,0 +1,35 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds tagged translation.formatter services to translation writer.
*/
class TranslationDumperPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('translation.writer')) {
return;
}
$definition = $container->getDefinition('translation.writer');
foreach ($container->findTaggedServiceIds('translation.dumper') as $id => $attributes) {
$definition->addMethodCall('addDumper', array($attributes[0]['alias'], new Reference($id)));
}
}
}

View File

@@ -0,0 +1,39 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds tagged translation.extractor services to translation extractor.
*/
class TranslationExtractorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('translation.extractor')) {
return;
}
$definition = $container->getDefinition('translation.extractor');
foreach ($container->findTaggedServiceIds('translation.extractor') as $id => $attributes) {
if (!isset($attributes[0]['alias'])) {
throw new \RuntimeException(sprintf('The alias for the tag "translation.extractor" of service "%s" must be set.', $id));
}
$definition->addMethodCall('addExtractor', array($attributes[0]['alias'], new Reference($id)));
}
}
}

View File

@@ -0,0 +1,45 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class TranslatorPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('translator.default')) {
return;
}
$loaders = array();
foreach ($container->findTaggedServiceIds('translation.loader') as $id => $attributes) {
$loaders[$id][] = $attributes[0]['alias'];
if (isset($attributes[0]['legacy-alias'])) {
$loaders[$id][] = $attributes[0]['legacy-alias'];
}
}
if ($container->hasDefinition('translation.loader')) {
$definition = $container->getDefinition('translation.loader');
foreach ($loaders as $id => $formats) {
foreach ($formats as $format) {
$definition->addMethodCall('addLoader', array($format, new Reference($id)));
}
}
}
$container->findDefinition('translator.default')->replaceArgument(2, $loaders);
}
}

View File

@@ -0,0 +1,87 @@
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Find all service tags which are defined, but not used and yield a warning log message.
*
* @author Florian Pfitzer <pfitzer@wurzel3.de>
*/
class UnusedTagsPass implements CompilerPassInterface
{
private $whitelist = array(
'console.command',
'config_cache.resource_checker',
'data_collector',
'form.type',
'form.type_extension',
'form.type_guesser',
'kernel.cache_clearer',
'kernel.cache_warmer',
'kernel.event_listener',
'kernel.event_subscriber',
'kernel.fragment_renderer',
'monolog.logger',
'routing.expression_language_provider',
'routing.loader',
'security.expression_language_provider',
'security.remember_me_aware',
'security.voter',
'serializer.encoder',
'serializer.normalizer',
'templating.helper',
'translation.dumper',
'translation.extractor',
'translation.loader',
'twig.extension',
'twig.loader',
'validator.constraint_validator',
'validator.initializer',
);
public function process(ContainerBuilder $container)
{
$compiler = $container->getCompiler();
$formatter = $compiler->getLoggingFormatter();
$tags = array_unique(array_merge($container->findTags(), $this->whitelist));
foreach ($container->findUnusedTags() as $tag) {
// skip whitelisted tags
if (in_array($tag, $this->whitelist)) {
continue;
}
// check for typos
$candidates = array();
foreach ($tags as $definedTag) {
if ($definedTag === $tag) {
continue;
}
if (false !== strpos($definedTag, $tag) || levenshtein($tag, $definedTag) <= strlen($tag) / 3) {
$candidates[] = $definedTag;
}
}
$services = array_keys($container->findTaggedServiceIds($tag));
$message = sprintf('Tag "%s" was defined on service(s) "%s", but was never used.', $tag, implode('", "', $services));
if (!empty($candidates)) {
$message .= sprintf(' Did you mean "%s"?', implode('", "', $candidates));
}
$compiler->addLogMessage($formatter->format($this, $message));
}
}
}

View File

@@ -0,0 +1,536 @@
<?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\Bundle\FrameworkBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* FrameworkExtension configuration structure.
*
* @author Jeremy Mikola <jmikola@gmail.com>
*/
class Configuration implements ConfigurationInterface
{
private $debug;
/**
* @param bool $debug Whether debugging is enabled or not
*/
public function __construct($debug)
{
$this->debug = (bool) $debug;
}
/**
* Generates the configuration tree builder.
*
* @return TreeBuilder The tree builder
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('framework');
$rootNode
->beforeNormalization()
->ifTrue(function ($v) { return !isset($v['assets']) && isset($v['templating']); })
->then(function ($v) {
$v['assets'] = array();
return $v;
})
->end()
->children()
->scalarNode('secret')->end()
->scalarNode('http_method_override')
->info("Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. Note: When using the HttpCache, you need to call the method in your front controller instead")
->defaultTrue()
->end()
->arrayNode('trusted_proxies')
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v) && null !== $v; })
->then(function ($v) { return is_bool($v) ? array() : preg_split('/\s*,\s*/', $v); })
->end()
->prototype('scalar')
->validate()
->ifTrue(function ($v) {
if (empty($v)) {
return false;
}
if (false !== strpos($v, '/')) {
if ('0.0.0.0/0' === $v) {
return false;
}
list($v, $mask) = explode('/', $v, 2);
if (strcmp($mask, (int) $mask) || $mask < 1 || $mask > (false !== strpos($v, ':') ? 128 : 32)) {
return true;
}
}
return !filter_var($v, FILTER_VALIDATE_IP);
})
->thenInvalid('Invalid proxy IP "%s"')
->end()
->end()
->end()
->scalarNode('ide')->defaultNull()->end()
->booleanNode('test')->end()
->scalarNode('default_locale')->defaultValue('en')->end()
->arrayNode('trusted_hosts')
->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end()
->prototype('scalar')->end()
->end()
->end()
;
$this->addCsrfSection($rootNode);
$this->addFormSection($rootNode);
$this->addEsiSection($rootNode);
$this->addSsiSection($rootNode);
$this->addFragmentsSection($rootNode);
$this->addProfilerSection($rootNode);
$this->addRouterSection($rootNode);
$this->addSessionSection($rootNode);
$this->addRequestSection($rootNode);
$this->addTemplatingSection($rootNode);
$this->addAssetsSection($rootNode);
$this->addTranslatorSection($rootNode);
$this->addValidationSection($rootNode);
$this->addAnnotationsSection($rootNode);
$this->addSerializerSection($rootNode);
$this->addPropertyAccessSection($rootNode);
$this->addPropertyInfoSection($rootNode);
return $treeBuilder;
}
private function addCsrfSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('csrf_protection')
->canBeEnabled()
->end()
->end()
;
}
private function addFormSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('form')
->info('form configuration')
->canBeEnabled()
->children()
->arrayNode('csrf_protection')
->treatFalseLike(array('enabled' => false))
->treatTrueLike(array('enabled' => true))
->treatNullLike(array('enabled' => true))
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')->defaultNull()->end() // defaults to framework.csrf_protection.enabled
->scalarNode('field_name')->defaultValue('_token')->end()
->end()
->end()
->end()
->end()
->end()
;
}
private function addEsiSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('esi')
->info('esi configuration')
->canBeEnabled()
->end()
->end()
;
}
private function addSsiSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('ssi')
->info('ssi configuration')
->canBeEnabled()
->end()
->end();
}
private function addFragmentsSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('fragments')
->info('fragments configuration')
->canBeEnabled()
->children()
->scalarNode('path')->defaultValue('/_fragment')->end()
->end()
->end()
->end()
;
}
private function addProfilerSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('profiler')
->info('profiler configuration')
->canBeEnabled()
->children()
->booleanNode('collect')->defaultTrue()->end()
->booleanNode('only_exceptions')->defaultFalse()->end()
->booleanNode('only_master_requests')->defaultFalse()->end()
->scalarNode('dsn')->defaultValue('file:%kernel.cache_dir%/profiler')->end()
->arrayNode('matcher')
->canBeUnset()
->performNoDeepMerging()
->fixXmlConfig('ip')
->children()
->scalarNode('path')
->info('use the urldecoded format')
->example('^/path to resource/')
->end()
->scalarNode('service')->end()
->arrayNode('ips')
->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end()
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end()
->end()
;
}
private function addRouterSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('router')
->info('router configuration')
->canBeUnset()
->children()
->scalarNode('resource')->isRequired()->end()
->scalarNode('type')->end()
->scalarNode('http_port')->defaultValue(80)->end()
->scalarNode('https_port')->defaultValue(443)->end()
->scalarNode('strict_requirements')
->info(
"set to true to throw an exception when a parameter does not match the requirements\n".
"set to false to disable exceptions when a parameter does not match the requirements (and return null instead)\n".
"set to null to disable parameter checks against requirements\n".
"'true' is the preferred configuration in development mode, while 'false' or 'null' might be preferred in production"
)
->defaultTrue()
->end()
->end()
->end()
->end()
;
}
private function addSessionSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('session')
->info('session configuration')
->canBeUnset()
->children()
->scalarNode('storage_id')->defaultValue('session.storage.native')->end()
->scalarNode('handler_id')->defaultValue('session.handler.native_file')->end()
->scalarNode('name')->end()
->scalarNode('cookie_lifetime')->end()
->scalarNode('cookie_path')->end()
->scalarNode('cookie_domain')->end()
->booleanNode('cookie_secure')->end()
->booleanNode('cookie_httponly')->defaultTrue()->end()
->booleanNode('use_cookies')->end()
->scalarNode('gc_divisor')->end()
->scalarNode('gc_probability')->defaultValue(1)->end()
->scalarNode('gc_maxlifetime')->end()
->scalarNode('save_path')->defaultValue('%kernel.cache_dir%/sessions')->end()
->integerNode('metadata_update_threshold')
->defaultValue('0')
->info('seconds to wait between 2 session metadata updates, it will also prevent the session handler to write if the session has not changed')
->end()
->end()
->end()
->end()
;
}
private function addRequestSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('request')
->info('request configuration')
->canBeUnset()
->fixXmlConfig('format')
->children()
->arrayNode('formats')
->useAttributeAsKey('name')
->prototype('array')
->beforeNormalization()
->ifTrue(function ($v) { return is_array($v) && isset($v['mime_type']); })
->then(function ($v) { return $v['mime_type']; })
->end()
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end()
;
}
private function addTemplatingSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('templating')
->info('templating configuration')
->canBeUnset()
->children()
->scalarNode('hinclude_default_template')->defaultNull()->end()
->scalarNode('cache')->end()
->arrayNode('form')
->addDefaultsIfNotSet()
->fixXmlConfig('resource')
->children()
->arrayNode('resources')
->addDefaultChildrenIfNoneSet()
->prototype('scalar')->defaultValue('FrameworkBundle:Form')->end()
->validate()
->ifTrue(function ($v) {return !in_array('FrameworkBundle:Form', $v); })
->then(function ($v) {
return array_merge(array('FrameworkBundle:Form'), $v);
})
->end()
->end()
->end()
->end()
->end()
->fixXmlConfig('engine')
->children()
->arrayNode('engines')
->example(array('twig'))
->isRequired()
->requiresAtLeastOneElement()
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->end()
->fixXmlConfig('loader')
->children()
->arrayNode('loaders')
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
;
}
private function addAssetsSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('assets')
->info('assets configuration')
->canBeUnset()
->fixXmlConfig('base_url')
->children()
->scalarNode('version')->defaultNull()->end()
->scalarNode('version_format')->defaultValue('%%s?%%s')->end()
->scalarNode('base_path')->defaultValue('')->end()
->arrayNode('base_urls')
->requiresAtLeastOneElement()
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->end()
->fixXmlConfig('package')
->children()
->arrayNode('packages')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('base_url')
->children()
->scalarNode('version')
->beforeNormalization()
->ifTrue(function ($v) { return '' === $v; })
->then(function ($v) { return; })
->end()
->end()
->scalarNode('version_format')->defaultNull()->end()
->scalarNode('base_path')->defaultValue('')->end()
->arrayNode('base_urls')
->requiresAtLeastOneElement()
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
;
}
private function addTranslatorSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('translator')
->info('translator configuration')
->canBeEnabled()
->fixXmlConfig('fallback')
->fixXmlConfig('path')
->children()
->arrayNode('fallbacks')
->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end()
->prototype('scalar')->end()
->defaultValue(array('en'))
->end()
->booleanNode('logging')->defaultValue($this->debug)->end()
->arrayNode('paths')
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
;
}
private function addValidationSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('validation')
->info('validation configuration')
->canBeEnabled()
->children()
->scalarNode('cache')->end()
->booleanNode('enable_annotations')->defaultFalse()->end()
->arrayNode('static_method')
->defaultValue(array('loadValidatorMetadata'))
->prototype('scalar')->end()
->treatFalseLike(array())
->validate()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return (array) $v; })
->end()
->end()
->scalarNode('translation_domain')->defaultValue('validators')->end()
->booleanNode('strict_email')->defaultFalse()->end()
->end()
->end()
->end()
;
}
private function addAnnotationsSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('annotations')
->info('annotation configuration')
->addDefaultsIfNotSet()
->children()
->scalarNode('cache')->defaultValue('file')->end()
->scalarNode('file_cache_dir')->defaultValue('%kernel.cache_dir%/annotations')->end()
->booleanNode('debug')->defaultValue($this->debug)->end()
->end()
->end()
->end()
;
}
private function addSerializerSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('serializer')
->info('serializer configuration')
->canBeEnabled()
->children()
->booleanNode('enable_annotations')->defaultFalse()->end()
->scalarNode('cache')->end()
->scalarNode('name_converter')->end()
->end()
->end()
->end()
;
}
private function addPropertyAccessSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('property_access')
->addDefaultsIfNotSet()
->info('Property access configuration')
->children()
->booleanNode('magic_call')->defaultFalse()->end()
->booleanNode('throw_exception_on_invalid_index')->defaultFalse()->end()
->end()
->end()
->end()
;
}
private function addPropertyInfoSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('property_info')
->info('Property info configuration')
->canBeEnabled()
->end()
->end()
;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
<?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\Bundle\FrameworkBundle\EventListener;
use Symfony\Component\HttpKernel\EventListener\SessionListener as BaseSessionListener;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Sets the session in the request.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SessionListener extends BaseSessionListener
{
/**
* @var ContainerInterface
*/
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
protected function getSession()
{
if (!$this->container->has('session')) {
return;
}
return $this->container->get('session');
}
}

View File

@@ -0,0 +1,39 @@
<?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\Bundle\FrameworkBundle\EventListener;
use Symfony\Component\HttpKernel\EventListener\TestSessionListener as BaseTestSessionListener;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* TestSessionListener.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TestSessionListener extends BaseTestSessionListener
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
protected function getSession()
{
if (!$this->container->has('session')) {
return;
}
return $this->container->get('session');
}
}

View File

@@ -0,0 +1,98 @@
<?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\Bundle\FrameworkBundle;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\PropertyInfoPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheWarmerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheClearerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddExpressionLanguageProvidersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CompilerDebugDumpPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationExtractorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ConfigCachePass;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* Bundle.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FrameworkBundle extends Bundle
{
public function boot()
{
ErrorHandler::register(null, false)->throwAt($this->container->getParameter('debug.error_handler.throw_at'), true);
if ($trustedProxies = $this->container->getParameter('kernel.trusted_proxies')) {
Request::setTrustedProxies($trustedProxies);
}
if ($this->container->getParameter('kernel.http_method_override')) {
Request::enableHttpMethodParameterOverride();
}
if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
Request::setTrustedHosts($trustedHosts);
}
}
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new RoutingResolverPass());
$container->addCompilerPass(new ProfilerPass());
// must be registered before removing private services as some might be listeners/subscribers
// but as late as possible to get resolved parameters
$container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new TemplatingPass());
$container->addCompilerPass(new AddConstraintValidatorsPass());
$container->addCompilerPass(new AddValidatorInitializersPass());
$container->addCompilerPass(new AddConsoleCommandPass());
$container->addCompilerPass(new FormPass());
$container->addCompilerPass(new TranslatorPass());
$container->addCompilerPass(new LoggingTranslatorPass());
$container->addCompilerPass(new AddCacheWarmerPass());
$container->addCompilerPass(new AddCacheClearerPass());
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
$container->addCompilerPass(new TranslationExtractorPass());
$container->addCompilerPass(new TranslationDumperPass());
$container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new SerializerPass());
$container->addCompilerPass(new PropertyInfoPass());
if ($container->getParameter('kernel.debug')) {
$container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new CompilerDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new ConfigCachePass());
}
}
}

View File

@@ -0,0 +1,82 @@
<?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\Bundle\FrameworkBundle\HttpCache;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\HttpCache\HttpCache as BaseHttpCache;
use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\HttpKernel\HttpCache\Store;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Manages HTTP cache objects in a Container.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class HttpCache extends BaseHttpCache
{
protected $cacheDir;
protected $kernel;
/**
* Constructor.
*
* @param HttpKernelInterface $kernel An HttpKernelInterface instance
* @param string $cacheDir The cache directory (default used if null)
*/
public function __construct(HttpKernelInterface $kernel, $cacheDir = null)
{
$this->kernel = $kernel;
$this->cacheDir = $cacheDir;
parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge(array('debug' => $kernel->isDebug()), $this->getOptions()));
}
/**
* Forwards the Request to the backend and returns the Response.
*
* @param Request $request A Request instance
* @param bool $raw Whether to catch exceptions or not
* @param Response $entry A Response instance (the stale entry if present, null otherwise)
*
* @return Response A Response instance
*/
protected function forward(Request $request, $raw = false, Response $entry = null)
{
$this->getKernel()->boot();
$this->getKernel()->getContainer()->set('cache', $this);
$this->getKernel()->getContainer()->set($this->getSurrogate()->getName(), $this->getSurrogate());
return parent::forward($request, $raw, $entry);
}
/**
* Returns an array of options to customize the Cache configuration.
*
* @return array An array of options
*/
protected function getOptions()
{
return array();
}
protected function createSurrogate()
{
return new Esi();
}
protected function createStore()
{
return new Store($this->cacheDir ?: $this->kernel->getCacheDir().'/http_cache');
}
}

View File

@@ -0,0 +1,87 @@
<?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\Bundle\FrameworkBundle\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Routing\RouteCollectionBuilder;
/**
* A Kernel that provides configuration hooks.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
trait MicroKernelTrait
{
/**
* Add or import routes into your application.
*
* $routes->import('config/routing.yml');
* $routes->add('/admin', 'AppBundle:Admin:dashboard', 'admin_dashboard');
*
* @param RouteCollectionBuilder $routes
*/
abstract protected function configureRoutes(RouteCollectionBuilder $routes);
/**
* Configures the container.
*
* You can register extensions:
*
* $c->loadFromExtension('framework', array(
* 'secret' => '%secret%'
* ));
*
* Or services:
*
* $c->register('halloween', 'FooBundle\HalloweenProvider');
*
* Or parameters:
*
* $c->setParameter('halloween', 'lot of fun');
*
* @param ContainerBuilder $c
* @param LoaderInterface $loader
*/
abstract protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader);
/**
* {@inheritdoc}
*/
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(function (ContainerBuilder $container) use ($loader) {
$container->loadFromExtension('framework', array(
'router' => array(
'resource' => 'kernel:loadRoutes',
'type' => 'service',
),
));
$this->configureContainer($container, $loader);
$container->addObjectResource($this);
});
}
/**
* @internal
*/
public function loadRoutes(LoaderInterface $loader)
{
$routes = new RouteCollectionBuilder($loader);
$this->configureRoutes($routes);
return $routes->build();
}
}

19
vendor/symfony/framework-bundle/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
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.

View File

@@ -0,0 +1,10 @@
FrameworkBundle
===============
Resources
---------
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="annotations.reader" class="Doctrine\Common\Annotations\AnnotationReader" public="false" />
<service id="annotations.cached_reader" class="Doctrine\Common\Annotations\CachedReader" public="false">
<argument type="service" id="annotations.reader" />
<argument /><!-- Cache Implementation -->
<argument /><!-- Debug-Flag -->
</service>
<service id="annotations.filesystem_cache" class="Doctrine\Common\Cache\FilesystemCache" public="false">
<argument /><!-- Cache-Directory -->
</service>
<service id="annotation_reader" alias="annotations.reader" />
</services>
</container>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="assets.packages" class="Symfony\Component\Asset\Packages">
<argument type="service" id="assets.empty_package" /> <!-- default package -->
<argument type="collection" /> <!-- named packages -->
</service>
<service id="assets.empty_package" class="Symfony\Component\Asset\Package" public="false">
<argument type="service" id="assets.empty_version_strategy" />
</service>
<service id="assets.context" class="Symfony\Component\Asset\Context\RequestStackContext">
<argument type="service" id="request_stack" />
</service>
<service id="assets.path_package" class="Symfony\Component\Asset\PathPackage" abstract="true">
<argument /> <!-- base path -->
<argument type="service" /> <!-- version strategy -->
<argument type="service" id="assets.context" />
</service>
<service id="assets.url_package" class="Symfony\Component\Asset\UrlPackage" abstract="true">
<argument /> <!-- base URLs -->
<argument type="service" /> <!-- version strategy -->
<argument type="service" id="assets.context" />
</service>
<service id="assets.static_version_strategy" class="Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy" abstract="true">
<argument /> <!-- version -->
<argument /> <!-- format -->
</service>
<service id="assets.empty_version_strategy" class="Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy" public="false" />
</services>
</container>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="data_collector.config" class="Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector" public="false">
<tag name="data_collector" template="@WebProfiler/Collector/config.html.twig" id="config" priority="-255" />
<call method="setKernel"><argument type="service" id="kernel" on-invalid="ignore" /></call>
</service>
<service id="data_collector.request" class="Symfony\Component\HttpKernel\DataCollector\RequestDataCollector">
<tag name="kernel.event_subscriber" />
<tag name="data_collector" template="@WebProfiler/Collector/request.html.twig" id="request" priority="335" />
</service>
<service id="data_collector.ajax" class="Symfony\Component\HttpKernel\DataCollector\AjaxDataCollector" public="false">
<tag name="data_collector" template="@WebProfiler/Collector/ajax.html.twig" id="ajax" priority="315" />
</service>
<service id="data_collector.exception" class="Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector" public="false">
<tag name="data_collector" template="@WebProfiler/Collector/exception.html.twig" id="exception" priority="305" />
</service>
<service id="data_collector.events" class="Symfony\Component\HttpKernel\DataCollector\EventDataCollector" public="false">
<tag name="data_collector" template="@WebProfiler/Collector/events.html.twig" id="events" priority="290" />
<argument type="service" id="event_dispatcher" on-invalid="ignore" />
</service>
<service id="data_collector.logger" class="Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector" public="false">
<tag name="data_collector" template="@WebProfiler/Collector/logger.html.twig" id="logger" priority="300" />
<tag name="monolog.logger" channel="profiler" />
<argument type="service" id="logger" on-invalid="ignore" />
</service>
<service id="data_collector.time" class="Symfony\Component\HttpKernel\DataCollector\TimeDataCollector" public="false">
<tag name="data_collector" template="@WebProfiler/Collector/time.html.twig" id="time" priority="330" />
<argument type="service" id="kernel" on-invalid="ignore" />
<argument type="service" id="debug.stopwatch" on-invalid="ignore" />
</service>
<service id="data_collector.memory" class="Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector" public="false">
<tag name="data_collector" template="@WebProfiler/Collector/memory.html.twig" id="memory" priority="325" />
</service>
<service id="data_collector.router" class="Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector" >
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController"/>
<tag name="data_collector" template="@WebProfiler/Collector/router.html.twig" id="router" priority="285" />
</service>
</services>
</container>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="debug.container.dump">%kernel.cache_dir%/%kernel.container_class%.xml</parameter>
<parameter key="debug.error_handler.throw_at">-1</parameter>
</parameters>
<services>
<service id="debug.event_dispatcher" class="Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher">
<tag name="monolog.logger" channel="event" />
<argument type="service" id="debug.event_dispatcher.parent" />
<argument type="service" id="debug.stopwatch" />
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="debug.controller_resolver" class="Symfony\Component\HttpKernel\Controller\TraceableControllerResolver">
<argument type="service" id="controller_resolver" />
<argument type="service" id="debug.stopwatch" />
</service>
</services>
</container>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="debug.error_handler.throw_at">0</parameter>
</parameters>
<services>
<service id="debug.debug_handlers_listener" class="Symfony\Component\HttpKernel\EventListener\DebugHandlersListener">
<tag name="kernel.event_subscriber" />
<tag name="monolog.logger" channel="php" />
<argument>null</argument><!-- Exception handler -->
<argument type="service" id="logger" on-invalid="null" />
<argument>null</argument><!-- Log levels map for enabled error levels -->
<argument>null</argument>
<argument>true</argument>
<argument>null</argument><!-- %templating.helper.code.file_link_format% -->
</service>
<service id="debug.stopwatch" class="Symfony\Component\Stopwatch\Stopwatch" />
</services>
</container>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="esi" class="Symfony\Component\HttpKernel\HttpCache\Esi" />
<service id="esi_listener" class="Symfony\Component\HttpKernel\EventListener\SurrogateListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="esi" on-invalid="ignore" />
</service>
</services>
</container>

View File

@@ -0,0 +1,192 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<!-- ResolvedFormTypeFactory -->
<service id="form.resolved_type_factory" class="Symfony\Component\Form\ResolvedFormTypeFactory" />
<!-- FormRegistry -->
<service id="form.registry" class="Symfony\Component\Form\FormRegistry">
<argument type="collection">
<!--
We don't need to be able to add more extensions.
* more types can be registered with the form.type tag
* more type extensions can be registered with the form.type_extension tag
* more type_guessers can be registered with the form.type_guesser tag
-->
<argument type="service" id="form.extension" />
</argument>
<argument type="service" id="form.resolved_type_factory" />
</service>
<!-- FormFactory -->
<service id="form.factory" class="Symfony\Component\Form\FormFactory">
<argument type="service" id="form.registry" />
<argument type="service" id="form.resolved_type_factory" />
</service>
<!-- DependencyInjectionExtension -->
<service id="form.extension" class="Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension" public="false">
<argument type="service" id="service_container" />
<!-- All services with tag "form.type" are inserted here by FormPass -->
<argument type="collection" />
<!-- All services with tag "form.type_extension" are inserted here by FormPass -->
<argument type="collection" />
<!-- All services with tag "form.type_guesser" are inserted here by FormPass -->
<argument type="collection" />
</service>
<!-- ValidatorTypeGuesser -->
<service id="form.type_guesser.validator" class="Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser">
<tag name="form.type_guesser" />
<argument type="service" id="validator.mapping.class_metadata_factory" />
</service>
<!-- CoreExtension -->
<service id="form.property_accessor" alias="property_accessor" public="false" />
<service id="form.choice_list_factory.default" class="Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory" public="false"/>
<service id="form.choice_list_factory.property_access" class="Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator" public="false">
<argument type="service" id="form.choice_list_factory.default"/>
<argument type="service" id="form.property_accessor"/>
</service>
<service id="form.choice_list_factory.cached" class="Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator" public="false">
<argument type="service" id="form.choice_list_factory.property_access"/>
</service>
<service id="form.choice_list_factory" alias="form.choice_list_factory.cached" public="false"/>
<service id="form.type.form" class="Symfony\Component\Form\Extension\Core\Type\FormType">
<argument type="service" id="form.property_accessor" />
<tag name="form.type" />
</service>
<service id="form.type.birthday" class="Symfony\Component\Form\Extension\Core\Type\BirthdayType">
<tag name="form.type" />
</service>
<service id="form.type.checkbox" class="Symfony\Component\Form\Extension\Core\Type\CheckboxType">
<tag name="form.type" />
</service>
<service id="form.type.choice" class="Symfony\Component\Form\Extension\Core\Type\ChoiceType">
<tag name="form.type" />
<argument type="service" id="form.choice_list_factory"/>
</service>
<service id="form.type.collection" class="Symfony\Component\Form\Extension\Core\Type\CollectionType">
<tag name="form.type" />
</service>
<service id="form.type.country" class="Symfony\Component\Form\Extension\Core\Type\CountryType">
<tag name="form.type" />
</service>
<service id="form.type.date" class="Symfony\Component\Form\Extension\Core\Type\DateType">
<tag name="form.type" />
</service>
<service id="form.type.datetime" class="Symfony\Component\Form\Extension\Core\Type\DateTimeType">
<tag name="form.type" />
</service>
<service id="form.type.email" class="Symfony\Component\Form\Extension\Core\Type\EmailType">
<tag name="form.type" />
</service>
<service id="form.type.file" class="Symfony\Component\Form\Extension\Core\Type\FileType">
<tag name="form.type" />
</service>
<service id="form.type.hidden" class="Symfony\Component\Form\Extension\Core\Type\HiddenType">
<tag name="form.type" />
</service>
<service id="form.type.integer" class="Symfony\Component\Form\Extension\Core\Type\IntegerType">
<tag name="form.type" />
</service>
<service id="form.type.language" class="Symfony\Component\Form\Extension\Core\Type\LanguageType">
<tag name="form.type" />
</service>
<service id="form.type.locale" class="Symfony\Component\Form\Extension\Core\Type\LocaleType">
<tag name="form.type" />
</service>
<service id="form.type.money" class="Symfony\Component\Form\Extension\Core\Type\MoneyType">
<tag name="form.type" />
</service>
<service id="form.type.number" class="Symfony\Component\Form\Extension\Core\Type\NumberType">
<tag name="form.type" />
</service>
<service id="form.type.password" class="Symfony\Component\Form\Extension\Core\Type\PasswordType">
<tag name="form.type" />
</service>
<service id="form.type.percent" class="Symfony\Component\Form\Extension\Core\Type\PercentType">
<tag name="form.type" />
</service>
<service id="form.type.radio" class="Symfony\Component\Form\Extension\Core\Type\RadioType">
<tag name="form.type" />
</service>
<service id="form.type.range" class="Symfony\Component\Form\Extension\Core\Type\RangeType">
<tag name="form.type" />
</service>
<service id="form.type.repeated" class="Symfony\Component\Form\Extension\Core\Type\RepeatedType">
<tag name="form.type" />
</service>
<service id="form.type.search" class="Symfony\Component\Form\Extension\Core\Type\SearchType">
<tag name="form.type" />
</service>
<service id="form.type.textarea" class="Symfony\Component\Form\Extension\Core\Type\TextareaType">
<tag name="form.type" />
</service>
<service id="form.type.text" class="Symfony\Component\Form\Extension\Core\Type\TextType">
<tag name="form.type" />
</service>
<service id="form.type.time" class="Symfony\Component\Form\Extension\Core\Type\TimeType">
<tag name="form.type" />
</service>
<service id="form.type.timezone" class="Symfony\Component\Form\Extension\Core\Type\TimezoneType">
<tag name="form.type" />
</service>
<service id="form.type.url" class="Symfony\Component\Form\Extension\Core\Type\UrlType">
<tag name="form.type" />
</service>
<service id="form.type.button" class="Symfony\Component\Form\Extension\Core\Type\ButtonType">
<tag name="form.type" />
</service>
<service id="form.type.submit" class="Symfony\Component\Form\Extension\Core\Type\SubmitType">
<tag name="form.type" />
</service>
<service id="form.type.reset" class="Symfony\Component\Form\Extension\Core\Type\ResetType">
<tag name="form.type" />
</service>
<service id="form.type.currency" class="Symfony\Component\Form\Extension\Core\Type\CurrencyType">
<tag name="form.type" />
</service>
<!-- FormTypeHttpFoundationExtension -->
<service id="form.type_extension.form.http_foundation" class="Symfony\Component\Form\Extension\HttpFoundation\Type\FormTypeHttpFoundationExtension">
<argument type="service" id="form.type_extension.form.request_handler" />
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
</service>
<!-- HttpFoundationRequestHandler -->
<service id="form.type_extension.form.request_handler" class="Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler" public="false">
<argument type="service" id="form.server_params" />
</service>
<service id="form.server_params" class="Symfony\Component\Form\Util\ServerParams" public="false">
<argument type="service" id="request_stack" />
</service>
<!-- FormTypeValidatorExtension -->
<service id="form.type_extension.form.validator" class="Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<argument type="service" id="validator" />
</service>
<service id="form.type_extension.repeated.validator" class="Symfony\Component\Form\Extension\Validator\Type\RepeatedTypeValidatorExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\RepeatedType" />
</service>
<service id="form.type_extension.submit.validator" class="Symfony\Component\Form\Extension\Validator\Type\SubmitTypeValidatorExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\SubmitType" />
</service>
<service id="form.type_extension.upload.validator" class="Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<argument type="service" id="translator"/>
<argument type="string">%validator.translation_domain%</argument>
</service>
</services>
</container>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="form.type_extension.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<argument type="service" id="security.csrf.token_manager" />
<argument>%form.type_extension.csrf.enabled%</argument>
<argument>%form.type_extension.csrf.field_name%</argument>
<argument type="service" id="translator.default" />
<argument>%validator.translation_domain%</argument>
</service>
</services>
</container>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="form.resolved_type_factory" class="Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeFactoryDataCollectorProxy">
<argument type="service">
<service class="Symfony\Component\Form\ResolvedFormTypeFactory" />
</argument>
<argument type="service" id="data_collector.form" />
</service>
<!-- DataCollectorTypeExtension -->
<service id="form.type_extension.form.data_collector" class="Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<argument type="service" id="data_collector.form" />
</service>
<!-- DataCollector -->
<service id="data_collector.form.extractor" class="Symfony\Component\Form\Extension\DataCollector\FormDataExtractor" />
<service id="data_collector.form" class="Symfony\Component\Form\Extension\DataCollector\FormDataCollector">
<tag name="data_collector" template="@WebProfiler/Collector/form.html.twig" id="form" priority="310" />
<argument type="service" id="data_collector.form.extractor" />
</service>
</services>
</container>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="fragment.listener" class="Symfony\Component\HttpKernel\EventListener\FragmentListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="uri_signer" />
<argument>%fragment.path%</argument>
</service>
</services>
</container>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="fragment.renderer.hinclude.global_template"></parameter>
<parameter key="fragment.path">/_fragment</parameter>
</parameters>
<services>
<service id="fragment.handler" class="Symfony\Component\HttpKernel\DependencyInjection\LazyLoadingFragmentHandler">
<argument type="service" id="service_container" />
<argument type="service" id="request_stack" />
<argument>%kernel.debug%</argument>
</service>
<service id="fragment.renderer.inline" class="Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer">
<tag name="kernel.fragment_renderer" alias="inline" />
<argument type="service" id="http_kernel" />
<argument type="service" id="event_dispatcher" />
<call method="setFragmentPath"><argument>%fragment.path%</argument></call>
</service>
<service id="fragment.renderer.hinclude" class="Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer">
<argument /> <!-- templating or Twig service -->
<argument type="service" id="uri_signer" />
<argument>%fragment.renderer.hinclude.global_template%</argument>
<call method="setFragmentPath"><argument>%fragment.path%</argument></call>
</service>
<service id="fragment.renderer.esi" class="Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer">
<tag name="kernel.fragment_renderer" alias="esi" />
<argument type="service" id="esi" on-invalid="null" />
<argument type="service" id="fragment.renderer.inline" />
<argument type="service" id="uri_signer" />
<call method="setFragmentPath"><argument>%fragment.path%</argument></call>
</service>
<service id="fragment.renderer.ssi" class="Symfony\Component\HttpKernel\Fragment\SsiFragmentRenderer">
<tag name="kernel.fragment_renderer" alias="ssi" />
<argument type="service" id="ssi" on-invalid="null" />
<argument type="service" id="fragment.renderer.inline" />
<argument type="service" id="uri_signer" />
<call method="setFragmentPath"><argument>%fragment.path%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="profiler" class="Symfony\Component\HttpKernel\Profiler\Profiler">
<tag name="monolog.logger" channel="profiler" />
<argument type="service" id="profiler.storage" />
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="profiler.storage" class="Symfony\Component\HttpKernel\Profiler\FileProfilerStorage" public="false">
<argument>%profiler.storage.dsn%</argument>
</service>
<service id="profiler_listener" class="Symfony\Component\HttpKernel\EventListener\ProfilerListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="profiler" />
<argument type="service" id="request_stack" />
<argument type="service" id="profiler.request_matcher" on-invalid="null" />
<argument>%profiler_listener.only_exceptions%</argument>
<argument>%profiler_listener.only_master_requests%</argument>
</service>
</services>
</container>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="property_accessor" class="Symfony\Component\PropertyAccess\PropertyAccessor" >
<argument /> <!-- magicCall, set by the extension -->
<argument /> <!-- throwExceptionOnInvalidIndex, set by the extension -->
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="property_info" class="Symfony\Component\PropertyInfo\PropertyInfoExtractor" >
<argument type="collection" />
<argument type="collection" />
<argument type="collection" />
<argument type="collection" />
</service>
<!-- Extractor -->
<service id="property_info.reflection_extractor" class="Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor" public="false">
<tag name="property_info.list_extractor" priority="-1000" />
<tag name="property_info.type_extractor" priority="-1000" />
<tag name="property_info.access_extractor" priority="-1000" />
</service>
</services>
</container>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="request.add_request_formats_listener" class="Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener">
<tag name="kernel.event_subscriber" />
<argument/>
</service>
</services>
</container>

View File

@@ -0,0 +1,42 @@
<?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.
*/
/*
* This file implements rewrite rules for PHP built-in web server.
*
* See: http://www.php.net/manual/en/features.commandline.webserver.php
*
* If you have custom directory layout, then you have to write your own router
* and pass it as a value to 'router' option of server:run command.
*
* @author: Michał Pipa <michal.pipa.xsolve@gmail.com>
* @author: Albert Jessurum <ajessu@gmail.com>
*/
// Workaround https://bugs.php.net/64566
if (ini_get('auto_prepend_file') && !in_array(realpath(ini_get('auto_prepend_file')), get_included_files(), true)) {
require ini_get('auto_prepend_file');
}
if (is_file($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.$_SERVER['SCRIPT_NAME'])) {
return false;
}
$_SERVER = array_merge($_SERVER, $_ENV);
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app_dev.php';
// Since we are rewriting to app_dev.php, adjust SCRIPT_NAME and PHP_SELF accordingly
$_SERVER['SCRIPT_NAME'] = DIRECTORY_SEPARATOR.'app_dev.php';
$_SERVER['PHP_SELF'] = DIRECTORY_SEPARATOR.'app_dev.php';
require 'app_dev.php';
error_log(sprintf('%s:%d [%d]: %s', $_SERVER['REMOTE_ADDR'], $_SERVER['REMOTE_PORT'], http_response_code(), $_SERVER['REQUEST_URI']), 4);

View File

@@ -0,0 +1,42 @@
<?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.
*/
/*
* This file implements rewrite rules for PHP built-in web server.
*
* See: http://www.php.net/manual/en/features.commandline.webserver.php
*
* If you have custom directory layout, then you have to write your own router
* and pass it as a value to 'router' option of server:run command.
*
* @author: Michał Pipa <michal.pipa.xsolve@gmail.com>
* @author: Albert Jessurum <ajessu@gmail.com>
*/
// Workaround https://bugs.php.net/64566
if (ini_get('auto_prepend_file') && !in_array(realpath(ini_get('auto_prepend_file')), get_included_files(), true)) {
require ini_get('auto_prepend_file');
}
if (is_file($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.$_SERVER['SCRIPT_NAME'])) {
return false;
}
$_SERVER = array_merge($_SERVER, $_ENV);
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app.php';
// Since we are rewriting to app.php, adjust SCRIPT_NAME and PHP_SELF accordingly
$_SERVER['SCRIPT_NAME'] = DIRECTORY_SEPARATOR.'app.php';
$_SERVER['PHP_SELF'] = DIRECTORY_SEPARATOR.'app.php';
require 'app.php';
error_log(sprintf('%s:%d [%d]: %s', $_SERVER['REMOTE_ADDR'], $_SERVER['REMOTE_PORT'], http_response_code(), $_SERVER['REQUEST_URI']), 4);

View File

@@ -0,0 +1,31 @@
<?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.
*/
/*
* This file implements rewrite rules for PHP built-in web server.
*
* See: http://www.php.net/manual/en/features.commandline.webserver.php
*
* If you have custom directory layout, then you have to write your own router
* and pass it as a value to 'router' option of server:run command.
*
* @author: Michał Pipa <michal.pipa.xsolve@gmail.com>
* @author: Albert Jessurum <ajessu@gmail.com>
*/
if (is_file($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.$_SERVER['SCRIPT_NAME'])) {
return false;
}
$_SERVER = array_merge($_SERVER, $_ENV);
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app_test.php';
require 'app_test.php';

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="router.options.generator_class">Symfony\Component\Routing\Generator\UrlGenerator</parameter>
<parameter key="router.options.generator_base_class">Symfony\Component\Routing\Generator\UrlGenerator</parameter>
<parameter key="router.options.generator_dumper_class">Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper</parameter>
<parameter key="router.options.matcher_class">Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher</parameter>
<parameter key="router.options.matcher_base_class">Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher</parameter>
<parameter key="router.options.matcher_dumper_class">Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper</parameter>
<parameter key="router.options.matcher.cache_class">%router.cache_class_prefix%UrlMatcher</parameter>
<parameter key="router.options.generator.cache_class">%router.cache_class_prefix%UrlGenerator</parameter>
<parameter key="router.request_context.host">localhost</parameter>
<parameter key="router.request_context.scheme">http</parameter>
<parameter key="router.request_context.base_url"></parameter>
</parameters>
<services>
<service id="routing.resolver" class="Symfony\Component\Config\Loader\LoaderResolver" public="false" />
<service id="routing.loader.xml" class="Symfony\Component\Routing\Loader\XmlFileLoader" public="false">
<tag name="routing.loader" />
<argument type="service" id="file_locator" />
</service>
<service id="routing.loader.yml" class="Symfony\Component\Routing\Loader\YamlFileLoader" public="false">
<tag name="routing.loader" />
<argument type="service" id="file_locator" />
</service>
<service id="routing.loader.php" class="Symfony\Component\Routing\Loader\PhpFileLoader" public="false">
<tag name="routing.loader" />
<argument type="service" id="file_locator" />
</service>
<service id="routing.loader.directory" class="Symfony\Component\Routing\Loader\DirectoryLoader" public="false">
<tag name="routing.loader" />
<argument type="service" id="file_locator" />
</service>
<service id="routing.loader.service" class="Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader" public="false">
<tag name="routing.loader" />
<argument type="service" id="service_container" />
</service>
<service id="routing.loader" class="Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader">
<argument type="service" id="controller_name_converter" />
<argument type="service" id="routing.resolver" />
</service>
<service id="router.default" class="Symfony\Bundle\FrameworkBundle\Routing\Router" public="false">
<tag name="monolog.logger" channel="router" />
<argument type="service" id="service_container" />
<argument>%router.resource%</argument>
<argument type="collection">
<argument key="cache_dir">%kernel.cache_dir%</argument>
<argument key="debug">%kernel.debug%</argument>
<argument key="generator_class">%router.options.generator_class%</argument>
<argument key="generator_base_class">%router.options.generator_base_class%</argument>
<argument key="generator_dumper_class">%router.options.generator_dumper_class%</argument>
<argument key="generator_cache_class">%router.options.generator.cache_class%</argument>
<argument key="matcher_class">%router.options.matcher_class%</argument>
<argument key="matcher_base_class">%router.options.matcher_base_class%</argument>
<argument key="matcher_dumper_class">%router.options.matcher_dumper_class%</argument>
<argument key="matcher_cache_class">%router.options.matcher.cache_class%</argument>
</argument>
<argument type="service" id="router.request_context" on-invalid="ignore" />
<argument type="service" id="logger" on-invalid="ignore" />
<call method="setConfigCacheFactory">
<argument type="service" id="config_cache_factory" />
</call>
</service>
<service id="router" alias="router.default" />
<service id="router.request_context" class="Symfony\Component\Routing\RequestContext" public="false">
<argument>%router.request_context.base_url%</argument>
<argument>GET</argument>
<argument>%router.request_context.host%</argument>
<argument>%router.request_context.scheme%</argument>
<argument>%request_listener.http_port%</argument>
<argument>%request_listener.https_port%</argument>
</service>
<service id="router.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\RouterCacheWarmer" public="false">
<tag name="kernel.cache_warmer" />
<argument type="service" id="router" />
</service>
<service id="router_listener" class="Symfony\Component\HttpKernel\EventListener\RouterListener">
<tag name="kernel.event_subscriber" />
<tag name="monolog.logger" channel="request" />
<argument type="service" id="router" />
<argument type="service" id="request_stack" />
<argument type="service" id="router.request_context" on-invalid="ignore" />
<argument type="service" id="logger" on-invalid="ignore" />
</service>
</services>
</container>

View File

@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://symfony.com/schema/dic/symfony"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://symfony.com/schema/dic/symfony"
elementFormDefault="qualified">
<xsd:element name="config" type="config" />
<xsd:complexType name="config">
<xsd:all>
<xsd:element name="assets" type="assets" minOccurs="0" maxOccurs="1" />
<xsd:element name="form" type="form" minOccurs="0" maxOccurs="1" />
<xsd:element name="csrf-protection" type="csrf_protection" minOccurs="0" maxOccurs="1" />
<xsd:element name="esi" type="esi" minOccurs="0" maxOccurs="1" />
<xsd:element name="fragments" type="fragments" minOccurs="0" maxOccurs="1" />
<xsd:element name="profiler" type="profiler" minOccurs="0" maxOccurs="1" />
<xsd:element name="router" type="router" minOccurs="0" maxOccurs="1" />
<xsd:element name="session" type="session" minOccurs="0" maxOccurs="1" />
<xsd:element name="request" type="request" minOccurs="0" maxOccurs="1" />
<xsd:element name="templating" type="templating" minOccurs="0" maxOccurs="1" />
<xsd:element name="translator" type="translator" minOccurs="0" maxOccurs="1" />
<xsd:element name="validation" type="validation" minOccurs="0" maxOccurs="1" />
<xsd:element name="annotations" type="annotations" minOccurs="0" maxOccurs="1" />
<xsd:element name="property-access" type="property_access" minOccurs="0" maxOccurs="1" />
<xsd:element name="serializer" type="serializer" minOccurs="0" maxOccurs="1" />
<xsd:element name="property-info" type="property_info" minOccurs="0" maxOccurs="1" />
</xsd:all>
<xsd:attribute name="http-method-override" type="xsd:boolean" />
<xsd:attribute name="trusted-proxies" type="xsd:string" />
<xsd:attribute name="ide" type="xsd:string" />
<xsd:attribute name="secret" type="xsd:string" />
<xsd:attribute name="default-locale" type="xsd:string" />
<xsd:attribute name="test" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="form">
<xsd:all>
<xsd:element name="csrf-protection" type="form_csrf_protection" minOccurs="0" maxOccurs="1" />
</xsd:all>
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="form_csrf_protection">
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="field-name" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="csrf_protection">
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="esi">
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="fragments">
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="path" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="profiler">
<xsd:all>
<xsd:element name="matcher" type="profiler_matcher" minOccurs="0" maxOccurs="1" />
</xsd:all>
<xsd:attribute name="collect" type="xsd:string" />
<xsd:attribute name="only-exceptions" type="xsd:string" />
<xsd:attribute name="only-master-requests" type="xsd:string" />
<xsd:attribute name="enabled" type="xsd:string" />
<xsd:attribute name="dsn" type="xsd:string" />
<xsd:attribute name="username" type="xsd:string" />
<xsd:attribute name="password" type="xsd:string" />
<xsd:attribute name="lifetime" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="profiler_matcher">
<xsd:attribute name="ip" type="xsd:string" />
<xsd:attribute name="path" type="xsd:string" />
<xsd:attribute name="service" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="router">
<xsd:attribute name="resource" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="http-port" type="xsd:string" />
<xsd:attribute name="https-port" type="xsd:string" />
<xsd:attribute name="strict-requirements" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="session">
<xsd:attribute name="storage-id" type="xsd:string" />
<xsd:attribute name="handler-id" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="cookie-lifetime" type="xsd:string" />
<xsd:attribute name="cookie-path" type="xsd:string" />
<xsd:attribute name="cookie-domain" type="xsd:string" />
<xsd:attribute name="cookie-secure" type="xsd:boolean" />
<xsd:attribute name="cookie-httponly" type="xsd:boolean" />
<xsd:attribute name="use-cookies" type="xsd:boolean" />
<xsd:attribute name="cache-limiter" type="xsd:string" />
<xsd:attribute name="gc-maxlifetime" type="xsd:string" />
<xsd:attribute name="gc-divisor" type="xsd:string" />
<xsd:attribute name="gc-probability" type="xsd:string" />
<xsd:attribute name="save-path" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="request">
<xsd:sequence>
<xsd:element name="format" type="format" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="format">
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="mime-type" type="xsd:string" />
</xsd:choice>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="assets">
<xsd:sequence>
<xsd:element name="base-url" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="package" type="package" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="base-path" type="xsd:string" />
<xsd:attribute name="version" type="xsd:string" />
<xsd:attribute name="version-format" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="package">
<xsd:sequence>
<xsd:element name="base-url" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="base-path" type="xsd:string" />
<xsd:attribute name="version" type="xsd:string" />
<xsd:attribute name="version-format" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="templating">
<xsd:sequence>
<xsd:element name="loader" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="engine" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="form" type="form-resources" minOccurs="0" maxOccurs="1" />
</xsd:sequence>
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="hinclude-default-template" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="form-resources">
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="resource" type="xsd:string" />
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="translator">
<xsd:sequence>
<xsd:element name="fallback" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="path" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="fallback" type="xsd:string" />
<xsd:attribute name="logging" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="validation">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="static-method" type="xsd:string" />
</xsd:choice>
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
<xsd:attribute name="static-method" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="annotations">
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="debug" type="xsd:string" />
<xsd:attribute name="file-cache-dir" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="property_access">
<xsd:attribute name="magic-call" type="xsd:boolean" />
<xsd:attribute name="throw-exception-on-invalid-index" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="serializer">
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
<xsd:attribute name="name-converter" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="property_info">
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="security.csrf.token_generator" class="Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator" public="false" />
<service id="security.csrf.token_storage" class="Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage" public="false">
<argument type="service" id="session" />
</service>
<service id="security.csrf.token_manager" class="Symfony\Component\Security\Csrf\CsrfTokenManager">
<argument type="service" id="security.csrf.token_generator" />
<argument type="service" id="security.csrf.token_storage" />
</service>
</services>
</container>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="serializer.mapping.cache.prefix" />
</parameters>
<services>
<service id="serializer" class="Symfony\Component\Serializer\Serializer">
<argument type="collection" />
<argument type="collection" />
</service>
<service id="serializer.property_accessor" alias="property_accessor" public="false" />
<!-- Normalizer -->
<service id="serializer.normalizer.object" class="Symfony\Component\Serializer\Normalizer\ObjectNormalizer" public="false">
<argument type="service" id="serializer.mapping.class_metadata_factory" />
<argument>null</argument> <!-- name converter -->
<argument type="service" id="serializer.property_accessor" />
<!-- Run after all custom serializers -->
<tag name="serializer.normalizer" priority="-1000" />
</service>
<!-- Loader -->
<service id="serializer.mapping.chain_loader" class="Symfony\Component\Serializer\Mapping\Loader\LoaderChain" public="false">
<argument type="collection" />
</service>
<!-- Class Metadata Factory -->
<service id="serializer.mapping.class_metadata_factory" class="Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory" public="false">
<argument type="service" id="serializer.mapping.chain_loader" />
<argument>null</argument>
</service>
<!-- Cache -->
<service id="serializer.mapping.cache.apc" class="Doctrine\Common\Cache\ApcCache" public="false">
<call method="setNamespace">
<argument>%serializer.mapping.cache.prefix%</argument>
</call>
</service>
<!-- Encoders -->
<service id="serializer.encoder.xml" class="Symfony\Component\Serializer\Encoder\XmlEncoder" public="false">
<tag name="serializer.encoder" />
</service>
<service id="serializer.encoder.json" class="Symfony\Component\Serializer\Encoder\JsonEncoder" public="false">
<tag name="serializer.encoder" />
</service>
<!-- Name converter -->
<service id="serializer.name_converter.camel_case_to_snake_case" class="Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter" public="false" />
</services>
</container>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="event_dispatcher" class="Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher">
<argument type="service" id="service_container" />
</service>
<service id="http_kernel" class="Symfony\Component\HttpKernel\HttpKernel">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="controller_resolver" />
<argument type="service" id="request_stack" />
</service>
<service id="request_stack" class="Symfony\Component\HttpFoundation\RequestStack" />
<service id="cache_warmer" class="Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate">
<argument type="collection" />
</service>
<service id="kernel.class_cache.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\ClassCacheCacheWarmer">
<tag name="kernel.cache_warmer" />
</service>
<service id="cache_clearer" class="Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer">
<argument type="collection" />
</service>
<service id="service_container" synthetic="true">
<autowiring-type>Symfony\Component\DependencyInjection\ContainerInterface</autowiring-type>
<autowiring-type>Symfony\Component\DependencyInjection\Container</autowiring-type>
</service>
<service id="kernel" synthetic="true" />
<service id="filesystem" class="Symfony\Component\Filesystem\Filesystem" />
<service id="file_locator" class="Symfony\Component\HttpKernel\Config\FileLocator">
<argument type="service" id="kernel" />
<argument>%kernel.root_dir%/Resources</argument>
</service>
<service id="uri_signer" class="Symfony\Component\HttpKernel\UriSigner">
<argument>%kernel.secret%</argument>
</service>
<service id="config_cache_factory" class="Symfony\Component\Config\ResourceCheckerConfigCacheFactory">
<argument type="collection"></argument>
</service>
<service class="Symfony\Component\Config\Resource\SelfCheckingResourceChecker" public="false">
<tag name="config_cache.resource_checker" priority="-990" />
</service>
</services>
</container>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="session.metadata.storage_key">_sf2_meta</parameter>
</parameters>
<services>
<service id="session" class="Symfony\Component\HttpFoundation\Session\Session">
<argument type="service" id="session.storage" />
<argument type="service" id="session.attribute_bag" />
<argument type="service" id="session.flash_bag" />
</service>
<service id="session.storage.metadata_bag" class="Symfony\Component\HttpFoundation\Session\Storage\MetadataBag" public="false">
<argument>%session.metadata.storage_key%</argument>
<argument>%session.metadata.update_threshold%</argument>
</service>
<service id="session.storage.native" class="Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage">
<argument>%session.storage.options%</argument>
<argument type="service" id="session.handler" />
<argument type="service" id="session.storage.metadata_bag" />
</service>
<service id="session.storage.php_bridge" class="Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage">
<argument type="service" id="session.handler" />
<argument type="service" id="session.storage.metadata_bag" />
</service>
<service id="session.flash_bag" class="Symfony\Component\HttpFoundation\Session\Flash\FlashBag" public="false" />
<service id="session.attribute_bag" class="Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag" public="false" />
<service id="session.storage.mock_file" class="Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage" public="false">
<argument>%kernel.cache_dir%/sessions</argument>
<argument>MOCKSESSID</argument>
<argument type="service" id="session.storage.metadata_bag" />
</service>
<service id="session.handler.native_file" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler" public="false">
<argument>%session.save_path%</argument>
</service>
<service id="session.handler.write_check" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler" public="false" />
<service id="session_listener" class="Symfony\Bundle\FrameworkBundle\EventListener\SessionListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="service_container" />
</service>
<service id="session.save_listener" class="Symfony\Component\HttpKernel\EventListener\SaveSessionListener">
<tag name="kernel.event_subscriber" />
</service>
<!-- for BC -->
<service id="session.storage.filesystem" alias="session.storage.mock_file" />
</services>
</container>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="ssi" class="Symfony\Component\HttpKernel\HttpCache\Ssi" />
<service id="ssi_listener" class="Symfony\Component\HttpKernel\EventListener\SurrogateListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="ssi" on-invalid="ignore" />
</service>
</services>
</container>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="templating.engine.delegating" class="Symfony\Bundle\FrameworkBundle\Templating\DelegatingEngine" public="false">
<argument type="service" id="service_container" />
<argument type="collection" /> <!-- engines -->
</service>
<service id="templating.name_parser" class="Symfony\Bundle\FrameworkBundle\Templating\TemplateNameParser">
<argument type="service" id="kernel" />
</service>
<service id="templating.filename_parser" class="Symfony\Bundle\FrameworkBundle\Templating\TemplateFilenameParser" />
<service id="templating.locator" class="Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator" public="false">
<argument type="service" id="file_locator" />
<argument>%kernel.cache_dir%</argument>
</service>
<service id="templating.finder" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplateFinder" public="false">
<argument type="service" id="kernel" />
<argument type="service" id="templating.filename_parser" />
<argument>%kernel.root_dir%/Resources</argument>
</service>
<service id="templating.cache_warmer.template_paths" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplatePathsCacheWarmer" public="false">
<tag name="kernel.cache_warmer" priority="20" />
<argument type="service" id="templating.finder" />
<argument type="service" id="templating.locator" />
</service>
<service id="templating.loader.filesystem" class="Symfony\Bundle\FrameworkBundle\Templating\Loader\FilesystemLoader" public="false">
<argument type="service" id="templating.locator" />
</service>
<service id="templating.loader.cache" class="Symfony\Component\Templating\Loader\CacheLoader" public="false">
<argument type="service" id="templating.loader.wrapped" />
<argument>%templating.loader.cache.path%</argument>
</service>
<service id="templating.loader.chain" class="Symfony\Component\Templating\Loader\ChainLoader" public="false">
</service>
<service id="templating.loader" alias="templating.loader.filesystem" />
</services>
</container>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="debug.templating.engine.php" class="Symfony\Bundle\FrameworkBundle\Templating\TimedPhpEngine" public="false">
<argument type="service" id="templating.name_parser" />
<argument type="service" id="service_container" />
<argument type="service" id="templating.loader" />
<argument type="service" id="debug.stopwatch" />
<argument type="service" id="templating.globals" />
<call method="setCharset"><argument>%kernel.charset%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="templating.engine.php" class="Symfony\Bundle\FrameworkBundle\Templating\PhpEngine" public="false">
<argument type="service" id="templating.name_parser" />
<argument type="service" id="service_container" />
<argument type="service" id="templating.loader" />
<argument type="service" id="templating.globals" />
<call method="setCharset"><argument>%kernel.charset%</argument></call>
</service>
<service id="templating.helper.slots" class="Symfony\Component\Templating\Helper\SlotsHelper">
<tag name="templating.helper" alias="slots" />
</service>
<service id="templating.helper.request" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\RequestHelper">
<tag name="templating.helper" alias="request" />
<argument type="service" id="request_stack" />
</service>
<service id="templating.helper.session" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\SessionHelper">
<tag name="templating.helper" alias="session" />
<argument type="service" id="request_stack" />
</service>
<service id="templating.helper.router" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\RouterHelper">
<tag name="templating.helper" alias="router" />
<argument type="service" id="router" />
</service>
<service id="templating.helper.assets" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\AssetsHelper">
<tag name="templating.helper" alias="assets" />
<argument /> <!-- packages -->
</service>
<service id="templating.helper.actions" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\ActionsHelper">
<tag name="templating.helper" alias="actions" />
<argument type="service" id="fragment.handler" />
</service>
<service id="templating.helper.code" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\CodeHelper">
<tag name="templating.helper" alias="code" />
<argument>%templating.helper.code.file_link_format%</argument>
<argument>%kernel.root_dir%</argument>
<argument>%kernel.charset%</argument>
</service>
<service id="templating.helper.translator" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\TranslatorHelper">
<tag name="templating.helper" alias="translator" />
<argument type="service" id="translator" />
</service>
<service id="templating.helper.form" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper">
<tag name="templating.helper" alias="form" />
<argument type="service" id="templating.form.renderer" />
</service>
<service id="templating.helper.stopwatch" class="Symfony\Bundle\FrameworkBundle\Templating\Helper\StopwatchHelper">
<tag name="templating.helper" alias="stopwatch" />
<argument type="service" id="debug.stopwatch" on-invalid="ignore" />
</service>
<service id="templating.form.engine" class="Symfony\Component\Form\Extension\Templating\TemplatingRendererEngine" public="false">
<argument type="service" id="templating.engine.php" />
<argument>%templating.helper.form.resources%</argument>
</service>
<service id="templating.form.renderer" class="Symfony\Component\Form\FormRenderer" public="false">
<argument type="service" id="templating.form.engine" />
<argument type="service" id="security.csrf.token_manager" on-invalid="null" />
</service>
<service id="templating.globals" class="Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables">
<argument type="service" id="service_container" />
</service>
</services>
</container>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="test.client.parameters" type="collection"></parameter>
</parameters>
<services>
<service id="test.client" class="Symfony\Bundle\FrameworkBundle\Client" shared="false">
<argument type="service" id="kernel" />
<argument>%test.client.parameters%</argument>
<argument type="service" id="test.client.history" />
<argument type="service" id="test.client.cookiejar" />
</service>
<service id="test.client.history" class="Symfony\Component\BrowserKit\History" shared="false" />
<service id="test.client.cookiejar" class="Symfony\Component\BrowserKit\CookieJar" shared="false" />
<service id="test.session.listener" class="Symfony\Bundle\FrameworkBundle\EventListener\TestSessionListener">
<argument type="service" id="service_container" />
<tag name="kernel.event_subscriber" />
</service>
</services>
</container>

View File

@@ -0,0 +1,135 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="translator.default" class="Symfony\Bundle\FrameworkBundle\Translation\Translator">
<argument type="service" id="service_container" />
<argument type="service" id="translator.selector" />
<argument type="collection" /> <!-- translation loaders -->
<argument type="collection">
<argument key="cache_dir">%kernel.cache_dir%/translations</argument>
<argument key="debug">%kernel.debug%</argument>
</argument>
<argument type="collection" /> <!-- translation resources -->
<call method="setConfigCacheFactory">
<argument type="service" id="config_cache_factory" />
</call>
<autowiring-type>Symfony\Component\Translation\TranslatorInterface</autowiring-type>
</service>
<service id="translator.logging" class="Symfony\Component\Translation\LoggingTranslator" public="false">
<argument type="service" id="translator.logging.inner" />
<argument type="service" id="logger" />
<tag name="monolog.logger" channel="translation" />
</service>
<service id="translator" class="Symfony\Component\Translation\IdentityTranslator">
<argument type="service" id="translator.selector" />
</service>
<service id="translator.selector" class="Symfony\Component\Translation\MessageSelector" public="false" />
<service id="translation.loader.php" class="Symfony\Component\Translation\Loader\PhpFileLoader">
<tag name="translation.loader" alias="php" />
</service>
<service id="translation.loader.yml" class="Symfony\Component\Translation\Loader\YamlFileLoader">
<tag name="translation.loader" alias="yml" />
</service>
<service id="translation.loader.xliff" class="Symfony\Component\Translation\Loader\XliffFileLoader">
<tag name="translation.loader" alias="xlf" legacy-alias="xliff" />
</service>
<service id="translation.loader.po" class="Symfony\Component\Translation\Loader\PoFileLoader">
<tag name="translation.loader" alias="po" />
</service>
<service id="translation.loader.mo" class="Symfony\Component\Translation\Loader\MoFileLoader">
<tag name="translation.loader" alias="mo" />
</service>
<service id="translation.loader.qt" class="Symfony\Component\Translation\Loader\QtFileLoader">
<tag name="translation.loader" alias="ts" />
</service>
<service id="translation.loader.csv" class="Symfony\Component\Translation\Loader\CsvFileLoader">
<tag name="translation.loader" alias="csv" />
</service>
<service id="translation.loader.res" class="Symfony\Component\Translation\Loader\IcuResFileLoader">
<tag name="translation.loader" alias="res" />
</service>
<service id="translation.loader.dat" class="Symfony\Component\Translation\Loader\IcuDatFileLoader">
<tag name="translation.loader" alias="dat" />
</service>
<service id="translation.loader.ini" class="Symfony\Component\Translation\Loader\IniFileLoader">
<tag name="translation.loader" alias="ini" />
</service>
<service id="translation.loader.json" class="Symfony\Component\Translation\Loader\JsonFileLoader">
<tag name="translation.loader" alias="json" />
</service>
<service id="translation.dumper.php" class="Symfony\Component\Translation\Dumper\PhpFileDumper">
<tag name="translation.dumper" alias="php" />
</service>
<service id="translation.dumper.xliff" class="Symfony\Component\Translation\Dumper\XliffFileDumper">
<tag name="translation.dumper" alias="xlf" />
</service>
<service id="translation.dumper.po" class="Symfony\Component\Translation\Dumper\PoFileDumper">
<tag name="translation.dumper" alias="po" />
</service>
<service id="translation.dumper.mo" class="Symfony\Component\Translation\Dumper\MoFileDumper">
<tag name="translation.dumper" alias="mo" />
</service>
<service id="translation.dumper.yml" class="Symfony\Component\Translation\Dumper\YamlFileDumper">
<tag name="translation.dumper" alias="yml" />
</service>
<service id="translation.dumper.qt" class="Symfony\Component\Translation\Dumper\QtFileDumper">
<tag name="translation.dumper" alias="ts" />
</service>
<service id="translation.dumper.csv" class="Symfony\Component\Translation\Dumper\CsvFileDumper">
<tag name="translation.dumper" alias="csv" />
</service>
<service id="translation.dumper.ini" class="Symfony\Component\Translation\Dumper\IniFileDumper">
<tag name="translation.dumper" alias="ini" />
</service>
<service id="translation.dumper.json" class="Symfony\Component\Translation\Dumper\JsonFileDumper">
<tag name="translation.dumper" alias="json" />
</service>
<service id="translation.dumper.res" class="Symfony\Component\Translation\Dumper\IcuResFileDumper">
<tag name="translation.dumper" alias="res" />
</service>
<service id="translation.extractor.php" class="Symfony\Bundle\FrameworkBundle\Translation\PhpExtractor">
<tag name="translation.extractor" alias="php" />
</service>
<service id="translation.loader" class="Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader"/>
<service id="translation.extractor" class="Symfony\Component\Translation\Extractor\ChainExtractor"/>
<service id="translation.writer" class="Symfony\Component\Translation\Writer\TranslationWriter"/>
<service id="translation.warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\TranslationsCacheWarmer" public="false">
<argument type="service" id="translator" />
<tag name="kernel.cache_warmer" />
</service>
</services>
</container>

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