From 4b23c80556362e6b27367a077dfd4c2f82264a80 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 26 Oct 2020 16:58:20 -0400 Subject: [PATCH 01/24] override Laravel Relation sync() method --- src/Database/Relations/BelongsToMany.php | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 0275ff3e2..0033c9dbc 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -409,4 +409,53 @@ public function getRelatedIds($sessionKey = null) traceLog('Method BelongsToMany::allRelatedIds has been deprecated, use BelongsToMany::allRelatedIds instead.'); return $this->allRelatedIds($sessionKey)->all(); } + + /** + * Sync the intermediate tables with a list of IDs or collection of models. + * + * @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids + * @param bool $detaching + * @return array + */ + public function sync($ids, $detaching = true) + { + $changes = [ + 'attached' => [], 'detached' => [], 'updated' => [], + ]; + + // First we need to attach any of the associated models that are not currently + // in this joining table. We'll spin through the given IDs, checking to see + // if they exist in the array of current ones, and if not we will insert. + $current = $this->allRelatedIds()->all(); + + $detach = array_diff($current, array_keys( + $records = $this->formatRecordsList($this->parseIds($ids)) + )); + + // Next, we will take the differences of the currents and given IDs and detach + // all of the entities that exist in the "current" array but are not in the + // array of the new IDs given to the method which will complete the sync. + if ($detaching && count($detach) > 0) { + $this->detach($detach); + + $changes['detached'] = $this->castKeys($detach); + } + + // Now we are finally ready to attach the new records. Note that we'll disable + // touching until after the entire operation is complete so we don't fire a + // ton of touch operations until we are totally done syncing the records. + $changes = array_merge( + $changes, $this->attachNew($records, $current, false) + ); + + // Once we have finished attaching or detaching the records, we will see if we + // have done any attaching or detaching, and if we have we will touch these + // relationships if they are configured to touch on any database updates. + if (count($changes['attached']) || + count($changes['updated'])) { + $this->touchIfTouching(); + } + + return $changes; + } } From 9e19b6683560951e22904a1dcb63deda1fcc8835 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 26 Oct 2020 17:07:34 -0400 Subject: [PATCH 02/24] fix code quality --- src/Database/Relations/BelongsToMany.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 0033c9dbc..f0166536e 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -437,16 +437,13 @@ public function sync($ids, $detaching = true) // array of the new IDs given to the method which will complete the sync. if ($detaching && count($detach) > 0) { $this->detach($detach); - $changes['detached'] = $this->castKeys($detach); } // Now we are finally ready to attach the new records. Note that we'll disable // touching until after the entire operation is complete so we don't fire a // ton of touch operations until we are totally done syncing the records. - $changes = array_merge( - $changes, $this->attachNew($records, $current, false) - ); + $changes = array_merge($changes, $this->attachNew($records, $current, false)); // Once we have finished attaching or detaching the records, we will see if we // have done any attaching or detaching, and if we have we will touch these From 624461a737b1d9e063beaa55e3bf4bdd31edd2c6 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 26 Oct 2020 17:25:27 -0400 Subject: [PATCH 03/24] fix comment --- src/Database/Relations/BelongsToMany.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index f0166536e..5883497f6 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -423,9 +423,7 @@ public function sync($ids, $detaching = true) 'attached' => [], 'detached' => [], 'updated' => [], ]; - // First we need to attach any of the associated models that are not currently - // in this joining table. We'll spin through the given IDs, checking to see - // if they exist in the array of current ones, and if not we will insert. + // Get all the IDs for the related model $current = $this->allRelatedIds()->all(); $detach = array_diff($current, array_keys( From 9775ab5f6b5295dd0e160d1b1622d1cd8531f55a Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 27 Oct 2020 22:58:16 -0400 Subject: [PATCH 04/24] fix detach method to only detach related ids, honoring the conditions & scopes --- src/Database/Relations/BelongsToMany.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 5883497f6..d9eb25e06 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -164,7 +164,7 @@ public function detach($ids = null, $touch = true) { $attachedIdList = $this->parseIds($ids); if (empty($attachedIdList)) { - $attachedIdList = $this->newPivotQuery()->lists($this->relatedPivotKey); + $attachedIdList = $this->allRelatedIds()->all(); } /** @@ -188,7 +188,7 @@ public function detach($ids = null, $touch = true) /* * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable */ - parent::detach($ids, $touch); + parent::detach($attachedIdList, $touch); /** * @event model.relation.afterDetach From 7fee28bc4e0d0ada273ad0e2168bc931c6f69b22 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Thu, 29 Oct 2020 02:22:25 -0600 Subject: [PATCH 05/24] Update src/Database/Relations/BelongsToMany.php --- src/Database/Relations/BelongsToMany.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index d9eb25e06..b67fb7fc0 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -406,7 +406,7 @@ public function getOtherKey() */ public function getRelatedIds($sessionKey = null) { - traceLog('Method BelongsToMany::allRelatedIds has been deprecated, use BelongsToMany::allRelatedIds instead.'); + traceLog('Method BelongsToMany::getRelatedIds has been deprecated, use BelongsToMany::allRelatedIds instead.'); return $this->allRelatedIds($sessionKey)->all(); } From 8db8f62638dcd651a88af3c7be6115eee331eb7d Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 31 Oct 2020 11:25:00 -0400 Subject: [PATCH 06/24] rewrite getCurrentlyAttachedPivots() to take conditions and scopes into account --- src/Database/Relations/BelongsToMany.php | 45 +++++------------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index b67fb7fc0..d75904921 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -3,6 +3,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection as CollectionBase; +use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Database\Eloquent\Relations\BelongsToMany as BelongsToManyBase; class BelongsToMany extends BelongsToManyBase @@ -411,46 +412,16 @@ public function getRelatedIds($sessionKey = null) } /** - * Sync the intermediate tables with a list of IDs or collection of models. + * Get the pivot models that are currently attached (taking conditions & scopes into account). * - * @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids - * @param bool $detaching - * @return array + * @return \Illuminate\Support\Collection */ - public function sync($ids, $detaching = true) + protected function getCurrentlyAttachedPivots() { - $changes = [ - 'attached' => [], 'detached' => [], 'updated' => [], - ]; - - // Get all the IDs for the related model - $current = $this->allRelatedIds()->all(); - - $detach = array_diff($current, array_keys( - $records = $this->formatRecordsList($this->parseIds($ids)) - )); - - // Next, we will take the differences of the currents and given IDs and detach - // all of the entities that exist in the "current" array but are not in the - // array of the new IDs given to the method which will complete the sync. - if ($detaching && count($detach) > 0) { - $this->detach($detach); - $changes['detached'] = $this->castKeys($detach); - } - - // Now we are finally ready to attach the new records. Note that we'll disable - // touching until after the entire operation is complete so we don't fire a - // ton of touch operations until we are totally done syncing the records. - $changes = array_merge($changes, $this->attachNew($records, $current, false)); - - // Once we have finished attaching or detaching the records, we will see if we - // have done any attaching or detaching, and if we have we will touch these - // relationships if they are configured to touch on any database updates. - if (count($changes['attached']) || - count($changes['updated'])) { - $this->touchIfTouching(); - } + $related = $this->getRelated(); + $fullKey = $related->getQualifiedKeyName(); + $pivotKey = $this->relatedPivotKey; - return $changes; + return $this->getQuery()->select($fullKey . ' as ' . $pivotKey)->get(); } } From 4943e245a44374ab63c215a989fd8d175fbd03a1 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 31 Oct 2020 11:30:55 -0400 Subject: [PATCH 07/24] simplify code a bit --- src/Database/Relations/BelongsToMany.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index d75904921..ea18a7c32 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -418,8 +418,7 @@ public function getRelatedIds($sessionKey = null) */ protected function getCurrentlyAttachedPivots() { - $related = $this->getRelated(); - $fullKey = $related->getQualifiedKeyName(); + $fullKey = $this->getRelated()->getQualifiedKeyName(); $pivotKey = $this->relatedPivotKey; return $this->getQuery()->select($fullKey . ' as ' . $pivotKey)->get(); From e561aa90c2d306c6add3a34fdd0a2a9c05d6cb02 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 31 Oct 2020 11:38:20 -0400 Subject: [PATCH 08/24] remove unused Pivot class --- src/Database/Relations/BelongsToMany.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index ea18a7c32..7f461ee9f 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -3,7 +3,6 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection as CollectionBase; -use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Database\Eloquent\Relations\BelongsToMany as BelongsToManyBase; class BelongsToMany extends BelongsToManyBase From c6135352ced1637c9662164edac4a4342522c737 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 31 Oct 2020 12:42:29 -0400 Subject: [PATCH 09/24] no need to complicate things here... --- src/Database/Relations/BelongsToMany.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 7f461ee9f..df154b48c 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -417,9 +417,6 @@ public function getRelatedIds($sessionKey = null) */ protected function getCurrentlyAttachedPivots() { - $fullKey = $this->getRelated()->getQualifiedKeyName(); - $pivotKey = $this->relatedPivotKey; - - return $this->getQuery()->select($fullKey . ' as ' . $pivotKey)->get(); + return $this->getQuery()->get(); } } From 560bc08d0b324570f5bb74fb048b89e241092d22 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 10:57:05 -0500 Subject: [PATCH 10/24] add initial relations tests --- tests/Database/Relations/RelationsTest.php | 136 +++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/Database/Relations/RelationsTest.php diff --git a/tests/Database/Relations/RelationsTest.php b/tests/Database/Relations/RelationsTest.php new file mode 100644 index 000000000..454ec0733 --- /dev/null +++ b/tests/Database/Relations/RelationsTest.php @@ -0,0 +1,136 @@ +capsule = $capsule = new Illuminate\Database\Capsule\Manager; + $capsule->addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '' + ]); + + $capsule->setAsGlobal(); + $capsule->bootEloquent(); + + $this->create_tables(); + $this->seed_tables(); + } + + public function create_tables() + { + $this->capsule->schema()->create('posts', function ($table) { + $table->increments('id'); + $table->string('title')->default(''); + $table->timestamps(); + }); + + $this->capsule->schema()->create('terms', function ($table) { + $table->increments('id'); + $table->string('type'); + $table->string('name'); + $table->timestamps(); + + }); + + $this->capsule->schema()->create('posts_terms', function ($table) { + $table->increments('id'); + $table->unsignedInteger('post_id'); + $table->unsignedInteger('term_id'); + }); + } + + public function seed_tables() + { + $post = Post::create([ + 'title' => 'A Post', + ]); + + $category = Term::create([ + 'type' => 'category', + 'name' => 'A Category', + ]); + $category2 = Term::create([ + 'type' => 'category', + 'name' => 'Second Category', + ]); + + $tag = Term::create([ + 'type' => 'tag', + 'name' => 'A Tag', + ]); + $tag2 = Term::create([ + 'type' => 'tag', + 'name' => 'Second Tag', + ]); + + $post->tags()->add($tag); + $post->tags()->add($tag2); + $post->categories()->add($category); + $post->categories()->add($category2); + } + + public function testTablesExist() + { + $this->assertTrue($this->capsule->schema()->hasTable('posts')); + $this->assertTrue($this->capsule->schema()->hasTable('terms')); + $this->assertTrue($this->capsule->schema()->hasTable('posts_terms')); + } + + public function testTablesProperlySeeded() + { + $this->assertEquals(1, Post::count()); + $this->assertEquals(4, Term::count()); + $this->assertEquals(2, Term::where('type', 'tag')->count()); + $this->assertEquals(2, Term::where('type', 'category')->count()); + } + + public function testBelongsToMany() + { + $post = Post::first(); + $this->assertEquals(2, $post->tags()->count()); + $this->assertEquals(2, $post->categories()->count()); + } +} + +class Post extends \October\Rain\Database\Model +{ + public $table = 'posts'; + + public $fillable = ['title']; + + public $belongsToMany = [ + 'tags' => [ + Term::class, + 'table' => 'posts_terms', + 'key' => 'post_id', + 'otherKey' => 'term_id', + 'conditions' => 'type = "tag"' + ], + 'categories' => [ + Term::class, + 'table' => 'posts_terms', + 'key' => 'post_id', + 'otherKey' => 'term_id', + 'conditions' => 'type = "category"' + ], + ]; +} + +class Term extends \October\Rain\Database\Model +{ + public $table = 'terms'; + + public $fillable = ['type', 'name']; + + public $belongsToMany = [ + 'posts' => [ + 'Post', + 'table' => 'posts_terms', + 'key' => 'term_id', + 'otherKey' => 'post_id', + 'conditions' => 'type = "post"' + ], + ]; +} From cef177dd3321f892ac7f34989af06e10f4b23467 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 11:04:17 -0500 Subject: [PATCH 11/24] remove empty line before closing brace --- tests/Database/Relations/RelationsTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Database/Relations/RelationsTest.php b/tests/Database/Relations/RelationsTest.php index 454ec0733..afdc18d8f 100644 --- a/tests/Database/Relations/RelationsTest.php +++ b/tests/Database/Relations/RelationsTest.php @@ -31,7 +31,6 @@ public function create_tables() $table->string('type'); $table->string('name'); $table->timestamps(); - }); $this->capsule->schema()->create('posts_terms', function ($table) { From 246337d4f83295b2d09d92f6da04d291afc4f2a5 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 13:14:23 -0500 Subject: [PATCH 12/24] add DbTestCase and use it for tests needing database --- composer.json | 3 +- .../{Relations => }/RelationsTest.php | 50 +++++-------------- tests/Database/Traits/EncryptableTest.php | 14 ++---- tests/DbTestCase.php | 17 +++++++ 4 files changed, 34 insertions(+), 50 deletions(-) rename tests/Database/{Relations => }/RelationsTest.php (62%) create mode 100644 tests/DbTestCase.php diff --git a/composer.json b/composer.json index e2336fde3..edeeabbf8 100644 --- a/composer.json +++ b/composer.json @@ -88,7 +88,8 @@ }, "autoload-dev": { "classmap": [ - "tests/TestCase.php" + "tests/TestCase.php", + "tests/DbTestCase.php" ] }, "scripts": { diff --git a/tests/Database/Relations/RelationsTest.php b/tests/Database/RelationsTest.php similarity index 62% rename from tests/Database/Relations/RelationsTest.php rename to tests/Database/RelationsTest.php index afdc18d8f..92d13f6cc 100644 --- a/tests/Database/Relations/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -1,18 +1,10 @@ capsule = $capsule = new Illuminate\Database\Capsule\Manager; - $capsule->addConnection([ - 'driver' => 'sqlite', - 'database' => ':memory:', - 'prefix' => '' - ]); - - $capsule->setAsGlobal(); - $capsule->bootEloquent(); + parent::setUp(); $this->create_tables(); $this->seed_tables(); @@ -20,20 +12,20 @@ public function setUp(): void public function create_tables() { - $this->capsule->schema()->create('posts', function ($table) { + $this->db->schema()->create('posts', function ($table) { $table->increments('id'); $table->string('title')->default(''); $table->timestamps(); }); - $this->capsule->schema()->create('terms', function ($table) { + $this->db->schema()->create('terms', function ($table) { $table->increments('id'); $table->string('type'); $table->string('name'); $table->timestamps(); }); - $this->capsule->schema()->create('posts_terms', function ($table) { + $this->db->schema()->create('posts_terms', function ($table) { $table->increments('id'); $table->unsignedInteger('post_id'); $table->unsignedInteger('term_id'); @@ -46,35 +38,17 @@ public function seed_tables() 'title' => 'A Post', ]); - $category = Term::create([ - 'type' => 'category', - 'name' => 'A Category', - ]); - $category2 = Term::create([ - 'type' => 'category', - 'name' => 'Second Category', - ]); - - $tag = Term::create([ - 'type' => 'tag', - 'name' => 'A Tag', - ]); - $tag2 = Term::create([ - 'type' => 'tag', - 'name' => 'Second Tag', - ]); - - $post->tags()->add($tag); - $post->tags()->add($tag2); - $post->categories()->add($category); - $post->categories()->add($category2); + $post->tags()->create(['type'=>'tag', 'name'=>'A Tag']); + $post->tags()->create(['type'=>'tag', 'name'=>'Second Tag']); + $post->categories()->create(['type'=>'category', 'name'=>'A Category']); + $post->categories()->create(['type'=>'category', 'name'=>'Second Category']); } public function testTablesExist() { - $this->assertTrue($this->capsule->schema()->hasTable('posts')); - $this->assertTrue($this->capsule->schema()->hasTable('terms')); - $this->assertTrue($this->capsule->schema()->hasTable('posts_terms')); + $this->assertTrue($this->db->schema()->hasTable('posts')); + $this->assertTrue($this->db->schema()->hasTable('terms')); + $this->assertTrue($this->db->schema()->hasTable('posts_terms')); } public function testTablesProperlySeeded() diff --git a/tests/Database/Traits/EncryptableTest.php b/tests/Database/Traits/EncryptableTest.php index cb29130e3..55c5ac5a8 100644 --- a/tests/Database/Traits/EncryptableTest.php +++ b/tests/Database/Traits/EncryptableTest.php @@ -2,7 +2,7 @@ use Illuminate\Encryption\Encrypter; -class EncryptableTest extends TestCase +class EncryptableTest extends DbTestCase { const TEST_CRYPT_KEY = 'gBmM1S5bxZ5ePRj5'; @@ -13,17 +13,9 @@ class EncryptableTest extends TestCase public function setUp(): void { - $capsule = new Illuminate\Database\Capsule\Manager; - $capsule->addConnection([ - 'driver' => 'sqlite', - 'database' => ':memory:', - 'prefix' => '' - ]); + parent::setUp(); - $capsule->setAsGlobal(); - $capsule->bootEloquent(); - - $capsule->schema()->create('secrets', function ($table) { + $this->db->schema()->create('secrets', function ($table) { $table->increments('id'); $table->string('secret'); $table->timestamps(); diff --git a/tests/DbTestCase.php b/tests/DbTestCase.php new file mode 100644 index 000000000..f49b1ef60 --- /dev/null +++ b/tests/DbTestCase.php @@ -0,0 +1,17 @@ +db = new Illuminate\Database\Capsule\Manager; + $this->db->addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '' + ]); + + $this->db->setAsGlobal(); + $this->db->bootEloquent(); + } +} From 1965c6204b58d5e9ec6bb083df4f86d8854952b5 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 13:48:22 -0500 Subject: [PATCH 13/24] add actual tests that prove this PR resolves the issue --- tests/Database/RelationsTest.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index 92d13f6cc..15d183040 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -59,12 +59,27 @@ public function testTablesProperlySeeded() $this->assertEquals(2, Term::where('type', 'category')->count()); } - public function testBelongsToMany() + public function testBelongsToManyCount() { $post = Post::first(); $this->assertEquals(2, $post->tags()->count()); $this->assertEquals(2, $post->categories()->count()); } + + public function testBelongsToManySync() + { + $post = Post::first(); + + $id = $post->categories()->first()->id; + $post->categories()->sync([$id]); + $this->assertEquals(1, $post->categories()->count()); + $this->assertEquals($id, $post->categories()->first()->id); + + $id = $post->tags()->first()->id; + $post->tags()->sync([$id]); + $this->assertEquals(1, $post->tags()->count()); + $this->assertEquals($id, $post->tags()->first()->id); + } } class Post extends \October\Rain\Database\Model From 22ccd13a1fc119ae336996b3f61234e40902897e Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 3 Nov 2020 16:49:38 -0500 Subject: [PATCH 14/24] complet tests --- tests/Database/RelationsTest.php | 43 +++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index 15d183040..199047890 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -66,20 +66,57 @@ public function testBelongsToManyCount() $this->assertEquals(2, $post->categories()->count()); } - public function testBelongsToManySync() + public function testBelongsToManySyncAll() { $post = Post::first(); $id = $post->categories()->first()->id; $post->categories()->sync([$id]); - $this->assertEquals(1, $post->categories()->count()); + $this->assertEquals(1, $post->categories->count()); $this->assertEquals($id, $post->categories()->first()->id); $id = $post->tags()->first()->id; $post->tags()->sync([$id]); - $this->assertEquals(1, $post->tags()->count()); + $this->assertEquals(1, $post->tags->count()); $this->assertEquals($id, $post->tags()->first()->id); } + + public function testBelongsToManySyncTags() + { + $post = Post::first(); + + $post->categories()->detach(); + $this->assertEquals(0, $post->categories->count()); + + $id = $post->tags()->first()->id; + $post->tags()->sync([$id]); + $this->assertEquals(1, $post->tags->count()); + $this->assertEquals($id, $post->tags()->first()->id); + } + + public function testBelongsToManySyncCategories() + { + $post = Post::first(); + + $id = $post->categories()->first()->id; + $post->categories()->sync([$id]); + $this->assertEquals(1, $post->categories->count()); + $this->assertEquals($id, $post->categories()->first()->id); + + $post->tags()->detach(); + $this->assertEquals(0, $post->tags->count()); + } + + public function testBelongsToManyDetach() + { + $post = Post::first(); + + $post->categories()->detach(); + $this->assertEquals(0, $post->categories->count()); + + $post->tags()->detach(); + $this->assertEquals(0, $post->tags->count()); + } } class Post extends \October\Rain\Database\Model From 4d1887d9e1597d13a9a2279fdb51a36465c5637f Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 4 Nov 2020 07:50:07 -0500 Subject: [PATCH 15/24] flush event listeners on models after each test --- tests/Database/RelationsTest.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index 199047890..ac1074b1b 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -42,6 +42,8 @@ public function seed_tables() $post->tags()->create(['type'=>'tag', 'name'=>'Second Tag']); $post->categories()->create(['type'=>'category', 'name'=>'A Category']); $post->categories()->create(['type'=>'category', 'name'=>'Second Category']); + + $post->flushEventListeners(); } public function testTablesExist() @@ -62,8 +64,10 @@ public function testTablesProperlySeeded() public function testBelongsToManyCount() { $post = Post::first(); - $this->assertEquals(2, $post->tags()->count()); - $this->assertEquals(2, $post->categories()->count()); + $this->assertEquals(2, $post->tags->count()); + $this->assertEquals(2, $post->categories->count()); + + $post->flushEventListeners(); } public function testBelongsToManySyncAll() @@ -79,6 +83,8 @@ public function testBelongsToManySyncAll() $post->tags()->sync([$id]); $this->assertEquals(1, $post->tags->count()); $this->assertEquals($id, $post->tags()->first()->id); + + $post->flushEventListeners(); } public function testBelongsToManySyncTags() @@ -92,6 +98,8 @@ public function testBelongsToManySyncTags() $post->tags()->sync([$id]); $this->assertEquals(1, $post->tags->count()); $this->assertEquals($id, $post->tags()->first()->id); + + $post->flushEventListeners(); } public function testBelongsToManySyncCategories() @@ -105,6 +113,8 @@ public function testBelongsToManySyncCategories() $post->tags()->detach(); $this->assertEquals(0, $post->tags->count()); + + $post->flushEventListeners(); } public function testBelongsToManyDetach() @@ -116,6 +126,8 @@ public function testBelongsToManyDetach() $post->tags()->detach(); $this->assertEquals(0, $post->tags->count()); + + $post->flushEventListeners(); } } From b57d1b988fe4af8dbda93c3fec60936f76c4e471 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 4 Nov 2020 08:00:29 -0500 Subject: [PATCH 16/24] add tearDown method to DbTestCase to flush event listeners on instanciated models --- tests/Database/RelationsTest.php | 12 ----------- tests/DbTestCase.php | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index ac1074b1b..161fe37e5 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -42,8 +42,6 @@ public function seed_tables() $post->tags()->create(['type'=>'tag', 'name'=>'Second Tag']); $post->categories()->create(['type'=>'category', 'name'=>'A Category']); $post->categories()->create(['type'=>'category', 'name'=>'Second Category']); - - $post->flushEventListeners(); } public function testTablesExist() @@ -66,8 +64,6 @@ public function testBelongsToManyCount() $post = Post::first(); $this->assertEquals(2, $post->tags->count()); $this->assertEquals(2, $post->categories->count()); - - $post->flushEventListeners(); } public function testBelongsToManySyncAll() @@ -83,8 +79,6 @@ public function testBelongsToManySyncAll() $post->tags()->sync([$id]); $this->assertEquals(1, $post->tags->count()); $this->assertEquals($id, $post->tags()->first()->id); - - $post->flushEventListeners(); } public function testBelongsToManySyncTags() @@ -98,8 +92,6 @@ public function testBelongsToManySyncTags() $post->tags()->sync([$id]); $this->assertEquals(1, $post->tags->count()); $this->assertEquals($id, $post->tags()->first()->id); - - $post->flushEventListeners(); } public function testBelongsToManySyncCategories() @@ -113,8 +105,6 @@ public function testBelongsToManySyncCategories() $post->tags()->detach(); $this->assertEquals(0, $post->tags->count()); - - $post->flushEventListeners(); } public function testBelongsToManyDetach() @@ -126,8 +116,6 @@ public function testBelongsToManyDetach() $post->tags()->detach(); $this->assertEquals(0, $post->tags->count()); - - $post->flushEventListeners(); } } diff --git a/tests/DbTestCase.php b/tests/DbTestCase.php index f49b1ef60..a6d537841 100644 --- a/tests/DbTestCase.php +++ b/tests/DbTestCase.php @@ -1,5 +1,7 @@ db->setAsGlobal(); $this->db->bootEloquent(); } + + public function tearDown() : void + { + $this->flushModelEventListeners(); + parent::tearDown(); + unset($this->db); + } + + /** + * The models in October use a static property to store their events, these + * will need to be targeted and reset ready for a new test cycle. + * Pivot models are an exception since they are internally managed. + * @return void + */ + protected function flushModelEventListeners() + { + foreach (get_declared_classes() as $class) { + if ($class == 'October\Rain\Database\Pivot') { + continue; + } + + $reflectClass = new ReflectionClass($class); + if ( + !$reflectClass->isInstantiable() || + !$reflectClass->isSubclassOf('October\Rain\Database\Model') || + $reflectClass->isSubclassOf('October\Rain\Database\Pivot') + ) { + continue; + } + + $class::flushEventListeners(); + } + + ActiveRecord::flushEventListeners(); + } } From 2b8c815456efcb8651b1ce056549c6d9fa37f013 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Wed, 4 Nov 2020 20:08:28 -0500 Subject: [PATCH 17/24] fix method names --- tests/Database/RelationsTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index 161fe37e5..e43e50c0a 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -6,11 +6,11 @@ public function setUp(): void { parent::setUp(); - $this->create_tables(); - $this->seed_tables(); + $this->createTables(); + $this->seedTables(); } - public function create_tables() + public function createTables() { $this->db->schema()->create('posts', function ($table) { $table->increments('id'); @@ -32,7 +32,7 @@ public function create_tables() }); } - public function seed_tables() + public function seedTables() { $post = Post::create([ 'title' => 'A Post', From 957cda2545b9dd8e4bc280e1caf295cd08351e83 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sat, 7 Nov 2020 10:01:43 -0500 Subject: [PATCH 18/24] rework DbTestCase class handling --- tests/DbTestCase.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/DbTestCase.php b/tests/DbTestCase.php index a6d537841..d2bf6ebe4 100644 --- a/tests/DbTestCase.php +++ b/tests/DbTestCase.php @@ -1,12 +1,14 @@ db = new Illuminate\Database\Capsule\Manager; + $this->db = new CapsuleManager; $this->db->addConnection([ 'driver' => 'sqlite', 'database' => ':memory:', @@ -33,15 +35,15 @@ public function tearDown() : void protected function flushModelEventListeners() { foreach (get_declared_classes() as $class) { - if ($class == 'October\Rain\Database\Pivot') { + if ($class === Pivot::class) { continue; } $reflectClass = new ReflectionClass($class); if ( !$reflectClass->isInstantiable() || - !$reflectClass->isSubclassOf('October\Rain\Database\Model') || - $reflectClass->isSubclassOf('October\Rain\Database\Pivot') + !$reflectClass->isSubclassOf(Model::class) || + $reflectClass->isSubclassOf(Pivot::class) ) { continue; } @@ -49,6 +51,6 @@ protected function flushModelEventListeners() $class::flushEventListeners(); } - ActiveRecord::flushEventListeners(); + Model::flushEventListeners(); } } From 9187bf468d3221fd6f676c3ecdfdd2d4117a3e77 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 8 Nov 2020 11:12:44 -0500 Subject: [PATCH 19/24] call parent::attach() instead of duplicating code here --- src/Database/Relations/BelongsToMany.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index df154b48c..79cf1a726 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -130,14 +130,10 @@ public function attach($id, array $attributes = [], $touch = true) return; } - // Here we will insert the attachment records into the pivot table. Once we have - // inserted the records, we will touch the relationships if necessary and the - // function will return. We can parse the IDs before inserting the records. - $this->newPivotStatement()->insert($insertData); - - if ($touch) { - $this->touchIfTouching(); - } + /* + * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable + */ + parent::attach($id, $attributes, $touch); /** * @event model.relation.afterAttach From 8a205f84f7b0d03c5fd52d63f67c08cf9a333377 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Sun, 8 Nov 2020 11:14:26 -0500 Subject: [PATCH 20/24] Revert "call parent::attach() instead of duplicating code here" This reverts commit 9187bf468d3221fd6f676c3ecdfdd2d4117a3e77. --- src/Database/Relations/BelongsToMany.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Database/Relations/BelongsToMany.php b/src/Database/Relations/BelongsToMany.php index 79cf1a726..df154b48c 100644 --- a/src/Database/Relations/BelongsToMany.php +++ b/src/Database/Relations/BelongsToMany.php @@ -130,10 +130,14 @@ public function attach($id, array $attributes = [], $touch = true) return; } - /* - * See Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithPivotTable - */ - parent::attach($id, $attributes, $touch); + // Here we will insert the attachment records into the pivot table. Once we have + // inserted the records, we will touch the relationships if necessary and the + // function will return. We can parse the IDs before inserting the records. + $this->newPivotStatement()->insert($insertData); + + if ($touch) { + $this->touchIfTouching(); + } /** * @event model.relation.afterAttach From 83fa7dbc48201c5e4277c00bf9145ad3e6f46e85 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 9 Nov 2020 23:38:36 -0500 Subject: [PATCH 21/24] add spaces around => operator Co-authored-by: Ben Thomson --- tests/Database/RelationsTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index e43e50c0a..e72fda8e2 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -38,10 +38,10 @@ public function seedTables() 'title' => 'A Post', ]); - $post->tags()->create(['type'=>'tag', 'name'=>'A Tag']); - $post->tags()->create(['type'=>'tag', 'name'=>'Second Tag']); - $post->categories()->create(['type'=>'category', 'name'=>'A Category']); - $post->categories()->create(['type'=>'category', 'name'=>'Second Category']); + $post->tags()->create(['type' => 'tag', 'name' => 'A Tag']); + $post->tags()->create(['type' => 'tag', 'name' => 'Second Tag']); + $post->categories()->create(['type' => 'category', 'name' => 'A Category']); + $post->categories()->create(['type' => 'category', 'name' => 'Second Category']); } public function testTablesExist() From 4e0f857bfd33195394cffb09a4da884843847a8c Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 10 Nov 2020 00:27:33 -0500 Subject: [PATCH 22/24] add multiple records sync and single record detach --- tests/Database/RelationsTest.php | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index e72fda8e2..30454d809 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -38,8 +38,12 @@ public function seedTables() 'title' => 'A Post', ]); + Term::create(['type' => 'category', 'name' => 'category tag #1']); + Term::create(['type' => 'category', 'name' => 'category tag #2']); + $post->tags()->create(['type' => 'tag', 'name' => 'A Tag']); $post->tags()->create(['type' => 'tag', 'name' => 'Second Tag']); + $post->categories()->create(['type' => 'category', 'name' => 'A Category']); $post->categories()->create(['type' => 'category', 'name' => 'Second Category']); } @@ -54,9 +58,9 @@ public function testTablesExist() public function testTablesProperlySeeded() { $this->assertEquals(1, Post::count()); - $this->assertEquals(4, Term::count()); + $this->assertEquals(6, Term::count()); $this->assertEquals(2, Term::where('type', 'tag')->count()); - $this->assertEquals(2, Term::where('type', 'category')->count()); + $this->assertEquals(4, Term::where('type', 'category')->count()); } public function testBelongsToManyCount() @@ -117,6 +121,25 @@ public function testBelongsToManyDetach() $post->tags()->detach(); $this->assertEquals(0, $post->tags->count()); } + + public function testBelongsToManySyncMultipleCategories() + { + $post = Post::first(); + + $category_ids = Term::where('type', 'category')->lists('id'); + $this->assertEquals(4, count($category_ids)); + + $post->categories()->sync($category_ids); + $this->assertEquals(4, $post->categories()->count()); + } + + public function testBelongsToManyDetachOneCategory() + { + $post = Post::first(); + + $post->categories()->detach([6]); + $this->assertEquals(1, $post->categories->count()); + } } class Post extends \October\Rain\Database\Model From 1c17771bca1116887d89d5d2b6809dbd7c6828a9 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Tue, 10 Nov 2020 22:30:02 -0500 Subject: [PATCH 23/24] find the last category type term and detach it --- tests/Database/RelationsTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index 30454d809..ab240ea1a 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -137,7 +137,8 @@ public function testBelongsToManyDetachOneCategory() { $post = Post::first(); - $post->categories()->detach([6]); + $id = Term::where('type', 'category')->get()->last()->id; + $post->categories()->detach([$id]); $this->assertEquals(1, $post->categories->count()); } } From e21358619de575c685c21f810ee8a4a6b70932d8 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Thu, 12 Nov 2020 12:37:13 -0500 Subject: [PATCH 24/24] flush cache after query if needed --- tests/Database/RelationsTest.php | 41 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/tests/Database/RelationsTest.php b/tests/Database/RelationsTest.php index ab240ea1a..4311cf4e6 100644 --- a/tests/Database/RelationsTest.php +++ b/tests/Database/RelationsTest.php @@ -74,26 +74,35 @@ public function testBelongsToManySyncAll() { $post = Post::first(); - $id = $post->categories()->first()->id; - $post->categories()->sync([$id]); + $catid = $post->categories()->first()->id; + $tagid = $post->tags()->first()->id; + + Post::flushDuplicateCache(); + + $post->categories()->sync([$catid]); + $this->assertEquals(1, $post->categories->count()); - $this->assertEquals($id, $post->categories()->first()->id); + $this->assertEquals($catid, $post->categories()->first()->id); + + $post->tags()->sync([$tagid]); - $id = $post->tags()->first()->id; - $post->tags()->sync([$id]); $this->assertEquals(1, $post->tags->count()); - $this->assertEquals($id, $post->tags()->first()->id); + $this->assertEquals($tagid, $post->tags()->first()->id); } public function testBelongsToManySyncTags() { $post = Post::first(); + $id = $post->tags()->first()->id; + + Post::flushDuplicateCache(); + $post->categories()->detach(); - $this->assertEquals(0, $post->categories->count()); + $this->assertEquals(0, $post->categories()->count()); - $id = $post->tags()->first()->id; $post->tags()->sync([$id]); + $this->assertEquals(1, $post->tags->count()); $this->assertEquals($id, $post->tags()->first()->id); } @@ -103,8 +112,12 @@ public function testBelongsToManySyncCategories() $post = Post::first(); $id = $post->categories()->first()->id; + + Post::flushDuplicateCache(); + $post->categories()->sync([$id]); - $this->assertEquals(1, $post->categories->count()); + + $this->assertEquals(1, $post->categories()->count()); $this->assertEquals($id, $post->categories()->first()->id); $post->tags()->detach(); @@ -116,10 +129,10 @@ public function testBelongsToManyDetach() $post = Post::first(); $post->categories()->detach(); - $this->assertEquals(0, $post->categories->count()); + $this->assertEquals(0, $post->categories()->count()); $post->tags()->detach(); - $this->assertEquals(0, $post->tags->count()); + $this->assertEquals(0, $post->tags()->count()); } public function testBelongsToManySyncMultipleCategories() @@ -137,9 +150,11 @@ public function testBelongsToManyDetachOneCategory() { $post = Post::first(); - $id = Term::where('type', 'category')->get()->last()->id; + $id = $post->categories()->get()->last()->id; + Post::flushDuplicateCache(); + $post->categories()->detach([$id]); - $this->assertEquals(1, $post->categories->count()); + $this->assertEquals(1, $post->categories()->count()); } }