Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/Eloquent/Concerns/InteractsWithRelations.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,23 +236,45 @@ protected function fillHasManyRelation(Relations\HasMany $relation, array $value
*
* @param Relations\BelongsToMany $relation
* @param array $data
* @param bool $detaching
* @return void
*/
public function connectBelongsToManyRelation(Relations\BelongsToMany $relation, array $data)
public function connectBelongsToManyRelation(Relations\BelongsToMany $relation, array $data, $detaching = true)
{
$accessor = $relation->getPivotAccessor();
$relatedKey = $relation->getRelated()->getKeyName();

$pivotClass = $relation->getPivotClass();
$pivotInstance = resolve($pivotClass);

$data = collect($data)->mapWithKeys(function ($data, $key) use ($accessor, $relatedKey) {
if (! is_array($data)) {
return [$key => $data];
}

return [$data[$relatedKey] => $data[$accessor]];
})->map(function ($attributes) use ($pivotClass) {
if (! is_array($attributes)) {
return $attributes;
}

$instance = new $pivotClass;
$pivotSchema = $this->registry->getSchemaForModel($instance);
$pivotSchema->fill($attributes);

return $pivotSchema->getInstance()->getAttributes();
});

$this->queue(function () use ($relation, $data) {
$relation->sync($data);
$this->queue(function () use ($pivotInstance, $data, $detaching, $relation) {
if ($pivotInstance) {
$pivotInstance::unguard();
}

$relation->sync($data, $detaching);

if ($pivotInstance) {
$pivotInstance::reguard();
}
});
}

Expand Down
25 changes: 10 additions & 15 deletions src/Mutations/AttachPivotMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Bakery\Mutations;

use Bakery\Fields\Field;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model;
use GraphQL\Type\Definition\ResolveInfo;
use Bakery\Types\Concerns\InteractsWithPivot;
Expand Down Expand Up @@ -74,26 +75,20 @@ protected function getRelation(Model $model): BelongsToMany
*/
public function resolve($root, array $args, $context, ResolveInfo $info): Model
{
$input = $args['input'];
$model = $this->findOrFail($root, $args, $context, $info);
$relation = $this->getRelation($model);
$modelSchema = $this->registry->getSchemaForModel($model);

$permission = 'set'.studly_case($relation->getRelationName());
$modelSchema->authorize($permission, $model);
return DB::transaction(function () use ($input, $model) {
$modelSchema = $this->registry->getSchemaForModel($model);

$relatedKey = $relation->getRelated()->getKeyName();
$accessor = $relation->getPivotAccessor();
$relation = $this->getRelation($model);

$data = collect($args['input'])->mapWithKeys(function ($data, $key) use ($accessor, $relatedKey) {
if (! is_array($data)) {
return [$key => $data];
}
$permission = 'set'.studly_case($relation->getRelationName());
$modelSchema->authorize($permission, $model);
$modelSchema->connectBelongsToManyRelation($relation, $input, false);
$modelSchema->save();

return [$data[$relatedKey] => $data[$accessor]];
return $modelSchema->getInstance();
});

$relation->attach($data);

return $model;
}
}
67 changes: 67 additions & 0 deletions tests/Feature/AttachPivotMutationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,73 @@ public function it_lets_you_attach_pivot_ids_with_pivot_data()
]);
}

/** @test */
public function it_lets_you_attach_pivot_ids_with_pivot_relation_data()
{
$user = factory(User::class)->create();
$role = factory(Role::class)->create();
$tag = factory(Tag::class)->create();
$this->actingAs($user);

$query = '
mutation {
attachCustomRolesOnUser(id: "'.$user->id.'", input: [
{ id: "'.$role->id.'", customPivot: {tagId: "'.$tag->id.'" } }
]) {
id
customRoles {
customPivot {
comment
}
}
}
}
';

$response = $this->json('GET', '/graphql', ['query' => $query]);
$response->assertJsonKey('id');
$this->assertDatabaseHas('role_user', [
'user_id' => '1',
'role_id' => '1',
'tag_id' => '1',
]);
}

/** @test */
public function it_lets_you_attach_pivot_with_create()
{
$user = factory(User::class)->create();
$role = factory(Role::class)->create();
$this->actingAs($user);

$query = '
mutation {
attachCustomRolesOnUser(id: "'.$user->id.'", input: [
{ id: "'.$role->id.'", customPivot: {tag: {name: "foobar"} } }
]) {
id
customRoles {
customPivot {
comment
}
}
}
}
';

$response = $this->json('GET', '/graphql', ['query' => $query]);
$response->assertJsonKey('id');
$this->assertDatabaseHas('role_user', [
'user_id' => '1',
'role_id' => '1',
'tag_id' => '1',
]);

$this->assertDatabaseHas('tags', [
'name' => 'foobar',
]);
}

/** @test */
public function it_lets_you_attach_pivot_ids_with_pivot_data_inversed()
{
Expand Down
1 change: 1 addition & 0 deletions tests/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ protected function setUp()
$this->gate = resolve(Gate::class);
$this->gate->policy(Models\User::class, Policies\UserPolicy::class);
$this->gate->policy(Models\Role::class, Policies\RolePolicy::class);
$this->gate->policy(Models\UserRole::class, Policies\UserRolePolicy::class);
$this->gate->policy(Models\Article::class, Policies\ArticlePolicy::class);
$this->gate->policy(Models\Phone::class, Policies\PhonePolicy::class);
$this->gate->policy(Models\Comment::class, Policies\CommentPolicy::class);
Expand Down
2 changes: 1 addition & 1 deletion tests/Stubs/Models/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function users()
{
return $this->belongsToMany(User::class)
->using(UserRole::class)
->withPivot('comment')
->withPivot(['comment', 'tag_id'])
->withTimestamps();
}
}
2 changes: 1 addition & 1 deletion tests/Stubs/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function customRoles()
return $this->belongsToMany(Role::class)
->as('customPivot')
->using(UserRole::class)
->withPivot('comment')
->withPivot(['comment', 'tag_id'])
->withTimestamps();
}
}
7 changes: 4 additions & 3 deletions tests/Stubs/Models/UserRole.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class UserRole extends Pivot
{
protected $primaryKey = null;

public $fillable = [
'comment',
];
public function tag()
{
return $this->belongsTo(Tag::class);
}
}
26 changes: 26 additions & 0 deletions tests/Stubs/Policies/UserRolePolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Bakery\Tests\Stubs\Policies;

class UserRolePolicy
{
public function create(): bool
{
return true;
}

public function update(): bool
{
return true;
}

public function setTag(): bool
{
return true;
}

public function createTag(): bool
{
return true;
}
}
9 changes: 8 additions & 1 deletion tests/Stubs/Schemas/UserRoleSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ class UserRoleSchema extends ModelSchema
public function fields(): array
{
return [
'comment' => Field::string(),
'comment' => Field::string()->nullable(),
];
}

public function relations(): array
{
return [
'tag' => Field::model(TagSchema::class)->nullable(),
];
}
}
5 changes: 5 additions & 0 deletions tests/migrations/0000_00_00_000005_create_role_user_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public function up()
Schema::create('role_user', function ($table) {
$table->unsignedInteger('user_id');
$table->unsignedInteger('role_id');
$table->unsignedInteger('tag_id')->nullable();
$table->text('comment')->nullable();
$table->timestamps();

Expand All @@ -23,6 +24,10 @@ public function up()
$table->foreign('role_id')
->references('id')->on('roles')
->onDelete('cascade');

$table->foreign('tag_id')
->references('id')->on('tags')
->onDelete('cascade');
});
}

Expand Down