From b9883a3bad9cbcd3c32b6d858ced952784fea67b Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 1 Apr 2011 18:55:11 -0500 Subject: [PATCH] [Config] Improving the exception when a resource cannot be imported This improves, for example, the exception one would receive if they tried to import a resource from a bundle that doesn't exist. Previously, the deep "bundle is not activated" exception would be thrown. That has value, however there is no indication of where the exception is actually occurring. In this new implementation, we throw an exception that explains exactly which resource, and from which source resource, cannot be loaded. The deeper exception is still thrown as a nested exception. Two caveats: * The `HttpKernel::varToString` method was replicated * This introduces a new `Exception` class, which allows us to prevent lot's of exceptions from nesting into each other in the case that some deeply imported resource cannot be imported (each upstream import that fails doesn't add its own exception). --- .../Exception/FileLoaderImportException.php | 63 +++++++++++++++++++ .../Component/Config/Loader/FileLoader.php | 10 ++- .../Loader/XmlFileLoader.php | 2 +- .../Loader/YamlFileLoader.php | 2 +- .../Routing/Loader/XmlFileLoader.php | 2 +- .../Routing/Loader/YamlFileLoader.php | 2 +- 6 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 src/Symfony/Component/Config/Exception/FileLoaderImportException.php diff --git a/src/Symfony/Component/Config/Exception/FileLoaderImportException.php b/src/Symfony/Component/Config/Exception/FileLoaderImportException.php new file mode 100644 index 0000000000..cfab0f5326 --- /dev/null +++ b/src/Symfony/Component/Config/Exception/FileLoaderImportException.php @@ -0,0 +1,63 @@ + + * + * 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 + */ +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)); + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Config/Loader/FileLoader.php b/src/Symfony/Component/Config/Loader/FileLoader.php index 3f6abfb68c..ad4f7c403d 100644 --- a/src/Symfony/Component/Config/Loader/FileLoader.php +++ b/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); } } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 8a639bf192..8c456a4782 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/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'], null, (Boolean) $import->getAttributeAsPhp('ignore-errors')); + $this->import((string) $import['resource'], null, (Boolean) $import->getAttributeAsPhp('ignore-errors'), $file); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 62d8a5993f..6e8d151d03 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/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'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false); + $this->import($import['resource'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false, $file); } } diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php index 1c7f5a9dc2..909fc65066 100644 --- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php +++ b/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)); diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php index 1f82f24c7b..c3d641d820 100644 --- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php +++ b/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 {