From 05fdae9e35b6010ef8b7aed3e5de136bd65ff3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 19:04:49 +0200 Subject: [PATCH 01/21] added a method for retrieving all indices --- src/EloquentModel.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/EloquentModel.php b/src/EloquentModel.php index fd90c3e..4c2ac2f 100644 --- a/src/EloquentModel.php +++ b/src/EloquentModel.php @@ -64,4 +64,10 @@ private function fill($type, $attributes) return $object; } + private function allIndices($type) + { + $object = new $type; + return $type->all()->get($object->primaryKey); + } + } From 21ef8d5bbf55fd62d8a3fa67d98ae8e96bc87ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 19:06:06 +0200 Subject: [PATCH 02/21] added a method to retrieve a random index of an existing entry, using model:FactoryName instead of factory:FactoryName for the foreign key --- src/Builder.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Builder.php b/src/Builder.php index d0d8f90..1ceadb9 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -139,6 +139,14 @@ protected function persist($name, array $attributes = []) return $entity; } + protected function existingIndex($name) + { + $indices = $this->model->allIndices($name); + $rand = mt_rand(0, count($indices)-1); + $index = $indices[$rand]; + return $index; + } + /** * Merge the fixture with any potential overrides. * @@ -284,6 +292,7 @@ protected function assignRelationships($entity, $attributes) foreach ($modelAttributes as $columnName => $value) { if ($relationship = $this->findRelation($value)) { + // $relationship is now our $matches array from findRelation $entity[$columnName] = $this->fetchRelationId($relationship, $columnName, $attributes); } } @@ -300,7 +309,8 @@ protected function assignRelationships($entity, $attributes) protected function findRelation($attribute) { if (is_string($attribute) && preg_match('/^factory:(.+)$/i', $attribute, $matches)) { - return $matches[1]; +// return $matches[1]; + return $matches; } return false; @@ -316,8 +326,19 @@ protected function findRelation($attribute) */ protected function fetchRelationId($factoryName, $relationshipName, array $attributes) { - $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); - $relationKey = $this->persist($factoryName, $attributes)->getKey(); + // $factoryName is our matches, containing both 'model:factoryName'/'factory:factoryName' and just the factoryName + $type = preg_replace('/' . $factoryName[1] . '/', '', $factoryName[0]); + switch ($type) { + case 'factory:': + $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); + $relationKey = $this->persist($factoryName[1], $attributes)->getKey(); + break; + case 'model:': +// $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); + $relationKey = $this->exists($relationshipName); + } +// $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); +// $relationKey = $this->persist($factoryName, $attributes)->getKey(); return $relationKey; } From eb492e938191c50b9213bdaf64bb23a476c244b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 19:07:37 +0200 Subject: [PATCH 03/21] added comment for existing post to test the ability to use an existing entry. The related model is currently not eager-loaded, I think, so I expect errors in further testing... --- tests/support/factories/factories.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/support/factories/factories.php b/tests/support/factories/factories.php index 4618dd5..549b1a3 100644 --- a/tests/support/factories/factories.php +++ b/tests/support/factories/factories.php @@ -24,6 +24,11 @@ 'body' => $faker->word ]); +$factory('Comment', 'comment_for_existing_post', [ + 'post_id' => 'model:Post', + 'body' => $faker->word +]); + $factory('Foo', function($faker) { return [ 'name' => $faker->word From d638bb11263cf1b99c21e504c01a1e2dd7b5c4e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 19:09:26 +0200 Subject: [PATCH 04/21] using $this for testing and added test to check if it can establish a relationship to an existing model --- tests/FactoryTest.php | 62 +++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/tests/FactoryTest.php b/tests/FactoryTest.php index 813cd88..bd108fc 100644 --- a/tests/FactoryTest.php +++ b/tests/FactoryTest.php @@ -64,8 +64,8 @@ public function it_builds_up_attributes_for_an_entity() { $attributes = TestDummy::build('Post'); - assertInstanceOf('Post', $attributes); - assertEquals('Post Title', $attributes->title); + $this->assertInstanceOf('Post', $attributes); + $this->assertEquals('Post Title', $attributes->title); } /** @test */ @@ -73,7 +73,7 @@ public function it_allows_for_overriding_attributes() { $post = TestDummy::build('Post', ['title' => 'override']); - assertEquals('override', $post->title); + $this->assertEquals('override', $post->title); } /** @test */ @@ -81,7 +81,7 @@ public function it_accepts_a_short_name_identifier_instead_of_the_model_class() { $post = TestDummy::build('scheduled_post'); - assertInstanceOf('Post', $post); + $this->assertInstanceOf('Post', $post); } /** @test */ @@ -89,11 +89,11 @@ public function it_allows_a_closure_to_be_used_for_defining_factories() { $comments = TestDummy::times(2)->create('Comment'); - assertInstanceOf('Comment', $comments[0]); - assertInternalType('string', $comments[0]->body); + $this->assertInstanceOf('Comment', $comments[0]); + $this->assertInternalType('string', $comments[0]->body); // Faker should produce a unique value for each generation. - assertNotEquals($comments[0]->body, $comments[1]->body); + $this->assertNotEquals($comments[0]->body, $comments[1]->body); } /** @test */ @@ -101,8 +101,8 @@ public function it_gets_an_array_only_of_attributes() { $attributes = TestDummy::attributesFor('Post', ['title' => 'override']); - assertInternalType('array', $attributes); - assertEquals('override', $attributes['title']); + $this->assertInternalType('array', $attributes); + $this->assertEquals('override', $attributes['title']); } /** @test */ @@ -110,8 +110,8 @@ public function it_builds_and_persists_attributes() { $post = TestDummy::create('Post'); - assertInstanceOf('Post', $post); - assertNotNull($post->id); + $this->assertInstanceOf('Post', $post); + $this->assertNotNull($post->id); } /** @test */ @@ -119,8 +119,8 @@ public function it_builds_up_relationships_if_specified() { $comment = TestDummy::create('Comment'); - assertInstanceOf('Comment', $comment); - assertInstanceOf('Post', $comment->post); + $this->assertInstanceOf('Comment', $comment); + $this->assertInstanceOf('Post', $comment->post); } /** @test */ @@ -128,8 +128,8 @@ public function it_can_build_and_persist_multiple_times() { $posts = TestDummy::times(3)->create('Post'); - assertInstanceOf('Illuminate\Support\Collection', $posts); - assertCount(3, $posts); + $this->assertInstanceOf('Illuminate\Support\Collection', $posts); + $this->assertCount(3, $posts); } /** @@ -154,7 +154,7 @@ public function it_overrides_relationship_attributes_if_specified() 'post_id.title' => 'override' ]); - assertEquals('override', $comment->post->title); + $this->assertEquals('override', $comment->post->title); } /** @test */ @@ -165,8 +165,8 @@ public function it_overrides_relationship_attributes_separately_for_relationship 'receiver_id.name' => 'Jeffrey', ]); - assertEquals('Adam', $message->sender->name); - assertEquals('Jeffrey', $message->receiver->name); + $this->assertEquals('Adam', $message->sender->name); + $this->assertEquals('Jeffrey', $message->receiver->name); } /** @test */ @@ -178,9 +178,9 @@ public function it_can_override_deeply_nested_relationships() 'post_id.author_id.name' => 'Overridden Author Name', ]); - assertEquals('Overridden Comment Body', $comment->body); - assertEquals('Overridden Post Title', $comment->post->title); - assertEquals('Overridden Author Name', $comment->post->author->name); + $this->assertEquals('Overridden Comment Body', $comment->body); + $this->assertEquals('Overridden Post Title', $comment->post->title); + $this->assertEquals('Overridden Author Name', $comment->post->author->name); } /** @test */ @@ -191,9 +191,25 @@ public function relationship_overrides_are_ignored_if_the_relationship_is_not_ac 'post_id.title' => 'override' ]); - assertNull($comment->post); - assertNull($comment->getAttribute('post_id.title')); + $this->assertNull($comment->post); + $this->assertNull($comment->getAttribute('post_id.title')); } + + /* Tests for using existing data + * @author Leo "Phroggyy" Sjöberg + */ + + /** @test */ + public function it_establishes_relationships_if_specified() + { + $post = TestDummy::create('Post'); + $comment = TestDummy::create('comment_for_existing_post'); + + $this->assertInstanceOf('Comment', $comment); + $this->assertInstanceOf('Post', $comment->post); + $this->assertEquals($post->id, $comment->post->id); + } + } function comment() From 29c8af7913d280d1dfcd4a922c18a826f57ccd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 20:43:23 +0200 Subject: [PATCH 05/21] corrected preg matching --- src/Builder.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Builder.php b/src/Builder.php index 1ceadb9..693095c 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -139,6 +139,11 @@ protected function persist($name, array $attributes = []) return $entity; } + protected function () + { + + } + protected function existingIndex($name) { $indices = $this->model->allIndices($name); @@ -296,7 +301,6 @@ protected function assignRelationships($entity, $attributes) $entity[$columnName] = $this->fetchRelationId($relationship, $columnName, $attributes); } } - return $entity; } @@ -308,7 +312,7 @@ protected function assignRelationships($entity, $attributes) */ protected function findRelation($attribute) { - if (is_string($attribute) && preg_match('/^factory:(.+)$/i', $attribute, $matches)) { + if (is_string($attribute) && (preg_match('/^factory:(.+)$/i', $attribute, $matches) || preg_match('/^model:(.+)$/i', $attribute, $matches))) { // return $matches[1]; return $matches; } @@ -334,8 +338,11 @@ protected function fetchRelationId($factoryName, $relationshipName, array $attri $relationKey = $this->persist($factoryName[1], $attributes)->getKey(); break; case 'model:': -// $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); - $relationKey = $this->exists($relationshipName); + $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); + $relationKey = $this->existingIndex($factoryName[1]); + break; + default: + throw new \Exception('Relation identifier not allowed. Please use model or factory.'); } // $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); // $relationKey = $this->persist($factoryName, $attributes)->getKey(); From 4bafcab32031a43c95dc6b695ba861cc10ce8000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 20:43:34 +0200 Subject: [PATCH 06/21] fixed allIndices --- src/EloquentModel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EloquentModel.php b/src/EloquentModel.php index 4c2ac2f..5a11df8 100644 --- a/src/EloquentModel.php +++ b/src/EloquentModel.php @@ -64,10 +64,10 @@ private function fill($type, $attributes) return $object; } - private function allIndices($type) + public function allIndices($type) { $object = new $type; - return $type->all()->get($object->primaryKey); + return $object->all()->lists($object->getKeyName())->toArray(); } } From 1df1af9722b458e78136b3c153395dd28816c6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 20:48:37 +0200 Subject: [PATCH 07/21] added random method to interface --- src/IsPersistable.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/IsPersistable.php b/src/IsPersistable.php index 9cec361..8ed5589 100644 --- a/src/IsPersistable.php +++ b/src/IsPersistable.php @@ -31,4 +31,6 @@ public function save($entity); */ public function getAttributes($entity); + public function random($type, array $attributes); + } From 97d860291a273f2bf5b8e2c1a40616badda92311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 20:48:48 +0200 Subject: [PATCH 08/21] added random and exists methods --- src/Builder.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Builder.php b/src/Builder.php index 693095c..43c93ce 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -139,9 +139,25 @@ protected function persist($name, array $attributes = []) return $entity; } - protected function () + protected function random($name, $overrides) { - + $attributes = $this->getAttributes($name, $overrides); + $class = $this->getFixture($name)->name; + + // We'll pass off the process of creating the entity. + // That way, folks can use different persistence layers. + + return $this->model->random($class, $attributes); + } + + protected function exists($name, $attributes) + { + $entity = $this->random($name, $attributes); + + $this->assignRelationships($entity, $attributes); + $this->model->save($entity); + + return $entity; } protected function existingIndex($name) From 1b9f7d25db2874a24a8644edd26305c9d84d83e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 20:52:08 +0200 Subject: [PATCH 09/21] added random and get random methods --- src/EloquentModel.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/EloquentModel.php b/src/EloquentModel.php index 5a11df8..dc598b3 100644 --- a/src/EloquentModel.php +++ b/src/EloquentModel.php @@ -24,6 +24,16 @@ public function build($type, array $attributes) return $this->fill($type, $attributes); } + + public function random($type, array $attributes) + { + if ( ! class_exists($type)) { + throw new TestDummyException("The {$type} model was not found."); + } + + return $this->getRandom($type); + } + /** * Persist the entity. * @@ -64,10 +74,12 @@ private function fill($type, $attributes) return $object; } - public function allIndices($type) + private function getRandom($type) { $object = new $type; - return $object->all()->lists($object->getKeyName())->toArray(); + $count = $type::count(); + $rand = mt_rand(0,$count-1); + return $object->all()[$rand]; } } From 21d3da108c38932def56d04408aba3817f611cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 22:31:59 +0200 Subject: [PATCH 10/21] removed existingIndex and made exists public --- src/Builder.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Builder.php b/src/Builder.php index 43c93ce..ddc0c09 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -150,7 +150,7 @@ protected function random($name, $overrides) return $this->model->random($class, $attributes); } - protected function exists($name, $attributes) + public function exists($name, $attributes) { $entity = $this->random($name, $attributes); @@ -160,14 +160,6 @@ protected function exists($name, $attributes) return $entity; } - protected function existingIndex($name) - { - $indices = $this->model->allIndices($name); - $rand = mt_rand(0, count($indices)-1); - $index = $indices[$rand]; - return $index; - } - /** * Merge the fixture with any potential overrides. * @@ -355,7 +347,7 @@ protected function fetchRelationId($factoryName, $relationshipName, array $attri break; case 'model:': $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); - $relationKey = $this->existingIndex($factoryName[1]); + $relationKey = $this->exists($factoryName[1], $attributes)->getKey(); break; default: throw new \Exception('Relation identifier not allowed. Please use model or factory.'); From f3573865dd776b5e1e136e342f17125feb82c4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 22:34:12 +0200 Subject: [PATCH 11/21] allowed overwriting attributes of existing posts --- src/EloquentModel.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/EloquentModel.php b/src/EloquentModel.php index dc598b3..c987833 100644 --- a/src/EloquentModel.php +++ b/src/EloquentModel.php @@ -31,7 +31,13 @@ public function random($type, array $attributes) throw new TestDummyException("The {$type} model was not found."); } - return $this->getRandom($type); + $model = $this->getRandom($type); + + Eloquent::unguard(); + $model->fill($attributes); + Eloquent::reguard(); + + return $model; } /** From a2472a5e97725408c35f0fc270a366da9235b420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 22:34:37 +0200 Subject: [PATCH 12/21] added new factories for testing purposes --- tests/support/factories/factories.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/support/factories/factories.php b/tests/support/factories/factories.php index 549b1a3..f5ec310 100644 --- a/tests/support/factories/factories.php +++ b/tests/support/factories/factories.php @@ -41,6 +41,18 @@ 'receiver_id' => 'factory:Person', ]); +$factory('Message', 'message_between_existing_people', [ + 'contents' => $faker->sentence, + 'sender_id' => 'model:Person', + 'receiver_id' => 'model:Person', +]); + +$factory('Message', 'message_between_existing_and_new_people', [ + 'contents' => $faker->sentence, + 'sender_id' => 'factory:Person', + 'receiver_id' => 'model:Person', +]); + $factory('Person', [ 'name' => $faker->name ]); From fe153e0e574b3266931d1c2d444f9f86db46fd17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 22:54:46 +0200 Subject: [PATCH 13/21] added existing keys to support excluding related models that have already been assigned (since a `factory:factoryName` attribute will create a new entry of `factoryName`, which might otherwise be taken by `model:factoryName`) --- src/Builder.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Builder.php b/src/Builder.php index ddc0c09..3d42857 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -139,7 +139,7 @@ protected function persist($name, array $attributes = []) return $entity; } - protected function random($name, $overrides) + protected function random($name, $overrides, array $existingKeys = []) { $attributes = $this->getAttributes($name, $overrides); $class = $this->getFixture($name)->name; @@ -147,12 +147,12 @@ protected function random($name, $overrides) // We'll pass off the process of creating the entity. // That way, folks can use different persistence layers. - return $this->model->random($class, $attributes); + return $this->model->random($class, $attributes, $existingKeys); } - public function exists($name, $attributes) + public function exists($name, $attributes, array $existingKeys = []) { - $entity = $this->random($name, $attributes); + $entity = $this->random($name, $attributes, $existingKeys); $this->assignRelationships($entity, $attributes); $this->model->save($entity); @@ -303,10 +303,12 @@ protected function assignRelationships($entity, $attributes) // to see if there are any defined relationships. If there // are, then we'll need to create those records as well. + $existing = []; + foreach ($modelAttributes as $columnName => $value) { if ($relationship = $this->findRelation($value)) { // $relationship is now our $matches array from findRelation - $entity[$columnName] = $this->fetchRelationId($relationship, $columnName, $attributes); + $existing[] = $entity[$columnName] = $this->fetchRelationId($relationship, $columnName, $attributes, $existing); } } return $entity; @@ -336,7 +338,7 @@ protected function findRelation($attribute) * @param array $attributes * @return int */ - protected function fetchRelationId($factoryName, $relationshipName, array $attributes) + protected function fetchRelationId($factoryName, $relationshipName, array $attributes, array $existingKeys) { // $factoryName is our matches, containing both 'model:factoryName'/'factory:factoryName' and just the factoryName $type = preg_replace('/' . $factoryName[1] . '/', '', $factoryName[0]); @@ -347,7 +349,7 @@ protected function fetchRelationId($factoryName, $relationshipName, array $attri break; case 'model:': $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); - $relationKey = $this->exists($factoryName[1], $attributes)->getKey(); + $relationKey = $this->exists($factoryName[1], $attributes, $existingKeys)->getKey(); break; default: throw new \Exception('Relation identifier not allowed. Please use model or factory.'); From 9cb9edb5eaa685b6731f569bfc500fcff432a78d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 22:55:57 +0200 Subject: [PATCH 14/21] now exclude the already taken keys when fetching a random existing model --- src/EloquentModel.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/EloquentModel.php b/src/EloquentModel.php index c987833..cb1fdb4 100644 --- a/src/EloquentModel.php +++ b/src/EloquentModel.php @@ -25,13 +25,13 @@ public function build($type, array $attributes) } - public function random($type, array $attributes) + public function random($type, array $attributes, array $existingKeys) { if ( ! class_exists($type)) { throw new TestDummyException("The {$type} model was not found."); } - $model = $this->getRandom($type); + $model = $this->getRandom($type, $existingKeys); Eloquent::unguard(); $model->fill($attributes); @@ -80,12 +80,12 @@ private function fill($type, $attributes) return $object; } - private function getRandom($type) + private function getRandom($type, array $existingKeys) { $object = new $type; - $count = $type::count(); + $count = $type::count() - count($existingKeys); $rand = mt_rand(0,$count-1); - return $object->all()[$rand]; + return $object->whereNotIn($object->getKeyName(), $existingKeys)->get()[$rand]; } } From 70826e49f2de32ff77ed4c4301da834d19f1855b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 22:56:10 +0200 Subject: [PATCH 15/21] added existing keys to interface --- src/IsPersistable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IsPersistable.php b/src/IsPersistable.php index 8ed5589..fb078a3 100644 --- a/src/IsPersistable.php +++ b/src/IsPersistable.php @@ -31,6 +31,6 @@ public function save($entity); */ public function getAttributes($entity); - public function random($type, array $attributes); + public function random($type, array $attributes, array $existingKeys); } From 046b57a3b420489c5001b7c92080aa7882e64d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 23:12:36 +0200 Subject: [PATCH 16/21] ensured a new instance is created if the user used the `model:factoryName` attribute without having existing data --- src/EloquentModel.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/EloquentModel.php b/src/EloquentModel.php index cb1fdb4..34afdbc 100644 --- a/src/EloquentModel.php +++ b/src/EloquentModel.php @@ -84,8 +84,11 @@ private function getRandom($type, array $existingKeys) { $object = new $type; $count = $type::count() - count($existingKeys); - $rand = mt_rand(0,$count-1); - return $object->whereNotIn($object->getKeyName(), $existingKeys)->get()[$rand]; + if ($count > 0) { + $rand = mt_rand(0,$count-1); + return $object->whereNotIn($object->getKeyName(), $existingKeys)->get()[$rand]; + } + return $object; } } From 391d4da03b880518af8413ec77c1c9f1e364e145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 23:18:52 +0200 Subject: [PATCH 17/21] set a default timezone to avoid errors about using get_default_timezone() --- tests/FactoryTest.php | 59 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/FactoryTest.php b/tests/FactoryTest.php index bd108fc..412eb20 100644 --- a/tests/FactoryTest.php +++ b/tests/FactoryTest.php @@ -8,6 +8,7 @@ class FactoryTest extends PHPUnit_Framework_TestCase public function setUp() { parent::setUp(); + date_default_timezone_set("Europe/Stockholm"); TestDummy::$factoriesPath = __DIR__ . '/support/factories'; @@ -210,6 +211,64 @@ public function it_establishes_relationships_if_specified() $this->assertEquals($post->id, $comment->post->id); } + /** @test */ + public function it_overrides_existing_relationship_attributes_if_specified() + { + $post = TestDummy::create('Post'); + $comment = TestDummy::create('comment_for_existing_post', [ + 'post_id.title' => 'override' + ]); + + $this->assertEquals('override', $comment->post->title); + } + + /** @test */ + public function it_overrides_existing_relationship_attributes_separately_for_relationships_that_use_the_same_factory() + { + TestDummy::times(2)->create('Person'); //We create 2 to ensure sender_id != receiver_id, since that will create an error + $message = TestDummy::create('message_between_existing_people', [ + 'sender_id.name' => 'Adam', + 'receiver_id.name' => 'Jeffrey', + ]); + + /* + * If the test fails, run again, you ran into a collision + */ + + $this->assertEquals('Adam', $message->sender->name); + $this->assertEquals('Jeffrey', $message->receiver->name); + } + + /** @test */ + public function it_handles_both_creating_new_relations_and_using_existing_ones_in_the_same_factory() + { + TestDummy::create('Person'); + $message = TestDummy::create('message_between_existing_and_new_people', [ + 'sender_id.name' => 'Adam', + 'receiver_id.name' => 'Jeffrey', + ]); + + $this->assertEquals('Adam', $message->sender->name); + $this->assertEquals('Jeffrey', $message->receiver->name); + } + + /** @test */ + public function it_can_override_deeply_nested_existing_relationships() + { + TestDummy::create('Person'); + TestDummy::create('post_by_existing_person'); + $comment = TestDummy::create('comment_for_existing_post_by_existing_person', [ + 'body' => 'Overridden Comment Body', + 'post_id.title' => 'Overridden Post Title', + 'post_id.author_id.name' => 'Overridden Author Name', + ]); + + $this->assertEquals('Overridden Comment Body', $comment->body); + $this->assertEquals('Overridden Post Title', $comment->post->title); + $this->assertEquals('Overridden Author Name', $comment->post->author->name); + } + + } function comment() From f9483b68f3b32b3a73a337113b50432d204dead6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 23:19:13 +0200 Subject: [PATCH 18/21] added the `post_by_existing_person` factory --- tests/support/factories/factories.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/support/factories/factories.php b/tests/support/factories/factories.php index f5ec310..790fbf7 100644 --- a/tests/support/factories/factories.php +++ b/tests/support/factories/factories.php @@ -9,6 +9,11 @@ 'title' => 'Post Title' ]); +$factory('Post', 'post_by_existing_person', [ + 'author_id' => 'model:Person', + 'title' => 'Post Title' +]); + $factory('Comment', function($faker) { return [ @@ -29,6 +34,11 @@ 'body' => $faker->word ]); +$factory('Comment', 'comment_for_existing_post_by_existing_person', [ + 'post_id' => 'model:post_by_existing_person', + 'body' => $faker->word +]); + $factory('Foo', function($faker) { return [ 'name' => $faker->word From 3edf5f1b6a74c025b3ee6f2476830f38d3ba63a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 23:33:31 +0200 Subject: [PATCH 19/21] added test case to check if it still works multiple times when using existing data --- tests/FactoryTest.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/FactoryTest.php b/tests/FactoryTest.php index 412eb20..c7c24ba 100644 --- a/tests/FactoryTest.php +++ b/tests/FactoryTest.php @@ -231,10 +231,6 @@ public function it_overrides_existing_relationship_attributes_separately_for_rel 'receiver_id.name' => 'Jeffrey', ]); - /* - * If the test fails, run again, you ran into a collision - */ - $this->assertEquals('Adam', $message->sender->name); $this->assertEquals('Jeffrey', $message->receiver->name); } @@ -268,6 +264,26 @@ public function it_can_override_deeply_nested_existing_relationships() $this->assertEquals('Overridden Author Name', $comment->post->author->name); } + /** @test */ + public function it_creates_models_if_no_existing_are_found() + { + $comment = TestDummy::create('comment_for_existing_post'); + + $this->assertInstanceOf('Comment', $comment); + $this->assertInstanceOf('Post', $comment->post); + } + + /** @test */ + public function it_can_create_and_persist_multiple_times_with_existing() + { + $posts = TestDummy::times(3)->create('post_by_existing_person'); + + $this->assertInstanceOf('Illuminate\Support\Collection', $posts); + $this->assertCount(3, $posts); + // Since we have no existing person the first time, it will be automatically created, but only once... + $this->assertEquals($posts[0]->author, $posts[1]->author); + } + } From a1a3be38472258e500cc00d800a9420e8b691dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 23:44:45 +0200 Subject: [PATCH 20/21] added docblocks --- src/Builder.php | 21 ++++++++++++++++++--- src/EloquentModel.php | 16 ++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Builder.php b/src/Builder.php index 3d42857..f4c1b3d 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -139,6 +139,15 @@ protected function persist($name, array $attributes = []) return $entity; } + /** + * Fetch a random existing entity, or create a new one + * + * @param $name + * @param $overrides + * @param array $existingKeys + * @return mixed + * @throws TestDummyException + */ protected function random($name, $overrides, array $existingKeys = []) { $attributes = $this->getAttributes($name, $overrides); @@ -150,6 +159,13 @@ protected function random($name, $overrides, array $existingKeys = []) return $this->model->random($class, $attributes, $existingKeys); } + /** + * Assign relationships to a randomly fetched entity + * @param $name + * @param $attributes + * @param array $existingKeys + * @return mixed + */ public function exists($name, $attributes, array $existingKeys = []) { $entity = $this->random($name, $attributes, $existingKeys); @@ -323,7 +339,6 @@ protected function assignRelationships($entity, $attributes) protected function findRelation($attribute) { if (is_string($attribute) && (preg_match('/^factory:(.+)$/i', $attribute, $matches) || preg_match('/^model:(.+)$/i', $attribute, $matches))) { -// return $matches[1]; return $matches; } @@ -336,7 +351,9 @@ protected function findRelation($attribute) * @param string $factoryName * @param string $relationshipName * @param array $attributes + * @param array $existingKeys * @return int + * @throws \Exception */ protected function fetchRelationId($factoryName, $relationshipName, array $attributes, array $existingKeys) { @@ -354,8 +371,6 @@ protected function fetchRelationId($factoryName, $relationshipName, array $attri default: throw new \Exception('Relation identifier not allowed. Please use model or factory.'); } -// $attributes = $this->extractRelationshipAttributes($relationshipName, $attributes); -// $relationKey = $this->persist($factoryName, $attributes)->getKey(); return $relationKey; } diff --git a/src/EloquentModel.php b/src/EloquentModel.php index 34afdbc..0a991fe 100644 --- a/src/EloquentModel.php +++ b/src/EloquentModel.php @@ -25,6 +25,14 @@ public function build($type, array $attributes) } + /** + * Get a random entity and fill any override attributes + * @param $type + * @param array $attributes + * @param array $existingKeys + * @return mixed + * @throws TestDummyException + */ public function random($type, array $attributes, array $existingKeys) { if ( ! class_exists($type)) { @@ -80,6 +88,14 @@ private function fill($type, $attributes) return $object; } + /** + * Fetch a random entity from the database which is not already in use + * If none exists, create a new one + * + * @param $type + * @param array $existingKeys + * @return mixed + */ private function getRandom($type, array $existingKeys) { $object = new $type; From 23b5a92ce4950ee40940f65b2aee3595e28c64e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sjo=CC=88berg?= Date: Sat, 23 May 2015 23:45:50 +0200 Subject: [PATCH 21/21] added a test to assert that we never receive the same related child entity for two relationships on one parent entity --- tests/FactoryTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/FactoryTest.php b/tests/FactoryTest.php index c7c24ba..9fa69da 100644 --- a/tests/FactoryTest.php +++ b/tests/FactoryTest.php @@ -284,6 +284,14 @@ public function it_can_create_and_persist_multiple_times_with_existing() $this->assertEquals($posts[0]->author, $posts[1]->author); } + /** @test */ + public function it_will_create_a_new_when_two_are_required_but_only_one_exists() + { + TestDummy::create('Person'); //We create 2 to ensure sender_id != receiver_id, since that will create an error + $message = TestDummy::create('message_between_existing_people'); + + $this->assertNotEquals($message->sender, $message->receiver); + } }