Skip to content

Commit

Permalink
[PropertyAccess] Show property path in all exception messages
Browse files Browse the repository at this point in the history
  • Loading branch information
mpajunen authored and fabpot committed Feb 4, 2015
1 parent 54e07c9 commit b286863
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 9 deletions.
22 changes: 22 additions & 0 deletions UPGRADE-2.7.md
Expand Up @@ -83,3 +83,25 @@ Serializer
$nameConverter = new CamelCaseToSnakeCaseNameConverter(array('fooBar', 'barFoo'));
$normalizer = new GetSetMethodNormalizer(null, $nameConverter);
```

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);
```
6 changes: 6 additions & 0 deletions src/Symfony/Component/PropertyAccess/CHANGELOG.md
@@ -1,6 +1,12 @@
CHANGELOG
=========

2.7.0
------

* `UnexpectedTypeException` now expects three constructor arguments: The invalid property value,
the `PropertyPathInterface` object and the current index of the property path.

2.5.0
------

Expand Down
Expand Up @@ -11,15 +11,40 @@

namespace Symfony\Component\PropertyAccess\Exception;

use Symfony\Component\PropertyAccess\PropertyPathInterface;

/**
* Thrown when a value does not match an expected type.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class UnexpectedTypeException extends RuntimeException
{
public function __construct($value, $expectedType)
/**
* @param mixed $value The unexpected value found while traversing property path
* @param PropertyPathInterface $path The property path
* @param int $pathIndex The property path index when the unexpected value was found
*/
public function __construct($value, $path, $pathIndex = null)
{
parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
if (func_num_args() === 3 && $path instanceof PropertyPathInterface) {
$message = sprintf(
'PropertyAccessor requires a graph of objects or arrays to operate on, '.
'but it found type "%s" while trying to traverse path "%s" at property "%s".',
gettype($value),
(string) $path,
$path->getElement($pathIndex)
);
} else {
trigger_error('The '.__CLASS__.' constructor now expects 3 arguments: the invalid property value, the '.__NAMESPACE__.'\PropertyPathInterface object and the current index of the property path.', E_USER_DEPRECATED);

$message = sprintf(
'Expected argument of type "%s", "%s" given',
$path,
is_object($value) ? get_class($value) : gettype($value)
);
}

parent::__construct($message);
}
}
4 changes: 2 additions & 2 deletions src/Symfony/Component/PropertyAccess/PropertyAccessor.php
Expand Up @@ -97,7 +97,7 @@ public function setValue(&$objectOrArray, $propertyPath, $value)

if ($overwrite) {
if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
throw new UnexpectedTypeException($objectOrArray, 'object or array');
throw new UnexpectedTypeException($objectOrArray, $propertyPath, $i);
}

$property = $propertyPath->getElement($i);
Expand Down Expand Up @@ -221,7 +221,7 @@ private function &readPropertiesUntil(&$objectOrArray, PropertyPathInterface $pr

for ($i = 0; $i < $lastIndex; ++$i) {
if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
throw new UnexpectedTypeException($objectOrArray, 'object or array');
throw new UnexpectedTypeException($objectOrArray, $propertyPath, $i);
}

$property = $propertyPath->getElement($i);
Expand Down
11 changes: 8 additions & 3 deletions src/Symfony/Component/PropertyAccess/PropertyPath.php
Expand Up @@ -11,9 +11,9 @@

namespace Symfony\Component\PropertyAccess;

use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException;
use Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException;
use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException;
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;

/**
* Default implementation of {@link PropertyPathInterface}.
Expand Down Expand Up @@ -70,7 +70,7 @@ class PropertyPath implements \IteratorAggregate, PropertyPathInterface
*
* @param PropertyPath|string $propertyPath The property path as string or instance
*
* @throws UnexpectedTypeException If the given path is not a string
* @throws InvalidArgumentException If the given path is not a string
* @throws InvalidPropertyPathException If the syntax of the property path is not valid
*/
public function __construct($propertyPath)
Expand All @@ -87,7 +87,12 @@ public function __construct($propertyPath)
return;
}
if (!is_string($propertyPath)) {
throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPath');
throw new InvalidArgumentException(sprintf(
'The property path constructor needs a string or an instance of '.
'"Symfony\Component\PropertyAccess\PropertyPath". '.
'Got: "%s"',
is_object($propertyPath) ? get_class($propertyPath) : gettype($propertyPath)
));
}

if ('' === $propertyPath) {
Expand Down
Expand Up @@ -139,6 +139,7 @@ public function testGetValueReadsMagicCallThatReturnsConstant()

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "string" while trying to traverse path "foobar" at property "foobar".
*/
public function testGetValueThrowsExceptionIfNotObjectOrArray()
{
Expand All @@ -147,6 +148,7 @@ public function testGetValueThrowsExceptionIfNotObjectOrArray()

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "NULL" while trying to traverse path "foobar" at property "foobar".
*/
public function testGetValueThrowsExceptionIfNull()
{
Expand All @@ -155,12 +157,22 @@ public function testGetValueThrowsExceptionIfNull()

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "string" while trying to traverse path "foobar" at property "foobar".
*/
public function testGetValueThrowsExceptionIfEmpty()
{
$this->propertyAccessor->getValue('', 'foobar');
}

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "NULL" while trying to traverse path "foobar.baz" at property "baz".
*/
public function testGetValueNestedExceptionMessage()
{
$this->propertyAccessor->getValue((object) array('foobar' => null), 'foobar.baz');
}

/**
* @dataProvider getValidPropertyPaths
*/
Expand Down Expand Up @@ -249,6 +261,7 @@ public function testSetValueUpdatesMagicCallIfEnabled()

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "string" while trying to traverse path "foobar" at property "foobar".
*/
public function testSetValueThrowsExceptionIfNotObjectOrArray()
{
Expand All @@ -259,6 +272,7 @@ public function testSetValueThrowsExceptionIfNotObjectOrArray()

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "NULL" while trying to traverse path "foobar" at property "foobar".
*/
public function testSetValueThrowsExceptionIfNull()
{
Expand All @@ -269,6 +283,7 @@ public function testSetValueThrowsExceptionIfNull()

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "string" while trying to traverse path "foobar" at property "foobar".
*/
public function testSetValueThrowsExceptionIfEmpty()
{
Expand All @@ -277,6 +292,17 @@ public function testSetValueThrowsExceptionIfEmpty()
$this->propertyAccessor->setValue($value, 'foobar', 'bam');
}

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedExceptionMessage PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "NULL" while trying to traverse path "foobar.baz" at property "baz".
*/
public function testSetValueNestedExceptionMessage()
{
$value = (object) array('foobar' => null);

$this->propertyAccessor->setValue($value, 'foobar.baz', 'bam');
}

public function testGetValueWhenArrayValueIsNull()
{
$this->propertyAccessor = new PropertyAccessor(false, true);
Expand Down
Expand Up @@ -69,15 +69,15 @@ public function testPathCannotBeEmpty()
}

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException
*/
public function testPathCannotBeNull()
{
new PropertyPath(null);
}

/**
* @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException
* @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException
*/
public function testPathCannotBeFalse()
{
Expand Down

0 comments on commit b286863

Please sign in to comment.