Skip to content

Commit

Permalink
feature -- experimental support of HasMany and BelongsTo relations
Browse files Browse the repository at this point in the history
  • Loading branch information
phoenix committed Jan 14, 2021
1 parent 717d29a commit c8464b9
Show file tree
Hide file tree
Showing 14 changed files with 311 additions and 34 deletions.
2 changes: 1 addition & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 27 additions & 13 deletions resources/js/components/DetailField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
</template>

<script>
import {FormField, HandlesValidationErrors} from 'laravel-nova'
import { FormField, HandlesValidationErrors } from "laravel-nova";
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
components: {Treeselect},
Expand All @@ -39,7 +39,7 @@ export default {
data()
{
return {
selectedValues: [],
selectedValues: null,
};
},
methods: {
Expand All @@ -56,17 +56,31 @@ export default {
},
setInitialValue()
{
let baseUrl = '/nova-vendor/nova-nested-tree-attach-many/';
let baseUrl = '/nova-vendor/nova-nested-tree-attach-many/';
if( this.resourceId )
{
const url = [
baseUrl + this.resourceName,
this.resourceId,
"attached",
this.field.attribute,
this.field.idKey
];
if( this.resourceId )
{
Nova.request( baseUrl + this.resourceName + '/' + this.resourceId + '/attached/' + this.field.attribute )
.then( ( data ) =>
{
this.selectedValues = data.data || [];
} );
}
Nova.request( url.join( "/" ) )
.then( ( data ) =>
{
if(!this.field.multiple)
{
this.selectedValues = data.data || undefined;
}
else
{
this.selectedValues = data.data || [];
}
} );
}
},
fill( formData )
{
Expand Down
38 changes: 32 additions & 6 deletions resources/js/components/FormField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default {
data()
{
return {
selectedValues: [],
selectedValues: null,
};
},
methods: {
Expand All @@ -63,12 +63,38 @@ export default {
if( this.resourceId )
{
Nova.request( baseUrl + this.resourceName + '/' + this.resourceId + '/attached/' + this.field.attribute )
.then( ( data ) =>
{
this.selectedValues = data.data || [];
const url = [
baseUrl + this.resourceName,
this.resourceId,
'attached',
this.field.attribute,
this.field.idKey
];
Nova.request( url.join('/') )
.then( ( data ) => {
if(!this.field.multiple)
{
this.selectedValues = data.data || undefined;
}
else
{
this.selectedValues = data.data || [];
}
} );
}
else
{
if(!this.field.multiple)
{
this.selectedValues = undefined;
}
else
{
this.selectedValues = [];
}
}
},
fill( formData )
{
Expand All @@ -81,7 +107,7 @@ export default {
},
firstError: function() {
return this.errors.errors[this.field.attribute][0]
},
}
}
}
</script>
2 changes: 1 addition & 1 deletion routes/api.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?php

Route::get('/{resource}/{resourceId}/attached/{relationship}', 'PhoenixLib\NovaNestedTreeAttachMany\Http\Controllers\NestedTreeController@attached');
Route::get('/{resource}/{resourceId}/attached/{relationship}/{idKey}', 'PhoenixLib\NovaNestedTreeAttachMany\Http\Controllers\NestedTreeController@attached');
38 changes: 38 additions & 0 deletions src/Domain/Relation/Handlers/BelongsToHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
namespace PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers;

use DomainException;

class BelongsToHandler implements RelationHandler
{
public function relation(): string
{
return 'Illuminate\Database\Eloquent\Relations\BelongsTo';
}

public function attach( $model, $relationship, $value): void
{
if(is_array($value))
{
throw new DomainException('Can`t use BelongsTo relation with multiple select.');
}

if(intval($value) > 0)
{
$relationModel = $model->{$relationship}()->getModel();

$model->{$relationship}()->associate($relationModel->find($value));
}
else
{
$model->{$relationship}()->dissociate();
}

$model->saveQuietly();
}

public function retrieve($model, $relationship, $idKey)
{
return $model->{$relationship} ? $model->{$relationship}->{$idKey}: null;
}
}
20 changes: 20 additions & 0 deletions src/Domain/Relation/Handlers/BelongsToManyHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
namespace PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers;

class BelongsToManyHandler implements RelationHandler
{
public function relation(): string
{
return 'Illuminate\Database\Eloquent\Relations\BelongsToMany';
}

public function attach( $model, $relationship, $values): void
{
$model->{$relationship}()->sync($values);
}

public function retrieve($model, $relationship, $idKey)
{
return $model->{$relationship}->pluck($idKey)->all();
}
}
69 changes: 69 additions & 0 deletions src/Domain/Relation/Handlers/HasManyHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
namespace PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers;

class HasManyHandler implements RelationHandler
{
private $updated = false;

public function relation(): string
{
return 'Illuminate\Database\Eloquent\Relations\HasMany';
}

public function attach( $model, $relationship, $values): void
{
$dispatcher = $model->getEventDispatcher();

$model->unsetEventDispatcher();



$relationModel = $model->{$relationship}()->getModel();

$models = $relationModel->find($values);

$models->each(function ( $children ) use ( $model ){

if(!$children->is($model))
{
if(!$model->ancestors->contains($children))
{
$this->updated = true;

$children->parent()->associate($model);
$children->save();
}
}

});



foreach($model->{$relationship} as $children )
{
if(!$models->contains($children))
{
$this->updated = true;

$children->parent()->dissociate();
$children->save();
}
}



if($this->updated)
{
$model->fixTree();
}



$model->setEventDispatcher($dispatcher);
}

public function retrieve($model, $relationship, $idKey)
{
return $model->{$relationship}->pluck($idKey)->all();
}
}
11 changes: 11 additions & 0 deletions src/Domain/Relation/Handlers/RelationHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
namespace PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers;

interface RelationHandler
{
public function relation(): string;

public function attach( $model, $relationship, $values): void;

public function retrieve($model, $relationship, $idKey);
}
19 changes: 19 additions & 0 deletions src/Domain/Relation/RelationHandlerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation;

use Illuminate\Support\Collection;
use PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers\RelationHandler;

interface RelationHandlerFactory
{
public function make($relation): RelationHandler;

public function register( RelationHandler $handler ): void;

public function unregister( RelationHandler $handler ): void;

public function registeredHandlers(): Collection;

public function unregisterAll(): void;
}
49 changes: 49 additions & 0 deletions src/Domain/Relation/RelationHandlerResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation;

use DomainException;
use Illuminate\Support\Collection;
use PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers\RelationHandler;

class RelationHandlerResolver implements RelationHandlerFactory
{
private $handlers;

public function __construct(){
$this->handlers = new Collection;
}

public function make( $relation ): RelationHandler
{
if($this->handlers->has( $relation ))
{
return $this->handlers->get( $relation );
}

throw new DomainException(sprintf('RelationHandler for relation: %s is not registered', $relation));
}

public function register( RelationHandler $handler ): void
{
$this->handlers->put($handler->relation(), $handler);
}

public function unregister( RelationHandler $handler ): void
{
if($this->handlers->has($handler->relation()))
{
$this->handlers->forget($handler->relation());
}
}

public function registeredHandlers(): Collection
{
return $this->handlers;
}

public function unregisterAll(): void
{
$this->handlers = new Collection;
}
}
13 changes: 12 additions & 1 deletion src/FieldServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
use Illuminate\Support\ServiceProvider;
use Laravel\Nova\Events\ServingNova;
use Laravel\Nova\Nova;
use PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers\BelongsToHandler;
use PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers\BelongsToManyHandler;
use PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\Handlers\HasManyHandler;
use PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\RelationHandlerFactory;
use PhoenixLib\NovaNestedTreeAttachMany\Domain\Relation\RelationHandlerResolver;

class FieldServiceProvider extends ServiceProvider
{
Expand Down Expand Up @@ -34,6 +39,12 @@ public function boot()
*/
public function register()
{
//
$this->app->singleton(RelationHandlerFactory::class, RelationHandlerResolver::class);

$factory = $this->app->make(RelationHandlerFactory::class);

$factory->register($this->app->make(BelongsToManyHandler::class));
$factory->register($this->app->make(BelongsToHandler::class));
$factory->register($this->app->make(HasManyHandler::class));
}
}
Loading

0 comments on commit c8464b9

Please sign in to comment.