From 1abd0dd9f60e8f1451916f86e240b0bd1ecf6042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 5 Jul 2016 16:15:42 +0200 Subject: [PATCH] Adding setter injection --- src/TdbmHydrator.php | 106 +++++++++++++++++++++++++++++------- tests/Fixtures/FixtureA.php | 19 ++++++- tests/Fixtures/FixtureB.php | 26 +++++++++ tests/TdbmHydratorTest.php | 31 ++++++++++- 4 files changed, 157 insertions(+), 25 deletions(-) create mode 100644 tests/Fixtures/FixtureB.php diff --git a/src/TdbmHydrator.php b/src/TdbmHydrator.php index f8a376c..b1a5de8 100644 --- a/src/TdbmHydrator.php +++ b/src/TdbmHydrator.php @@ -5,6 +5,7 @@ use Stringy\StaticStringy; +use function Stringy\create as s; class TdbmHydrator implements Hydrator { @@ -19,40 +20,52 @@ class TdbmHydrator implements Hydrator public function hydrateNewObject(array $data, string $className) { $reflectionClass = new \ReflectionClass($className); - $constructor = $reflectionClass->getConstructor(); - $constructorParameters = $constructor->getParameters(); + $underscoredData = $this->underscoreData($data); + $parameters = []; - $underscoredData = []; - foreach ($data as $key => $value) { - $underscoredData[(string) StaticStringy::underscored($key)] = $value; - } + $constructor = $reflectionClass->getConstructor(); - $parameters = []; + if ($constructor !== null) { + $constructorParameters = $constructor->getParameters(); - foreach ($constructorParameters as $constructorParameter) { - $underscoredVariableName = (string) StaticStringy::underscored($constructorParameter->getName()); + foreach ($constructorParameters as $constructorParameter) { + $underscoredVariableName = (string) StaticStringy::underscored($constructorParameter->getName()); - if (array_key_exists($underscoredVariableName, $underscoredData)) { - $value = $underscoredData[$underscoredVariableName]; - unset($underscoredData[$underscoredVariableName]); - } else { - if (!$constructorParameter->isDefaultValueAvailable()) { - throw MissingParameterException::create($constructorParameter->getName()); + if (array_key_exists($underscoredVariableName, $underscoredData)) { + $value = $underscoredData[$underscoredVariableName]; + unset($underscoredData[$underscoredVariableName]); + } else { + if (!$constructorParameter->isDefaultValueAvailable()) { + throw MissingParameterException::create($constructorParameter->getName()); + } + $value = $constructorParameter->getDefaultValue(); } - $value = $constructorParameter->getDefaultValue(); - } - // TODO: check if sub object! - $parameters[] = $value; + // TODO: check if sub object! + $parameters[] = $value; + } } $object = $reflectionClass->newInstanceArgs($parameters); - $this->hydrateObject($data, $object); + $this->hydrateObjectFromUnderscoredData($underscoredData, $object); return $object; } + /** + * Underscores the keys of the array. + * + * @param array $data + */ + private function underscoreData(array $data) + { + $underscoredData = []; + foreach ($data as $key => $value) { + $underscoredData[(string) StaticStringy::underscored($key)] = $value; + } + return $underscoredData; + } /** * Fills $object with $data. @@ -62,6 +75,57 @@ public function hydrateNewObject(array $data, string $className) */ public function hydrateObject(array $data, $object) { - // TODO + $underscoredData = $this->underscoreData($data); + $this->hydrateObjectFromUnderscoredData($underscoredData, $object); + } + + private function hydrateObjectFromUnderscoredData(array $underscoredData, $object) + { + $reflectionClass = new \ReflectionClass($object); + + $setters = $this->getSetters($reflectionClass); + + foreach ($setters as $underscoredName => $setter) { + + if (array_key_exists($underscoredName, $underscoredData)) { + $value = $underscoredData[$underscoredName]; + unset($underscoredData[$underscoredName]); + $setterName = $setter->getName(); + + $object->$setterName($value); + } + + // TODO: check if sub object! + } + } + + /** + * Returns an array of setters reflection methods, indexed by "underscored" name. + * + * @param \ReflectionClass $reflectionClass + * @return \ReflectionMethod[] + */ + private function getSetters(\ReflectionClass $reflectionClass) { + $reflectionMethods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC); + + $setters = []; + + foreach ($reflectionMethods as $reflectionMethod) { + $methodName = s($reflectionMethod->getName()); + $parameters = $reflectionMethod->getParameters(); + if ($methodName->startsWith('set') && count($parameters) >= 1) { + // Let's check that the setter has no more than 1 compulsory parameter. + array_shift($parameters); + foreach ($parameters as $optionalParameters) { + if (!$optionalParameters->isDefaultValueAvailable()) { + continue 2; + } + } + $underscored = (string) $methodName->substr(3)->underscored(); + $setters[$underscored] = $reflectionMethod; + } + } + + return $setters; } } diff --git a/tests/Fixtures/FixtureA.php b/tests/Fixtures/FixtureA.php index d9bf6cc..0782e2b 100644 --- a/tests/Fixtures/FixtureA.php +++ b/tests/Fixtures/FixtureA.php @@ -9,6 +9,7 @@ class FixtureA private $one; private $two; private $three; + private $four; /** * FixtureA constructor. @@ -52,7 +53,23 @@ public function getThree() */ public function setThree($three) { - $this->three = $three; + throw new \Exception('This should never be called.'); } + /** + * @return mixed + */ + public function getFour() + { + return $this->four; + } + + /** + * @param mixed $four + */ + public function setFour($four) + { + $this->four = $four; + } + } diff --git a/tests/Fixtures/FixtureB.php b/tests/Fixtures/FixtureB.php new file mode 100644 index 0000000..0cc6013 --- /dev/null +++ b/tests/Fixtures/FixtureB.php @@ -0,0 +1,26 @@ +one; + } + + /** + * @param mixed $one + */ + public function setOne($one, $two) + { + $this->one = $one; + } +} diff --git a/tests/TdbmHydratorTest.php b/tests/TdbmHydratorTest.php index 0f51078..69bea95 100644 --- a/tests/TdbmHydratorTest.php +++ b/tests/TdbmHydratorTest.php @@ -1,25 +1,26 @@ hydrateNewObject([ 'one' => 1, 'two' => 2, + 'four' => 4 ], FixtureA::class); /** @var $a FixtureA */ $this->assertEquals(1, $a->getOne()); $this->assertEquals(2, $a->getTwo()); $this->assertEquals(3, $a->getThree()); + $this->assertEquals(4, $a->getFour()); } public function testHydrateNull() @@ -44,6 +45,30 @@ public function testMissingCompulsoryParameter() $hydrator->hydrateNewObject([ 'one' => 1, ], FixtureA::class); + } + public function testNoHydrateSettersWithMultipleValues() + { + $hydrator = new TdbmHydrator(); + $b = $hydrator->hydrateNewObject([ + 'one' => 1, + ], FixtureB::class); + + /** @var $b FixtureB */ + $this->assertEquals(null, $b->getOne()); } + + public function testHydrate() + { + $hydrator = new TdbmHydrator(); + $a = new FixtureA(1 , 2); + + $hydrator->hydrateObject([ + 'four' => 4 + ], $a); + + /** @var $a FixtureA */ + $this->assertEquals(4, $a->getFour()); + } + }