Craftable supports all Eloquent Relationships defined in Laravel documentation.
Code from example section is placed in Craftable demo repository.
Let's imagine you have articles with authors and you want to implement this behavior:
Our example migration contains author_id
column which reference to authors
table.
Schema::create('articles_with_relationships', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('perex')->nullable();
$table->date('published_at')->nullable();
$table->boolean('enabled')->default(false);
$table->integer('author_id')->nullable();
$table->foreign('author_id')->references('id')->on('authors')->onDelete('cascade');
$table->timestamps();
});
In Author model add hasMany relation to ArticlesWithRelationship::class
public function articlesWithRelationships()
{
return $this->hasMany(ArticlesWithRelationship::class);
}
In ArticlesWithRelationship model add belongsTo relation to Author::class
public function author() {
return $this->belongsTo(Author::class);
}
Controller methods should look like:
public function index(IndexArticlesWithRelationship $request)
{
// create and AdminListing instance for a specific model and
$data = AdminListing::create(ArticlesWithRelationship::class)->processRequestAndGet(
// pass the request with params
$request,
// set columns to query
['id', 'title', 'published_at', 'enabled', 'author_id'],
// set columns to searchIn
['id', 'title', 'perex'],
function ($query) use ($request) {
$query->with(['author']);
if($request->has('authors')){
$query->whereIn('author_id', $request->get('authors'));
}
}
);
if ($request->ajax()) {
return ['data' => $data];
}
return view('admin.articles-with-relationship.index', [
'data' => $data,
'authors' => Author::all()
]);
}
public function create()
{
$this->authorize('admin.articles-with-relationship.create');
return view('admin.articles-with-relationship.create', [
'authors' => Author::all(),
]);
}
public function store(StoreArticlesWithRelationship $request)
{
// Sanitize input
$sanitized = $request->validated();
$sanitized['author_id'] = $request->getAuthorId();
// Store the ArticlesWithRelationship
$articlesWithRelationship = ArticlesWithRelationship::create($sanitized);
if ($request->ajax()) {
return [
'redirect' => url('admin/articles-with-relationships'),
'message' => trans('brackets/admin-ui::admin.operation.succeeded')
];
}
return redirect('admin/articles-with-relationships');
}
public function edit(ArticlesWithRelationship $articlesWithRelationship)
{
$this->authorize('admin.articles-with-relationship.edit', $articlesWithRelationship);
return view('admin.articles-with-relationship.edit', [
'articlesWithRelationship' => $articlesWithRelationship,
'authors' => Author::all(),
]);
}
public function update(UpdateArticlesWithRelationship $request, ArticlesWithRelationship $articlesWithRelationship)
{
// Sanitize input
$sanitized = $request->validated();
$sanitized['author_id'] = $request->getAuthorId();
// Update changed values ArticlesWithRelationship
$articlesWithRelationship->update($sanitized);
if ($request->ajax()) {
return ['redirect' => url('admin/articles-with-relationships'), 'message' => trans('brackets/admin-ui::admin.operation.succeeded')];
}
return redirect('admin/articles-with-relationships');
}
Store request requires methods:
public function rules()
{
return [
'title' => ['required', 'string'],
'perex' => ['nullable', 'string'],
'published_at' => ['nullable', 'date'],
'enabled' => ['required', 'boolean'],
'author' => ['required'],
];
}
public function getAuthorId(){
if ($this->has('author')){
return $this->get('author')['id'];
}
return null;
}
Update request requires methods:
public function rules()
{
return [
'title' => ['sometimes', 'string'],
'perex' => ['nullable', 'string'],
'published_at' => ['nullable', 'date'],
'enabled' => ['sometimes', 'boolean'],
'author' => ['required'],
];
}
public function getAuthorId(){
if ($this->has('author')){
return $this->get('author')['id'];
}
return null;
}
Add author property in data form object.
author: '' ,
Add following code to data()
and watch
data() {
return {
showAuthorsFilter: false,
authorsMultiselect: {},
filters: {
authors: [],
},
}
},
watch: {
showAuthorsFilter: function (newVal, oldVal) {
this.authorsMultiselect = [];
},
authorsMultiselect: function(newVal, oldVal) {
this.filters.authors = newVal.map(function(object) { return object['key']; });
this.filter('authors', this.filters.authors);
}
}
Add authors prop to form component.
:authors="{{$authors->toJson()}}"
Add authors prop to form component.
:authors="{{$authors->toJson()}}"
In place where you want to have authors filter add following code.
Also you can prepare :options
value on backend with own properties.
<div class="row" v-if="showAuthorsFilter">
<div class="col-sm-auto form-group">
<p>{{ __('Select author/s') }}</p>
</div>
<div class="col col-lg-12 col-xl-12 form-group">
<multiselect v-model="authorsMultiselect"
:options="{{ $authors->map(function($author) { return ['key' => $author->id, 'label' => $author->title]; })->toJson() }}"
label="label"
track-by="key"
placeholder="{{ __('Type to search a author/s') }}"
:limit="2"
:multiple="true">
</multiselect>
</div>
</div>
You can also use User detail tooltip in <tbody>
<user-detail-tooltip :user="item.author" v-if="item.author">
</user-detail-tooltip>
In form-elements.blade.php add following code in place where you want to have option to choose author of article.
<div class="form-group row align-items-center"
:class="{'has-danger': errors.has('author_id'), 'has-success': this.fields.author_id && this.fields.author_id.valid }">
<label for="author_id"
class="col-form-label text-center col-md-4 col-lg-3">{{ trans('admin.post.columns.author_id') }}</label>
<div class="col-md-8 col-lg-9">
<multiselect
v-model="form.author"
:options="authors"
:multiple="false"
track-by="id"
label="full_name"
tag-placeholder="{{ __('Select Author') }}"
placeholder="{{ __('Author') }}">
</multiselect>
<div v-if="errors.has('author_id')" class="form-control-feedback form-text" v-cloak>@{{
errors.first('author_id') }}
</div>
</div>
</div>