Merge branch '2.8'

* 2.8: (61 commits)
  [Debug] Fix ClassNotFoundFatalErrorHandler candidates lookups
  [2.6][Translator] Extend, refactor and simplify Translator tests.
  [VarDumper] Allow preserving a subset of cut arrays
  [Console] Bind the closure (code) to the Command if possible
  [VarDumper] Added support for SplFileObject
  [VarDumper] Added support for SplFileInfo
  Update DebugClassLoader.php
  inject asset packages in assets helper service
  [travis] Do not exclude legacy tests on 2.7
  [HttpFoundation] remove getExtension method
  [2.6][Translation] fix legacy tests.
  [Form] Removed remaining deprecation notices in the test suite
  [Form] Moved deprecation notice triggers to file level
  [Debug] Map PHP errors to LogLevel::CRITICAL
  [FrameworkBundle][Server Command] add address port number option.
  [Routing][DependencyInjection] Support .yaml extension in YAML loaders
  [DX] improve file loader error for router/other resources in bundle
  [FrameworkBundle] Initialize translator with the default locale.
  [FrameworkBundle] Fix Routing\DelegatingLoader resiliency to fatal errors
  [2.7][Translation] remove duplicate code for loading catalogue.
  ...

Conflicts:
	composer.json
	src/Symfony/Bridge/Swiftmailer/composer.json
	src/Symfony/Component/Console/Helper/DialogHelper.php
	src/Symfony/Component/Debug/ErrorHandler.php
	src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php
	src/Symfony/Component/Form/Extension/HttpFoundation/EventListener/BindRequestListener.php
	src/Symfony/Component/Locale/composer.json
This commit is contained in:
Nicolas Grekas 2015-04-24 09:09:27 +02:00
commit 6b738fd700
170 changed files with 1366 additions and 1345 deletions

View File

@ -1,530 +0,0 @@
UPGRADE FROM 2.6 to 2.7
=======================
Router
------
* Route conditions now support container parameters which
can be injected into condition using `%parameter%` notation.
Due to the fact that it works by replacing all parameters
with their corresponding values before passing condition
expression for compilation there can be BC breaks where you
could already have used percentage symbols. Single percentage symbol
usage is not affected in any way. Conflicts may occur where
you might have used `%` as a modulo operator, here's an example:
`foo%bar%2` which would be compiled to `$foo % $bar % 2` in 2.6
but in 2.7 you would get an error if `bar` parameter
doesn't exist or unexpected result otherwise.
* The `getMatcherDumperInstance()` and `getGeneratorDumperInstance()` methods in the
`Symfony\Component\Routing\Router` have been changed from `protected` to `public`.
If you override these methods in a subclass, you will need to change your
methods to `public` as well. Note however that this is a temporary change needed for
PHP 5.3 compatibility only. It will be reverted in Symfony 3.0.
Form
----
* In form types and extension overriding the "setDefaultOptions" of the
AbstractType or AbstractExtensionType has been deprecated in favor of
overriding the new "configureOptions" method.
The method "setDefaultOptions(OptionsResolverInterface $resolver)" will
be renamed in Symfony 3.0 to "configureOptions(OptionsResolver $resolver)".
Before:
```php
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskType extends AbstractType
{
// ...
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Task',
));
}
}
```
After:
```php
use Symfony\Component\OptionsResolver\OptionsResolver;
class TaskType extends AbstractType
{
// ...
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Task',
));
}
}
```
* The "choice_list" option of ChoiceType was deprecated. You should use
"choices_as_values" or "choice_loader" now.
Before:
```php
$form->add('status', 'choice', array(
'choice_list' => new ObjectChoiceList(array(
Status::getInstance(Status::ENABLED),
Status::getInstance(Status::DISABLED),
Status::getInstance(Status::IGNORED),
)),
));
```
After:
```php
$form->add('status', 'choice', array(
'choices' => array(
Status::getInstance(Status::ENABLED),
Status::getInstance(Status::DISABLED),
Status::getInstance(Status::IGNORED),
),
'choices_as_values' => true,
));
```
* You should flip the keys and values of the "choices" option in ChoiceType
and set the "choices_as_values" option to `true`. The default value of that
option will be switched to `true` in Symfony 3.0.
Before:
```php
$form->add('status', 'choice', array(
'choices' => array(
Status::ENABLED => 'Enabled',
Status::DISABLED => 'Disabled',
Status::IGNORED => 'Ignored',
)),
));
```
After:
```php
$form->add('status', 'choice', array(
'choices' => array(
'Enabled' => Status::ENABLED,
'Disabled' => Status::DISABLED,
'Ignored' => Status::IGNORED,
),
'choices_as_values' => true,
));
```
* `Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface` was
deprecated and will be removed in Symfony 3.0. You should use
`Symfony\Component\Form\ChoiceList\ChoiceListInterface` instead.
Before:
```php
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
public function doSomething(ChoiceListInterface $choiceList)
{
// ...
}
```
After:
```php
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
public function doSomething(ChoiceListInterface $choiceList)
{
// ...
}
```
* `Symfony\Component\Form\Extension\Core\ChoiceList\View\ChoiceView` was
deprecated and will be removed in Symfony 3.0. You should use
`Symfony\Component\Form\ChoiceList\View\ChoiceView` instead.
Note that the order of the arguments passed to the constructor was inverted.
Before:
```php
use Symfony\Component\Form\Extension\Core\ChoiceList\View\ChoiceView;
$view = new ChoiceView($data, 'value', 'Label');
```
After:
```php
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
$view = new ChoiceView('Label', 'value', $data);
```
* `Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList` was
deprecated and will be removed in Symfony 3.0. You should use
`Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory` instead.
Before:
```php
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
$choiceList = new ChoiceList(
array(Status::ENABLED, Status::DISABLED, Status::IGNORED),
array('Enabled', 'Disabled', 'Ignored'),
// Preferred choices
array(Status::ENABLED),
);
```
After:
```php
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
$factory = new DefaultChoiceListFactory();
$choices = array(Status::ENABLED, Status::DISABLED, Status::IGNORED);
$labels = array('Enabled', 'Disabled', 'Ignored');
$choiceList = $factory->createListFromChoices($choices);
$choiceListView = $factory->createView(
$choiceList,
// Preferred choices
array(Status::ENABLED),
// Labels
function ($choice, $key) use ($labels) {
return $labels[$key];
}
);
```
* `Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList` was
deprecated and will be removed in Symfony 3.0. You should use
`Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory::createListFromLoader()`
together with an implementation of
`Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface` instead.
Before:
```php
use Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList;
class MyLazyChoiceList extends LazyChoiceList
{
public function loadChoiceList()
{
// load $choiceList
return $choiceList;
}
}
$choiceList = new MyLazyChoiceList();
```
After:
```php
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
class MyChoiceLoader implements ChoiceLoaderInterface
{
// ...
}
$factory = new DefaultChoiceListFactory();
$choiceList = $factory->createListFromLoader(new MyChoiceLoader());
```
* `Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList` was
deprecated and will be removed in Symfony 3.0. You should use
`Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory` instead.
Before:
```php
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
$choiceList = new ObjectChoiceList(
array(Status::getInstance(Status::ENABLED), Status::getInstance(Status::DISABLED)),
// Label property
'name'
);
```
After:
```php
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
$factory = new DefaultChoiceListFactory();
$choiceList = $factory->createListFromChoices(array(
Status::getInstance(Status::ENABLED),
Status::getInstance(Status::DISABLED),
));
$choiceListView = $factory->createView(
$choiceList,
// Preferred choices
array(),
// Label property
'name'
);
```
* `Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList` was
deprecated and will be removed in Symfony 3.0. You should use
`Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory` instead.
Before:
```php
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
$choiceList = new SimpleChoiceList(array(
Status::ENABLED => 'Enabled',
Status::DISABLED => 'Disabled',
));
```
After:
```php
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
$factory = new DefaultChoiceListFactory();
$choices = array(Status::ENABLED, Status::DISABLED);
$labels = array('Enabled', 'Disabled');
$choiceList = $factory->createListFromChoices($choices);
$choiceListView = $factory->createView(
$choiceList,
// Preferred choices
array(),
// Label
function ($choice, $key) use ($labels) {
return $labels[$key];
}
);
```
* The "property" option of `DoctrineType` was deprecated. You should use the
new inherited option "choice_label" instead, which has the same effect.
Before:
```php
$form->add('tags', 'entity', array(
'class' => 'Acme\Entity\MyTag',
'property' => 'name',
))
```
After:
```php
$form->add('tags', 'entity', array(
'class' => 'Acme\Entity\MyTag',
'choice_label' => 'name',
))
```
* The "loader" option of `DoctrineType` was deprecated and will be removed in
Symfony 3.0. You should override the `getLoader()` method instead in a custom
type.
Before:
```php
$form->add('tags', 'entity', array(
'class' => 'Acme\Entity\MyTag',
'loader' => new MyEntityLoader(),
))
```
After:
```php
class MyEntityType extends DoctrineType
{
// ...
public function getLoader()
{
return new MyEntityLoader();
}
}
```
* `Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList` was
deprecated and will be removed in Symfony 3.0. You should use
`Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader` instead.
Before:
```php
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
$choiceList = new EntityChoiceList($em, 'Acme\Entity\MyEntity');
```
After:
```php
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
$factory = new DefaultChoiceListFactory();
$choices = array(Status::ENABLED, Status::DISABLED);
$labels = array('Enabled', 'Disabled');
$choiceLoader = new DoctrineChoiceLoader($factory, $em, 'Acme\Entity\MyEntity');
$choiceList = $factory->createListFromLoader($choiceLoader);
```
* Passing a query builder closure to `ORMQueryBuilderLoader` was deprecated and
will not be supported anymore in Symfony 3.0. You should pass resolved query
builders only.
Consequently, the arguments `$manager` and `$class` of `ORMQueryBuilderLoader`
have been deprecated as well.
Note that the "query_builder" option of `DoctrineType` *does* support
closures, but the closure is now resolved in the type instead of in the
loader.
Before:
```php
use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader;
$queryBuilder = function () {
// return QueryBuilder
};
$loader = new ORMQueryBuilderLoader($queryBuilder);
```
After:
```php
use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader;
// create $queryBuilder
$loader = new ORMQueryBuilderLoader($queryBuilder);
```
* The classes `ChoiceToBooleanArrayTransformer`,
`ChoicesToBooleanArrayTransformer`, `FixRadioInputListener` and
`FixCheckboxInputListener` were deprecated and will be removed in Symfony 3.0.
Their functionality is covered by the new classes `RadioListMapper` and
`CheckboxListMapper`.
* The ability to translate Doctrine type entries by the translator component
is now disabled by default and to enable it you must explicitly set the option
"choice_translation_domain" to true
Before:
```php
$form->add('products', 'entity', array(
'class' => 'AppBundle/Entity/Product',
));
```
After:
```php
$form->add('products', 'entity', array(
'class' => 'AppBundle/Entity/Product',
'choice_translation_domain' => true,
));
```
* In the block `choice_widget_options` the `translation_domain` has been replaced
with the `choice_translation_domain` option.
Before:
```jinja
{{ choice.label|trans({}, translation_domain) }}
```
After:
```jinja
{{ choice_translation_domain is sameas(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}
```
Serializer
----------
* The `setCamelizedAttributes()` method of the
`Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer` and
`Symfony\Component\Serializer\Normalizer\PropertyNormalizer` classes is marked
as deprecated in favor of the new NameConverter system.
Before:
```php
$normalizer->setCamelizedAttributes(array('foo_bar', 'bar_foo'));
```
After:
```php
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
$nameConverter = new CamelCaseToSnakeCaseNameConverter(array('fooBar', 'barFoo'));
$normalizer = new GetSetMethodNormalizer(null, $nameConverter);
```
* `Symfony\Component\Serializer\Exception\ExceptionInterface` is the new name for the now
deprecated `Symfony\Component\Serializer\Exception\Exception` interface.
PropertyAccess
--------------
* `UnexpectedTypeException` now expects three constructor arguments: The invalid property value,
the `PropertyPathInterface` object and the current index of the property path.
Before:
```php
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
new UnexpectedTypeException($value, $expectedType);
```
After:
```php
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
new UnexpectedTypeException($value, $path, $pathIndex);
```
Config
------
* The `__toString()` method of the `\Symfony\Component\Config\ConfigCache` is marked as
deprecated in favor of the new `getPath()` method.

View File

@ -72,19 +72,18 @@
"doctrine/orm": "~2.2,>=2.2.3",
"doctrine/doctrine-bundle": "~1.2",
"monolog/monolog": "~1.11",
"propel/propel1": "~1.6",
"ocramius/proxy-manager": "~0.4|~1.0",
"egulias/email-validator": "~1.2"
},
"autoload": {
"psr-0": {
"Symfony\\Bridge\\Doctrine\\": "src/",
"Symfony\\Bridge\\Monolog\\": "src/",
"Symfony\\Bridge\\ProxyManager\\": "src/",
"Symfony\\Bridge\\Swiftmailer\\": "src/",
"Symfony\\Bridge\\Twig\\": "src/",
"Symfony\\Bundle\\": "src/",
"Symfony\\Component\\": "src/"
"psr-4": {
"Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/",
"Symfony\\Bridge\\Monolog\\": "src/Symfony/Bridge/Monolog/",
"Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/",
"Symfony\\Bridge\\Swiftmailer\\": "src/Symfony/Bridge/Swiftmailer/",
"Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/",
"Symfony\\Bundle\\": "src/Symfony/Bundle/",
"Symfony\\Component\\": "src/Symfony/Component/"
},
"classmap": [
"src/Symfony/Component/HttpFoundation/Resources/stubs",

View File

@ -11,6 +11,8 @@
namespace Symfony\Bridge\Doctrine\Form\ChoiceList;
trigger_error('The '.__NAMESPACE__.'\EntityChoiceList class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader instead.', E_USER_DEPRECATED);
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\Exception\RuntimeException;
@ -129,8 +131,6 @@ class EntityChoiceList extends ObjectChoiceList
}
parent::__construct($entities, $labelPath, $preferredEntities, $groupPath, null, $propertyAccessor);
trigger_error('The '.__CLASS__.' class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader instead.', E_USER_DEPRECATED);
}
/**

View File

@ -42,9 +42,8 @@
"doctrine/orm": ""
},
"autoload": {
"psr-0": { "Symfony\\Bridge\\Doctrine\\": "" }
"psr-4": { "Symfony\\Bridge\\Doctrine\\": "" }
},
"target-dir": "Symfony/Bridge/Doctrine",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -31,9 +31,8 @@
"symfony/event-dispatcher": "Needed when using log messages in console commands."
},
"autoload": {
"psr-0": { "Symfony\\Bridge\\Monolog\\": "" }
"psr-4": { "Symfony\\Bridge\\Monolog\\": "" }
},
"target-dir": "Symfony/Bridge/Monolog",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -23,9 +23,8 @@
},
"autoload": {
"files": [ "bootstrap.php" ],
"psr-0": { "Symfony\\Bridge\\PhpUnit\\": "" }
"psr-4": { "Symfony\\Bridge\\PhpUnit\\": "" }
},
"target-dir": "Symfony/Bridge/PhpUnit",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -25,11 +25,8 @@
"symfony/config": "~2.8|~3.0"
},
"autoload": {
"psr-0": {
"Symfony\\Bridge\\ProxyManager\\": ""
}
"psr-4": { "Symfony\\Bridge\\ProxyManager\\": "" }
},
"target-dir": "Symfony/Bridge/ProxyManager",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -58,7 +58,7 @@ class CodeExtension extends \Twig_Extension
$parts = explode('\\', $class);
$short = array_pop($parts);
return sprintf("<abbr title=\"%s\">%s</abbr>", $class, $short);
return sprintf('<abbr title="%s">%s</abbr>', $class, $short);
}
public function abbrMethod($method)
@ -67,9 +67,9 @@ class CodeExtension extends \Twig_Extension
list($class, $method) = explode('::', $method, 2);
$result = sprintf('%s::%s()', $this->abbrClass($class), $method);
} elseif ('Closure' === $method) {
$result = sprintf("<abbr title=\"%s\">%s</abbr>", $method, $method);
$result = sprintf('<abbr title="%s">%s</abbr>', $method, $method);
} else {
$result = sprintf("<abbr title=\"%s\">%s</abbr>()", $method, $method);
$result = sprintf('<abbr title="%s">%s</abbr>()', $method, $method);
}
return $result;
@ -89,7 +89,7 @@ class CodeExtension extends \Twig_Extension
if ('object' === $item[0]) {
$parts = explode('\\', $item[1]);
$short = array_pop($parts);
$formattedValue = sprintf("<em>object</em>(<abbr title=\"%s\">%s</abbr>)", $item[1], $short);
$formattedValue = sprintf('<em>object</em>(<abbr title="%s">%s</abbr>)', $item[1], $short);
} elseif ('array' === $item[0]) {
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
} elseif ('string' === $item[0]) {

View File

@ -12,7 +12,7 @@
namespace Symfony\Bridge\Twig\Node;
/**
* Compiles a call to {@link FormRendererInterface::renderBlock()}.
* Compiles a call to {@link \Symfony\Component\Form\FormRendererInterface::renderBlock()}.
*
* The function name is used as block name. For example, if the function name
* is "foo", the block "foo" will be rendered.

View File

@ -51,9 +51,8 @@
"symfony/expression-language": "For using the ExpressionExtension"
},
"autoload": {
"psr-0": { "Symfony\\Bridge\\Twig\\": "" }
"psr-4": { "Symfony\\Bridge\\Twig\\": "" }
},
"target-dir": "Symfony/Bridge/Twig",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Registers the file link format for the {@link DumpDataCollector}.
* Registers the file link format for the {@link \Symfony\Component\HttpKernel\DataCollector\DumpDataCollector\DumpDataCollector}.
*
* @author Christian Flothmann <christian.flothmann@xabbuh.de>
*/

View File

@ -31,9 +31,8 @@
"symfony/dependency-injection": "For using as a service from the container"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\DebugBundle\\": "" }
"psr-4": { "Symfony\\Bundle\\DebugBundle\\": "" }
},
"target-dir": "Symfony/Bundle/DebugBundle",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
@ -28,14 +29,23 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand
{
$output->writeln('Available registered bundles with their extension alias if available:');
$table = $this->getHelperSet()->get('table');
if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table = new Table($output);
} else {
$table = $this->getHelperSet()->get('table');
}
$table->setHeaders(array('Bundle name', 'Extension alias'));
foreach ($this->getContainer()->get('kernel')->getBundles() as $bundle) {
$extension = $bundle->getContainerExtension();
$table->addRow(array($bundle->getName(), $extension ? $extension->getAlias() : ''));
}
$table->render($output);
if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table->render();
} else {
$table->render($output);
}
}
protected function findExtension($name)

View File

@ -44,7 +44,8 @@ class ServerRunCommand extends ContainerAwareCommand
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'),
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'),
))
@ -101,10 +102,15 @@ EOF
$output->writeln('<error>Running PHP built-in server in production environment is NOT recommended!</error>');
}
$output->writeln(sprintf("Server running on <info>http://%s</info>\n", $input->getArgument('address')));
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$address = $address.':'.$input->getOption('port');
}
$output->writeln(sprintf("Server running on <info>http://%s</info>\n", $address));
$output->writeln('Quit the server with CONTROL-C.');
if (null === $builder = $this->createPhpProcessBuilder($input, $output, $env)) {
if (null === $builder = $this->createPhpProcessBuilder($input, $output, $env, $address)) {
return 1;
}
@ -131,7 +137,7 @@ EOF
return $process->getExitCode();
}
private function createPhpProcessBuilder(InputInterface $input, OutputInterface $output, $env)
private function createPhpProcessBuilder(InputInterface $input, OutputInterface $output, $env, $address)
{
$router = $input->getOption('router') ?: $this
->getContainer()
@ -154,6 +160,6 @@ EOF
return;
}
return new ProcessBuilder(array($binary, '-S', $input->getArgument('address'), $router));
return new ProcessBuilder(array($binary, '-S', $address, $router));
}
}

View File

@ -33,7 +33,8 @@ class ServerStartCommand extends ServerCommand
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'),
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'),
))
@ -98,12 +99,15 @@ EOF
}
$env = $this->getContainer()->getParameter('kernel.environment');
if (false === $router = $this->determineRouterScript($input->getOption('router'), $env, $output)) {
return 1;
}
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$output->writeln('The address has to be of the form <comment>bind-address:port</comment>.');
return 1;
$address = $address.':'.$input->getOption('port');
}
if ($this->isOtherServerProcessRunning($address)) {
@ -136,7 +140,7 @@ EOF
return 1;
}
if (null === $process = $this->createServerProcess($output, $address, $documentRoot, $input->getOption('router'), $env, null)) {
if (null === $process = $this->createServerProcess($output, $address, $documentRoot, $router)) {
return 1;
}
@ -183,6 +187,35 @@ EOF
return false;
}
/**
* 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 OutputInterface $output An OutputInterface instance
*
* @return string|bool The absolute file path of the router script, or false on failure
*/
private function determineRouterScript($router, $env, OutputInterface $output)
{
if (null === $router) {
$router = $this
->getContainer()
->get('kernel')
->locateResource(sprintf('@FrameworkBundle/Resources/config/router_%s.php', $env))
;
}
if (false === $path = realpath($router)) {
$output->writeln(sprintf('<error>The given router script "%s" does not exist</error>', $router));
return false;
}
return $path;
}
/**
* Creates a process to start PHP's built-in web server.
*
@ -190,19 +223,11 @@ EOF
* @param string $address IP address and port to listen to
* @param string $documentRoot The application's document root
* @param string $router The router filename
* @param string $env The application environment
* @param int $timeout Process timeout
*
* @return Process The process
*/
private function createServerProcess(OutputInterface $output, $address, $documentRoot, $router, $env, $timeout = null)
private function createServerProcess(OutputInterface $output, $address, $documentRoot, $router)
{
$router = $router ?: $this
->getContainer()
->get('kernel')
->locateResource(sprintf('@FrameworkBundle/Resources/config/router_%s.php', $env))
;
$finder = new PhpExecutableFinder();
if (false === $binary = $finder->find()) {
$output->writeln('<error>Unable to find PHP binary to start server</error>');
@ -217,6 +242,6 @@ EOF
$router,
)));
return new Process('exec '.$script, $documentRoot, null, null, $timeout);
return new Process('exec '.$script, $documentRoot, null, null, null);
}
}

View File

@ -14,6 +14,7 @@ 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;
/**
* Stops a background process running PHP's built-in web server.
@ -29,7 +30,8 @@ class ServerStopCommand extends ServerCommand
{
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'),
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')
@ -53,6 +55,10 @@ EOF
protected function execute(InputInterface $input, OutputInterface $output)
{
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$address = $address.':'.$input->getOption('port');
}
$lockFile = $this->getLockFile($address);
if (!file_exists($lockFile)) {

View File

@ -154,8 +154,11 @@ EOF
}
}
/** @var \Symfony\Component\Console\Helper\Table $table */
$table = new Table($output);
if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table = new Table($output);
} else {
$table = $this->getHelperSet()->get('table');
}
// Display header line
$headers = array('State(s)', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale));
@ -200,7 +203,11 @@ EOF
}
}
$table->render();
if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table->render();
} else {
$table->render($output);
}
$output->writeln('');
$output->writeln('<info>Legend:</info>');

View File

@ -558,6 +558,12 @@ class FrameworkExtension extends Extension
'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\FilesystemLoader',
));
}
if ($container->hasDefinition('assets.packages')) {
$container->getDefinition('templating.helper.assets')->replaceArgument(0, new Reference('assets.packages'));
} else {
$container->removeDefinition('templating.helper.assets');
}
}
/**

View File

@ -21,6 +21,11 @@
* @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;
}

View File

@ -21,6 +21,11 @@
* @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;
}

View File

@ -12,10 +12,10 @@
namespace Symfony\Bundle\FrameworkBundle\Routing;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
use Symfony\Component\Config\Loader\DelegatingLoader as BaseDelegatingLoader;
use Symfony\Component\Config\Loader\LoaderResolverInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\RouteCollection;
/**
* DelegatingLoader delegates route loading to other loaders using a loader resolver.
@ -29,6 +29,7 @@ class DelegatingLoader extends BaseDelegatingLoader
{
protected $parser;
protected $logger;
private $loading = false;
/**
* Constructor.
@ -46,16 +47,39 @@ class DelegatingLoader extends BaseDelegatingLoader
}
/**
* Loads a resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return RouteCollection A RouteCollection instance
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
$collection = parent::load($resource, $type);
if ($this->loading) {
// This can happen if a fatal error occurs in parent::load().
// Here is the scenario:
// - while routes are being loaded by parent::load() below, a fatal error
// occurs (e.g. parse error in a controller while loading annotations);
// - PHP abruptly empties the stack trace, bypassing all catch blocks;
// it then calls the registered shutdown functions;
// - the ErrorHandler catches the fatal error and re-injects it for rendering
// thanks to HttpKernel->terminateWithException() (that calls handleException());
// - at this stage, if we try to load the routes again, we must prevent
// the fatal error from occurring a second time,
// otherwise the PHP process would be killed immediately;
// - while rendering the exception page, the router can be required
// (by e.g. the web profiler that needs to generate an URL);
// - this handles the case and prevents the second fatal error
// by triggering an exception beforehand.
throw new FileLoaderLoadException($resource);
}
$this->loading = true;
try {
$collection = parent::load($resource, $type);
} catch (\Exception $e) {
$this->loading = false;
throw $e;
}
$this->loading = false;
foreach ($collection->all() as $route) {
if ($controller = $route->getDefault('_controller')) {

View File

@ -55,7 +55,7 @@ class CodeHelper extends Helper
$parts = explode('\\', $class);
$short = array_pop($parts);
return sprintf("<abbr title=\"%s\">%s</abbr>", $class, $short);
return sprintf('<abbr title="%s">%s</abbr>', $class, $short);
}
public function abbrMethod($method)
@ -64,9 +64,9 @@ class CodeHelper extends Helper
list($class, $method) = explode('::', $method, 2);
$result = sprintf('%s::%s()', $this->abbrClass($class), $method);
} elseif ('Closure' === $method) {
$result = sprintf("<abbr title=\"%s\">%s</abbr>", $method, $method);
$result = sprintf('<abbr title="%s">%s</abbr>', $method, $method);
} else {
$result = sprintf("<abbr title=\"%s\">%s</abbr>()", $method, $method);
$result = sprintf('<abbr title="%s">%s</abbr>()', $method, $method);
}
return $result;
@ -86,7 +86,7 @@ class CodeHelper extends Helper
if ('object' === $item[0]) {
$parts = explode('\\', $item[1]);
$short = array_pop($parts);
$formattedValue = sprintf("<em>object</em>(<abbr title=\"%s\">%s</abbr>)", $item[1], $short);
$formattedValue = sprintf('<em>object</em>(<abbr title="%s">%s</abbr>)', $item[1], $short);
} elseif ('array' === $item[0]) {
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
} elseif ('string' === $item[0]) {

View File

@ -0,0 +1,7 @@
<?php
$container->loadFromExtension('framework', array(
'templating' => array(
'engines' => array('php', 'twig'),
),
));

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"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config>
<framework:templating>
<framework:engine>php</framework:engine>
<framework:engine>twig</framework:engine>
</framework:templating>
</framework:config>
</container>

View File

@ -0,0 +1,3 @@
framework:
templating:
engines: [php, twig]

View File

@ -456,6 +456,22 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertTrue($container->has('serializer'));
}
public function testAssetHelperWhenAssetsAreEnabled()
{
$container = $this->createContainerFromFile('full');
$packages = $container->getDefinition('templating.helper.assets')->getArgument(0);
$this->assertSame('assets.packages', (string) $packages);
}
public function testAssetHelperWhenTemplatesAreEnabledAndAssetsAreDisabled()
{
$container = $this->createContainerFromFile('assets_disabled');
$packages = $container->getDefinition('templating.helper.assets')->getArgument(0);
$this->assertSame('assets.packages', (string) $packages);
}
protected function createContainer(array $data = array())
{
return new ContainerBuilder(new ParameterBag(array_merge(array(

View File

@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Translation;
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Translation\MessageSelector;
@ -77,6 +78,8 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
// do it another time as the cache is primed now
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
$loader->expects($this->never())->method('load');
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir));
$translator->setLocale('fr');
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
@ -145,12 +148,30 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('répertoire', $translator->trans('folder'));
}
protected function getCatalogue($locale, $messages)
public function testGetDefaultLocale()
{
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container
->expects($this->once())
->method('getParameter')
->with('kernel.default_locale')
->will($this->returnValue('en'))
;
$translator = new Translator($container, new MessageSelector());
$this->assertSame('en', $translator->getLocale());
}
protected function getCatalogue($locale, $messages, $resources = array())
{
$catalogue = new MessageCatalogue($locale);
foreach ($messages as $key => $translation) {
$catalogue->set($key, $translation);
}
foreach ($resources as $resource) {
$catalogue->addResource($resource);
}
return $catalogue;
}
@ -227,12 +248,7 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
public function getTranslator($loader, $options = array(), $loaderFomat = 'loader', $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator')
{
$translator = new $translatorClass(
$this->getContainer($loader),
new MessageSelector(),
array($loaderFomat => array($loaderFomat)),
$options
);
$translator = $this->createTranslator($loader, $options, $translatorClass, $loaderFomat);
if ('loader' === $loaderFomat) {
$translator->addResource('loader', 'foo', 'fr');
@ -267,6 +283,16 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
$translator->warmup($this->tmpDir);
$this->assertTrue(file_exists($this->tmpDir.'/catalogue.fr.'.$catalogueHash.'.php'));
}
private function createTranslator($loader, $options, $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator', $loaderFomat = 'loader')
{
return new $translatorClass(
$this->getContainer($loader),
new MessageSelector(),
array($loaderFomat => array($loaderFomat)),
$options
);
}
}
class TranslatorWithInvalidLocale extends Translator

View File

@ -69,7 +69,7 @@ class Translator extends BaseTranslator implements WarmableInterface
$this->loadResources();
}
parent::__construct(null, $selector, $this->options['cache_dir'], $this->options['debug']);
parent::__construct($container->getParameter('kernel.default_locale'), $selector, $this->options['cache_dir'], $this->options['debug']);
}
/**

View File

@ -57,9 +57,8 @@
"doctrine/cache": "For using alternative cache drivers"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\FrameworkBundle\\": "" }
"psr-4": { "Symfony\\Bundle\\FrameworkBundle\\": "" }
},
"target-dir": "Symfony/Bundle/FrameworkBundle",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -40,9 +40,8 @@
"twig/twig": "~1.12"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\SecurityBundle\\": "" }
"psr-4": { "Symfony\\Bundle\\SecurityBundle\\": "" }
},
"target-dir": "Symfony/Bundle/SecurityBundle",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -33,9 +33,8 @@
"symfony/framework-bundle": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\TwigBundle\\": "" }
"psr-4": { "Symfony\\Bundle\\TwigBundle\\": "" }
},
"target-dir": "Symfony/Bundle/TwigBundle",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -61,10 +61,14 @@ class WebDebugToolbarListener implements EventSubscriberInterface
$request = $event->getRequest();
if ($response->headers->has('X-Debug-Token') && null !== $this->urlGenerator) {
$response->headers->set(
'X-Debug-Token-Link',
$this->urlGenerator->generate('_profiler', array('token' => $response->headers->get('X-Debug-Token')))
);
try {
$response->headers->set(
'X-Debug-Token-Link',
$this->urlGenerator->generate('_profiler', array('token' => $response->headers->get('X-Debug-Token')))
);
} catch (\Exception $e) {
$response->headers->set('X-Debug-Error', get_class($e).': '.$e->getMessage());
}
}
if (!$event->isMasterRequest()) {

View File

@ -93,7 +93,7 @@
{% set is_deprecation = log.context.level is defined and log.context.type is defined and (constant('E_DEPRECATED') == log.context.type or constant('E_USER_DEPRECATED') == log.context.type) %}
{% if priority == '-100' ? is_deprecation : log.priority >= priority %}
{% set log_loop_index = log_loop_index + 1 %}
<li class="{{ cycle(['odd', 'even'], log_loop_index) }}{% if log.context.scream is defined %} scream{% elseif log.priority >= 400 %} error{% elseif log.priority >= 300 %} warning{% endif %}">
<li class="{{ cycle(['odd', 'even'], log_loop_index) }}{% if log.context.scream is defined %} scream{% elseif log.priority >= 400 %} error{% elseif log.priority >= 300 or is_deprecation %} warning{% endif %}">
{{ logger.display_message(loop.index, log, is_deprecation) }}
</li>
{% endif %}
@ -114,6 +114,8 @@
{% set stack = log.context.stack|default([]) %}
{% set id = 'sf-call-stack-' ~ log_index %}
DEPRECATED - {{ log.message }}
{% if stack %}
<a href="#" onclick="Sfjs.toggle('{{ id }}', document.getElementById('{{ id }}-on'), document.getElementById('{{ id }}-off')); return false;">
<img class="toggle" id="{{ id }}-off" alt="-" src="data:image/gif;base64,R0lGODlhEgASAMQSANft94TG57Hb8GS44ez1+mC24IvK6ePx+Wa44dXs92+942e54o3L6W2844/M6dnu+P/+/l614P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABIALAAAAAASABIAQAVCoCQBTBOd6Kk4gJhGBCTPxysJb44K0qD/ER/wlxjmisZkMqBEBW5NHrMZmVKvv9hMVsO+hE0EoNAstEYGxG9heIhCADs=" style="display:none">

View File

@ -103,13 +103,13 @@
return dict.hasOwnProperty(key)
? dict[key]
: null;
}
};
this.set = function(key, value) {
dict[key] = value;
return value;
}
};
};
/**
@ -383,7 +383,7 @@
return this;
};
};
}
function canvasAutoUpdateOnResizeAndSubmit(e) {
e.preventDefault();

View File

@ -115,7 +115,7 @@
for (elem in menuItems) {
if (typeof(menuItems[elem].children) !== 'undefined' &&
menuItems[elem].children.length > 0) {
child = menuItems[elem].children[0]
child = menuItems[elem].children[0];
if ('' === child.getAttribute('title') ||
null === child.getAttribute('title')) {

View File

@ -206,6 +206,27 @@ class WebDebugToolbarListenerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('/_profiler/xxxxxxxx', $response->headers->get('X-Debug-Token-Link'));
}
public function testThrowingUrlGenerator()
{
$response = new Response();
$response->headers->set('X-Debug-Token', 'xxxxxxxx');
$urlGenerator = $this->getUrlGeneratorMock();
$urlGenerator
->expects($this->once())
->method('generate')
->with('_profiler', array('token' => 'xxxxxxxx'))
->will($this->throwException(new \Exception('foo')))
;
$event = new FilterResponseEvent($this->getKernelMock(), $this->getRequestMock(), HttpKernelInterface::MASTER_REQUEST, $response);
$listener = new WebDebugToolbarListener($this->getTwigMock(), false, WebDebugToolbarListener::ENABLED, 'bottom', $urlGenerator);
$listener->onKernelResponse($event);
$this->assertEquals('Exception: foo', $response->headers->get('X-Debug-Error'));
}
protected function getRequestMock($isXmlHttpRequest = false, $requestFormat = 'html', $hasSession = true)
{
$request = $this->getMock(

View File

@ -29,9 +29,8 @@
"symfony/stopwatch": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\WebProfilerBundle\\": "" }
"psr-4": { "Symfony\\Bundle\\WebProfilerBundle\\": "" }
},
"target-dir": "Symfony/Bundle/WebProfilerBundle",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -93,6 +93,7 @@ class Cookie
$dateTime = \DateTime::createFromFormat('U', $this->expires, new \DateTimeZone('GMT'));
if ($dateTime === false) {
// this throw will provoke PHP fatal
throw new \UnexpectedValueException(sprintf('The cookie expiration time "%s" is not valid.'), $this->expires);
}

View File

@ -28,9 +28,8 @@
"symfony/process": ""
},
"autoload": {
"psr-0": { "Symfony\\Component\\BrowserKit\\": "" }
"psr-4": { "Symfony\\Component\\BrowserKit\\": "" }
},
"target-dir": "Symfony/Component/BrowserKit",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -24,9 +24,8 @@
"symfony/finder": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Component\\ClassLoader\\": "" }
"psr-4": { "Symfony\\Component\\ClassLoader\\": "" }
},
"target-dir": "Symfony/Component/ClassLoader",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"

View File

@ -37,8 +37,11 @@ class ConfigCacheFactory implements ConfigCacheFactoryInterface
*/
public function cache($file, $callback)
{
$cache = new ConfigCache($file, $this->debug);
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf('Invalid type for callback argument. Expected callable, but got "%s".', gettype($callback)));
}
$cache = new ConfigCache($file, $this->debug);
if (!$cache->isFresh()) {
call_user_func($callback, $cache);
}

View File

@ -58,7 +58,8 @@ class FileLoaderLoadException extends \Exception
if ('@' === $resource[0]) {
$parts = explode(DIRECTORY_SEPARATOR, $resource);
$bundle = substr($parts[0], 1);
$message .= ' '.sprintf('Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
$message .= sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
$message .= sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource);
}
parent::__construct($message, $code, $previous);

View File

@ -103,7 +103,12 @@ abstract class FileLoader extends Loader
}
self::$loading[$resource] = true;
$ret = $loader->load($resource, $type);
try {
$ret = $loader->load($resource, $type);
} catch (\Exception $e) {
unset(self::$loading[$resource]);
throw $e;
}
unset(self::$loading[$resource]);

View File

@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Config\Tests;
use Symfony\Component\Config\ConfigCacheFactory;
class ConfigCacheFactoryTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Invalid type for callback argument. Expected callable, but got "object".
*/
public function testCachWithInvalidCallback()
{
$cacheFactory = new ConfigCacheFactory(true);
$cacheFactory->cache('file', new \stdClass());
}
}

View File

@ -32,7 +32,8 @@ class FileLoaderLoadExceptionTest extends \PHPUnit_Framework_TestCase
$exception = new FileLoaderLoadException('@resource', 'sourceResource');
$this->assertEquals(
'Cannot import resource "@resource" from "sourceResource". '.
'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class.',
'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class. '.
'If the bundle is registered, make sure the bundle path "@resource" is not empty.',
$exception->getMessage()
);
}
@ -76,7 +77,8 @@ class FileLoaderLoadExceptionTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(
'There was a previous error with an ending dot in @resource '.
'(which is loaded in resource "@resource"). '.
'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class.',
'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class. '.
'If the bundle is registered, make sure the bundle path "@resource" is not empty.',
$exception->getMessage()
);
}

View File

@ -23,9 +23,8 @@
"symfony/phpunit-bridge": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Component\\Config\\": "" }
"psr-4": { "Symfony\\Component\\Config\\": "" }
},
"target-dir": "Symfony/Component/Config",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -281,6 +281,13 @@ class Command
throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
}
if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
$r = new \ReflectionFunction($code);
if (null === $r->getClosureThis()) {
$code = \Closure::bind($code, $this);
}
}
$this->code = $code;
return $this;

View File

@ -146,9 +146,11 @@ class ApplicationDescription
}
ksort($namespacedCommands);
foreach ($namespacedCommands as &$commands) {
ksort($commands);
foreach ($namespacedCommands as &$commandsSet) {
ksort($commandsSet);
}
// unset reference to keep scope clear
unset($commandsSet);
return $namespacedCommands;
}

View File

@ -192,7 +192,7 @@ class TextDescriptor extends Descriptor
$width = $this->getColumnWidth($description->getCommands());
if ($describedNamespace) {
$this->writeText(sprintf("<comment>Available commands for the \"%s\" namespace:</comment>", $describedNamespace), $options);
$this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
} else {
$this->writeText('<comment>Available commands:</comment>', $options);
}

View File

@ -73,7 +73,7 @@ class SymfonyStyle extends OutputStyle
$message = OutputFormatter::escape($message);
$lines = array_merge($lines, explode("\n", wordwrap($message, $this->lineLength - Helper::strlen($prefix))));
if (count($messages) > 1 && $key < count($message)) {
if (count($messages) > 1 && $key < count($messages) - 1) {
$lines[] = '';
}
}

View File

@ -293,6 +293,33 @@ class CommandTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay());
}
public function getSetCodeBindToClosureTests()
{
return array(
array(true, 'not bound to the command'),
array(false, 'bound to the command'),
);
}
/** @dataProvider getSetCodeBindToClosureTests */
public function testSetCodeBindToClosure($previouslyBound, $expected)
{
if (PHP_VERSION_ID < 50400) {
$this->markTestSkipped('Test skipped, for PHP 5.4+ only.');
}
$code = createClosure();
if ($previouslyBound) {
$code = $code->bindTo($this);
}
$command = new \TestCommand();
$command->setCode($code);
$tester = new CommandTester($command);
$tester->execute(array());
$this->assertEquals('interact called'.PHP_EOL.$expected.PHP_EOL, $tester->getDisplay());
}
public function testSetCodeWithNonClosureCallable()
{
$command = new \TestCommand();
@ -318,3 +345,13 @@ class CommandTest extends \PHPUnit_Framework_TestCase
$output->writeln('from the code...');
}
}
// In order to get an unbound closure, we should create it outside a class
// scope.
function createClosure()
{
return function(InputInterface $input, OutputInterface $output)
{
$output->writeln($this instanceof Command ? 'bound to the command' : 'not bound to the command');
};
}

View File

@ -28,7 +28,7 @@ class OutputFormatterTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo<bar', $formatter->format('foo\\<bar'));
$this->assertEquals('<info>some info</info>', $formatter->format('\\<info>some info\\</info>'));
$this->assertEquals("\\<info>some info\\</info>", OutputFormatter::escape('<info>some info</info>'));
$this->assertEquals('\\<info>some info\\</info>', OutputFormatter::escape('<info>some info</info>'));
$this->assertEquals(
"\033[33mSymfony\\Component\\Console does work very well!\033[39m",
@ -162,7 +162,7 @@ class OutputFormatterTest extends \PHPUnit_Framework_TestCase
public function testFormatLongString()
{
$formatter = new OutputFormatter(true);
$long = str_repeat("\\", 14000);
$long = str_repeat('\\', 14000);
$this->assertEquals("\033[37;41msome error\033[39;49m".$long, $formatter->format('<error>some error</error>'.$long));
}

View File

@ -30,9 +30,8 @@
"psr/log": "For using the console logger"
},
"autoload": {
"psr-0": { "Symfony\\Component\\Console\\": "" }
"psr-4": { "Symfony\\Component\\Console\\": "" }
},
"target-dir": "Symfony/Component/Console",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -100,7 +100,7 @@ class TokenStream
throw new InternalErrorException('Unexpected token stream end.');
}
return $this->tokens[$this->cursor ++];
return $this->tokens[$this->cursor++];
}
/**

View File

@ -26,9 +26,8 @@
"symfony/phpunit-bridge": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Component\\CssSelector\\": "" }
"psr-4": { "Symfony\\Component\\CssSelector\\": "" }
},
"target-dir": "Symfony/Component/CssSelector",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -168,7 +168,7 @@ class DebugClassLoader
}
$parent = $refl->getParentClass();
if (!$parent || strncmp($ns, $parent, $len)) {
if (!$parent || strncmp($ns, $parent->name, $len)) {
if ($parent && isset(self::$deprecated[$parent->name]) && strncmp($ns, $parent->name, $len)) {
trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent->name, self::$deprecated[$parent->name]), E_USER_DEPRECATED);
}

View File

@ -73,12 +73,12 @@ class ErrorHandler
E_USER_WARNING => array(null, LogLevel::WARNING),
E_COMPILE_WARNING => array(null, LogLevel::WARNING),
E_CORE_WARNING => array(null, LogLevel::WARNING),
E_USER_ERROR => array(null, LogLevel::ERROR),
E_RECOVERABLE_ERROR => array(null, LogLevel::ERROR),
E_COMPILE_ERROR => array(null, LogLevel::EMERGENCY),
E_PARSE => array(null, LogLevel::EMERGENCY),
E_ERROR => array(null, LogLevel::EMERGENCY),
E_CORE_ERROR => array(null, LogLevel::EMERGENCY),
E_USER_ERROR => array(null, LogLevel::CRITICAL),
E_RECOVERABLE_ERROR => array(null, LogLevel::CRITICAL),
E_COMPILE_ERROR => array(null, LogLevel::CRITICAL),
E_PARSE => array(null, LogLevel::CRITICAL),
E_ERROR => array(null, LogLevel::CRITICAL),
E_CORE_ERROR => array(null, LogLevel::CRITICAL),
);
private $thrownErrors = 0x1FFF; // E_ALL - E_DEPRECATED - E_USER_DEPRECATED
@ -381,7 +381,7 @@ class ErrorHandler
} else {
try {
$this->isRecursive = true;
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, $e);
$this->loggers[$type][0]->log(($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, $message, $e);
$this->isRecursive = false;
} catch (\Exception $e) {
$this->isRecursive = false;
@ -403,13 +403,12 @@ class ErrorHandler
*/
public function handleException(\Exception $exception, array $error = null)
{
$level = error_reporting();
if ($this->loggedErrors & E_ERROR & ($level | $this->screamedErrors)) {
if ($this->loggedErrors & E_ERROR) {
$e = array(
'type' => E_ERROR,
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'level' => $level,
'level' => error_reporting(),
'stack' => $exception->getTrace(),
);
if ($exception instanceof FatalErrorException) {
@ -513,7 +512,7 @@ class ErrorHandler
}
/**
* Unstacks stacked errors and forwards to the logger
* Unstacks stacked errors and forwards to the logger.
*/
public static function unstackErrors()
{

View File

@ -388,7 +388,7 @@ EOF;
{
$parts = explode('\\', $class);
return sprintf("<abbr title=\"%s\">%s</abbr>", $class, array_pop($parts));
return sprintf('<abbr title="%s">%s</abbr>', $class, array_pop($parts));
}
private function formatPath($path, $line)

View File

@ -76,7 +76,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
/**
* Tries to guess the full namespace for a given class name.
*
* By default, it looks for PSR-0 classes registered via a Symfony or a Composer
* By default, it looks for PSR-0 and PSR-4 classes registered via a Symfony or a Composer
* autoloader (that should cover all common cases).
*
* @param string $class A class name (without its namespace)
@ -112,6 +112,13 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
}
}
}
if ($function[0] instanceof ComposerClassLoader) {
foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) {
foreach ($paths as $path) {
$classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
}
}
}
}
return array_unique($classes);
@ -126,13 +133,13 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
*/
private function findClassInPath($path, $class, $prefix)
{
if (!$path = realpath($path)) {
if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
return array();
}
$classes = array();
$filename = $class.'.php';
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) {
$classes[] = $class;
}
@ -154,13 +161,21 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
// namespaced class
$namespacedClass = str_replace(array($path.DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
// namespaced class (with target dir)
$namespacedClassTargetDir = $prefix.str_replace(array($path.DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
$prefix.$namespacedClass,
// namespaced class (with target dir and separator)
$prefix.'\\'.$namespacedClass,
// PEAR class
str_replace('\\', '_', $namespacedClass),
// PEAR class (with target dir)
str_replace('\\', '_', $namespacedClassTargetDir),
str_replace('\\', '_', $prefix.$namespacedClass),
// PEAR class (with target dir and separator)
str_replace('\\', '_', $prefix.'\\'.$namespacedClass),
);
if ($prefix) {
$candidates = array_filter($candidates, function ($candidate) use ($prefix) {return 0 === strpos($candidate, $prefix);});
}
// We cannot use the autoloader here as most of them use require; but if the class
// is not found, the new autoloader call will require the file again leading to a
// "cannot redeclare class" error.

View File

@ -148,12 +148,12 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
E_USER_WARNING => array(null, LogLevel::WARNING),
E_COMPILE_WARNING => array(null, LogLevel::WARNING),
E_CORE_WARNING => array(null, LogLevel::WARNING),
E_USER_ERROR => array(null, LogLevel::ERROR),
E_RECOVERABLE_ERROR => array(null, LogLevel::ERROR),
E_COMPILE_ERROR => array(null, LogLevel::EMERGENCY),
E_PARSE => array(null, LogLevel::EMERGENCY),
E_ERROR => array(null, LogLevel::EMERGENCY),
E_CORE_ERROR => array(null, LogLevel::EMERGENCY),
E_USER_ERROR => array(null, LogLevel::CRITICAL),
E_RECOVERABLE_ERROR => array(null, LogLevel::CRITICAL),
E_COMPILE_ERROR => array(null, LogLevel::CRITICAL),
E_PARSE => array(null, LogLevel::CRITICAL),
E_ERROR => array(null, LogLevel::CRITICAL),
E_CORE_ERROR => array(null, LogLevel::CRITICAL),
);
$this->assertSame($loggers, $handler->setLoggers(array()));

View File

@ -13,18 +13,52 @@ namespace Symfony\Component\Debug\Tests\FatalErrorHandler;
use Symfony\Component\Debug\Exception\FatalErrorException;
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
use Symfony\Component\Debug\DebugClassLoader;
use Composer\Autoload\ClassLoader as ComposerClassLoader;
class ClassNotFoundFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
{
public static function setUpBeforeClass()
{
foreach (spl_autoload_functions() as $function) {
if (!is_array($function)) {
continue;
}
// get class loaders wrapped by DebugClassLoader
if ($function[0] instanceof DebugClassLoader) {
$function = $function[0]->getClassLoader();
}
if ($function[0] instanceof ComposerClassLoader) {
$function[0]->add('Symfony_Component_Debug_Tests_Fixtures', dirname(dirname(dirname(dirname(dirname(__DIR__))))));
break;
}
}
}
/**
* @dataProvider provideClassNotFoundData
*/
public function testHandleClassNotFound($error, $translatedMessage)
public function testHandleClassNotFound($error, $translatedMessage, $autoloader = null)
{
if ($autoloader) {
// Unregister all autoloaders to ensure the custom provided
// autoloader is the only one to be used during the test run.
$autoloaders = spl_autoload_functions();
array_map('spl_autoload_unregister', $autoloaders);
spl_autoload_register($autoloader);
}
$handler = new ClassNotFoundFatalErrorHandler();
$exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line']));
if ($autoloader) {
spl_autoload_unregister($autoloader);
array_map('spl_autoload_register', $autoloaders);
}
$this->assertInstanceof('Symfony\Component\Debug\Exception\ClassNotFoundException', $exception);
$this->assertSame($translatedMessage, $exception->getMessage());
$this->assertSame($error['type'], $exception->getSeverity());
@ -34,6 +68,13 @@ class ClassNotFoundFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
public function provideClassNotFoundData()
{
$prefixes = array('Symfony\Component\Debug\Exception\\' => realpath(__DIR__.'/../../Exception'));
$symfonyAutoloader = new SymfonyClassLoader();
$symfonyAutoloader->addPrefixes($prefixes);
$debugClassLoader = new DebugClassLoader($symfonyAutoloader);
return array(
array(
array(
@ -80,6 +121,36 @@ class ClassNotFoundFatalErrorHandlerTest extends \PHPUnit_Framework_TestCase
),
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
),
array(
array(
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
),
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
array($symfonyAutoloader, 'loadClass'),
),
array(
array(
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
),
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
array($debugClassLoader, 'loadClass'),
),
array(
array(
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
),
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?",
function ($className) { /* do nothing here */ },
),
);
}

View File

@ -33,9 +33,8 @@
"symfony/http-kernel": ""
},
"autoload": {
"psr-0": { "Symfony\\Component\\Debug\\": "" }
"psr-4": { "Symfony\\Component\\Debug\\": "" }
},
"target-dir": "Symfony/Component/Debug",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -39,7 +39,7 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
foreach (array_keys($container->getDefinitions()) as $id) {
foreach ($container->getDefinitions() as $id => $definition) {
// yes, we are specifically fetching the definition from the
// container to ensure we are not operating on stale data
$definition = $container->getDefinition($id);

View File

@ -307,7 +307,7 @@ class Container implements IntrospectableContainerInterface
}
$alternatives = array();
foreach (array_keys($this->services) as $key) {
foreach ($this->services as $key => $associatedService) {
$lev = levenshtein($id, $key);
if ($lev <= strlen($id) / 3 || false !== strpos($key, $id)) {
$alternatives[] = $key;

View File

@ -560,7 +560,7 @@ class PhpDumper extends Dumper
if ($definition->isSynthetic()) {
$return[] = '@throws RuntimeException always since this service is expected to be injected dynamically';
} elseif ($class = $definition->getClass()) {
$return[] = sprintf('@return %s A %s instance.', 0 === strpos($class, '%') ? 'object' : "\\".$class, $class);
$return[] = sprintf('@return %s A %s instance.', 0 === strpos($class, '%') ? 'object' : '\\'.$class, $class);
} elseif ($definition->getFactory()) {
$factory = $definition->getFactory();
if (is_string($factory)) {
@ -1346,7 +1346,7 @@ EOF;
}
}
return sprintf("new \\%s(%s)", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
return sprintf('new \\%s(%s)', substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
} elseif ($value instanceof Variable) {
return '$'.$value;
} elseif ($value instanceof Reference) {

View File

@ -18,7 +18,6 @@ use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\ExpressionLanguage\Expression;
/**
@ -32,20 +31,6 @@ class YamlDumper extends Dumper
{
private $dumper;
/**
* Constructor.
*
* @param ContainerBuilder $container The service container to dump
*
* @api
*/
public function __construct(ContainerBuilder $container)
{
parent::__construct($container);
$this->dumper = new YmlDumper();
}
/**
* Dumps the service container as an YAML string.
*
@ -57,6 +42,14 @@ class YamlDumper extends Dumper
*/
public function dump(array $options = array())
{
if (!class_exists('Symfony\Component\Yaml\Dumper')) {
throw new RuntimeException('Unable to dump the container as the Symfony Yaml Component is not installed.');
}
if (null === $this->dumper) {
$this->dumper = new YmlDumper();
}
return $this->addParameters()."\n".$this->addServices();
}

View File

@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\ExpressionLanguage\Expression;
@ -74,7 +75,7 @@ class YamlFileLoader extends FileLoader
*/
public function supports($resource, $type = null)
{
return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
return is_string($resource) && in_array(pathinfo($resource, PATHINFO_EXTENSION), array('yml', 'yaml'), true);
}
/**
@ -295,6 +296,10 @@ class YamlFileLoader extends FileLoader
*/
protected function loadFile($file)
{
if (!class_exists('Symfony\Component\Yaml\Parser')) {
throw new RuntimeException('Unable to load YAML config files as the Symfony Yaml Component is not installed.');
}
if (!stream_is_local($file)) {
throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file));
}
@ -330,7 +335,7 @@ class YamlFileLoader extends FileLoader
throw new InvalidArgumentException(sprintf('The service file "%s" is not valid. It should contain an array. Check your YAML syntax.', $file));
}
foreach (array_keys($content) as $namespace) {
foreach ($content as $namespace => $data) {
if (in_array($namespace, array('imports', 'parameters', 'services'))) {
continue;
}

View File

@ -96,7 +96,7 @@ class ParameterBag implements ParameterBagInterface
}
$alternatives = array();
foreach (array_keys($this->parameters) as $key) {
foreach ($this->parameters as $key => $parameterValue) {
$lev = levenshtein($name, $key);
if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) {
$alternatives[] = $key;

View File

@ -89,21 +89,21 @@ class XmlDumperTest extends \PHPUnit_Framework_TestCase
{
$container = include self::$fixturesPath.'/containers/container11.php';
$dumper = new XmlDumper($container);
$this->assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\"?>
<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\">
$this->assertEquals('<?xml version="1.0" encoding="utf-8"?>
<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=\"foo\" class=\"FooClass\">
<argument type=\"service\">
<service class=\"BarClass\">
<argument type=\"service\">
<service class=\"BazClass\"/>
<service id="foo" class="FooClass">
<argument type="service">
<service class="BarClass">
<argument type="service">
<service class="BazClass"/>
</argument>
</service>
</argument>
</service>
</services>
</container>
", $dumper->dump());
', $dumper->dump());
}
public function testDumpEntities()

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\DependencyInjection\Tests\Loader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\Config\FileLocator;

View File

@ -14,7 +14,6 @@ namespace Symfony\Component\DependencyInjection\Tests\Loader;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;

View File

@ -13,7 +13,6 @@ namespace Symfony\Component\DependencyInjection\Tests\Loader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
@ -222,6 +221,7 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
$loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator());
$this->assertTrue($loader->supports('foo.yml'), '->supports() returns true if the resource is loadable');
$this->assertTrue($loader->supports('foo.yaml'), '->supports() returns true if the resource is loadable');
$this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
}

View File

@ -30,9 +30,8 @@
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
},
"autoload": {
"psr-0": { "Symfony\\Component\\DependencyInjection\\": "" }
"psr-4": { "Symfony\\Component\\DependencyInjection\\": "" }
},
"target-dir": "Symfony/Component/DependencyInjection",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -163,7 +163,7 @@ class Link
if ('..' === $segment) {
array_pop($output);
} elseif ('.' !== $segment) {
array_push($output, $segment);
$output[] = $segment;
}
}

View File

@ -26,9 +26,8 @@
"symfony/css-selector": ""
},
"autoload": {
"psr-0": { "Symfony\\Component\\DomCrawler\\": "" }
"psr-4": { "Symfony\\Component\\DomCrawler\\": "" }
},
"target-dir": "Symfony/Component/DomCrawler",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -121,7 +121,7 @@ class ContainerAwareEventDispatcher extends EventDispatcher
public function getListeners($eventName = null)
{
if (null === $eventName) {
foreach (array_keys($this->listenerIds) as $serviceEventName) {
foreach ($this->listenerIds as $serviceEventName => $args) {
$this->lazyLoad($serviceEventName);
}
} else {

View File

@ -31,6 +31,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
private $called;
private $dispatcher;
private $wrappedListeners;
/**
* Constructor.
@ -45,6 +46,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->called = array();
$this->wrappedListeners = array();
}
/**
@ -68,6 +70,16 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
*/
public function removeListener($eventName, $listener)
{
if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
if ($wrappedListener->getWrappedListener() === $listener) {
$listener = $wrappedListener;
unset($this->wrappedListeners[$eventName][$index]);
break;
}
}
}
return $this->dispatcher->removeListener($eventName, $listener);
}
@ -216,12 +228,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
$this->dispatcher->removeListener($eventName, $listener);
$info = $this->getListenerInfo($listener, $eventName);
$name = isset($info['class']) ? $info['class'] : $info['type'];
$this->dispatcher->addListener($eventName, new WrappedListener($listener, $name, $this->stopwatch, $this));
$wrappedListener = new WrappedListener($listener, $name, $this->stopwatch, $this);
$this->wrappedListeners[$eventName][] = $wrappedListener;
$this->dispatcher->addListener($eventName, $wrappedListener);
}
}
private function postProcess($eventName)
{
unset($this->wrappedListeners[$eventName]);
$skipped = false;
foreach ($this->dispatcher->getListeners($eventName) as $listener) {
if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch.
@ -259,7 +274,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
/**
* Returns information about the listener
* Returns information about the listener.
*
* @param object $listener The listener
* @param string $eventName The event name

View File

@ -65,7 +65,7 @@ class EventDispatcher implements EventDispatcherInterface
return $this->sorted[$eventName];
}
foreach (array_keys($this->listeners) as $eventName) {
foreach ($this->listeners as $eventName => $eventListeners) {
if (!isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\EventDispatcher\Tests\Debug;
use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\Event;
@ -174,6 +175,19 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$dispatcher->dispatch('foo');
$this->assertTrue($nestedCall);
}
public function testListenerCanRemoveItselfWhenExecuted()
{
$eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
$listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) {
$dispatcher->removeListener('foo', $listener1);
};
$eventDispatcher->addListener('foo', $listener1);
$eventDispatcher->addListener('foo', function () {});
$eventDispatcher->dispatch('foo');
$this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');
}
}
class EventSubscriber implements EventSubscriberInterface

View File

@ -31,9 +31,8 @@
"symfony/http-kernel": ""
},
"autoload": {
"psr-0": { "Symfony\\Component\\EventDispatcher\\": "" }
"psr-4": { "Symfony\\Component\\EventDispatcher\\": "" }
},
"target-dir": "Symfony/Component/EventDispatcher",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -22,9 +22,8 @@
"symfony/phpunit-bridge": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Component\\ExpressionLanguage\\": "" }
"psr-4": { "Symfony\\Component\\ExpressionLanguage\\": "" }
},
"target-dir": "Symfony/Component/ExpressionLanguage",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -22,9 +22,8 @@
"symfony/phpunit-bridge": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Component\\Filesystem\\": "" }
"psr-4": { "Symfony\\Component\\Filesystem\\": "" }
},
"target-dir": "Symfony/Component/Filesystem",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Finder\Expression;
use Symfony\Component\Finder\Glob as FinderGlob;
/**
* @author Jean-François Simon <contact@jfsimon.fr>
*/
@ -100,58 +102,8 @@ class Glob implements ValueInterface
*/
public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
{
$firstByte = true;
$escaping = false;
$inCurlies = 0;
$regex = '';
$sizeGlob = strlen($this->pattern);
for ($i = 0; $i < $sizeGlob; $i++) {
$car = $this->pattern[$i];
if ($firstByte) {
if ($strictLeadingDot && '.' !== $car) {
$regex .= '(?=[^\.])';
}
$regex = FinderGlob::toRegex($this->pattern, $strictLeadingDot, $strictWildcardSlash, '');
$firstByte = false;
}
if ('/' === $car) {
$firstByte = true;
}
if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
$regex .= "\\$car";
} elseif ('*' === $car) {
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
} elseif ('?' === $car) {
$regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
} elseif ('{' === $car) {
$regex .= $escaping ? '\\{' : '(';
if (!$escaping) {
++$inCurlies;
}
} elseif ('}' === $car && $inCurlies) {
$regex .= $escaping ? '}' : ')';
if (!$escaping) {
--$inCurlies;
}
} elseif (',' === $car && $inCurlies) {
$regex .= $escaping ? ',' : '|';
} elseif ('\\' === $car) {
if ($escaping) {
$regex .= '\\\\';
$escaping = false;
} else {
$escaping = true;
}
continue;
} else {
$regex .= $car;
}
$escaping = false;
}
return new Regex('^'.$regex.'$');
return new Regex($regex);
}
}

View File

@ -41,10 +41,11 @@ class Glob
* @param string $glob The glob pattern
* @param bool $strictLeadingDot
* @param bool $strictWildcardSlash
* @param string $delimiter Optional delimiter
*
* @return string regex The regexp
*/
public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true)
public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
{
$firstByte = true;
$escaping = false;
@ -98,6 +99,6 @@ class Glob
$escaping = false;
}
return '#^'.$regex.'$#';
return $delimiter.'^'.$regex.'$'.$delimiter;
}
}

View File

@ -306,7 +306,7 @@ class FinderTest extends Iterator\RealIteratorTestCase
$finder = $this->buildFinder($adapter);
$iterator = $finder->files()->name('*.php')->depth('< 1')->in(array(self::$tmpDir, __DIR__))->getIterator();
$this->assertIterator(array(self::$tmpDir.DIRECTORY_SEPARATOR.'test.php', __DIR__.DIRECTORY_SEPARATOR.'FinderTest.php'), $iterator);
$this->assertIterator(array(self::$tmpDir.DIRECTORY_SEPARATOR.'test.php', __DIR__.DIRECTORY_SEPARATOR.'FinderTest.php', __DIR__.DIRECTORY_SEPARATOR.'GlobTest.php'), $iterator);
}
/**

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Finder\Tests;
use Symfony\Component\Finder\Glob;
class GlobTest extends \PHPUnit_Framework_TestCase
{
public function testGlobToRegexDelimiters()
{
$this->assertEquals(Glob::toRegex('.*'), '#^\.[^/]*$#');
$this->assertEquals(Glob::toRegex('.*', true, true, ''), '^\.[^/]*$');
$this->assertEquals(Glob::toRegex('.*', true, true, '/'), '/^\.[^/]*$/');
}
}

View File

@ -51,7 +51,7 @@ abstract class IteratorTestCase extends \PHPUnit_Framework_TestCase
foreach ($expected as $subarray) {
$temp = array();
while (count($values) && count($temp) < count($subarray)) {
array_push($temp, array_shift($values));
$temp[] = array_shift($values);
}
sort($temp);
sort($subarray);

View File

@ -22,9 +22,8 @@
"symfony/phpunit-bridge": "~2.8|~3.0"
},
"autoload": {
"psr-0": { "Symfony\\Component\\Finder\\": "" }
"psr-4": { "Symfony\\Component\\Finder\\": "" }
},
"target-dir": "Symfony/Component/Finder",
"minimum-stability": "dev",
"extra": {
"branch-alias": {

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
trigger_error('The '.__NAMESPACE__.'\ChoiceList class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\ArrayChoiceList instead.', E_USER_DEPRECATED);
use Symfony\Component\Form\FormConfigBuilder;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Exception\InvalidConfigurationException;
@ -92,8 +94,6 @@ class ChoiceList implements ChoiceListInterface
}
$this->initialize($choices, $labels, $preferredChoices);
trigger_error('The '.__CLASS__.' class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\ArrayChoiceList instead.', E_USER_DEPRECATED);
}
/**

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
use Symfony\Component\Form\ChoiceList\ChoiceListInterface as BaseChoiceListInterface;
use Symfony\Component\Form\FormConfigBuilder;
/**
* Contains choices that can be selected in a form field.
@ -87,7 +88,7 @@ interface ChoiceListInterface extends BaseChoiceListInterface
* Returns the indices corresponding to the given choices.
*
* The indices must be positive integers or strings accepted by
* {@link FormConfigBuilder::validateName()}.
* {@link \Symfony\Component\Form\FormConfigBuilder::validateName()}.
*
* The index "placeholder" is internally reserved.
*
@ -107,7 +108,7 @@ interface ChoiceListInterface extends BaseChoiceListInterface
* Returns the indices corresponding to the given values.
*
* The indices must be positive integers or strings accepted by
* {@link FormConfigBuilder::validateName()}.
* {@link \Symfony\Component\Form\FormConfigBuilder::validateName()}.
*
* The index "placeholder" is internally reserved.
*

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
trigger_error('The '.__NAMESPACE__.'\LazyChoiceList class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\ArrayChoiceList instead.', E_USER_DEPRECATED);
use Symfony\Component\Form\Exception\InvalidArgumentException;
/**
@ -34,11 +36,6 @@ abstract class LazyChoiceList implements ChoiceListInterface
*/
private $choiceList;
public function __construct()
{
trigger_error('The '.__CLASS__.' class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\LazyChoiceList instead.', E_USER_DEPRECATED);
}
/**
* {@inheritdoc}
*/

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
trigger_error('The '.__NAMESPACE__.'\ObjectChoiceList class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\ArrayChoiceList instead.', E_USER_DEPRECATED);
use Symfony\Component\Form\Exception\StringCastException;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\PropertyAccess\PropertyPath;
@ -96,8 +98,6 @@ class ObjectChoiceList extends ChoiceList
$this->valuePath = null !== $valuePath ? new PropertyPath($valuePath) : null;
parent::__construct($choices, array(), $preferredChoices);
trigger_error('The '.__CLASS__.' class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\ArrayChoiceList instead.', E_USER_DEPRECATED);
}
/**

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
trigger_error('The '.__NAMESPACE__.'\SimpleChoiceList class is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\ArrayChoiceList instead.', E_USER_DEPRECATED);
/**
* A choice list for choices of type string or integer.
*

View File

@ -40,11 +40,11 @@ abstract class BaseDateTimeTransformer implements DataTransformerInterface
*/
public function __construct($inputTimezone = null, $outputTimezone = null)
{
if (!is_string($inputTimezone) && null !== $inputTimezone) {
if (null !== $inputTimezone && !is_string($inputTimezone)) {
throw new UnexpectedTypeException($inputTimezone, 'string');
}
if (!is_string($outputTimezone) && null !== $outputTimezone) {
if (null !== $outputTimezone && !is_string($outputTimezone)) {
throw new UnexpectedTypeException($outputTimezone, 'string');
}

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\DataTransformer;
trigger_error('The class '.__NAMESPACE__.'\ChoiceToBooleanArrayTransformer is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper instead.', E_USER_DEPRECATED);
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
@ -37,8 +39,6 @@ class ChoiceToBooleanArrayTransformer implements DataTransformerInterface
{
$this->choiceList = $choiceList;
$this->placeholderPresent = $placeholderPresent;
trigger_error('The class '.__CLASS__.' is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\LazyChoiceList instead.', E_USER_DEPRECATED);
}
/**

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\DataTransformer;
trigger_error('The class '.__NAMESPACE__.'\ChoicesToBooleanArrayTransformer is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\Extension\Core\DataMapper\CheckboxListMapper instead.', E_USER_DEPRECATED);
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
@ -28,8 +30,6 @@ class ChoicesToBooleanArrayTransformer implements DataTransformerInterface
public function __construct(ChoiceListInterface $choiceList)
{
$this->choiceList = $choiceList;
trigger_error('The class '.__CLASS__.' is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\ChoiceList\LazyChoiceList instead.', E_USER_DEPRECATED);
}
/**

View File

@ -99,6 +99,8 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
// remove leading zeros
$entry = (string) (int) $entry;
}
// unset reference to keep scope clear
unset($entry);
}
return $result;

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
trigger_error('The class '.__NAMESPACE__.'\FixCheckboxInputListener is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\Extension\Core\DataMapper\CheckboxListMapper instead.', E_USER_DEPRECATED);
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
@ -38,8 +40,6 @@ class FixCheckboxInputListener implements EventSubscriberInterface
public function __construct(ChoiceListInterface $choiceList)
{
$this->choiceList = $choiceList;
trigger_error('The class '.__CLASS__.' is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\Extension\Core\DataMapper\CheckboxListMapper instead.', E_USER_DEPRECATED);
}
public function preSubmit(FormEvent $event)

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
trigger_error('The class '.__NAMESPACE__.'\FixRadioInputListener is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper instead.', E_USER_DEPRECATED);
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\FormEvent;
@ -41,8 +43,6 @@ class FixRadioInputListener implements EventSubscriberInterface
{
$this->choiceList = $choiceList;
$this->placeholderPresent = $placeholderPresent;
trigger_error('The class '.__CLASS__.' is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper instead.', E_USER_DEPRECATED);
}
public function preSubmit(FormEvent $event)

View File

@ -74,7 +74,7 @@ class MergeCollectionListener implements EventSubscriberInterface
}
// If we are not allowed to change anything, return immediately
if ((!$this->allowAdd && !$this->allowDelete) || $data === $dataToMergeInto) {
if ($data === $dataToMergeInto || (!$this->allowAdd && !$this->allowDelete)) {
$event->setData($dataToMergeInto);
return;

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