ソースを参照

Merge remote branch 'weaverryan/better_import_exception_and_bug_fix'

* weaverryan/better_import_exception_and_bug_fix:
  [Config] Improving the exception when a resource cannot be imported
  [DependencyInjection] Fixing a bug where "ignore_errors" doesn't work in YAML and XML
Fabien Potencier 14 年 前
コミット
53274512e2

+ 63 - 0
src/Symfony/Component/Config/Exception/FileLoaderImportException.php

@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Exception;
+
+/**
+ * Exception class for when a resource cannot be imported.
+ *
+ * @author Ryan Weaver <ryan@thatsquality.com>
+ */
+class FileLoaderImportException extends \Exception
+{
+    /**
+     * @param  string    $resource The resource that could not be imported
+     * @param  string    $sourceResource The original resource importing the new resource
+     * @param  integer   $code     The error code
+     * @param  Exception $previous A previous exception
+     */
+    public function __construct($resource, $sourceResource, $code = null, $previous = null)
+    {
+        if (null === $sourceResource) {
+            $message = sprintf('Cannot import resource "%s".', $this->varToString($resource));
+        } else {
+            $message = sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource));
+        }
+
+        parent::__construct($message, $code, $previous);
+    }
+
+    private function varToString($var)
+    {
+        if (is_object($var)) {
+            return sprintf('[object](%s)', get_class($var));
+        }
+
+        if (is_array($var)) {
+            $a = array();
+            foreach ($var as $k => $v) {
+                $a[] = sprintf('%s => %s', $k, $this->varToString($v));
+            }
+
+            return sprintf("[array](%s)", implode(', ', $a));
+        }
+
+        if (is_resource($var)) {
+            return '[resource]';
+        }
+
+        if (null === $var) {
+            return 'null';
+        }
+
+        return str_replace("\n", '', var_export((string) $var, true));
+    }
+}

+ 8 - 2
src/Symfony/Component/Config/Loader/FileLoader.php

@@ -12,6 +12,7 @@
 namespace Symfony\Component\Config\Loader;
 
 use Symfony\Component\Config\FileLocatorInterface;
+use Symfony\Component\Config\Exception\FileLoaderImportException;
 
 /**
  * FileLoader is the abstract class used by all built-in loaders that are file based.
@@ -51,7 +52,7 @@ abstract class FileLoader extends Loader
      *
      * @return mixed
      */
-    public function import($resource, $type = null, $ignoreErrors = false)
+    public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
     {
         try {
             $loader = $this->resolve($resource, $type);
@@ -63,7 +64,12 @@ abstract class FileLoader extends Loader
             return $loader->load($resource);
         } catch (\Exception $e) {
             if (!$ignoreErrors) {
-                throw $e;
+                // prevent embedded imports from nesting multiple exceptions
+                if ($e instanceof FileLoaderImportException) {
+                    throw $e;
+                }
+
+                throw new FileLoaderImportException($resource, $sourceResource, null, $e);
             }
         }
     }

+ 1 - 1
src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

@@ -107,7 +107,7 @@ class XmlFileLoader extends FileLoader
 
         foreach ($imports as $import) {
             $this->setCurrentDir(dirname($file));
-            $this->import((string) $import['resource'], (Boolean) $import->getAttributeAsPhp('ignore-errors'));
+            $this->import((string) $import['resource'], null, (Boolean) $import->getAttributeAsPhp('ignore-errors'), $file);
         }
     }
 

+ 1 - 1
src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

@@ -97,7 +97,7 @@ class YamlFileLoader extends FileLoader
 
         foreach ($content['imports'] as $import) {
             $this->setCurrentDir(dirname($file));
-            $this->import($import['resource'], isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false);
+            $this->import($import['resource'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false, $file);
         }
     }
 

+ 1 - 1
src/Symfony/Component/Routing/Loader/XmlFileLoader.php

@@ -57,7 +57,7 @@ class XmlFileLoader extends FileLoader
                     $type = (string) $node->getAttribute('type');
                     $prefix = (string) $node->getAttribute('prefix');
                     $this->setCurrentDir(dirname($path));
-                    $collection->addCollection($this->import($resource, ('' !== $type ? $type : null)), $prefix);
+                    $collection->addCollection($this->import($resource, ('' !== $type ? $type : null), false, $file), $prefix);
                     break;
                 default:
                     throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName));

+ 1 - 1
src/Symfony/Component/Routing/Loader/YamlFileLoader.php

@@ -64,7 +64,7 @@ class YamlFileLoader extends FileLoader
                 $type = isset($config['type']) ? $config['type'] : null;
                 $prefix = isset($config['prefix']) ? $config['prefix'] : null;
                 $this->setCurrentDir(dirname($path));
-                $collection->addCollection($this->import($config['resource'], $type), $prefix);
+                $collection->addCollection($this->import($config['resource'], $type, false, $file), $prefix);
             } elseif (isset($config['pattern'])) {
                 $this->parseRoute($collection, $name, $config, $path);
             } else {

+ 9 - 0
tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/services4_bad_import.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 http://symfony.com/schema/dic/services/services-1.0.xsd">
+  <imports>
+    <import resource="foo_fake.xml" ignore-errors="true" />
+  </imports>
+</container>

+ 2 - 0
tests/Symfony/Tests/Component/DependencyInjection/Fixtures/yaml/services4_bad_import.yml

@@ -0,0 +1,2 @@
+imports:
+  - { resource: foo_fake.yml, ignore_errors: true }

+ 3 - 0
tests/Symfony/Tests/Component/DependencyInjection/Loader/XmlFileLoaderTest.php

@@ -104,6 +104,9 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
         $expected = array('a string', 'foo' => 'bar', 'values' => array(true, false), 'foo_bar' => new Reference('foo_bar'), 'mixedcase' => array('MixedCaseKey' => 'value'), 'bar' => '%foo%', 'imported_from_ini' => true, 'imported_from_yaml' => true);
 
         $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files');
+
+        // Bad import throws no exception due to ignore_errors value.
+        $loader->load('services4_bad_import.xml');
     }
 
     public function testLoadAnonymousServices()

+ 3 - 0
tests/Symfony/Tests/Component/DependencyInjection/Loader/YamlFileLoaderTest.php

@@ -90,6 +90,9 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
         $actual = $container->getParameterBag()->all();
         $expected = array('foo' => 'bar', 'values' => array(true, false), 'bar' => '%foo%', 'foo_bar' => new Reference('foo_bar'), 'mixedcase' => array('MixedCaseKey' => 'value'), 'imported_from_ini' => true, 'imported_from_xml' => true);
         $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files');
+
+        // Bad import throws no exception due to ignore_errors value.
+        $loader->load('services4_bad_import.yml');
     }
 
     public function testLoadServices()