Skip to content

Commit

Permalink
Merge branch '4.4'
Browse files Browse the repository at this point in the history
* 4.4:
  [DI] Dont cache classes with missing parents
  [HttpClient] Fix a crash when calling CurlHttpClient::__destruct()
  Unallow symfony/http-kernel ^5.0
  [FrameworkBundle] fix SodiumVault after stof review
  [HttpClient] allow arbitrary JSON values in requests
  [DependencyInjection] Added option `ignore_errors: not_found` while importing config files
  [Validator] Add the missing translations for the Hebrew (\"he\") locale and fix 2 typos
  [FrameworkBundle][Translation] Invalidate cached catalogues when the scanned directories change
  • Loading branch information
nicolas-grekas committed Nov 8, 2019
2 parents 87d30dd + 4f493e1 commit 2880986
Show file tree
Hide file tree
Showing 16 changed files with 146 additions and 16 deletions.
3 changes: 1 addition & 2 deletions ContainerBuilder.php
Expand Up @@ -337,7 +337,7 @@ public function getReflectionClass(?string $class, bool $throw = true): ?\Reflec
return null;
}

$resource = null;
$resource = $classReflector = null;

try {
if (isset($this->classReflectors[$class])) {
Expand All @@ -352,7 +352,6 @@ public function getReflectionClass(?string $class, bool $throw = true): ?\Reflec
if ($throw) {
throw $e;
}
$classReflector = false;
}

if ($this->trackResources) {
Expand Down
2 changes: 1 addition & 1 deletion Loader/Configurator/ContainerConfigurator.php
Expand Up @@ -60,7 +60,7 @@ final public function extension(string $namespace, array $config)
$this->container->loadFromExtension($namespace, static::processValue($config));
}

final public function import(string $resource, string $type = null, bool $ignoreErrors = false)
final public function import(string $resource, string $type = null, $ignoreErrors = false)
{
$this->loader->setCurrentDir(\dirname($this->path));
$this->loader->import($resource, $type, $ignoreErrors, $this->file);
Expand Down
46 changes: 40 additions & 6 deletions Loader/FileLoader.php
Expand Up @@ -11,8 +11,11 @@

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
use Symfony\Component\Config\Exception\LoaderLoadException;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Config\Resource\GlobResource;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down Expand Up @@ -41,6 +44,42 @@ public function __construct(ContainerBuilder $container, FileLocatorInterface $l
parent::__construct($locator);
}

/**
* {@inheritdoc}
*
* @param bool|string $ignoreErrors Whether errors should be ignored; pass "not_found" to ignore only when the loaded resource is not found
* @param string|string[]|null $exclude Glob patterns to exclude from the import
*/
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null/*, $exclude = null*/)
{
$args = \func_get_args();

if ($ignoreNotFound = 'not_found' === $ignoreErrors) {
$args[2] = false;
} elseif (!\is_bool($ignoreErrors)) {
@trigger_error(sprintf('Invalid argument $ignoreErrors provided to %s::import(): boolean or "not_found" expected, %s given.', \get_class($this), \gettype($ignoreErrors)), E_USER_DEPRECATED);
$args[2] = (bool) $ignoreErrors;
}

try {
parent::import(...$args);
} catch (LoaderLoadException $e) {
if (!$ignoreNotFound || !($prev = $e->getPrevious()) instanceof FileLocatorFileNotFoundException) {
throw $e;
}

foreach ($prev->getTrace() as $frame) {
if ('import' === ($frame['function'] ?? null) && is_a($frame['class'] ?? '', Loader::class, true)) {
break;
}
}

if ($args !== $frame['args']) {
throw $e;
}
}
}

/**
* Registers a set of classes as services using PSR-4 for discovery.
*
Expand Down Expand Up @@ -156,12 +195,7 @@ private function findClasses(string $namespace, string $pattern, array $excludeP
try {
$r = $this->container->getReflectionClass($class);
} catch (\ReflectionException $e) {
$classes[$class] = sprintf(
'While discovering services from namespace "%s", an error was thrown when processing the class "%s": "%s".',
$namespace,
$class,
$e->getMessage()
);
$classes[$class] = $e->getMessage();
continue;
}
// check to make sure the expected class exists
Expand Down
2 changes: 1 addition & 1 deletion Loader/XmlFileLoader.php
Expand Up @@ -105,7 +105,7 @@ private function parseImports(\DOMDocument $xml, string $file)
$defaultDirectory = \dirname($file);
foreach ($imports as $import) {
$this->setCurrentDir($defaultDirectory);
$this->import($import->getAttribute('resource'), XmlUtils::phpize($import->getAttribute('type')) ?: null, (bool) XmlUtils::phpize($import->getAttribute('ignore-errors')), $file);
$this->import($import->getAttribute('resource'), XmlUtils::phpize($import->getAttribute('type')) ?: null, XmlUtils::phpize($import->getAttribute('ignore-errors')) ?: false, $file);
}
}

Expand Down
2 changes: 1 addition & 1 deletion Loader/YamlFileLoader.php
Expand Up @@ -191,7 +191,7 @@ private function parseImports(array $content, string $file)
}

$this->setCurrentDir($defaultDirectory);
$this->import($import['resource'], isset($import['type']) ? $import['type'] : null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file);
$this->import($import['resource'], $import['type'] ?? null, $import['ignore_errors'] ?? false, $file);
}
}

Expand Down
8 changes: 7 additions & 1 deletion Loader/schema/dic/services/services-1.0.xsd
Expand Up @@ -78,7 +78,7 @@
]]></xsd:documentation>
</xsd:annotation>
<xsd:attribute name="resource" type="xsd:string" use="required" />
<xsd:attribute name="ignore-errors" type="boolean" />
<xsd:attribute name="ignore-errors" type="ignore_errors" />
<xsd:attribute name="type" type="xsd:string" />
</xsd:complexType>

Expand Down Expand Up @@ -273,6 +273,12 @@
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="ignore_errors">
<xsd:restriction base="xsd:string">
<xsd:pattern value="(true|false|not_found)" />
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="invalid_sequence">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="null" />
Expand Down
2 changes: 1 addition & 1 deletion Tests/Compiler/AutowirePassTest.php
Expand Up @@ -363,7 +363,7 @@ public function testParentClassNotFoundThrowsException()
$pass->process($container);
$this->fail('AutowirePass should have thrown an exception');
} catch (AutowiringFailedException $e) {
$this->assertSame('Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class is missing a parent class (Class Symfony\Bug\NotExistClass not found).', (string) $e->getMessage());
$this->assertRegExp('{^Cannot autowire service "a": argument "\$r" of method "(Symfony\\\\Component\\\\DependencyInjection\\\\Tests\\\\Compiler\\\\)BadParentTypeHintedArgument::__construct\(\)" has type "\1OptionalServiceClass" but this class is missing a parent class \(Class "?Symfony\\\\Bug\\\\NotExistClass"? not found}', (string) $e->getMessage());
}
}

Expand Down
9 changes: 9 additions & 0 deletions Tests/Fixtures/xml/services4_bad_import_file_not_found.xml
@@ -0,0 +1,9 @@
<?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 https://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="foo_fake.xml" ignore-errors="not_found" />
</imports>
</container>
9 changes: 9 additions & 0 deletions Tests/Fixtures/xml/services4_bad_import_nonvalid.xml
@@ -0,0 +1,9 @@
<?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 https://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="nonvalid.xml" ignore-errors="not_found" />
</imports>
</container>
9 changes: 9 additions & 0 deletions Tests/Fixtures/xml/services4_bad_import_with_errors.xml
@@ -0,0 +1,9 @@
<?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 https://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="foo_fake.xml" />
</imports>
</container>
2 changes: 2 additions & 0 deletions Tests/Fixtures/yaml/services4_bad_import_file_not_found.yml
@@ -0,0 +1,2 @@
imports:
- { resource: foo_fake.yml, ignore_errors: not_found }
2 changes: 2 additions & 0 deletions Tests/Fixtures/yaml/services4_bad_import_nonvalid.yml
@@ -0,0 +1,2 @@
imports:
- { resource: nonvalid2.yml, ignore_errors: not_found }
2 changes: 2 additions & 0 deletions Tests/Fixtures/yaml/services4_bad_import_with_errors.yml
@@ -0,0 +1,2 @@
imports:
- { resource: foo_fake.yml }
6 changes: 3 additions & 3 deletions Tests/Loader/FileLoaderTest.php
Expand Up @@ -196,9 +196,9 @@ public function testMissingParentClass()

$this->assertTrue($container->has(MissingParent::class));

$this->assertSame(
['While discovering services from namespace "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\", an error was thrown when processing the class "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingParent": "Class Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingClass not found".'],
$container->getDefinition(MissingParent::class)->getErrors()
$this->assertRegExp(
'{Class "?Symfony\\\\Component\\\\DependencyInjection\\\\Tests\\\\Fixtures\\\\Prototype\\\\BadClasses\\\\MissingClass"? not found}',
$container->getDefinition(MissingParent::class)->getErrors()[0]
);
}

Expand Down
31 changes: 31 additions & 0 deletions Tests/Loader/XmlFileLoaderTest.php
Expand Up @@ -183,6 +183,37 @@ public function testLoadImports()

// Bad import throws no exception due to ignore_errors value.
$loader->load('services4_bad_import.xml');

// Bad import with nonexistent file throws no exception due to ignore_errors: not_found value.
$loader->load('services4_bad_import_file_not_found.xml');

try {
$loader->load('services4_bad_import_with_errors.xml');
$this->fail('->load() throws a LoaderLoadException if the imported xml file configuration does not exist');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\\Component\\Config\\Exception\\LoaderLoadException', $e, '->load() throws a LoaderLoadException if the imported xml file configuration does not exist');
$this->assertRegExp(sprintf('#^The file "%1$s" does not exist \(in: .+\) in %1$s \(which is being imported from ".+%2$s"\)\.$#', 'foo_fake\.xml', 'services4_bad_import_with_errors\.xml'), $e->getMessage(), '->load() throws a LoaderLoadException if the imported xml file configuration does not exist');

$e = $e->getPrevious();
$this->assertInstanceOf('Symfony\\Component\\Config\\Exception\\FileLocatorFileNotFoundException', $e, '->load() throws a FileLocatorFileNotFoundException if the imported xml file configuration does not exist');
$this->assertRegExp(sprintf('#^The file "%s" does not exist \(in: .+\)\.$#', 'foo_fake\.xml'), $e->getMessage(), '->load() throws a FileLocatorFileNotFoundException if the imported xml file configuration does not exist');
}

try {
$loader->load('services4_bad_import_nonvalid.xml');
$this->fail('->load() throws an LoaderLoadException if the imported configuration does not validate the XSD');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\\Component\\Config\\Exception\\LoaderLoadException', $e, '->load() throws a LoaderLoadException if the imported configuration does not validate the XSD');
$this->assertRegExp(sprintf('#^Unable to parse file ".+%s": .+.$#', 'nonvalid\.xml'), $e->getMessage(), '->load() throws a LoaderLoadException if the imported configuration does not validate the XSD');

$e = $e->getPrevious();
$this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the configuration does not validate the XSD');
$this->assertRegExp(sprintf('#^Unable to parse file ".+%s": .+.$#', 'nonvalid\.xml'), $e->getMessage(), '->load() throws an InvalidArgumentException if the configuration does not validate the XSD');

$e = $e->getPrevious();
$this->assertInstanceOf('Symfony\\Component\\Config\\Util\\Exception\\XmlParsingException', $e, '->load() throws a XmlParsingException if the configuration does not validate the XSD');
$this->assertStringStartsWith('[ERROR 1845] Element \'nonvalid\': No matching global declaration available for the validation root. (in', $e->getMessage(), '->load() throws a XmlParsingException if the loaded file does not validate the XSD');
}
}

public function testLoadAnonymousServices()
Expand Down
27 changes: 27 additions & 0 deletions Tests/Loader/YamlFileLoaderTest.php
Expand Up @@ -135,6 +135,33 @@ public function testLoadImports()

// Bad import throws no exception due to ignore_errors value.
$loader->load('services4_bad_import.yml');

// Bad import with nonexistent file throws no exception due to ignore_errors: not_found value.
$loader->load('services4_bad_import_file_not_found.yml');

try {
$loader->load('services4_bad_import_with_errors.yml');
$this->fail('->load() throws a LoaderLoadException if the imported yaml file does not exist');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\\Component\\Config\\Exception\\LoaderLoadException', $e, '->load() throws a LoaderLoadException if the imported yaml file does not exist');
$this->assertRegExp(sprintf('#^The file "%1$s" does not exist \(in: .+\) in %1$s \(which is being imported from ".+%2$s"\)\.$#', 'foo_fake\.yml', 'services4_bad_import_with_errors\.yml'), $e->getMessage(), '->load() throws a LoaderLoadException if the imported yaml file does not exist');

$e = $e->getPrevious();
$this->assertInstanceOf('Symfony\\Component\\Config\\Exception\\FileLocatorFileNotFoundException', $e, '->load() throws a FileLocatorFileNotFoundException if the imported yaml file does not exist');
$this->assertRegExp(sprintf('#^The file "%s" does not exist \(in: .+\)\.$#', 'foo_fake\.yml'), $e->getMessage(), '->load() throws a FileLocatorFileNotFoundException if the imported yaml file does not exist');
}

try {
$loader->load('services4_bad_import_nonvalid.yml');
$this->fail('->load() throws a LoaderLoadException if the tag in the imported yaml file is not valid');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\\Component\\Config\\Exception\\LoaderLoadException', $e, '->load() throws a LoaderLoadException if the tag in the imported yaml file is not valid');
$this->assertRegExp(sprintf('#^The service file ".+%1$s" is not valid\. It should contain an array\. Check your YAML syntax in .+%1$s \(which is being imported from ".+%2$s"\)\.$#', 'nonvalid2\.yml', 'services4_bad_import_nonvalid.yml'), $e->getMessage(), '->load() throws a LoaderLoadException if the tag in the imported yaml file is not valid');

$e = $e->getPrevious();
$this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tag in the imported yaml file is not valid');
$this->assertRegExp(sprintf('#^The service file ".+%s" is not valid\. It should contain an array\. Check your YAML syntax\.$#', 'nonvalid2\.yml'), $e->getMessage(), '->load() throws an InvalidArgumentException if the tag in the imported yaml file is not valid');
}
}

public function testLoadServices()
Expand Down

0 comments on commit 2880986

Please sign in to comment.