آموزش ساخت فیلتر (Filter) محصولات در لاراول

23 مرداد 1397
laravel-model-factories

روش ساخت فیلتر در لاراول

در این آموزش قصد دارم روش ساخت فیلترها را به شما آموزش بدهم. و به شما نشان می دهم که چگونه داده هایتان را بسته به نوع و دسته بندی فیلتر کنید. در صورتی که قصد ساخت یک وب سایت فروشگاه اینترنتی را داشته باشید، فیلتر محصولات یکی از بخش های ضروری است که باید در پروژه تان پیاده سازی کنید.

مروری بر مطالب:

1- ایجاد فیلترها در لاراول

2- قدم اول: نصب لاراول

3- قدم دوم: ایجاد migration و داده های ساختگی

4- قدم 3: ایجاد یک endpoint

5- قدم چهار: ایجاد یک فیلتر

6- قدم 5: توضیحات

ایجاد فیلترها در لاراول

طبق معمول، برای شروع لاراول نسخه 5.6 را نصب می کنیم.

قدم اول: نصب لاراول

برای نصب لاراول دستور زیر را وارد کنید.

composer create-project laravel/laravel filters --prefer-dist

با اجرای دستور بالا، یک پروژه با نام filters ساخته می شود

سپس با دستور زیر وارد پروژه شوید:

cd filters

سپس پروژه را در یک ویرایشگر باز کنید، من از Visual Studio Code استفاده می کنم، اما شما می توانید از هر ویرایشگری استفاده کنید.

در قدم بعدی فایل .env را باز کرده و تنظیمات دیتابیس را در آن وارد می کنیم.

قدم دوم: ایجاد migration و استفاده از داده های ساختگی

حالا، ما می خواهیم محصولات مان را بر اساس نوع و دسته بندی آن فیلتر کنیم. برای اینکار مدل Product و migration مختص به آن را ایجاد می کنیم.

php artisan make:model Product –m

با اجرای دستور بالا، مدل به همراه فایل migration ایجاد می شود.

سپس داخل فایل create_products_table.php کد زیر را قرار دهید

این فایل در مسیر database/migration قرار دارد.

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('slug');
            $table->enum('type', ['Simple', 'Grouped', 'Variable', 'Gift']);                        
            $table->enum('categories', ['Electronics', 'Books', 'Games', 'Garden']);                                             
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
}

در قدم بعد، با دستور زیر همه جدول ها را در پایگاه داده migrate می کنیم.

php artisan migrate

سپس در قدم بعدی، یک سری داده های ساختگی با استفاده از factory  ایجاد می کنیم. برای ایجاد factory از دستور زیر استفاده می کنیم.

php artisan make:factory ProductFactory --model=Product

با اجرای دستور بالا، در پوشه database/factory یک فایل با نام ProductFactory.php ایجاد می شود.

<?php

use Faker\Generator as Faker;

$factory->define(App\Product::class, function (Faker $faker) {
    return [
        'name' => $name = $faker->sentence,
        'slug' => str_slug($name),
        'type' => ['Simple', 'Grouped', 'Variable', 'Gift'][rand(0,3)],
        'categories' => ['Electronics', 'Books', 'Games', 'Garden'][rand(0,3)],   
    ];
});

در این فایل ما یک سری کد برای Factory جهت تولید تصادفی داده ها نوشتیم. حالا می توانیم از این Factory برای ساخت داده های خود استفاده کنیم.

روش های زیادی برای انجام اینکار وجود دارد، اما من ترجیح می دهم از tinker در محیط کنسول استفاده کنم.

برای انجام اینکار به محیط ترمینال بروید و دستور زیر را تایپ کنید:

php artisan tinker

سپس از کد زیر برای تولید داده استفاده کنید.

factory(\App\Product::class, 20)->create()

و همان طور که در تصویر زیر هم می بینید، جدول Products مان با داده های ساختگی توسط Factory پر می شود:

 روش ساخت فیلتر در لاراول

قدم سوم: ساخت یک endpoint

در مرحله بعد، با دستور زیر یک کنترلر به نام ProductController  ایجاد می کنیم:

php artisan make:controller ProductController

سپس یک متد index در داخل ProductController ایجاد می کنیم:

<?php

// ProductController.php

namespace App\Http\Controllers;

use App\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function index()
    {
        return Product::get();
    }
}

سپس داخل فایل web.php یک روت(مسیر) برای این متد ایجاد می کنیم:

Route::get('/products', 'ProductController@index')->name('products');

حالا می توانید با رفتن به آدرس /Products متد index را اجرا و view مربوطه را مشاهده کنید.

برای رفتن به مسیر product آدرس زیر را در مرورگر تایپ کنید:

http://localhost:8000/products

در مرحله بعد، یک کلاس برای تعریف فیلتر تعیین و از این کلاس برای فیلتر محصولاتمان استفاده می کنیم.

قدم چهارم: ایجاد یک فیلتر

برای شروع، یک فولدر Filters داخل فولدر app ایجاد می کنیم.

در داخل همین فولدر، یک فایل با نام TypeFilter.php بوجود بیاورید.

<?php

// TypeFilter.php

namespace App\Filters;

class TypeFilter
{
    public function filter()
    {
            
    }

از کلاس TypeFilter برای فیلتر کردن داده ها بر اساس نوع محصولات استفاده می کنیم.

نوع محصولات را توسط query string به متد filter پاس می دهیم و این متد محصولات را بر اساس پارامتر دریافتی، فیلتر می کند. کد این متد را بعدا می نویسیم.

سپس داخل فایل ProductController.php کدهای زیر را بنویسید:

<?php

// ProductController.php

namespace App\Http\Controllers;

use App\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function index(Request $request)
    {
        return Product::filter($request)->get();
    }
}

داخل پوشه Filters، یک کلاس انتزاعی (از نوع abstract) با نام AbstractFilter.php  ایجاد می کنیم:

<?php

// AbstractFilter.php

namespace App\Filters;

use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Builder;

abstract class AbstractFilter
{
    protected $request;

    protected $filters = [];

    public function __construct(Request $request)
    {
        $this->request = $request;
    }
    public function filter(Builder $builder)
    {   
        
    }
}

به این دلیل نوع کلاس را abstract گذاشتیم که می خواهیم در آینده فیلترهای بیشتری را در پروژه ایجاد کنیم.پس بهتر است که نوع کلاس را abstract قرار دهیم و فیلترهای مختلفی که در آینده ایجاد می کنیم، این کلاس انتزاعی را extend کند. بنابراین موقع ایجاد یک فیلتر جدید، از دوباره نویسی کدهای  تکراری جلوگیری می شود.

در قدم بعد، یک فایل جدید با نام ProductFilter.php داخل فولدر Filters بوجود می آوریم.

در این فایل، ما یک کلاس برای تعریف فیلترها ایجاد می کنیم. در این مثال من فقط از نوع filter استفاده می کنم، اما شما می توانید از فیلترهای بیشتری مانند یک فیلتر برای سن، موجودی محصولات، قیمت و غیره استفاده کنید.

<?php

// ProductFilter.php

namespace App\Filters;

use App\Filters\AbstractFilter;
use Illuminate\Database\Eloquent\Builder;

class ProductFilter extends AbstractFilter
{
    protected $filters = [
        'type' => TypeFilter::class
    ];
}

در اینجا، من یک متد filter داخل مدل Product ایجاد می کنم و همه درخواست ها را به عنوان یک پارامتر به آن پاس می دهم.

<?php

namespace App;

use App\Filters\ProductFilter;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class Product extends Model
{
    public function scopeFilter(Builder $builder, $request)
    {
        return (new ProductFilter($request))->filter($builder);
    }
}

حالا، فایل AbstractFilter.php باید مانند زیر باشد:

<?php

// AbstractFilter.php

namespace App\Filters;

use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Builder;

abstract class AbstractFilter
{
    protected $request;

    protected $filters = [];

    public function __construct(Request $request)
    {
        $this->request = $request;
    }
    public function filter(Builder $builder)
    {   
        foreach($this->getFilters() as $filter => $value)
        {
            $this->resolveFilter($filter)->filter($builder, $value);
        }
        return $builder;
    }

    protected function getFilters()
    {
        return array_filter($this->request->only(array_keys($this->filters)));
    }

    protected function resolveFilter($filter)
    {
        return new $this->filters[$filter];
    }
}

و در انتها، کدهای اصلی filter را داخل فایل TypeFilter.php ایجاد می کنیم.

<?php

// TypeFilter.php

namespace App\Filters;

class TypeFilter
{
    public function filter($builder, $value)
    {
        return $builder->where('type', $value);
    }

قدم پنجم: تشریح کدها

در این قسمت می خواهم به شما توضیح بدهم که برای دریافت یک نتیجه فیلتر شده باید چکار بکنیم.

ابتدا، آدرس صفحه فیلتر شده باید به شکل زیر باشد :

http://filter.test/products?type=Gift

همان طور که می بینید query string مان برابر type=gift است، که type همان کلید(key) می باشد و Gift هم مقدار (value) کلیدمان است. که از این query string در کلاس TypeFilter.php استفاده می کنیم.

ما این type را به کلاس TypeFilter.php در داخل فایل ProductFilter.php نگاشت می‌کنیم.

سپس در متد index  کنترلر ProductController، متد filter یی که در مدل مان تعریف کردیم را فراخوانی کرده و درخواست (request) را به عنوان آرگومان به آن پاس می دهیم.

حالا در مدل Product، متد filter ایی که در ProductFilter تعریف کرده ایم را فراخوانی کرده و یک Eloquent query builder را به عنوان یک آرگومان به آن پاس می دهیم

دقت داشته باشید که ما متد filter را به طور مستقیم داخل ProductFilter ننوشتیم، اما چون ProductFilter یک کلاس انتزاعی را extends کرده است، از متد filter این کلاس انتزاعی استفاده می کند. اما ProductFilter یک آرایه ای از Filterها دارد. در این مثال، فقط TypeFilter را داریم، اما در برنامه های واقعی معمولا بیش از یک فیلتر استفاده می شود.

در قدم بعدی، متد filter را در فایل AbstractFilter.php تعریف کردیم.

ابتدا در میان فیلترها جستجو و فیلتری که با رشته فرستاده شده توسط query string مطابقت داشت را پیدا می کنیم، اگر مطابقت پیدا کرد، از کلاس فیلتری که با رشته query string مطابقت پیدا کرده را یک نمونه می گیریم و متد این کلاس را فراخوانی کرده و قسمت کلید query string را به عنوان query string به آن پاس می دهیم.

// AbstractFilter.php

public function filter(Builder $builder)
    {   
        foreach($this->getFilters() as $filter => $value)
        {
            $this->resolveFilter($filter)->filter($builder, $value);
        }
        return $builder;
    }

    protected function getFilters()
    {
        return array_filter($this->request->only(array_keys($this->filters)));
    }

    protected function resolveFilter($filter)
    {
        return new $this->filters[$filter];
    }

سپس type را به TypeFilter می دهیم. متد filterیی که در فایل TypeFilter.php  تعریف کرده ایم را فراخوانی کرده و یک متغیر $builder و مقدار (value) مربوط به query string را به عنوان آرگومان به متد پاس می دهیم. در این مثال مقدار value برابر Gift است.

بنابراین این متد تنها سطرهایی را بر می گرداند که مقدار ستون type آن برابر Gift  باشد. یعنی type=Gift

ما یک کلاس Filter وابسته به پارامتر query string  ایجاد می کنیم و سپس  از متد filter این کلاس برای فیلتر کردن نتایج استفاده خواهیم کرد.

ممکن است در ابتدا کمی پیچیده به نظر برسد، اما اگر شما نحوه کار برنامه نویسی شی گرا را درک کنید، فهم این مثال خیلی راحت می شود در غیر اینصورت فهم آن مشکل است.

ایجاد فیلتر محصولات در لاراول

می توانید از کدهای بالا به عنوان داده های آزمایشی برای این پروژه استفاده کنید.

نویسنده شوید

دیدگاه‌های شما (2 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

سعید
19 اسفند 1398
بسیار عالی دوست عزیز

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

mohammad
06 شهریور 1397
ممنون از پستی خوبی که گذاشتید.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.