[PropertyAccess] Simplified code

This commit is contained in:
Bernhard Schussek 2014-10-22 19:11:55 +02:00
parent 27d717e7f0
commit b712ac1174
3 changed files with 49 additions and 69 deletions

View File

@ -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));
}
$camelProp = $this->camelize($property);
$camelized = $this->camelize($property);
$reflClass = new \ReflectionClass($object);
$getter = 'get'.$camelProp;
$getter2 = lcfirst($camelProp);
$isser = 'is'.$camelProp;
$hasser = 'has'.$camelProp;
$getter = 'get'.$camelized;
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
$isser = 'is'.$camelized;
$hasser = 'has'.$camelized;
$classHasProperty = $reflClass->hasProperty($property);
if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) {
$result[self::VALUE] = $object->$getter();
} elseif ($this->isMethodAccessible($reflClass, $getter2, 0)) {
$result[self::VALUE] = $object->$getter2();
} elseif ($this->isMethodAccessible($reflClass, $getsetter, 0)) {
$result[self::VALUE] = $object->$getsetter();
} elseif ($reflClass->hasMethod($isser) && $reflClass->getMethod($isser)->isPublic()) {
$result[self::VALUE] = $object->$isser();
} 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
$result[self::VALUE] = $object->$getter();
} else {
$methods = array($getter, $getter2, $isser, $hasser, '__get');
$methods = array($getter, $getsetter, $isser, $hasser, '__get');
if ($this->magicCall) {
$methods[] = '__call';
}
@ -416,8 +416,8 @@ class PropertyAccessor implements PropertyAccessorInterface
}
$reflClass = new \ReflectionClass($object);
$plural = $this->camelize($property);
$singulars = (array) StringUtil::singularify($plural);
$camelized = $this->camelize($property);
$singulars = (array) StringUtil::singularify($camelized);
if (is_array($value) || $value instanceof \Traversable) {
$methods = $this->findAdderAndRemover($reflClass, $singulars);
@ -430,14 +430,14 @@ class PropertyAccessor implements PropertyAccessorInterface
}
}
$setter = 'set'.$this->camelize($property);
$setter2 = lcfirst($plural);
$setter = 'set'.$camelized;
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
$classHasProperty = $reflClass->hasProperty($property);
if ($this->isMethodAccessible($reflClass, $setter, 1)) {
$object->$setter($value);
} elseif ($this->isMethodAccessible($reflClass, $setter2, 1)) {
$object->$setter2($value);
} elseif ($this->isMethodAccessible($reflClass, $getsetter, 1)) {
$object->$getsetter($value);
} elseif ($this->isMethodAccessible($reflClass, '__set', 2)) {
$object->$property = $value;
} elseif ($classHasProperty && $reflClass->getProperty($property)->isPublic()) {
@ -461,7 +461,7 @@ class PropertyAccessor implements PropertyAccessorInterface
return '"add'.$singular.'()"/"remove'.$singular.'()", ';
}, $singulars)),
$setter,
$setter2,
$getsetter,
$reflClass->name
));
}
@ -529,12 +529,13 @@ class PropertyAccessor implements PropertyAccessorInterface
$reflClass = new \ReflectionClass($object);
$setter = 'set'.$this->camelize($property);
$setter2 = lcfirst($this->camelize($property));
$camelized = $this->camelize($property);
$setter = 'set'.$camelized;
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
$classHasProperty = $reflClass->hasProperty($property);
if ($this->isMethodAccessible($reflClass, $setter, 1)
|| $this->isMethodAccessible($reflClass, $setter2, 1)
|| $this->isMethodAccessible($reflClass, $getsetter, 1)
|| $this->isMethodAccessible($reflClass, '__set', 2)
|| ($classHasProperty && $reflClass->getProperty($property)->isPublic())
|| (!$classHasProperty && property_exists($object, $property))
@ -542,11 +543,9 @@ class PropertyAccessor implements PropertyAccessorInterface
return true;
}
$plural = $this->camelize($property);
$singulars = (array) StringUtil::singularify($camelized);
// Any of the two methods is required, but not yet known
$singulars = (array) StringUtil::singularify($plural);
if (null !== $this->findAdderAndRemover($reflClass, $singulars)) {
return true;
}
@ -563,7 +562,7 @@ class PropertyAccessor implements PropertyAccessorInterface
*/
private function camelize($string)
{
return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $string);
return strtr(ucwords(strtr($string, array('_' => ' '))), array(' ' => ''));
}
/**

View File

@ -19,7 +19,7 @@ class TestClass
private $publicAccessor;
private $publicMethodAccessor;
private $publicMethodMutator;
private $publicGetSetter;
private $publicAccessorWithDefaultValue;
private $publicAccessorWithRequiredAndDefaultValue;
private $publicAccessorWithMoreRequiredParameters;
@ -31,7 +31,7 @@ class TestClass
$this->publicProperty = $value;
$this->publicAccessor = $value;
$this->publicMethodAccessor = $value;
$this->publicMethodMutator = $value;
$this->publicGetSetter = $value;
$this->publicAccessorWithDefaultValue = $value;
$this->publicAccessorWithRequiredAndDefaultValue = $value;
$this->publicAccessorWithMoreRequiredParameters = $value;
@ -99,19 +99,18 @@ class TestClass
return $this->publicHasAccessor;
}
public function publicMethodAccessor()
public function publicGetSetter($value = null)
{
return $this->publicMethodAccessor;
}
if (null !== $value) {
$this->publicGetSetter = $value;
}
public function publicMethodMutator($value)
{
$this->publicMethodMutator = $value;
return $this->publicGetSetter;
}
public function getPublicMethodMutator()
{
return $this->publicMethodMutator;
return $this->publicGetSetter;
}
protected function setProtectedAccessor($value)

View File

@ -28,26 +28,6 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
$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()
{
return array(
@ -80,7 +60,7 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
}
/**
* @dataProvider getValidGetPropertyPaths
* @dataProvider getValidPropertyPaths
*/
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)
{
@ -297,7 +277,7 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
}
/**
* @dataProvider getValidGetPropertyPaths
* @dataProvider getValidPropertyPaths
*/
public function testIsReadable($objectOrArray, $path)
{
@ -365,11 +345,11 @@ class PropertyAccessorTest extends \PHPUnit_Framework_TestCase
}
/**
* @dataProvider getValidSetPropertyPaths
* @dataProvider getValidPropertyPaths
*/
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)
{
$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)
{
// 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);
// 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()
{
$this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicGet('Bernhard'), 'magicProperty', 'Updated'));
$this->assertTrue($this->propertyAccessor->isWritable(new TestClassMagicGet('Bernhard'), 'magicProperty'));
}
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()
{
$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(
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'), 'publicIsAccessor', 'Bernhard'),
array(new TestClass('Bernhard'), 'publicHasAccessor', 'Bernhard'),
array(new TestClass('Bernhard'), 'publicGetSetter', 'Bernhard'),
// Methods are camelized
array(new TestClass('Bernhard'), 'public_accessor', 'Bernhard'),
array(new TestClass('Bernhard'), '_public_accessor', 'Bernhard'),
// Missing indices
array(array('index' => array()), '[index][firstName]', null),