<?phpuseIlluminate\Support\Facades\Route;useApp\Http\Controllers\Admin\ArticlesController;/*|--------------------------------------------------------------------------| Web Routes|--------------------------------------------------------------------------|| Here is where you can register web routes for your application. These| routes are loaded by the RouteServiceProvider within a group which| contains the "web" middleware group. Now create something great!|*/Route::get('/',function () {returnview('welcome');});Route::group(['middleware'=> ['auth'],'prefix'=>'admin','as'=>'admin.'],function () {Route::resource('articles',ArticlesController::class);});Auth::routes();Route::get('/home', [App\Http\Controllers\HomeController::class,'index'])->name('home');
<?phpnamespaceApp\Http\Requests\Admin;useIlluminate\Foundation\Http\FormRequest;classStoreArticlesRequestextendsFormRequest{/** * Determine if the user is authorized to make this request. * * @returnbool */publicfunctionauthorize() {returntrue; }/** * Get the validation rules that apply to the request. * * @returnarray */publicfunctionrules() {return ['tag.*'=>'exists:tags,id', ]; }}
<?phpnamespaceApp\Http\Requests\Admin;useIlluminate\Foundation\Http\FormRequest;classUpdateArticlesRequestextendsFormRequest{/** * Determine if the user is authorized to make this request. * * @returnbool */publicfunctionauthorize() {returnfalse; }/** * Get the validation rules that apply to the request. * * @returnarray */publicfunctionrules() {return [// ]; }}
This article is a simple example of belongsToMany() relationships in Laravel, with managing the data in CRUD form and table, using Bootstrap framework and Select2 library.
Here’s what we’re building – a list of articles with their tags.
Notice: This example was mostly generated with our QuickAdminPanel generator, but will be explained step-by-step in plain Laravel, so you can use it without our generator.
Step 1. Database/model structure
Here are the migrations.
Articles:
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->string('title')->nullable();
$table->text('article_text')->nullable();
$table->timestamps();
});
Tags:
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->timestamps();
});
Pivot table:
Schema::create('article_tag', function (Blueprint $table) {
$table->integer('article_id')->unsigned()->nullable();
$table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');
$table->integer('tag_id')->unsigned()->nullable();
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
});
The models are really simple, too.
app/Tag.php:
class Tag extends Model
{
protected $fillable = ['name'];
}
app/Article.php:
class Article extends Model
{
protected $fillable = ['title', 'article_text'];
public function tag()
{
return $this->belongsToMany(Tag::class, 'article_tag');
}
}
Routes, Controller and Create Form
Our routes/web.php, in addition to Route Group and Middleware, will have this main line:
Route::group(['middleware' => ['auth'], 'prefix' => 'admin', 'as' => 'admin.'], function () {
// ... other routes
Route::resource('articles', 'Admin\ArticlesController');
});
namespace App\Http\Controllers\Admin;
use App\Article;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\StoreArticlesRequest;
use App\Http\Requests\Admin\UpdateArticlesRequest;
class ArticlesController extends Controller
{
public function index()
{
$articles = Article::all();
return view('admin.articles.index', compact('articles'));
}
public function create()
{
$tags = \App\Tag::get()->pluck('name', 'id');
return view('admin.articles.create', compact('tags'));
}
public function store(StoreArticlesRequest $request)
{
// ... to be discussed later
}
public function edit($id)
{
// ... to be discussed later
}
public function update(UpdateArticlesRequest $request, $id)
{
// ... to be discussed later
}
public function destroy($id)
{
// ... to be discussed later
}
}
To add the articles with their tags, we need to have a create form.
Here’s our resources/views/admin/articles/create.blade.php:
Now, there are quite a few places to explain here:
In this article, I won’t discuss the main layout and code like @extends(‘layouts.app’) and @section(‘content’) because you may have different design and structure, it’s not the subject of this article;
We use LaravelCollective/html package to build the forms with {!! Form::open() !!} and other methods;
See how $tags are passed into the form, we’re getting those values from the Controller, mentioned above;
Above the tags field, we have two buttons: Select all and Deselect all – their behavior in jQuery is implemented in @section(‘javascript’);
We use Select2 library to make the tags searchable and visually compelling.
So here we have our create form.
Saving the data
This part is pretty simple, here’s a method from app/Http/Controllers/Admin/ArticlesController.php:
public function store(StoreArticlesRequest $request)
{
$article = Article::create($request->all());
$article->tag()->sync((array)$request->input('tag'));
return redirect()->route('admin.articles.index');
}
To validate the data, we use app/Http/Requests/StoreArticlesRequest.php class:
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class StoreArticlesRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'tag.*' => 'exists:tags,id',
];
}
}
And in the Controller, we just store the article and then use sync() method of many-to-many relationships to store the tags.
Viewing tags in the table
In the screenshot on the top you can see how tags are structured in the table. Here’s our Blade file for this.
resources/views/admin/articles/index.blade.php:
As you can see, we pull in the current value as $article->tag->pluck(‘id’)->toArray().
Updating the data is straightforward, here’s the controller method, really similar to store():
public function update(CreateArticlesRequest $request, $id)
{
$article = Article::findOrFail($id);
$article->update($request->all());
$article->tag()->sync((array)$request->input('tag'));
return redirect()->route('admin.articles.index');
}
Deleting the data
This is probably the most simple code – here’s Controller method:
public function destroy($id)
{
$article = Article::findOrFail($id);
$article->delete();
return redirect()->route('admin.articles.index');
}
But keep in mind that in our migrations files we specified that we need to delete tags on deleting the article, with this rule onDelete(‘cascade’):
Schema::create('article_tag', function (Blueprint $table) {
$table->integer('article_id')->unsigned()->nullable();
$table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');
$table->integer('tag_id')->unsigned()->nullable();
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
});
Basically, that’s it – a simple demo of many-to-many with Select2 and Bootstrap. If you want it to be generated automatically, try our QuickAdminPanel!