Support saving deferred bindings with pivot data. (#5466)

* Support saving deferred bindings with pivot data.
This commit is contained in:
Sergey Kasyanov 2021-03-17 23:24:39 +04:00 committed by GitHub
parent 12520828ba
commit d865186ac1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 223 additions and 0 deletions

View File

@ -0,0 +1,22 @@
<?php
use October\Rain\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class DbAddPivotDataToDeferredBindings extends Migration
{
public function up()
{
Schema::table('deferred_bindings', function (Blueprint $table) {
$table->mediumText('pivot_data')->nullable()->after('slave_id');
});
}
public function down()
{
Schema::table('deferred_bindings', function (Blueprint $table) {
$table->dropColumn('pivot_data');
});
}
}

View File

@ -51,6 +51,15 @@ class Author extends Model
public $morphOne = [
'meta' => ['Database\Tester\Models\Meta', 'name' => 'taggable'],
];
public $morphToMany = [
'tags' => [
'Database\Tester\Models\Tag',
'name' => 'taggable',
'table' => 'database_tester_taggables',
'pivot' => ['added_by']
],
];
}
class SoftDeleteAuthor extends Author

View File

@ -9,6 +9,14 @@ class Category extends Model
*/
public $table = 'database_tester_categories';
public $belongsToMany = [
'posts' => [
'Database\Tester\Models\Post',
'table' => 'database_tester_categories_posts',
'pivot' => ['category_name', 'post_name']
]
];
public function getCustomNameAttribute()
{
return $this->name.' (#'.$this->id.')';

View File

@ -26,6 +26,14 @@ class Post extends Model
'author' => 'Database\Tester\Models\Author',
];
public $belongsToMany = [
'categories' => [
'Database\Tester\Models\Category',
'table' => 'database_tester_categories_posts',
'pivot' => ['category_name', 'post_name']
]
];
public $morphMany = [
'event_log' => ['Database\Tester\Models\EventLog', 'name' => 'related', 'delete' => true, 'softDelete' => true],
];
@ -33,6 +41,15 @@ class Post extends Model
public $morphOne = [
'meta' => ['Database\Tester\Models\Meta', 'name' => 'taggable'],
];
public $morphToMany = [
'tags' => [
'Database\Tester\Models\Tag',
'name' => 'taggable',
'table' => 'database_tester_taggables',
'pivot' => ['added_by']
],
];
}
class NullablePost extends Post

View File

@ -0,0 +1,36 @@
<?php namespace Database\Tester\Models;
use Model;
class Tag extends Model
{
/**
* @var string The database table used by the model.
*/
public $table = 'database_tester_tags';
/**
* @var array Guarded fields
*/
protected $guarded = [];
/**
* @var array Fillable fields
*/
protected $fillable = [];
public $morphedByMany = [
'authors' => [
'Database\Tester\Models\Author',
'name' => 'taggable',
'table' => 'database_tester_taggables',
'pivot' => ['added_by'],
],
'posts' => [
'Database\Tester\Models\Post',
'name' => 'taggable',
'table' => 'database_tester_taggables',
'pivot' => ['added_by'],
],
];
}

View File

@ -22,10 +22,20 @@ class CreatePostsTable extends Migration
$table->softDeletes();
$table->timestamps();
});
Schema::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 function down()
{
Schema::dropIfExists('database_tester_categories_posts');
Schema::dropIfExists('database_tester_posts');
}
}

View File

@ -0,0 +1,31 @@
<?php namespace Database\Tester\Updates;
use Schema;
use October\Rain\Database\Updates\Migration;
class CreateTagsTable extends Migration
{
public function up()
{
Schema::create('database_tester_tags', function ($table) {
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('database_tester_taggables', function ($table) {
$table->engine = 'InnoDB';
$table->unsignedInteger('tag_id');
$table->morphs('taggable', 'testings_taggable');
$table->unsignedInteger('added_by')->nullable();
});
}
public function down()
{
Schema::dropIfExists('database_tester_taggables');
Schema::dropIfExists('database_tester_tags');
}
}

View File

@ -10,3 +10,4 @@
- create_event_log_table.php
- create_meta_table.php
- create_countries_table.php
- create_tags_table.php

View File

@ -1,5 +1,7 @@
<?php
use Database\Tester\Models\Category;
use Database\Tester\Models\Post as PostModel;
use Database\Tester\Models\Role;
use Database\Tester\Models\Author;
@ -11,6 +13,8 @@ class BelongsToManyModelTest extends PluginTestCase
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Role.php';
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Author.php';
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Category.php';
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Post.php';
$this->runPluginRefreshCommand('Database.Tester');
}
@ -86,29 +90,57 @@ class BelongsToManyModelTest extends PluginTestCase
$author = Author::create(['name' => 'Stevie', 'email' => 'stevie@email.tld']);
$role1 = Role::create(['name' => "Designer", 'description' => "Quality"]);
$role2 = Role::create(['name' => "Programmer", 'description' => "Speed"]);
$category = Category::create(['name' => 'News']);
$post1 = PostModel::create(['title' => 'First post']);
$post2 = PostModel::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);
@ -116,14 +148,27 @@ class BelongsToManyModelTest extends PluginTestCase
// 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 testDetachAfterDelete()

View File

@ -1,6 +1,8 @@
<?php
use Database\Tester\Models\Author;
use Database\Tester\Models\Tag;
use Database\Tester\Models\Post;
use Database\Tester\Models\EventLog;
use October\Rain\Database\Collection;
@ -11,7 +13,9 @@ class MorphManyModelTest extends PluginTestCase
parent::setUp();
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Author.php';
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Post.php';
include_once base_path().'/tests/fixtures/plugins/database/tester/models/EventLog.php';
include_once base_path().'/tests/fixtures/plugins/database/tester/models/Tag.php';
$this->runPluginRefreshCommand('Database.Tester');
}
@ -84,6 +88,9 @@ class MorphManyModelTest extends PluginTestCase
Model::unguard();
$author = Author::create(['name' => 'Stevie']);
$event = EventLog::create(['action' => "user-created"]);
$post = Post::create(['title' => 'Hello world!']);
$tagForAuthor = Tag::create(['name' => 'ForAuthor']);
$tagForPost = Tag::create(['name' => 'ForPost']);
Model::reguard();
$eventId = $event->id;
@ -96,6 +103,18 @@ class MorphManyModelTest extends PluginTestCase
$this->assertEquals(0, $author->event_log()->count());
$this->assertEquals(1, $author->event_log()->withDeferred($sessionKey)->count());
$author->tags()->add($tagForAuthor, $sessionKey, ['added_by' => 99]);
$this->assertEmpty($author->tags);
$this->assertEquals(0, $author->tags()->count());
$this->assertEquals(1, $author->tags()->withDeferred($sessionKey)->count());
$tagForPost->posts()->add($post, $sessionKey, ['added_by' => 88]);
$this->assertEmpty($tagForPost->posts);
$this->assertEquals(0, $tagForPost->posts()->count());
$this->assertEquals(1, $tagForPost->posts()->withDeferred($sessionKey)->count());
// Commit deferred
$author->save(null, $sessionKey);
$event = EventLog::find($eventId);
@ -105,6 +124,15 @@ class MorphManyModelTest extends PluginTestCase
'user-created'
], $author->event_log->lists('action'));
$this->assertEquals(1, $author->tags()->count());
$this->assertEquals([$tagForAuthor->id], $author->tags->lists('id'));
$this->assertEquals(99, $author->tags->first()->pivot->added_by);
$tagForPost->save(null, $sessionKey);
$this->assertEquals(1, $tagForPost->posts()->count());
$this->assertEquals([$post->id], $tagForPost->posts->lists('id'));
$this->assertEquals(88, $tagForPost->posts->first()->pivot->added_by);
// New session
$sessionKey = uniqid('session_key', true);
@ -117,11 +145,27 @@ class MorphManyModelTest extends PluginTestCase
'user-created'
], $author->event_log->lists('action'));
$author->tags()->remove($tagForAuthor, $sessionKey);
$this->assertEquals(1, $author->tags()->count());
$this->assertEquals(0, $author->tags()->withDeferred($sessionKey)->count());
$this->assertEquals([$tagForAuthor->id], $author->tags->lists('id'));
$this->assertEquals(99, $author->tags->first()->pivot->added_by);
$tagForPost->posts()->remove($post, $sessionKey);
$this->assertEquals(1, $tagForPost->posts()->count());
$this->assertEquals(0, $tagForPost->posts()->withDeferred($sessionKey)->count());
$this->assertEquals([$post->id], $tagForPost->posts->lists('id'));
$this->assertEquals(88, $tagForPost->posts->first()->pivot->added_by);
// Commit deferred (model is deleted as per definition)
$author->save(null, $sessionKey);
$event = EventLog::find($eventId);
$this->assertEquals(0, $author->event_log()->count());
$this->assertNull($event);
$this->assertEmpty($author->event_log);
$this->assertEmpty(0, $author->tags);
$this->assertEmpty(0, $tagForPost->posts);
}
}