لارافيل, VueJs / 2024-05-14

سلسة عمليات CRUD بإستخدام Laravel + VueJs مع SPA - الجزء الخامس - إضافة filtering

سلسة عمليات CRUD بإستخدام Laravel + VueJs مع SPA - الجزء الخامس - إضافة filtering

2024-05-14 وقت القراءه : 4 دقائق

في هذا المقال سيتم إضافة ميزه عمل فلترة للمقالات ( القسم، العنوان ....)، للقيام بذلك يجب ان نقوم بالبداية بتحضير 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



التعليقات
Mohammed
منذ سنتين

ارجو ان يكون توضيح لكيفية استخدام paginate لاني استخدمت العديد من المكاتب

إضافة تعليق
Loading...