From f2c68cefd6b059d2d9b472024fce2dbe8b64dd69 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Mon, 19 Feb 2024 23:18:19 +0800 Subject: [PATCH] Add BelongsToMany, HasMany and HasOne tests --- tests/Database/Fixtures/Author.php | 36 +- tests/Database/Fixtures/EventLog.php | 60 +++ tests/Database/Fixtures/NullablePost.php | 20 + tests/Database/Fixtures/Phone.php | 57 +++ tests/Database/Fixtures/Post.php | 10 + tests/Database/Fixtures/RevisionablePost.php | 53 +++ tests/Database/Fixtures/Role.php | 79 ++++ tests/Database/Fixtures/SluggablePost.php | 21 + tests/Database/Fixtures/SoftDeleteAuthor.php | 8 + tests/Database/Fixtures/Tag.php | 72 ++++ tests/Database/Fixtures/User.php | 70 ++++ tests/Database/Fixtures/ValidateablePost.php | 18 + .../Database/Relations/BelongsToManyTest.php | 372 ++++++++++++++++++ tests/Database/Relations/HasManyTest.php | 220 +++++++++++ tests/Database/Relations/HasOneTest.php | 245 ++++++++++++ 15 files changed, 1332 insertions(+), 9 deletions(-) create mode 100644 tests/Database/Fixtures/EventLog.php create mode 100644 tests/Database/Fixtures/NullablePost.php create mode 100644 tests/Database/Fixtures/Phone.php create mode 100644 tests/Database/Fixtures/RevisionablePost.php create mode 100644 tests/Database/Fixtures/Role.php create mode 100644 tests/Database/Fixtures/SluggablePost.php create mode 100644 tests/Database/Fixtures/SoftDeleteAuthor.php create mode 100644 tests/Database/Fixtures/Tag.php create mode 100644 tests/Database/Fixtures/User.php create mode 100644 tests/Database/Fixtures/ValidateablePost.php create mode 100644 tests/Database/Relations/BelongsToManyTest.php create mode 100644 tests/Database/Relations/HasManyTest.php create mode 100644 tests/Database/Relations/HasOneTest.php diff --git a/tests/Database/Fixtures/Author.php b/tests/Database/Fixtures/Author.php index f0c0efce..160e1596 100644 --- a/tests/Database/Fixtures/Author.php +++ b/tests/Database/Fixtures/Author.php @@ -4,6 +4,9 @@ use Illuminate\Database\Schema\Builder; use Winter\Storm\Database\Model; +use Winter\Storm\Database\Relations\BelongsToMany; +use Winter\Storm\Database\Relations\HasMany; +use Winter\Storm\Database\Relations\HasOne; class Author extends Model { @@ -33,23 +36,18 @@ class Author extends Model ]; public $hasOne = [ - 'phone' => 'Database\Tester\Models\Phone', + 'phone' => Phone::class, ]; public $belongsToMany = [ 'roles' => [ - 'Database\Tester\Models\Role', + 'Winter\Storm\Tests\Database\Fixtures\Role', 'table' => 'database_tester_authors_roles' ], - 'executive_authors' => [ - 'Database\Tester\Models\Role', - 'table' => 'database_tester_authors_roles', - 'conditions' => 'is_executive = 1' - ], ]; public $morphMany = [ - 'event_log' => ['Database\Tester\Models\EventLog', 'name' => 'related', 'delete' => true, 'softDelete' => true], + 'event_log' => [EventLog::class, 'name' => 'related', 'delete' => true, 'softDelete' => true], ]; public $morphOne = [ @@ -58,13 +56,33 @@ class Author extends Model public $morphToMany = [ 'tags' => [ - 'Database\Tester\Models\Tag', + Tag::class, 'name' => 'taggable', 'table' => 'database_tester_taggables', 'pivot' => ['added_by'] ], ]; + public function contactNumber(): HasOne + { + return $this->hasOne(Phone::class); + } + + public function messages(): HasMany + { + return $this->hasMany(Post::class); + } + + public function scopes(): BelongsToMany + { + return $this->belongsToMany(Role::class, 'database_tester_authors_roles'); + } + + public function executiveAuthors(): BelongsToMany + { + return $this->belongsToMany(Role::class, 'database_tester_authors_roles')->wherePivot('is_executive', 1); + } + public static function migrateUp(Builder $builder): void { if ($builder->hasTable('database_tester_authors')) { diff --git a/tests/Database/Fixtures/EventLog.php b/tests/Database/Fixtures/EventLog.php new file mode 100644 index 00000000..24e0450a --- /dev/null +++ b/tests/Database/Fixtures/EventLog.php @@ -0,0 +1,60 @@ + [] + ]; + + public static function migrateUp(Builder $builder): void + { + if ($builder->hasTable('database_tester_event_log')) { + return; + } + + $builder->create('database_tester_event_log', function ($table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('action', 30)->nullable(); + $table->string('related_id')->index()->nullable(); + $table->string('related_type')->index()->nullable(); + $table->softDeletes(); + $table->timestamps(); + }); + } + + public static function migrateDown(Builder $builder): void + { + if (!$builder->hasTable('database_tester_event_log')) { + return; + } + + $builder->dropIfExists('database_tester_event_log'); + } +} diff --git a/tests/Database/Fixtures/NullablePost.php b/tests/Database/Fixtures/NullablePost.php new file mode 100644 index 00000000..bd9a8b1e --- /dev/null +++ b/tests/Database/Fixtures/NullablePost.php @@ -0,0 +1,20 @@ + Author::class, + ]; + + public static function migrateUp(Builder $builder): void + { + if ($builder->hasTable('database_tester_phones')) { + return; + } + + $builder->create('database_tester_phones', function ($table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('number')->nullable(); + $table->integer('author_id')->unsigned()->index()->nullable(); + $table->timestamps(); + }); + } + + public static function migrateDown(Builder $builder): void + { + if (!$builder->hasTable('database_tester_phones')) { + return; + } + + $builder->dropIfExists('database_tester_phones'); + } +} diff --git a/tests/Database/Fixtures/Post.php b/tests/Database/Fixtures/Post.php index 2b6f7ea4..d3d456c5 100644 --- a/tests/Database/Fixtures/Post.php +++ b/tests/Database/Fixtures/Post.php @@ -85,6 +85,15 @@ public static function migrateUp(Builder $builder): void $table->softDeletes(); $table->timestamps(); }); + + $builder->create('database_tester_categories_posts', function ($table) { + $table->engine = 'InnoDB'; + $table->integer('category_id')->unsigned(); + $table->integer('post_id')->unsigned(); + $table->primary(['category_id', 'post_id']); + $table->string('category_name')->nullable(); + $table->string('post_name')->nullable(); + }); } public static function migrateDown(Builder $builder): void @@ -93,6 +102,7 @@ public static function migrateDown(Builder $builder): void return; } + $builder->dropIfExists('database_tester_categories_posts'); $builder->dropIfExists('database_tester_posts'); } } diff --git a/tests/Database/Fixtures/RevisionablePost.php b/tests/Database/Fixtures/RevisionablePost.php new file mode 100644 index 00000000..2d0dc705 --- /dev/null +++ b/tests/Database/Fixtures/RevisionablePost.php @@ -0,0 +1,53 @@ + [Revision::class, 'name' => 'revisionable'] + ]; + + /** + * The user who made the revision. + */ + public function getRevisionableUser() + { + return 7; + } +} diff --git a/tests/Database/Fixtures/Role.php b/tests/Database/Fixtures/Role.php new file mode 100644 index 00000000..6487ad5a --- /dev/null +++ b/tests/Database/Fixtures/Role.php @@ -0,0 +1,79 @@ + [ + User::class, + 'table' => 'database_tester_authors_roles' + ], + ]; + + public function users(): BelongsToMany + { + return $this->belongsToMany(User::class, 'database_tester_authors_roles'); + } + + public static function migrateUp(Builder $builder): void + { + if ($builder->hasTable('database_tester_roles')) { + return; + } + + $builder->create('database_tester_roles', function ($table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('name')->nullable(); + $table->text('description')->nullable(); + $table->timestamps(); + }); + + $builder->create('database_tester_authors_roles', function ($table) { + $table->engine = 'InnoDB'; + $table->integer('author_id')->unsigned(); + $table->integer('role_id')->unsigned(); + $table->primary(['author_id', 'role_id']); + $table->string('clearance_level')->nullable(); + $table->boolean('is_executive')->default(false); + }); + } + + public static function migrateDown(Builder $builder): void + { + if (!$builder->hasTable('database_tester_roles')) { + return; + } + + $builder->dropIfExists('database_tester_roles'); + $builder->dropIfExists('database_tester_authors_roles'); + } +} diff --git a/tests/Database/Fixtures/SluggablePost.php b/tests/Database/Fixtures/SluggablePost.php new file mode 100644 index 00000000..b3387b95 --- /dev/null +++ b/tests/Database/Fixtures/SluggablePost.php @@ -0,0 +1,21 @@ + 'title', + 'long_slug' => ['title', 'description'] + ]; +} diff --git a/tests/Database/Fixtures/SoftDeleteAuthor.php b/tests/Database/Fixtures/SoftDeleteAuthor.php new file mode 100644 index 00000000..88c51dce --- /dev/null +++ b/tests/Database/Fixtures/SoftDeleteAuthor.php @@ -0,0 +1,8 @@ + [ + Author::class, + 'name' => 'taggable', + 'table' => 'database_tester_taggables', + 'pivot' => ['added_by'], + ], + 'posts' => [ + Post::class, + 'name' => 'taggable', + 'table' => 'database_tester_taggables', + 'pivot' => ['added_by'], + ], + ]; + + public static function migrateUp(Builder $builder): void + { + if ($builder->hasTable('database_tester_tags')) { + return; + } + + $builder->create('database_tester_tags', function ($table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('name'); + $table->timestamps(); + }); + + $builder->create('database_tester_taggables', function ($table) { + $table->engine = 'InnoDB'; + $table->unsignedInteger('tag_id'); + $table->morphs('taggable', 'testings_taggable'); + $table->unsignedInteger('added_by')->nullable(); + }); + } + + public static function migrateDown(Builder $builder): void + { + if (!$builder->hasTable('database_tester_tags')) { + return; + } + + $builder->dropIfExists('database_tester_taggables'); + $builder->dropIfExists('database_tester_tags'); + } +} diff --git a/tests/Database/Fixtures/User.php b/tests/Database/Fixtures/User.php new file mode 100644 index 00000000..1333d223 --- /dev/null +++ b/tests/Database/Fixtures/User.php @@ -0,0 +1,70 @@ + [ + Author::class, + ] + ]; + + public $hasOneThrough = [ + 'phone' => [ + Phone::class, + 'through' => Author::class, + ], + ]; + + public $attachOne = [ + 'avatar' => 'System\Models\File' + ]; + + public $attachMany = [ + 'photos' => 'System\Models\File' + ]; + + public static function migrateUp(Builder $builder): void + { + if ($builder->hasTable('database_tester_users')) { + return; + } + + $builder->create('database_tester_users', function ($table) { + $table->engine = 'InnoDB'; + $table->increments('id'); + $table->string('name')->nullable(); + $table->string('email')->nullable(); + $table->softDeletes(); + $table->timestamps(); + }); + } + + public static function migrateDown(Builder $builder): void + { + if (!$builder->hasTable('database_tester_users')) { + return; + } + + $builder->dropIfExists('database_tester_users'); + } +} diff --git a/tests/Database/Fixtures/ValidateablePost.php b/tests/Database/Fixtures/ValidateablePost.php new file mode 100644 index 00000000..cee4a49c --- /dev/null +++ b/tests/Database/Fixtures/ValidateablePost.php @@ -0,0 +1,18 @@ + 'required|min:3|max:255', + 'slug' => ['required', 'regex:/^[a-z0-9\/\:_\-\*\[\]\+\?\|]*$/i', 'unique:database_tester_posts'], + ]; +} diff --git a/tests/Database/Relations/BelongsToManyTest.php b/tests/Database/Relations/BelongsToManyTest.php new file mode 100644 index 00000000..f149f54c --- /dev/null +++ b/tests/Database/Relations/BelongsToManyTest.php @@ -0,0 +1,372 @@ + 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + // Add/remove to collection + $this->assertFalse($author->roles->contains($role1->id)); + $author->roles()->add($role1); + $author->roles()->add($role2); + $this->assertTrue($author->roles->contains($role1->id)); + $this->assertTrue($author->roles->contains($role2->id)); + + // Set by Model object + $author->roles = $role1; + $this->assertEquals(1, $author->roles->count()); + $this->assertEquals('Designer', $author->roles->first()->name); + + $author->roles = [$role1, $role2, $role3]; + $this->assertEquals(3, $author->roles->count()); + + // Set by primary key + $author->roles = $role2->id; + $this->assertEquals(1, $author->roles->count()); + $this->assertEquals('Programmer', $author->roles->first()->name); + + $author->roles = [$role2->id, $role3->id]; + $this->assertEquals(2, $author->roles->count()); + + // Nullify + $author->roles = null; + $this->assertEquals(0, $author->roles->count()); + + // Extra nullify checks (still exists in DB until saved) + $author->reloadRelations('roles'); + $this->assertEquals(2, $author->roles->count()); + $author->save(); + $author->reloadRelations('roles'); + $this->assertEquals(0, $author->roles->count()); + + // Deferred in memory + $author->roles = [$role2->id, $role3->id]; + $this->assertEquals(2, $author->roles->count()); + $this->assertEquals('Programmer', $author->roles->first()->name); + } + + public function testSetRelationValueLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + // Add/remove to collection + $this->assertFalse($author->scopes->contains($role1->id)); + $author->scopes()->add($role1); + $author->scopes()->add($role2); + $this->assertTrue($author->scopes->contains($role1->id)); + $this->assertTrue($author->scopes->contains($role2->id)); + + // Set by Model object + $author->scopes = $role1; + $this->assertEquals(1, $author->scopes->count()); + $this->assertEquals('Designer', $author->scopes->first()->name); + + $author->scopes = [$role1, $role2, $role3]; + $this->assertEquals(3, $author->scopes->count()); + + // Set by primary key + $author->scopes = $role2->id; + $this->assertEquals(1, $author->scopes->count()); + $this->assertEquals('Programmer', $author->scopes->first()->name); + + $author->scopes = [$role2->id, $role3->id]; + $this->assertEquals(2, $author->scopes->count()); + + // Nullify + $author->scopes = null; + $this->assertEquals(0, $author->scopes->count()); + + // Extra nullify checks (still exists in DB until saved) + $author->reloadRelations('scopes'); + $this->assertEquals(2, $author->scopes->count()); + $author->save(); + $author->reloadRelations('scopes'); + $this->assertEquals(0, $author->scopes->count()); + + // Deferred in memory + $author->scopes = [$role2->id, $role3->id]; + $this->assertEquals(2, $author->scopes->count()); + $this->assertEquals('Programmer', $author->scopes->first()->name); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + Model::reguard(); + + $author->roles()->add($role1); + $author->roles()->add($role2); + + $this->assertEquals([$role1->id, $role2->id], $author->getRelationValue('roles')); + } + + public function testGetRelationValueLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + Model::reguard(); + + $author->scopes()->add($role1); + $author->scopes()->add($role2); + + $this->assertEquals([$role1->id, $role2->id], $author->getRelationValue('scopes')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + + $category = Category::create(['name' => 'News']); + $post1 = Post::create(['title' => 'First post']); + $post2 = Post::create(['title' => 'Second post']); + Model::reguard(); + + // Deferred add + $author->roles()->add($role1, $sessionKey); + $author->roles()->add($role2, $sessionKey); + $category->posts()->add($post1, $sessionKey, [ + 'category_name' => $category->name . ' in pivot', + 'post_name' => $post1->title . ' in pivot', + ]); + $category->posts()->add($post2, $sessionKey, [ + 'category_name' => $category->name . ' in pivot', + 'post_name' => $post2->title . ' in pivot', + ]); + $this->assertEmpty($author->roles); + $this->assertEmpty($category->posts); + + $this->assertEquals(0, $author->roles()->count()); + $this->assertEquals(2, $author->roles()->withDeferred($sessionKey)->count()); + $this->assertEquals(0, $category->posts()->count()); + $this->assertEquals(2, $category->posts()->withDeferred($sessionKey)->count()); + + // Get simple value (implicit) + $author->reloadRelations(); + $author->sessionKey = $sessionKey; + $this->assertEquals([$role1->id, $role2->id], $author->getRelationValue('roles')); + $category->reloadRelations(); + $category->sessionKey = $sessionKey; + $this->assertEquals([$post1->id, $post2->id], $category->getRelationValue('posts')); + + // Get simple value (explicit) + $relatedIds = $author->roles()->allRelatedIds($sessionKey)->all(); + $this->assertEquals([$role1->id, $role2->id], $relatedIds); + $relatedIds = $category->posts()->allRelatedIds($sessionKey)->all(); + $this->assertEquals([$post1->id, $post2->id], $relatedIds); + + // Commit deferred + $author->save(null, $sessionKey); + $category->save(null, $sessionKey); + $this->assertEquals(2, $author->roles()->count()); + $this->assertEquals('Designer', $author->roles->first()->name); + $this->assertEquals(2, $category->posts()->count()); + $this->assertEquals('First post', $category->posts->first()->title); + $this->assertEquals('Second post', $category->posts->last()->title); + $this->assertEquals('First post in pivot', $category->posts->first()->pivot->post_name); + $this->assertEquals('Second post in pivot', $category->posts->last()->pivot->post_name); + $this->assertEquals('News in pivot', $category->posts->first()->pivot->category_name); + $this->assertEquals('News in pivot', $category->posts->last()->pivot->category_name); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->roles()->remove($role1, $sessionKey); + $author->roles()->remove($role2, $sessionKey); + $category->posts()->remove($post1, $sessionKey); + $category->posts()->remove($post2, $sessionKey); + $this->assertEquals(2, $author->roles()->count()); + $this->assertEquals(0, $author->roles()->withDeferred($sessionKey)->count()); + $this->assertEquals(2, $category->posts()->count()); + $this->assertEquals(0, $category->posts()->withDeferred($sessionKey)->count()); + $this->assertEquals('Designer', $author->roles->first()->name); + $this->assertEquals('First post', $category->posts->first()->title); + $this->assertEquals('Second post', $category->posts->last()->title); + $this->assertEquals('First post in pivot', $category->posts->first()->pivot->post_name); + $this->assertEquals('Second post in pivot', $category->posts->last()->pivot->post_name); + $this->assertEquals('News in pivot', $category->posts->first()->pivot->category_name); + $this->assertEquals('News in pivot', $category->posts->last()->pivot->category_name); + + // Commit deferred + $author->save(null, $sessionKey); + $category->save(null, $sessionKey); + $this->assertEquals(0, $author->roles()->count()); + $this->assertEquals(0, $author->roles->count()); + $this->assertEquals(0, $category->posts()->count()); + $this->assertEquals(0, $category->posts->count()); + } + + public function testDeferredBindingLaravelRelation() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + + $category = Category::create(['name' => 'News']); + $post1 = Post::create(['title' => 'First post']); + $post2 = Post::create(['title' => 'Second post']); + Model::reguard(); + + // Deferred add + $author->scopes()->add($role1, $sessionKey); + $author->scopes()->add($role2, $sessionKey); + $category->posts()->add($post1, $sessionKey, [ + 'category_name' => $category->name . ' in pivot', + 'post_name' => $post1->title . ' in pivot', + ]); + $category->posts()->add($post2, $sessionKey, [ + 'category_name' => $category->name . ' in pivot', + 'post_name' => $post2->title . ' in pivot', + ]); + $this->assertEmpty($author->scopes); + $this->assertEmpty($category->posts); + + $this->assertEquals(0, $author->scopes()->count()); + $this->assertEquals(2, $author->scopes()->withDeferred($sessionKey)->count()); + $this->assertEquals(0, $category->posts()->count()); + $this->assertEquals(2, $category->posts()->withDeferred($sessionKey)->count()); + + // Get simple value (implicit) + $author->reloadRelations(); + $author->sessionKey = $sessionKey; + $this->assertEquals([$role1->id, $role2->id], $author->getRelationValue('scopes')); + $category->reloadRelations(); + $category->sessionKey = $sessionKey; + $this->assertEquals([$post1->id, $post2->id], $category->getRelationValue('posts')); + + // Get simple value (explicit) + $relatedIds = $author->scopes()->allRelatedIds($sessionKey)->all(); + $this->assertEquals([$role1->id, $role2->id], $relatedIds); + $relatedIds = $category->posts()->allRelatedIds($sessionKey)->all(); + $this->assertEquals([$post1->id, $post2->id], $relatedIds); + + // Commit deferred + $author->save(null, $sessionKey); + $category->save(null, $sessionKey); + $this->assertEquals(2, $author->scopes()->count()); + $this->assertEquals('Designer', $author->scopes->first()->name); + $this->assertEquals(2, $category->posts()->count()); + $this->assertEquals('First post', $category->posts->first()->title); + $this->assertEquals('Second post', $category->posts->last()->title); + $this->assertEquals('First post in pivot', $category->posts->first()->pivot->post_name); + $this->assertEquals('Second post in pivot', $category->posts->last()->pivot->post_name); + $this->assertEquals('News in pivot', $category->posts->first()->pivot->category_name); + $this->assertEquals('News in pivot', $category->posts->last()->pivot->category_name); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->scopes()->remove($role1, $sessionKey); + $author->scopes()->remove($role2, $sessionKey); + $category->posts()->remove($post1, $sessionKey); + $category->posts()->remove($post2, $sessionKey); + $this->assertEquals(2, $author->scopes()->count()); + $this->assertEquals(0, $author->scopes()->withDeferred($sessionKey)->count()); + $this->assertEquals(2, $category->posts()->count()); + $this->assertEquals(0, $category->posts()->withDeferred($sessionKey)->count()); + $this->assertEquals('Designer', $author->scopes->first()->name); + $this->assertEquals('First post', $category->posts->first()->title); + $this->assertEquals('Second post', $category->posts->last()->title); + $this->assertEquals('First post in pivot', $category->posts->first()->pivot->post_name); + $this->assertEquals('Second post in pivot', $category->posts->last()->pivot->post_name); + $this->assertEquals('News in pivot', $category->posts->first()->pivot->category_name); + $this->assertEquals('News in pivot', $category->posts->last()->pivot->category_name); + + // Commit deferred + $author->save(null, $sessionKey); + $category->save(null, $sessionKey); + $this->assertEquals(0, $author->scopes()->count()); + $this->assertEquals(0, $author->scopes->count()); + $this->assertEquals(0, $category->posts()->count()); + $this->assertEquals(0, $category->posts->count()); + } + + public function testDetachAfterDelete() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + $author->roles()->add($role1); + $author->roles()->add($role2); + $author->roles()->add($role3); + $this->assertEquals(3, DB::table('database_tester_authors_roles')->where('author_id', $author->id)->count()); + + $author->delete(); + $this->assertEquals(0, DB::table('database_tester_authors_roles')->where('author_id', $author->id)->count()); + } + + public function testDetachAfterDeleteLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + $author->scopes()->add($role1); + $author->scopes()->add($role2); + $author->scopes()->add($role3); + $this->assertEquals(3, DB::table('database_tester_authors_roles')->where('author_id', $author->id)->count()); + + $author->delete(); + $this->assertEquals(0, DB::table('database_tester_authors_roles')->where('author_id', $author->id)->count()); + } + + public function testConditionsWithPivotAttributes() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $role1 = Role::create(['name' => "Designer", 'description' => "Quality"]); + $role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]); + $role3 = Role::create(['name' => "Manager", 'description' => "Budget"]); + Model::reguard(); + + $author->roles()->add($role1, null, ['is_executive' => 1]); + $author->roles()->add($role2, null, ['is_executive' => 1]); + $author->roles()->add($role3, null, ['is_executive' => 0]); + + $this->assertEquals([1, 2], $author->executiveAuthors->lists('id')); + $this->assertEquals([1, 2], $author->executiveAuthors()->lists('id')); + $this->assertEquals([1, 2], $author->executiveAuthors()->get()->lists('id')); + } +} diff --git a/tests/Database/Relations/HasManyTest.php b/tests/Database/Relations/HasManyTest.php new file mode 100644 index 00000000..564684f2 --- /dev/null +++ b/tests/Database/Relations/HasManyTest.php @@ -0,0 +1,220 @@ + 'Stevie', 'email' => 'stevie@example.com']); + $post1 = Post::create(['title' => "First post", 'description' => "Yay!!"]); + $post2 = Post::create(['title' => "Second post", 'description' => "Woohoo!!"]); + $post3 = Post::create(['title' => "Third post", 'description' => "Yipiee!!"]); + $post4 = Post::make(['title' => "Fourth post", 'description' => "Hooray!!"]); + Model::reguard(); + + // Set by Model object + $author->posts = new Collection([$post1, $post2]); + $author->save(); + $this->assertEquals($author->id, $post1->author_id); + $this->assertEquals($author->id, $post2->author_id); + $this->assertEquals([ + 'First post', + 'Second post' + ], $author->posts->lists('title')); + + // Set by primary key + $postId = $post3->id; + $author->posts = $postId; + $author->save(); + $post3 = Post::find($postId); + $this->assertEquals($author->id, $post3->author_id); + $this->assertEquals([ + 'Third post' + ], $author->posts->lists('title')); + + // Nullify + $author->posts = null; + $author->save(); + $post3 = Post::find($postId); + $this->assertNull($post3->author_id); + $this->assertNull($post3->author); + + // Deferred in memory + $author->posts = $post4; + $this->assertEquals($author->id, $post4->author_id); + $this->assertEquals([ + 'Fourth post' + ], $author->posts->lists('title')); + } + + public function testSetRelationValueLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $post1 = Post::create(['title' => "First post", 'description' => "Yay!!"]); + $post2 = Post::create(['title' => "Second post", 'description' => "Woohoo!!"]); + $post3 = Post::create(['title' => "Third post", 'description' => "Yipiee!!"]); + $post4 = Post::make(['title' => "Fourth post", 'description' => "Hooray!!"]); + Model::reguard(); + + // Set by Model object + $author->messages = new Collection([$post1, $post2]); + $author->save(); + $this->assertEquals($author->id, $post1->author_id); + $this->assertEquals($author->id, $post2->author_id); + $this->assertEquals([ + 'First post', + 'Second post' + ], $author->messages->lists('title')); + + // Set by primary key + $postId = $post3->id; + $author->messages = $postId; + $author->save(); + $post3 = Post::find($postId); + $this->assertEquals($author->id, $post3->author_id); + $this->assertEquals([ + 'Third post' + ], $author->messages->lists('title')); + + // Nullify + $author->messages = null; + $author->save(); + $post3 = Post::find($postId); + $this->assertNull($post3->author_id); + $this->assertNull($post3->author); + + // Deferred in memory + $author->messages = $post4; + $this->assertEquals($author->id, $post4->author_id); + $this->assertEquals([ + 'Fourth post' + ], $author->messages->lists('title')); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $post1 = Post::create(['title' => "First post", 'author_id' => $author->id]); + $post2 = Post::create(['title' => "Second post", 'author_id' => $author->id]); + Model::reguard(); + + $this->assertEquals([$post1->id, $post2->id], $author->getRelationValue('posts')); + } + + public function testGetRelationValueLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $post1 = Post::create(['title' => "First post", 'author_id' => $author->id]); + $post2 = Post::create(['title' => "Second post", 'author_id' => $author->id]); + Model::reguard(); + + $this->assertEquals([$post1->id, $post2->id], $author->getRelationValue('messages')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $post = Post::create(['title' => "First post", 'description' => "Yay!!"]); + Model::reguard(); + + $postId = $post->id; + + // Deferred add + $author->posts()->add($post, $sessionKey); + $this->assertNull($post->author_id); + $this->assertEmpty($author->posts); + + $this->assertEquals(0, $author->posts()->count()); + $this->assertEquals(1, $author->posts()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $post = Post::find($postId); + $this->assertEquals(1, $author->posts()->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals([ + 'First post' + ], $author->posts->lists('title')); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->posts()->remove($post, $sessionKey); + $this->assertEquals(1, $author->posts()->count()); + $this->assertEquals(0, $author->posts()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals([ + 'First post' + ], $author->posts->lists('title')); + + // Commit deferred + $author->save(null, $sessionKey); + $post = Post::find($postId); + $this->assertEquals(0, $author->posts()->count()); + $this->assertNull($post->author_id); + $this->assertEmpty($author->posts); + } + + public function testDeferredBindingLaravelRelation() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $post = Post::create(['title' => "First post", 'description' => "Yay!!"]); + Model::reguard(); + + $postId = $post->id; + + // Deferred add + $author->messages()->add($post, $sessionKey); + $this->assertNull($post->author_id); + $this->assertEmpty($author->messages); + + $this->assertEquals(0, $author->messages()->count()); + $this->assertEquals(1, $author->messages()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $post = Post::find($postId); + $this->assertEquals(1, $author->messages()->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals([ + 'First post' + ], $author->messages->lists('title')); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->messages()->remove($post, $sessionKey); + $this->assertEquals(1, $author->messages()->count()); + $this->assertEquals(0, $author->messages()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $post->author_id); + $this->assertEquals([ + 'First post' + ], $author->messages->lists('title')); + + // Commit deferred + $author->save(null, $sessionKey); + $post = Post::find($postId); + $this->assertEquals(0, $author->messages()->count()); + $this->assertNull($post->author_id); + $this->assertEmpty($author->messages); + } +} diff --git a/tests/Database/Relations/HasOneTest.php b/tests/Database/Relations/HasOneTest.php new file mode 100644 index 00000000..fe76b67a --- /dev/null +++ b/tests/Database/Relations/HasOneTest.php @@ -0,0 +1,245 @@ + 'Stevie', 'email' => 'stevie@example.com']); + $phone1 = Phone::create(['number' => '0404040404']); + $phone2 = Phone::create(['number' => '0505050505']); + $phone3 = Phone::make(['number' => '0606060606']); + Model::reguard(); + + // Set by Model object + $author->phone = $phone1; + $author->save(); + $this->assertEquals($author->id, $phone1->author_id); + $this->assertEquals('0404040404', $author->phone->number); + + // Double check + $phone1 = Phone::find($phone1->id); + $this->assertEquals($author->id, $phone1->author_id); + + // Set by primary key + $phoneId = $phone2->id; + $author->phone = $phoneId; + $author->save(); + $phone2 = Phone::find($phoneId); + $this->assertEquals($author->id, $phone2->author_id); + $this->assertEquals('0505050505', $author->phone->number); + + // Ensure relationship is "stolen" from first model + $phone1 = Phone::find($phone1->id); + $this->assertNotEquals($author->id, $phone1->author_id); + + // Nullify + $author->phone = null; + $author->save(); + $phone2 = Phone::find($phoneId); + $this->assertNull($phone2->author_id); + $this->assertNull($phone2->author); + + // Deferred in memory + $author->phone = $phone3; + $this->assertEquals('0606060606', $author->phone->number); + $this->assertEquals($author->id, $phone3->author_id); + } + + public function testSetRelationValueLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $phone1 = Phone::create(['number' => '0404040404']); + $phone2 = Phone::create(['number' => '0505050505']); + $phone3 = Phone::make(['number' => '0606060606']); + Model::reguard(); + + // Set by Model object + $author->contactNumber = $phone1; + $author->save(); + $this->assertEquals($author->id, $phone1->author_id); + $this->assertEquals('0404040404', $author->contactNumber->number); + + // Double check + $phone1 = Phone::find($phone1->id); + $this->assertEquals($author->id, $phone1->author_id); + + // Set by primary key + $phoneId = $phone2->id; + $author->contactNumber = $phoneId; + $author->save(); + $phone2 = Phone::find($phoneId); + $this->assertEquals($author->id, $phone2->author_id); + $this->assertEquals('0505050505', $author->contactNumber->number); + + // Ensure relationship is "stolen" from first model + $phone1 = Phone::find($phone1->id); + $this->assertNotEquals($author->id, $phone1->author_id); + + // Nullify + $author->contactNumber = null; + $author->save(); + $phone2 = Phone::find($phoneId); + $this->assertNull($phone2->author_id); + $this->assertNull($phone2->author); + + // Deferred in memory + $author->contactNumber = $phone3; + $this->assertEquals('0606060606', $author->contactNumber->number); + $this->assertEquals($author->id, $phone3->author_id); + } + + public function testSetRelationValueTwice() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $phone = Phone::create(['number' => '0505050505']); + Model::reguard(); + + $phoneId = $phone->id; + $author->phone = $phoneId; + $author->save(); + + $author->phone = $phoneId; + $author->save(); + + $phone = Phone::find($phoneId); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0505050505', $author->phone->number); + } + + public function testSetRelationValueTwiceLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie', 'email' => 'stevie@example.com']); + $phone = Phone::create(['number' => '0505050505']); + Model::reguard(); + + $phoneId = $phone->id; + $author->contactNumber = $phoneId; + $author->save(); + + $author->contactNumber = $phoneId; + $author->save(); + + $phone = Phone::find($phoneId); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0505050505', $author->contactNumber->number); + } + + public function testGetRelationValue() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $phone = Phone::create(['number' => '0404040404', 'author_id' => $author->id]); + Model::reguard(); + + $this->assertEquals($phone->id, $author->getRelationValue('phone')); + } + + public function testGetRelationValueLaravelRelation() + { + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $phone = Phone::create(['number' => '0404040404', 'author_id' => $author->id]); + Model::reguard(); + + $this->assertEquals($phone->id, $author->getRelationValue('contactNumber')); + } + + public function testDeferredBinding() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $phone = Phone::create(['number' => '0404040404']); + Model::reguard(); + + $phoneId = $phone->id; + + // Deferred add + $author->phone()->add($phone, $sessionKey); + $this->assertNull($phone->author_id); + $this->assertNull($author->phone); + + $this->assertEquals(0, $author->phone()->count()); + $this->assertEquals(1, $author->phone()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $phone = Phone::find($phoneId); + $this->assertEquals(1, $author->phone()->count()); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0404040404', $author->phone->number); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->phone()->remove($phone, $sessionKey); + $this->assertEquals(1, $author->phone()->count()); + $this->assertEquals(0, $author->phone()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0404040404', $author->phone->number); + + // Commit deferred + $author->save(null, $sessionKey); + $phone = Phone::find($phoneId); + $this->assertEquals(0, $author->phone()->count()); + $this->assertNull($phone->author_id); + $this->assertNull($author->phone); + } + + public function testDeferredBindingLaravelRelation() + { + $sessionKey = uniqid('session_key', true); + + Model::unguard(); + $author = Author::create(['name' => 'Stevie']); + $phone = Phone::create(['number' => '0404040404']); + Model::reguard(); + + $phoneId = $phone->id; + + // Deferred add + $author->contactNumber()->add($phone, $sessionKey); + $this->assertNull($phone->author_id); + $this->assertNull($author->contactNumber); + + $this->assertEquals(0, $author->contactNumber()->count()); + $this->assertEquals(1, $author->contactNumber()->withDeferred($sessionKey)->count()); + + // Commit deferred + $author->save(null, $sessionKey); + $phone = Phone::find($phoneId); + $this->assertEquals(1, $author->contactNumber()->count()); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0404040404', $author->contactNumber->number); + + // New session + $sessionKey = uniqid('session_key', true); + + // Deferred remove + $author->contactNumber()->remove($phone, $sessionKey); + $this->assertEquals(1, $author->contactNumber()->count()); + $this->assertEquals(0, $author->contactNumber()->withDeferred($sessionKey)->count()); + $this->assertEquals($author->id, $phone->author_id); + $this->assertEquals('0404040404', $author->contactNumber->number); + + // Commit deferred + $author->save(null, $sessionKey); + $phone = Phone::find($phoneId); + $this->assertEquals(0, $author->contactNumber()->count()); + $this->assertNull($phone->author_id); + $this->assertNull($author->contactNumber); + } +}