[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).
This commit is contained in:
Ryan Weaver 2011-04-01 18:55:11 -05:00
parent 65ac5ec7c0
commit b9883a3bad
6 changed files with 75 additions and 6 deletions

View File

@ -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));
}
}

View File

@ -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,8 +64,13 @@ abstract class FileLoader extends Loader
return $loader->load($resource);
} catch (\Exception $e) {
if (!$ignoreErrors) {
// prevent embedded imports from nesting multiple exceptions
if ($e instanceof FileLoaderImportException) {
throw $e;
}
throw new FileLoaderImportException($resource, $sourceResource, null, $e);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));

View File

@ -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 {