في هذا المقال سيتم إضافة ميزه عمل فلترة للمقالات ( القسم، العنوان ....)، للقيام بذلك يجب ان نقوم بالبداية بتحضير backEnd بإضافة Category، ومن ثم عرضها في FrontEnd وعرضها في select box وعندما يتم تغيير قيمة selectbox ان يتم إعادة تحميل للبيانات مع تنفيذ الفلتر، بدون إعادة تحميل الصفحة لأننا نتعامل مع SPA.
إعدادات لارافيل
إضافة حقل Category
php artisan make:model Category -mf
إضافة fillable
class Category extends Model
{
use HasFactory;
protected $fillable = ['name'];
}إضافة الحقول في ملف Categories migration
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}إضافة factory
class CategoryFactory extends Factory
{
protected $model = Category::class;
public function definition()
{
return [
"name" => $this->faker->word(),
];
}
}هنا يلزم أن يتم التعديل على ملف Posts Migration حتى يتم إضافة category_id لأن كل مقال يتبع لقسم
php artisan make:migration add_category_id_to_posts_table
public function up()
{
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('category_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');
});
}إضافة category_id إلى fillable في Post Model
class Post extends Model
{
use HasFactory;
protected $fillable = ['title','body','category_id'];
}التعديل على PostFactory بإضافة category_id
class PostFactory extends Factory
{
protected $model = Post::class;
public function definition()
{
return [
"title" => $this->faker->word(),
"body" => $this->faker->sentence(),
"category_id" => Category::all()->random()->id,
];
}
}إضافة category factory إلى ملف database seeder
class DatabaseSeeder extends Seeder
{
public function run()
{
Category::factory(10)->create();
Post::factory(100)->create();
}
}تنفيذ seeder مع migrate fresh
php artisan migrate:fresh --seed
التعديل على PostResource
يجب إضافة category_id في PostResource الموجود في المسار app/Http/Resources/PostResource.php
class PostResource extends JsonResource
{
public function toArray($request)
{
return [
'id'=> $this->id,
'title'=>$this->title,
'body'=>$this->body,
'category_id'=>$this->category_id,
'created_at'=>$this->created_at->toDateString(),
];
}
}إنشاء CategoryResource
php artisan make:resource CategoryResource
class CategoryResource extends JsonResource
{
public function toArray($request)
{
return parent::toArray($request);
}
}هنا لن اقوم بالتعديل على الكلاس، فلا يوجد تعديل على الحقول،. فيتم إرجاع جميع الحقول
إنشاء CategoryController
php artisan make:controller Api/CategoryController -r
بداخل الدالة index
class CategoryController extends Controller
{
public function index()
{
return CategoryResource::collection(Category::all());
}
}إضافة category route في الملف api.php
Route::get('posts', [PostController::class, 'index']);
Route::get('category', [CategoryController::class, 'index']);عند زيارتنا للرابط http://www.test.test/api/category فإنه يجب أن يتم عرض الأقسام
{
"data": [
{
"id": 1,
"name": "ullam",
"created_at": "2021-08-04T09:13:33.000000Z",
"updated_at": "2021-08-04T09:13:33.000000Z"
},
]
}تحضير Vue
بداخل Post Component نضيف وسم select
<select class="form-control col-3">
<option value="">--Choose Category--</option>
<option v-for="category in categories" :value="category.id">
{{ category.name}}
</option>
</select>بداخل script في data نعرف متغير categories وفي الدالة mounted نقوم بالإتصال مع api لجلب البيانات
<script>
export default {
data(){
return {
posts:{},
categories:{},
}
},
mounted() {
axios.get('/api/category')
.then(response => {
this.categories = response.data.data;
});
this.getResults();
},
methods:{
getResults(page = 1) {
axios.get('/api/posts?page=' + page)
.then(response => {
this.posts = response.data;
});
}
}
}
</script>
عمل filtering
عندما يختار المستخدم قسم معين، يجب أن يتم عرض المقالات التابعة لهذا القسم فقط، وللقيام بذلك نحتاج لإستخدام v-model ومن ثم إعطاءه متغير، بحيث يتم إستخدام هذا المتغير في data
<select v-model="category_id" class="form-control">
<option value="">--Choose Category--</option>
<option v-for="category in categories" :value="category.id">
{{ category.name}}
</option>
</select>وفي script بداخل الدالة data
data(){
return {
posts:{},
categories:{},
category_id:'',
}
},نحتاج للتعديل على دالة getResults بحيث يتم إرسال category_id
methods:{
getResults(page = 1) {
axios.get('/api/posts?page=' + page + '&category_id='+this.category_id)
.then(response => {
this.posts = response.data;
});
}
}نحتاج لإضافة الدالة watch حتى يتم مراقبة ما يحصل على select box فعند تغيير قيمتها تتنفذ الدالة
watch:{
category_id(value){
this.getResults()
}
},توضيح:
عندما يتم تغييرر قيمة select box فإن v-model ترسل القيمة إلى المتغير category_id الموجود بداخل الدالة data، ثم الدالة watch تلاحظ هذا التغير فتقوم بطلب البيانات من الـ api بإسخدام الدالة getResults.
اضافة filter إلى PostController
public function index()
{
$posts=Post::when(request('category_id','') !='',function ($q){
$q->where('category_id',request('category_id'));
})->paginate(20);
return PostResource::collection($posts);
}وبذلك تم تجهيز filter
ارجو ان يكون توضيح لكيفية استخدام paginate لاني استخدمت العديد من المكاتب