From f054e3c71e88691cc5dcc04a6fbc50122231cb3c Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Mon, 28 Sep 2020 08:02:03 -0400 Subject: [PATCH 1/2] [bug] allow array callables in Proxy::executeCallback() --- src/Proxy.php | 2 +- tests/Unit/ProxyTest.php | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Proxy.php b/src/Proxy.php index 5550332d2..67234900a 100644 --- a/src/Proxy.php +++ b/src/Proxy.php @@ -222,7 +222,7 @@ public function assertNotPersisted(string $message = 'The object is persisted bu public function executeCallback(callable $callback, ...$arguments): void { $object = $this; - $parameters = (new \ReflectionFunction($callback))->getParameters(); + $parameters = (new \ReflectionFunction(\Closure::fromCallable($callback)))->getParameters(); if (isset($parameters[0]) && $parameters[0]->getType() && $this->class === $parameters[0]->getType()->getName()) { $object = $object->object(); diff --git a/tests/Unit/ProxyTest.php b/tests/Unit/ProxyTest.php index d248f2f5b..2cbb50923 100644 --- a/tests/Unit/ProxyTest.php +++ b/tests/Unit/ProxyTest.php @@ -106,8 +106,46 @@ public function can_use_without_auto_refresh_with_proxy_or_object_typehint(): vo ->withoutAutoRefresh(static function() use (&$calls) { ++$calls; }) + ->withoutAutoRefresh([$this, 'functionWithProxy']) + ->withoutAutoRefresh([$this, 'functionWithObject']) + ->withoutAutoRefresh([$this, 'functionWithNoTypeHint']) + ->withoutAutoRefresh([self::class, 'staticFunctionWithProxy']) + ->withoutAutoRefresh([self::class, 'staticFunctionWithObject']) + ->withoutAutoRefresh([self::class, 'staticFunctionWithNoTypeHint']) ; $this->assertSame(4, $calls); } + + public function functionWithProxy(Proxy $proxy) + { + $this->assertInstanceOf(Category::class, $proxy->object()); + } + + public function functionWithObject(Category $category) + { + $this->assertInstanceOf(Category::class, $category); + } + + public function functionWithNoTypeHint($proxy) + { + $this->assertInstanceOf(Proxy::class, $proxy); + $this->assertInstanceOf(Category::class, $proxy->object()); + } + + public static function staticFunctionWithProxy(Proxy $proxy) + { + self::assertInstanceOf(Category::class, $proxy->object()); + } + + public static function staticFunctionWithObject(Category $category) + { + self::assertInstanceOf(Category::class, $category); + } + + public static function staticFunctionWithNoTypeHint($proxy) + { + self::assertInstanceOf(Proxy::class, $proxy); + self::assertInstanceOf(Category::class, $proxy->object()); + } } From 118186deddae1a76feaeadfba99a294dc9026145 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Mon, 28 Sep 2020 08:11:52 -0400 Subject: [PATCH 2/2] [bug] ensure all attributes passed to afterPersist events (fixes #31) --- src/Factory.php | 68 +++++++++++++++++--------------------- tests/Unit/FactoryTest.php | 18 +++++----- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/src/Factory.php b/src/Factory.php index e2588787a..87220e6bd 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -49,7 +49,36 @@ public function __construct(string $class, $defaultAttributes = []) */ final public function create($attributes = []): Proxy { - $proxy = new Proxy($this->instantiate($attributes)); + // merge the factory attribute set with the passed attributes + $attributeSet = \array_merge($this->attributeSet, [$attributes]); + + // normalize each attribute set and collapse + $attributes = \array_merge(...\array_map([$this, 'normalizeAttributes'], $attributeSet)); + + foreach ($this->beforeInstantiate as $callback) { + $attributes = $callback($attributes); + + if (!\is_array($attributes)) { + throw new \LogicException('Before Instantiate event callback must return an array.'); + } + } + + // filter each attribute to convert proxies and factories to objects + $attributes = \array_map( + function($value) { + return $this->normalizeAttribute($value); + }, + $attributes + ); + + // instantiate the object with the users instantiator or if not set, the default instantiator + $object = ($this->instantiator ?? self::configuration()->instantiator())($attributes, $this->class); + + foreach ($this->afterInstantiate as $callback) { + $callback($object, $attributes); + } + + $proxy = new Proxy($object); if (!$this->persist) { return $proxy; @@ -181,43 +210,6 @@ private static function normalizeAttributes($attributes): array return \is_callable($attributes) ? $attributes(self::faker()) : $attributes; } - /** - * @param array|callable $attributes - */ - private function instantiate($attributes): object - { - // merge the factory attribute set with the passed attributes - $attributeSet = \array_merge($this->attributeSet, [$attributes]); - - // normalize each attribute set and collapse - $attributes = \array_merge(...\array_map([$this, 'normalizeAttributes'], $attributeSet)); - - foreach ($this->beforeInstantiate as $callback) { - $attributes = $callback($attributes); - - if (!\is_array($attributes)) { - throw new \LogicException('Before Instantiate event callback must return an array.'); - } - } - - // filter each attribute to convert proxies and factories to objects - $attributes = \array_map( - function($value) { - return $this->normalizeAttribute($value); - }, - $attributes - ); - - // instantiate the object with the users instantiator or if not set, the default instantiator - $object = ($this->instantiator ?? self::configuration()->instantiator())($attributes, $this->class); - - foreach ($this->afterInstantiate as $callback) { - $callback($object, $attributes); - } - - return $object; - } - /** * @param mixed $value * diff --git a/tests/Unit/FactoryTest.php b/tests/Unit/FactoryTest.php index f7d2650f2..9700c1693 100644 --- a/tests/Unit/FactoryTest.php +++ b/tests/Unit/FactoryTest.php @@ -303,25 +303,25 @@ public function can_add_after_persist_events(): void $this->configuration->setManagerRegistry($registry); - $attributesArray = ['title' => 'title', 'body' => 'body']; + $expectedAttributes = ['short_description' => 'short desc', 'title' => 'title', 'body' => 'body']; $calls = 0; - $object = (new Factory(Post::class)) - ->afterPersist(function(Proxy $post, array $attributes) use ($attributesArray, &$calls) { + $object = (new Factory(Post::class, ['short_description' => 'short desc'])) + ->afterPersist(function(Proxy $post, array $attributes) use ($expectedAttributes, &$calls) { /* @var Post $post */ - $this->assertSame($attributesArray, $attributes); + $this->assertSame($expectedAttributes, $attributes); $post->increaseViewCount(); ++$calls; }) - ->afterPersist(function(Post $post, array $attributes) use ($attributesArray, &$calls) { - $this->assertSame($attributesArray, $attributes); + ->afterPersist(function(Post $post, array $attributes) use ($expectedAttributes, &$calls) { + $this->assertSame($expectedAttributes, $attributes); $post->increaseViewCount(); ++$calls; }) - ->afterPersist(function(Post $post, array $attributes) use ($attributesArray, &$calls) { - $this->assertSame($attributesArray, $attributes); + ->afterPersist(function(Post $post, array $attributes) use ($expectedAttributes, &$calls) { + $this->assertSame($expectedAttributes, $attributes); $post->increaseViewCount(); ++$calls; @@ -334,7 +334,7 @@ public function can_add_after_persist_events(): void ->afterPersist(static function() use (&$calls) { ++$calls; }) - ->create($attributesArray) + ->create(['title' => 'title', 'body' => 'body']) ; $this->assertSame(3, $object->getViewCount());