Skip to content

Commit

Permalink
[8.x] BelongsToMany->sync() will support touching for pivots when the…
Browse files Browse the repository at this point in the history
… result contains detached items (#38085)

* BelongsToMany->sync() should respect touching when sync was also removing any entries

* Add explicit check if we removed id=3

* style-ci

* style-ci

* style-ci
  • Loading branch information
christoph-kluge authored Jul 21, 2021
1 parent 34aa272 commit a17fd16
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ public function sync($ids, $detaching = true)
// 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'])) {
count($changes['updated']) ||
count($changes['detached'])) {
$this->touchIfTouching();
}

Expand Down
173 changes: 173 additions & 0 deletions tests/Database/DatabaseEloquentBelongsToManySyncTouchesParentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php

namespace Illuminate\Tests\Database;

use Illuminate\Database\Capsule\Manager as DB;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Eloquent\Relations\Pivot as EloquentPivot;
use Illuminate\Support\Carbon;
use PHPUnit\Framework\TestCase;

class DatabaseEloquentBelongsToManySyncTouchesParentTest extends TestCase
{
protected function setUp(): void
{
$db = new DB;

$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);

$db->bootEloquent();
$db->setAsGlobal();

$this->createSchema();
}

/**
* Setup the database schema.
*
* @return void
*/
public function createSchema()
{
$this->schema()->create('articles', function ($table) {
$table->string('id');
$table->string('title');

$table->primary('id');
$table->timestamps();
});

$this->schema()->create('article_user', function ($table) {
$table->string('article_id');
$table->foreign('article_id')->references('id')->on('articles');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});

$this->schema()->create('users', function ($table) {
$table->increments('id');
$table->string('email')->unique();
$table->timestamps();
});
}

/**
* Tear down the database schema.
*
* @return void
*/
protected function tearDown(): void
{
$this->schema()->drop('users');
$this->schema()->drop('articles');
$this->schema()->drop('article_user');
}

/**
* Helpers...
*/
protected function seedData()
{
DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser::create(['id' => 1, 'email' => '[email protected]']);
DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser::create(['id' => 2, 'email' => '[email protected]']);
DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser::create(['id' => 3, 'email' => '[email protected]']);
}

public function testSyncWithDetachedValuesShouldTouch()
{
$this->seedData();

Carbon::setTestNow('2021-07-19 10:13:14');
$article = DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticle::create(['id' => 1, 'title' => 'uuid title']);
$article->users()->sync([1, 2, 3]);
$this->assertSame('2021-07-19 10:13:14', $article->updated_at->format('Y-m-d H:i:s'));

Carbon::setTestNow('2021-07-20 19:13:14');
$result = $article->users()->sync([1, 2]);
$this->assertTrue(collect($result['detached'])->count() === 1);
$this->assertSame('3', collect($result['detached'])->first());

$article->refresh();
$this->assertSame('2021-07-20 19:13:14', $article->updated_at->format('Y-m-d H:i:s'));

$user1 = DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser::find(1);
$this->assertNotSame('2021-07-20 19:13:14', $user1->updated_at->format('Y-m-d H:i:s'));
$user2 = DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser::find(2);
$this->assertNotSame('2021-07-20 19:13:14', $user2->updated_at->format('Y-m-d H:i:s'));
$user3 = DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser::find(3);
$this->assertNotSame('2021-07-20 19:13:14', $user3->updated_at->format('Y-m-d H:i:s'));
}

/**
* Get a database connection instance.
*
* @return \Illuminate\Database\ConnectionInterface
*/
protected function connection()
{
return Eloquent::getConnectionResolver()->connection();
}

/**
* Get a schema builder instance.
*
* @return \Illuminate\Database\Schema\Builder
*/
protected function schema()
{
return $this->connection()->getSchemaBuilder();
}
}

class DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticle extends Eloquent
{
protected $table = 'articles';
protected $keyType = 'string';
public $incrementing = false;
protected $fillable = ['id', 'title'];

public function users()
{
return $this
->belongsToMany(DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticle::class, 'article_user', 'article_id', 'user_id')
->using(DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticleUser::class)
->withTimestamps();
}
}

class DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticleUser extends EloquentPivot
{
protected $table = 'article_user';
protected $fillable = ['article_id', 'user_id'];
protected $touches = ['article'];

public function article()
{
return $this->belongsTo(DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticle::class, 'article_id', 'id');
}

public function user()
{
return $this->belongsTo(DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser::class, 'user_id', 'id');
}
}

class DatabaseEloquentBelongsToManySyncTouchesParentTestTestUser extends Eloquent
{
protected $table = 'users';
protected $keyType = 'string';
public $incrementing = false;
protected $fillable = ['id', 'email'];

public function articles()
{
return $this
->belongsToMany(DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticle::class, 'article_user', 'user_id', 'article_id')
->using(DatabaseEloquentBelongsToManySyncTouchesParentTestTestArticleUser::class)
->withTimestamps();
}
}

0 comments on commit a17fd16

Please sign in to comment.