لاراول برای مبتدیان شماره 4 – یک داشبورد ایجاد کنید

کد منبع را از اینجا دانلود کنید. ⬅️
بالاخره نوبت به مهم ترین قسمت این آموزش می رسد. بیایید یک برنامه وبلاگ کاملاً برجسته با پست ها، دسته بندی ها و همچنین برچسب ها ایجاد کنیم. قبلاً در مورد عملیات CRUD برای پست ها صحبت کردیم و در این مقاله قصد داریم آن را برای دسته ها و برچسب ها تکرار کنیم و همچنین نحوه برخورد با روابط بین آنها را نیز مورد بحث قرار می دهیم.
یک پروژه جدید لاراول را راه اندازی کنید
یک بار دیگر، ما با یک پروژه جدید شروع می کنیم. یک پوشه کاری ایجاد کنید و آن را تغییر دهید. مطمئن شوید که Docker فعال است و سپس دستور زیر را اجرا کنید:
curl -s https://laravel.build/<app_name> | bash
به فهرست برنامه تغییر دهید و سرور را راه اندازی کنید.
cd <app_name>
./vendor/bin/sail up
برای آسانتر کردن کارها، بیایید یک نام مستعار برای آن ایجاد کنیم sail
. دستور زیر را اجرا کنید:
alias sail="[ -f sail ] && sh sail || sh vendor/bin/sail"
از این پس میتوانید بدون مشخص کردن کل مسیر، مستقیماً بادبان را اجرا کنید.
sail up
احراز هویت کاربر
مرحله دوم، همانطور که قبلا ذکر کردیم، لاراول با یک اکوسیستم بزرگ عرضه می شود، و Laravel Breeze بخشی از این اکوسیستم است. این یک راه سریع برای تنظیم احراز هویت و ثبت نام کاربر در برنامه لاراول ارائه می دهد.
Breeze شامل نماها و کنترلرهای احراز هویت از پیش ساخته شده، و همچنین مجموعه ای از APIهای پشتیبان برای رسیدگی به احراز هویت و ثبت نام کاربر است. بسته به گونه ای طراحی شده است که نصب و پیکربندی آسان و با حداقل تنظیمات مورد نیاز باشد.
برای نصب Laravel Breeze از دستورات زیر استفاده کنید:
sail composer require laravel/breeze --dev
sail artisan breeze:install
sail artisan migrate
sail npm install
sail npm run dev
این فرآیند به طور خودکار کنترلرهای مورد نیاز، میان افزارها و نماهایی را که برای ایجاد یک سیستم احراز هویت اولیه کاربر ضروری هستند، تولید می کند. با مراجعه به صفحه ثبت نام می توانید وارد شوید http://127.0.0.1/register
.
یک حساب کاربری جدید ثبت کنید و به داشبورد هدایت خواهید شد.
در این مقاله قصد نداریم دقیقاً درباره نحوه عملکرد این سیستم احراز هویت کاربر بحث کنیم، زیرا به مفاهیم نسبتاً پیشرفته مربوط می شود. اما به شدت توصیه می شود که نگاهی به فایل های تولید شده بیندازید، آنها بینش عمیق تری از نحوه کار چیزها در لاراول به شما ارائه می دهند.
راه اندازی پایگاه داده
در مرحله بعد، باید تصویری بزرگ از ظاهر برنامه وبلاگمان داشته باشیم. ابتدا باید پایگاه داده ای داشته باشیم که بتواند پست ها، دسته ها و برچسب ها را ذخیره کند. هر جدول پایگاه داده ساختار زیر را دارد:
نوشته ها
کلید | نوع |
---|---|
شناسه | bigInteger |
ایجاد شده در | |
updated_at | |
عنوان | رشته |
پوشش | رشته |
محتوا | متن |
منتشر شده است | بولی |
دسته بندی ها
کلید | نوع |
---|---|
شناسه | bigInteger |
ایجاد شده در | |
updated_at | |
نام | رشته |
برچسب ها
کلید | نوع |
---|---|
شناسه | bigInteger |
ایجاد شده در | |
updated_at | |
نام | رشته |
و البته، باید جدول کاربران نیز وجود داشته باشد، اما قبلاً توسط Laravel Breeze برای ما ساخته شده است، بنابراین این بار از آن می گذریم.
این جداول نیز همانطور که در لیست زیر نشان داده شده است با یکدیگر رابطه دارند:
- هر کاربر دارای چندین پست است
- هر دسته دارای پست های زیادی است
- هر تگ دارای پست های زیادی است
- هر پست متعلق به یک کاربر است
- هر پست متعلق به یک دسته است
- هر پست دارای برچسب های زیادی است
برای ایجاد این روابط، باید جدول پست ها را اصلاح کنیم:
پست هایی با روابط
کلید | نوع |
---|---|
شناسه | bigInteger |
ایجاد شده در | |
updated_at | |
عنوان | رشته |
پوشش | رشته |
محتوا | متن |
منتشر شده است | بولی |
شناسه کاربر | bigInteger |
category_id | bigInteger |
و همچنین به یک جدول جداگانه برای رابطه پست/تگ نیاز داریم:
پست/برچسب
کلید | نوع |
---|---|
post_id | bigInteger |
tag_id | bigInteger |
پیاده سازی ساختار پایگاه داده
برای پیاده سازی این طرح، مدل ها و فایل های مهاجرت را با استفاده از دستورات زیر تولید کنید:
sail artisan make:model Post --migration
sail artisan make:model Category --migration
sail artisan make:model Tag --migration
و یک فایل مهاجرت جداگانه برای post_tag
جدول:
sail artisan make:migration create_post_tag_table
database/migrations/create_posts_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title');
$table->string('cover');
$table->text('content');
$table->boolean('is_published');
$table->bigInteger('user_id');
$table->bigInteger('category_id');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
database/migrations/create_categories_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('name');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};
database/migrations/create_tags_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('name');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('tags');
}
};
database/migrations/create_post_tag_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('post_tag', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->bigInteger('post_id');
$table->bigInteger('tag_id');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('post_tag');
}
};
این تغییرات را با دستور زیر اعمال کنید:
sail artisan migrate
و سپس برای مدل های مربوطه، باید انتساب انبوه را برای فیلدهای انتخاب شده فعال کنیم تا بتوانیم از آن استفاده کنیم create
یا update
روش هایی که در مورد آنها وجود دارد، همانطور که در آموزش های قبلی در مورد آنها صحبت کردیم. و همچنین باید روابط بین جداول پایگاه داده را تعریف کنیم.
app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Post extends Model
{
use HasFactory;
protected $fillable = [
"title",
'content',
'cover',
'is_published'
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
}
app/Models/Category.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Category extends Model
{
use HasFactory;
protected $fillable = [
'name',
];
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
app/Models/Tag.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Tag extends Model
{
use HasFactory;
protected $fillable = [
'name',
];
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
}
app/Models/User.php
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
کنترلرها و مسیرها
در مورد کنترلکنندهها، برای هر منبع (پست، دسته و برچسب) به یک کنترلکننده منبع نیاز داریم.
php artisan make:controller PostController --resource
php artisan make:controller CategoryController --resource
php artisan make:controller TagController --resource
سپس مسیرهایی را برای هر یک از این کنترلرها ایجاد کنید:
routes/web.php
<?php
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\PostController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\TagController;
use Illuminate\Support\Facades\Route;
// Dashboard routes
Route::prefix('dashboard')->group(function () {
// Dashboard homepage
Route::get("https://dev.to/", function () {
return view('dashboard');
})->name('dashboard');
// Dashboard category resource
Route::resource('categories', CategoryController::class);
// Dashboard tag resource
Route::resource('tags', TagController::class);
// Dashboard post resource
Route::resource('posts', PostController::class);
})->middleware(['auth', 'verified']);
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
require __DIR__ . '/auth.php';
توجه داشته باشید که تمام مسیرها با a گروه بندی می شوند /dashboard
پیشوند، و گروه دارای یک میان افزار است auth
، به این معنی که کاربر برای دسترسی به داشبورد باید وارد سیستم شود.
کنترل کننده های دسته/برچسب
این CategoryController
و TagController
نسبتاً سرراست هستند. شما می توانید آنها را به همان روشی که ما ایجاد کردیم تنظیم کنید PostController
در مقاله قبلی
app/Http/Controllers/CategoryController.php
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CategoryController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(): View
{
$categories = Category::all();
return view('categories.index', [
'categories' => $categories
]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('categories.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
// Get the data from the request
$name = $request->input('name');
// Create a new Post instance and put the requested data to the corresponding column
$category = new Category();
$category->name = $name;
// Save the data
$category->save();
return redirect()->route('categories.index');
}
/**
* Display the specified resource.
*/
public function show(string $id): View
{
$category = Category::all()->find($id);
$posts = $category->posts();
return view('categories.show', [
'category' => $category,
'posts' => $posts
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id): View
{
$category = Category::all()->find($id);
return view('categories.edit', [
'category' => $category
]);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id): RedirectResponse
{
// Get the data from the request
$name = $request->input('name');
// Find the requested category and put the requested data to the corresponding column
$category = Category::all()->find($id);
$category->name = $name;
// Save the data
$category->save();
return redirect()->route('categories.index');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id): RedirectResponse
{
$category = Category::all()->find($id);
$category->delete();
return redirect()->route('categories.index');
}
}
app/Http/Controllers/TagController.php
<?php
namespace App\Http\Controllers;
use App\Models\Tag;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class TagController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(): View
{
$tags = Tag::all();
return view('tags.index', [
'tags' => $tags
]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('tags.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
// Get the data from the request
$name = $request->input('name');
// Create a new Post instance and put the requested data to the corresponding column
$tag = new Tag();
$tag->name = $name;
// Save the data
$tag->save();
return redirect()->route('tags.index');
}
/**
* Display the specified resource.
*/
public function show(string $id): View
{
$tag = Tag::all()->find($id);
$posts = $tag->posts();
return view('tags.show', [
'tag' => $tag,
'posts' => $posts
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id): View
{
$tag = Tag::all()->find($id);
return view('tags.edit', [
'tag' => $tag
]);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id): RedirectResponse
{
// Get the data from the request
$name = $request->input('name');
// Find the requested category and put the requested data to the corresponding column
$tag = Tag::all()->find($id);
$tag->name = $name;
// Save the data
$tag->save();
return redirect()->route('tags.index');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id): RedirectResponse
{
$tag = Tag::all()->find($id);
$tag->delete();
return redirect()->route('tags.index');
}
}
به یاد داشته باشید که با استفاده از دستور زیر می توانید نام مسیرها را بررسی کنید:
sail artisan route:list
کنترلر پست
از طرف دیگر، PostController کمی پیچیده تر است، زیرا شما باید با آپلود تصاویر و روابط در store()
روش. بیایید نگاه دقیق تری بیندازیم:
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\Builder;
class PostController extends Controller
{
. . .
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
// Get the data from the request
$title = $request->input('title');
$content = $request->input('content');
if ($request->input('is_published') == 'on') {
$is_published = true;
} else {
$is_published = false;
}
// Create a new Post instance and put the requested data to the corresponding column
$post = new Post();
$post->title = $title;
$post->content = $content;
$post->is_published = $is_published;
// Save the cover image
$path = $request->file('cover')->store('cover', 'public');
$post->cover = $path;
// Set user
$user = Auth::user();
$post->user()->associate($user);
// Set category
$category = Category::find($request->input('category'));
$post->category()->associate($category);
// Save post
$post->save();
//Set tags
$tags = $request->input('tags');
foreach ($tags as $tag) {
$post->tags()->attach($tag);
}
return redirect()->route('posts.index');
}
. . .
}
در این مورد چند نکته قابل ذکر است store()
روش. ابتدا، خط 28 تا 32، ما از یک چک باکس HTML برای نشان دادن آن استفاده می کنیم is_published
فیلد، و مقادیر آن یکی هستند 'on'
یا null
. اما در پایگاه داده مقادیر آن به صورت ذخیره می شود true
یا false
، پس باید از an استفاده کنیم if
بیانیه ای برای حل این موضوع
خط 41 تا 42 برای بازیابی فایل ها باید از file()
روش به جای input()
و فایل در قسمت ذخیره می شود public
دیسک زیر دایرکتوری cover
.
خط 45 تا 46، کاربر فعلی را دریافت کنید Auth::user()
و پست را با کاربر استفاده کننده مرتبط کنید associate()
روش. و خط 49 تا 50 همین کار را برای دسته انجام می دهد. به یاد داشته باشید که این کار را فقط از طریق می توانید انجام دهید $post
و نه $user
یا $category
، از آنجا که user_id
و category_id
ستون ها در posts
جدول.
در نهایت، برای تگ ها، همانطور که از خط 56 تا 60 نشان داده شد، باید پست فعلی را در پایگاه داده ذخیره کنید، و سپس لیستی از برچسب ها را بازیابی کنید و هر یک از آنها را یک به یک به پست پیوست کنید. attach()
روش.
برای update()
روش، همه چیز به طور مشابه کار می کند، با این تفاوت که قبل از اینکه بتوانید تگ های جدید را ضمیمه کنید، باید تمام تگ های موجود را حذف کنید.
$post->tags()->detach();
بازدیدها
هنگام ساختن یک سیستم دید، همیشه به یاد داشته باشید که سازماندهی شده باشید. این ساختاری است که من با آن می روم:
resources/views
├── auth
├── categories
│ ├── create.blade.php
│ ├── edit.blade.php
│ ├── index.blade.php
│ └── show.blade.php
├── components
├── layouts
├── posts
│ ├── create.blade.php
│ ├── edit.blade.php
│ ├── index.blade.php
│ └── show.blade.php
├── profile
├── tags
│ ├── create.blade.php
│ ├── edit.blade.php
│ ├── index.blade.php
│ └── show.blade.php
├── dashboard.blade.php
└── welcome.blade.php
من سه دایرکتوری ایجاد کرده ام، posts
، categories
و tags
و هر کدام دارای چهار الگو هستند، create
، edit
، index
و show
(بجز posts
از آنجایی که داشتن الف ضروری نیست show
صفحه برای پست ها در داشبورد).
گنجاندن همه این نماها در یک مقاله این آموزش را غیر ضروری طولانی می کند، بنابراین در عوض، من فقط صفحات ایجاد، ویرایش و فهرست بندی پست ها را نشان می دهم. با این حال، در صورت نیاز به مرجع، کد منبع این آموزش به صورت رایگان در اینجا موجود است.
مشاهده ایجاد پست
resources/views/posts/create.blade.php
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Posts') }}
</h2>
<a href="{{ route('posts.create') }}">
<x-primary-button>{{ __('New') }}</x-primary-button>
</a>
</div>
<script src="https://cdn.tiny.cloud/. . ./tinymce.min.js" referrerpolicy="origin"></script>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="">
<form action="{{ route('posts.store') }}" method="POST" class="mt-6 space-y-3" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="checkbox" name="is_published" id="is_published">
<x-input-label for="is_published">Make this post public</x-input-label>
<br>
<x-input-label for="title">{{ __('Title') }}</x-input-label>
<x-text-input id="title" name="title" type="text" class="mt-1 block w-full" required autofocus autocomplete="name" />
<br>
<x-input-label for="content">{{ __('Content') }}</x-input-label>
<textarea name="content" id="content" cols="30" rows="30"></textarea>
<br>
<x-input-label for="cover">{{ __('Cover Image') }}</x-input-label>
<x-text-input id="cover" name="cover" type="file" class="mt-1 block w-full" required autofocus autocomplete="cover" />
<br>
<x-input-label for="category">{{ __('Category') }}</x-input-label>
<select id="category" name="category">
@foreach($categories as $category)
<option value="{{ $category->id }}">{{ $category->name }}</option>
@endforeach
</select>
<br>
<x-input-label for="tags">{{ __('Tags') }}</x-input-label>
<select id="tags" name="tags[]" multiple>
@foreach($tags as $tag)
<option value="{{ $tag->id }}">{{ $tag->name }}</option>
@endforeach
</select>
<br>
<x-primary-button>{{ __('Save') }}</x-primary-button>
</form>
<script>
tinymce.init({. . .});
</script>
</div>
</div>
</div>
</div>
</x-app-layout>
من از TinyMCE به عنوان ویرایشگر متن غنی استفاده می کنم، می توانید آن را با چیز دیگری جایگزین کنید یا به سادگی از یک <textarea></textarea>
در صورت تمایل
خط 19، این فرم باید داشته باشد enctype="multipart/form-data"
از آنجایی که ما فقط متون را منتقل نمی کنیم، فایل ها نیز وجود دارد.
خط 31، به یاد داشته باشید که استفاده کنید type="file"
اینجا از آنجایی که ما در حال آپلود یک تصویر هستیم.
در خط 34 تا 38، مقدار گزینه به backend منتقل می شود.
خط 41 تا 45، در اینجا باید به دو نکته توجه کنید. ابتدا توجه کنید name="tags[]"
، []
به لاراول می گوید که یک آرایه تکرارپذیر را به جای متن ها منتقل کند. و دوم، multiple
یک فرم چند انتخابی به جای انتخاب واحد مانند فرم دسته ها ایجاد می کند.
مشاهده ویرایش پست
resources/views/posts/edit.blade.php
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Posts') }}
</h2>
<a href="{{ route('posts.create') }}">
<x-primary-button>{{ __('New') }}</x-primary-button>
</a>
</div>
<script src="https://cdn.tiny.cloud/. . ./tinymce.min.js" referrerpolicy="origin"></script>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
<div class="">
<form action="{{ route('posts.update', ['post' => $post->id]) }}" method="POST" class="mt-6 space-y-3" enctype="multipart/form-data">
{{ csrf_field() }}
{{ method_field('PUT') }}
<input type="checkbox" name="is_published" id="is_published" @checked($post->is_published)/>
<x-input-label for="is_published">Make this post public</x-input-label>
<br>
<x-input-label for="title">{{ __('Title') }}</x-input-label>
<x-text-input id="title" name="title" type="text" class="mt-1 block w-full" required autofocus autocomplete="name" value="{{ $post->title }}" />
<br>
<x-input-label for="content">{{ __('Content') }}</x-input-label>
<textarea name="content" id="content" cols="30" rows="30">{{ $post->content }}</textarea>
<br>
<x-input-label for="cover">{{ __('Update Cover Image') }}</x-input-label>
<img src="{{ Illuminate\Support\Facades\Storage::url($post->cover) }}" alt="cover image" width="200">
<x-text-input id="cover" name="cover" type="file" class="mt-1 block w-full" autofocus autocomplete="cover" />
<br>
<x-input-label for="category">{{ __('Category') }}</x-input-label>
<select id="category" name="category">
@foreach($categories as $category)
<option value="{{ $category->id }}" @selected($post->category->id == $category->id)>{{ $category->name }}</option>
@endforeach
</select>
<br>
<x-input-label for="tags">{{ __('Tags') }}</x-input-label>
<select id="tags" name="tags[]" multiple>
@foreach($tags as $tag)
<option value="{{ $tag->id }}" @selected($post->tags->contains($tag))>{{ $tag->name }}</option>
@endforeach
</select>
<br>
<x-primary-button>{{ __('Save') }}</x-primary-button>
</form>
<script>
tinymce.init({. . .});
</script>
</div>
</div>
</div>
</div>
</x-app-layout>
خط 19 تا 21، به طور پیش فرض، HTML از روش PUT پشتیبانی نمی کند، بنابراین کاری که می توانیم انجام دهیم استفاده از آن است. method="POST"
و سپس به لاراول بگویید از روش PUT استفاده کند {{ method_field('PUT') }}
.
نمای فهرست پست
resources/views/posts/index.blade.php
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Posts') }}
</h2>
<a href="{{ route('posts.create') }}">
<x-primary-button>{{ __('New') }}</x-primary-button>
</a>
</div>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
@foreach($posts as $post)
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg mb-4 px-4 h-20 flex justify-between items-center">
<div class="text-gray-900 dark:text-gray-100">
<p>{{ $post->title }}</p>
</div>
<div class="space-x-2">
<a href="{{ route('posts.edit', ['post' => $post->id]) }}"> <x-primary-button>{{ __('Edit') }}</x-primary-button></a>
<form method="post" action="{{ route('posts.destroy', ['post' => $post->id]) }}" class="inline">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<x-danger-button>
{{ __('Delete') }}
</x-danger-button>
</form>
</div>
</div>
@endforeach
</div>
</div>
</x-app-layout>
به دکمه حذف توجه کنید، به جای دکمه معمولی، باید فرمی با متد DELETE باشد، زیرا یک پیوند معمولی فقط متد GET دارد.
با این نمایش، شما باید بتوانید بقیه سیستم دید را به راحتی بسازید.
اسکرین شات ها
آخرین اما نه کم اهمیت، در اینجا اسکرین شات هایی از داشبوردی که من ایجاد کرده ام آورده شده است.
در مقاله بعدی، میخواهیم از داشبورد حرکت کنیم و قسمت جلویی برنامه را ایجاد کنیم که کاربر بتواند ببیند.
اگر این مقاله را دوست داشتید، لطفاً سایر آموزش های من را نیز بررسی کنید: