From 535ae65e5e52b7453f8b8bf1d2c5b47468a5c70b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 29 Jul 2018 16:00:13 +0200 Subject: [PATCH] Utilities > Reflection > setPropertyValue() method > sets value of given property --- CHANGELOG.md | 1 + .../NotExistingPropertyException.php | 33 +++++++ src/Utilities/Reflection.php | 33 +++++++ tests/Utilities/ReflectionTest.php | 87 +++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 src/Exception/Reflection/NotExistingPropertyException.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0da62..e8177d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Common and useful classes, methods, exceptions etc. 1. Documentation > Value Objects 2. Docker > improve performance +3. Utilities > Reflection > setPropertyValue() method > sets value of given property # 0.1.1 diff --git a/src/Exception/Reflection/NotExistingPropertyException.php b/src/Exception/Reflection/NotExistingPropertyException.php new file mode 100644 index 0000000..4b7484f --- /dev/null +++ b/src/Exception/Reflection/NotExistingPropertyException.php @@ -0,0 +1,33 @@ + + * @copyright Meritoo + */ +class NotExistingPropertyException extends \Exception +{ + /** + * Creates exception + * + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * @return NotExistingPropertyException + */ + public static function create($object, $property) + { + $template = 'Property \'%s\' does not exist in instance of class \'%s\'. Did you use proper name of property?'; + $message = sprintf($template, $property, get_class($object)); + + return new static($message); + } +} diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 2487159..b03a0bd 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -13,6 +13,7 @@ use Doctrine\Common\Util\Inflector; use Meritoo\Common\Collection\Collection; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; +use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; use Meritoo\Common\Exception\Reflection\TooManyChildClassesException; /** @@ -659,4 +660,36 @@ class Reflection return $parentClass->getName(); } + + /** + * Sets value of given property + * + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * @param mixed $value Value of the property + * @throws NotExistingPropertyException + */ + public static function setPropertyValue($object, $property, $value) + { + $reflectionProperty = self::getProperty($object, $property); + + /* + * Oops, property does not exist + */ + if (null === $reflectionProperty) { + throw NotExistingPropertyException::create($object, $property); + } + + $notAccessible = $reflectionProperty->isPrivate() || $reflectionProperty->isProtected(); + + if ($notAccessible) { + $reflectionProperty->setAccessible(true); + } + + $reflectionProperty->setValue($object, $value); + + if ($notAccessible) { + $reflectionProperty->setAccessible(false); + } + } } diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 06df8e8..69ce170 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -13,6 +13,7 @@ use Generator; use Meritoo\Common\Collection\Collection; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; +use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; use Meritoo\Common\Exception\Reflection\TooManyChildClassesException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Test\Utilities\Reflection\A; @@ -474,6 +475,37 @@ class ReflectionTest extends BaseTestCase static::assertEquals('name', $property->getName()); } + /** + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * + * @dataProvider provideObjectAndNotExistingProperty + */ + public function testSetPropertyValueUsingNotExistingProperty($object, $property) + { + $this->setExpectedException(NotExistingPropertyException::class); + + $object = new \stdClass(); + Reflection::setPropertyValue($object, 'test', 'test test test'); + } + + /** + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * @param mixed $value Value of the property + * + * @dataProvider provideObjectPropertyAndValue + */ + public function testSetPropertyValue($object, $property, $value) + { + $oldValue = Reflection::getPropertyValue($object, $property); + Reflection::setPropertyValue($object, $property, $value); + $newValue = Reflection::getPropertyValue($object, $property); + + static::assertNotSame($oldValue, $value); + static::assertSame($newValue, $value); + } + /** * Provides invalid class and trait * @@ -501,4 +533,59 @@ class ReflectionTest extends BaseTestCase [], ]; } + + /** + * Provides object and name of not existing property + * + * @return Generator + */ + public function provideObjectAndNotExistingProperty() + { + yield[ + new \stdClass(), + 'test', + ]; + + yield[ + new A(), + 'test', + ]; + + yield[ + new B(), + 'firstName', + ]; + } + + /** + * Provides object, name of property and value of the property + * + * @return Generator + */ + public function provideObjectPropertyAndValue() + { + yield[ + new A(), + 'count', + 123, + ]; + + yield[ + new B(), + 'name', + 'test test', + ]; + + yield[ + new G(), + 'firstName', + 'Jane', + ]; + + yield[ + new G(), + 'lastName', + 'Smith', + ]; + } }