Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Nested mutations #207

Merged
merged 3 commits into from
Aug 7, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add basic nested mutations
  • Loading branch information
spawnia committed Jul 17, 2018
commit cc795d53e7c758ca33932447edf70bd242bb2c55
101 changes: 101 additions & 0 deletions src/Execution/NestedMutationExecutor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace Nuwave\Lighthouse\Execution;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;

class NestedMutationExecutor
{
public static function executeCreate(Model $model, Collection $args, ?HasMany $parentRelation = null): Model
{
list($belongsTo, $remaining) = self::extractBelongsToArgs($model, $args);
list($hasMany, $remaining) = self::extractHasManyArgs($model, $remaining);

$model->fill($remaining->all());

$belongsTo->each(function ($value, $key) use ($model) {
$model->{$key}()->associate($value);
});

$parentRelation
? $parentRelation->save($model)
: $model->save();

$hasMany->each(function ($nestedOperations, $key) use ($model) {
/** @var HasMany $relation */
$relation = $model->{$key}();

collect($nestedOperations)->each(function ($values, $operationKey) use ($relation) {
if ($operationKey === 'create') {
self::handleHasManyCreate(collect($values), $relation);
}
});
});

return $model;
}

protected static function handleHasManyCreate(Collection $multiValues, HasMany $relation): void
{
$multiValues->each(function ($singleValues) use ($relation) {
self::executeCreate($relation->getModel()->newInstance(), collect($singleValues), $relation);
});
}

public static function executeUpdate(Model $model, Collection $args, ?HasMany $parentRelation = null): Model
{
list($belongsTo, $remaining) = self::extractBelongsToArgs($model, $args);
list($hasMany, $remaining) = self::extractHasManyArgs($model, $remaining);

$model = $model->newQuery()->findOrFail($args->pull('id'));
$model->fill($remaining->all());

$belongsTo->each(function ($value, $key) use ($model) {
$model->{$key}()->associate($value);
});

$parentRelation
? $parentRelation->save($model)
: $model->save();

$hasMany->each(function ($nestedOperations, $key) use ($model) {
/** @var HasMany $relation */
$relation = $model->{$key}();

collect($nestedOperations)->each(function ($values, $operationKey) use ($relation) {
if ($operationKey === 'create') {
self::handleHasManyCreate(collect($values), $relation);
}

if ($operationKey === 'update') {
collect($values)->each(function ($singleValues) use ($relation) {
self::executeUpdate($relation->getModel()->newInstance(), collect($singleValues), $relation);
});
}

if ($operationKey === 'delete') {
$relation->getModel()::destroy($values);
}
});
});

return $model;
}

protected static function extractBelongsToArgs(Model $model, Collection $args): Collection
{
return $args->partition(function ($value, $key) use ($model) {
return method_exists($model, $key) && ($model->{$key}() instanceof BelongsTo);
});
}

protected static function extractHasManyArgs(Model $model, Collection $args): Collection
{
return $args->partition(function ($value, $key) use ($model) {
return method_exists($model, $key) && ($model->{$key}() instanceof HasMany);
});
}
}
40 changes: 40 additions & 0 deletions src/Schema/Directives/Fields/CreateNestedDirective.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Nuwave\Lighthouse\Schema\Directives\Fields;

use Nuwave\Lighthouse\Execution\NestedMutationExecutor;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
use Nuwave\Lighthouse\Support\Exceptions\DirectiveException;

class CreateNestedDirective extends BaseDirective implements FieldResolver
{
/**
* Name of the directive.
*
* @return string
*/
public function name()
{
return 'createNested';
}

/**
* Resolve the field directive.
*
* @param FieldValue $value
*
* @return FieldValue
* @throws DirectiveException
*/
public function resolveField(FieldValue $value)
{
$modelClassName = $this->getModelClass();
$model = new $modelClassName();

return $value->setResolver(function ($root, $args) use ($model) {
return NestedMutationExecutor::executeCreate($model, collect($args['input']));
});
}
}
40 changes: 40 additions & 0 deletions src/Schema/Directives/Fields/UpdateNestedDirective.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Nuwave\Lighthouse\Schema\Directives\Fields;

use Nuwave\Lighthouse\Execution\NestedMutationExecutor;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
use Nuwave\Lighthouse\Support\Exceptions\DirectiveException;

class UpdateNestedDirective extends BaseDirective implements FieldResolver
{
/**
* Name of the directive.
*
* @return string
*/
public function name()
{
return 'updateNested';
}

/**
* Resolve the field directive.
*
* @param FieldValue $value
*
* @return FieldValue
* @throws DirectiveException
*/
public function resolveField(FieldValue $value)
{
$modelClassName = $this->getModelClass();
$model = new $modelClassName();

return $value->setResolver(function ($root, $args) use ($model) {
return NestedMutationExecutor::executeUpdate($model, collect($args['input']));
});
}
}