[PropertyAccess] Simplified code
This commit is contained in:
parent
27d717e7f0
commit
b712ac1174
@ -326,18 +326,18 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
|
throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property));
|
||||||
}
|
}
|
||||||
|
|
||||||
$camelProp = $this->camelize($property);
|
$camelized = $this->camelize($property);
|
||||||
$reflClass = new \ReflectionClass($object);
|
$reflClass = new \ReflectionClass($object);
|
||||||
$getter = 'get'.$camelProp;
|
$getter = 'get'.$camelized;
|
||||||
$getter2 = lcfirst($camelProp);
|
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
|
||||||
$isser = 'is'.$camelProp;
|
$isser = 'is'.$camelized;
|
||||||
$hasser = 'has'.$camelProp;
|
$hasser = 'has'.$camelized;
|
||||||
$classHasProperty = $reflClass->hasProperty($property);
|
$classHasProperty = $reflClass->hasProperty($property);
|
||||||
|
|
||||||
if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) {
|
if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) {
|
||||||
$result[self::VALUE] = $object->$getter();
|
$result[self::VALUE] = $object->$getter();
|
||||||
} elseif ($this->isMethodAccessible($reflClass, $getter2, 0)) {
|
} elseif ($this->isMethodAccessible($reflClass, $getsetter, 0)) {
|
||||||
$result[self::VALUE] = $object->$getter2();
|
$result[self::VALUE] = $object->$getsetter();
|
||||||
} elseif ($reflClass->hasMethod($isser) && $reflClass->getMethod($isser)->isPublic()) {
|
} elseif ($reflClass->hasMethod($isser) && $reflClass->getMethod($isser)->isPublic()) {
|
||||||
$result[self::VALUE] = $object->$isser();
|
$result[self::VALUE] = $object->$isser();
|
||||||
} elseif ($reflClass->hasMethod($hasser) && $reflClass->getMethod($hasser)->isPublic()) {
|
} elseif ($reflClass->hasMethod($hasser) && $reflClass->getMethod($hasser)->isPublic()) {
|
||||||
@ -359,7 +359,7 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
// we call the getter and hope the __call do the job
|
// we call the getter and hope the __call do the job
|
||||||
$result[self::VALUE] = $object->$getter();
|
$result[self::VALUE] = $object->$getter();
|
||||||
} else {
|
} else {
|
||||||
$methods = array($getter, $getter2, $isser, $hasser, '__get');
|
$methods = array($getter, $getsetter, $isser, $hasser, '__get');
|
||||||
if ($this->magicCall) {
|
if ($this->magicCall) {
|
||||||
$methods[] = '__call';
|
$methods[] = '__call';
|
||||||
}
|
}
|
||||||
@ -416,8 +416,8 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
$reflClass = new \ReflectionClass($object);
|
$reflClass = new \ReflectionClass($object);
|
||||||
$plural = $this->camelize($property);
|
$camelized = $this->camelize($property);
|
||||||
$singulars = (array) StringUtil::singularify($plural);
|
$singulars = (array) StringUtil::singularify($camelized);
|
||||||
|
|
||||||
if (is_array($value) || $value instanceof \Traversable) {
|
if (is_array($value) || $value instanceof \Traversable) {
|
||||||
$methods = $this->findAdderAndRemover($reflClass, $singulars);
|
$methods = $this->findAdderAndRemover($reflClass, $singulars);
|
||||||
@ -430,14 +430,14 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$setter = 'set'.$this->camelize($property);
|
$setter = 'set'.$camelized;
|
||||||
$setter2 = lcfirst($plural);
|
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
|
||||||
$classHasProperty = $reflClass->hasProperty($property);
|
$classHasProperty = $reflClass->hasProperty($property);
|
||||||
|
|
||||||
if ($this->isMethodAccessible($reflClass, $setter, 1)) {
|
if ($this->isMethodAccessible($reflClass, $setter, 1)) {
|
||||||
$object->$setter($value);
|
$object->$setter($value);
|
||||||
} elseif ($this->isMethodAccessible($reflClass, $setter2, 1)) {
|
} elseif ($this->isMethodAccessible($reflClass, $getsetter, 1)) {
|
||||||
$object->$setter2($value);
|
$object->$getsetter($value);
|
||||||
} elseif ($this->isMethodAccessible($reflClass, '__set', 2)) {
|
} elseif ($this->isMethodAccessible($reflClass, '__set', 2)) {
|
||||||
$object->$property = $value;
|
$object->$property = $value;
|
||||||
} elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
|
} elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
|
||||||
@ -461,7 +461,7 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
return '"add'.$singular.'()"/"remove'.$singular.'()", ';
|
return '"add'.$singular.'()"/"remove'.$singular.'()", ';
|
||||||
}, $singulars)),
|
}, $singulars)),
|
||||||
$setter,
|
$setter,
|
||||||
$setter2,
|
$getsetter,
|
||||||
$reflClass->name
|
$reflClass->name
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -529,12 +529,13 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
|
|
||||||
$reflClass = new \ReflectionClass($object);
|
$reflClass = new \ReflectionClass($object);
|
||||||
|
|
||||||
$setter = 'set'.$this->camelize($property);
|
$camelized = $this->camelize($property);
|
||||||
$setter2 = lcfirst($this->camelize($property));
|
$setter = 'set'.$camelized;
|
||||||
|
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
|
||||||
$classHasProperty = $reflClass->hasProperty($property);
|
$classHasProperty = $reflClass->hasProperty($property);
|
||||||
|
|
||||||
if ($this->isMethodAccessible($reflClass, $setter, 1)
|
if ($this->isMethodAccessible($reflClass, $setter, 1)
|
||||||
|| $this->isMethodAccessible($reflClass, $setter2, 1)
|
|| $this->isMethodAccessible($reflClass, $getsetter, 1)
|
||||||
|| $this->isMethodAccessible($reflClass, '__set', 2)
|
|| $this->isMethodAccessible($reflClass, '__set', 2)
|
||||||
|| ($classHasProperty && $reflClass->getProperty($property)->isPublic())
|
|| ($classHasProperty && $reflClass->getProperty($property)->isPublic())
|
||||||
|| (!$classHasProperty && property_exists($object, $property))
|
|| (!$classHasProperty && property_exists($object, $property))
|
||||||
@ -542,11 +543,9 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$plural = $this->camelize($property);
|
$singulars = (array) StringUtil::singularify($camelized);
|
||||||
|
|
||||||
// Any of the two methods is required, but not yet known
|
// Any of the two methods is required, but not yet known
|
||||||
$singulars = (array) StringUtil::singularify($plural);
|
|
||||||
|
|
||||||
if (null !== $this->findAdderAndRemover($reflClass, $singulars)) {
|
if (null !== $this->findAdderAndRemover($reflClass, $singulars)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -563,7 +562,7 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
*/
|
*/
|
||||||
private function camelize($string)
|
private function camelize($string)
|
||||||
{
|
{
|
||||||
return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $string);
|
return strtr(ucwords(strtr($string, array('_' => ' '))), array(' ' => ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +19,7 @@ class TestClass
|
|||||||
|
|
||||||
private $publicAccessor;
|
private $publicAccessor;
|
||||||
private $publicMethodAccessor;
|
private $publicMethodAccessor;
|
||||||
private $publicMethodMutator;
|
private $publicGetSetter;
|
||||||
private $publicAccessorWithDefaultValue;
|
private $publicAccessorWithDefaultValue;
|
||||||
private $publicAccessorWithRequiredAndDefaultValue;
|
private $publicAccessorWithRequiredAndDefaultValue;
|
||||||
private $publicAccessorWithMoreRequiredParameters;
|
private $publicAccessorWithMoreRequiredParameters;
|
||||||
@ -31,7 +31,7 @@ class TestClass
|
|||||||
$this->publicProperty = $value;
|
$this->publicProperty = $value;
|
||||||
$this->publicAccessor = $value;
|
$this->publicAccessor = $value;
|
||||||
$this->publicMethodAccessor = $value;
|
$this->publicMethodAccessor = $value;
|
||||||
$this->publicMethodMutator = $value;
|
$this->publicGetSetter = $value;
|
||||||
$this->publicAccessorWithDefaultValue = $value;
|
$this->publicAccessorWithDefaultValue = $value;
|
||||||
$this->publicAccessorWithRequiredAndDefaultValue = $value;
|
$this->publicAccessorWithRequiredAndDefaultValue = $value;
|
||||||
$this->publicAccessorWithMoreRequiredParameters = $value;
|
$this->publicAccessorWithMoreRequiredParameters = $value;
|
||||||
@ -99,19 +99,18 @@ class TestClass
|
|||||||
return $this->publicHasAccessor;
|
return $this->publicHasAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function publicMethodAccessor()
|
public function publicGetSetter($value = null)
|
||||||
{
|
{
|
||||||
return $this->publicMethodAccessor;
|
if (null !== $value) {
|
||||||
|
$this->publicGetSetter = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function publicMethodMutator($value)
|
return $this->publicGetSetter;
|
||||||
{
|
|
||||||
$this->publicMethodMutator = $value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPublicMethodMutator()
|
public function getPublicMethodMutator()
|
||||||
{
|
{
|
||||||
return $this->publicMethodMutator;
|
return $this->publicGetSetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function setProtectedAccessor($value)
|
protected function setProtectedAccessor($value)
|
||||||
|
@ -28,26 +28,6 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->propertyAccessor = new PropertyAccessor();
|
$this->propertyAccessor = new PropertyAccessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValidGetPropertyPaths()
|
|
||||||
{
|
|
||||||
return array_merge(
|
|
||||||
array(
|
|
||||||
array(new TestClass('Bernhard'), 'publicMethodAccessor', 'Bernhard', 'Bernhard'),
|
|
||||||
),
|
|
||||||
$this->getValidPropertyPaths()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getValidSetPropertyPaths()
|
|
||||||
{
|
|
||||||
return array_merge(
|
|
||||||
array(
|
|
||||||
array(new TestClass('Bernhard'), 'publicMethodMutator', 'Bernhard', 'Bernhard'),
|
|
||||||
),
|
|
||||||
$this->getValidPropertyPaths()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPathsWithMissingProperty()
|
public function getPathsWithMissingProperty()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
@ -80,7 +60,7 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getValidGetPropertyPaths
|
* @dataProvider getValidPropertyPaths
|
||||||
*/
|
*/
|
||||||
public function testGetValue($objectOrArray, $path, $value)
|
public function testGetValue($objectOrArray, $path, $value)
|
||||||
{
|
{
|
||||||
@ -181,7 +161,7 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getValidSetPropertyPaths
|
* @dataProvider getValidPropertyPaths
|
||||||
*/
|
*/
|
||||||
public function testSetValue($objectOrArray, $path)
|
public function testSetValue($objectOrArray, $path)
|
||||||
{
|
{
|
||||||
@ -297,7 +277,7 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getValidGetPropertyPaths
|
* @dataProvider getValidPropertyPaths
|
||||||
*/
|
*/
|
||||||
public function testIsReadable($objectOrArray, $path)
|
public function testIsReadable($objectOrArray, $path)
|
||||||
{
|
{
|
||||||
@ -365,11 +345,11 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getValidSetPropertyPaths
|
* @dataProvider getValidPropertyPaths
|
||||||
*/
|
*/
|
||||||
public function testIsWritable($objectOrArray, $path)
|
public function testIsWritable($objectOrArray, $path)
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path, 'Updated'));
|
$this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -377,7 +357,7 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
public function testIsWritableReturnsFalseIfPropertyNotFound($objectOrArray, $path)
|
public function testIsWritableReturnsFalseIfPropertyNotFound($objectOrArray, $path)
|
||||||
{
|
{
|
||||||
$this->assertFalse($this->propertyAccessor->isWritable($objectOrArray, $path, 'Updated'));
|
$this->assertFalse($this->propertyAccessor->isWritable($objectOrArray, $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -386,7 +366,7 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testIsWritableReturnsTrueIfIndexNotFound($objectOrArray, $path)
|
public function testIsWritableReturnsTrueIfIndexNotFound($objectOrArray, $path)
|
||||||
{
|
{
|
||||||
// Non-existing indices can be written. Arrays are created on-demand.
|
// Non-existing indices can be written. Arrays are created on-demand.
|
||||||
$this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path, 'Updated'));
|
$this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -397,42 +377,42 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->propertyAccessor = new PropertyAccessor(false, true);
|
$this->propertyAccessor = new PropertyAccessor(false, true);
|
||||||
|
|
||||||
// Non-existing indices can be written even if exceptions are enabled
|
// Non-existing indices can be written even if exceptions are enabled
|
||||||
$this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path, 'Updated'));
|
$this->assertTrue($this->propertyAccessor->isWritable($objectOrArray, $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsWritableRecognizesMagicSet()
|
public function testIsWritableRecognizesMagicSet()
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicGet('Bernhard'), 'magicProperty', 'Updated'));
|
$this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicGet('Bernhard'), 'magicProperty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsWritableDoesNotRecognizeMagicCallByDefault()
|
public function testIsWritableDoesNotRecognizeMagicCallByDefault()
|
||||||
{
|
{
|
||||||
$this->assertFalse($this->propertyAccessor->isWritable(new TestClassMagicCall('Bernhard'), 'magicCallProperty', 'Updated'));
|
$this->assertFalse($this->propertyAccessor->isWritable(new TestClassMagicCall('Bernhard'), 'magicCallProperty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsWritableRecognizesMagicCallIfEnabled()
|
public function testIsWritableRecognizesMagicCallIfEnabled()
|
||||||
{
|
{
|
||||||
$this->propertyAccessor = new PropertyAccessor(true);
|
$this->propertyAccessor = new PropertyAccessor(true);
|
||||||
|
|
||||||
$this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicCall('Bernhard'), 'magicCallProperty', 'Updated'));
|
$this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicCall('Bernhard'), 'magicCallProperty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsWritableThrowsExceptionIfNotObjectOrArray()
|
public function testNotObjectOrArrayIsNotWritable()
|
||||||
{
|
{
|
||||||
$this->assertFalse($this->propertyAccessor->isWritable('baz', 'foobar', 'Updated'));
|
$this->assertFalse($this->propertyAccessor->isWritable('baz', 'foobar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsWritableThrowsExceptionIfNull()
|
public function testNullIsNotWritable()
|
||||||
{
|
{
|
||||||
$this->assertFalse($this->propertyAccessor->isWritable(null, 'foobar', 'Updated'));
|
$this->assertFalse($this->propertyAccessor->isWritable(null, 'foobar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsWritableThrowsExceptionIfEmpty()
|
public function testEmptyIsNotWritable()
|
||||||
{
|
{
|
||||||
$this->assertFalse($this->propertyAccessor->isWritable('', 'foobar', 'Updated'));
|
$this->assertFalse($this->propertyAccessor->isWritable('', 'foobar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getValidPropertyPaths()
|
public function getValidPropertyPaths()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(array('Bernhard', 'Schussek'), '[0]', 'Bernhard'),
|
array(array('Bernhard', 'Schussek'), '[0]', 'Bernhard'),
|
||||||
@ -451,9 +431,11 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
|
|||||||
array(new TestClass('Bernhard'), 'publicAccessorWithRequiredAndDefaultValue', 'Bernhard'),
|
array(new TestClass('Bernhard'), 'publicAccessorWithRequiredAndDefaultValue', 'Bernhard'),
|
||||||
array(new TestClass('Bernhard'), 'publicIsAccessor', 'Bernhard'),
|
array(new TestClass('Bernhard'), 'publicIsAccessor', 'Bernhard'),
|
||||||
array(new TestClass('Bernhard'), 'publicHasAccessor', 'Bernhard'),
|
array(new TestClass('Bernhard'), 'publicHasAccessor', 'Bernhard'),
|
||||||
|
array(new TestClass('Bernhard'), 'publicGetSetter', 'Bernhard'),
|
||||||
|
|
||||||
// Methods are camelized
|
// Methods are camelized
|
||||||
array(new TestClass('Bernhard'), 'public_accessor', 'Bernhard'),
|
array(new TestClass('Bernhard'), 'public_accessor', 'Bernhard'),
|
||||||
|
array(new TestClass('Bernhard'), '_public_accessor', 'Bernhard'),
|
||||||
|
|
||||||
// Missing indices
|
// Missing indices
|
||||||
array(array('index' => array()), '[index][firstName]', null),
|
array(array('index' => array()), '[index][firstName]', null),
|
||||||
|
Reference in New Issue
Block a user