matejsvajger/laravel-distillery

优雅地过滤Eloquent模型。

v0.4.0 2018-11-14 23:02 UTC

This package is auto-updated.

Last update: 2024-09-17 11:19:34 UTC


README

Total Downloads License

简介

Laravel Distillery提供了一个优雅的方式来过滤和分页Eloquent模型。Distillery利用Laravel的API资源集合,同时构建了分页过滤后的模型/资源结果,并使使用Laravel的分页模板成为可能。

安装与配置

您可以使用Composer将Distillery安装到您的Laravel项目中。

 composer require matejsvajger/laravel-distillery

安装Distillery后,使用vendor:publish Artisan命令发布其配置。

php artisan vendor:publish --tag=distillery-config

发布Distillery的配置后,其配置文件将位于config/distillery.php。此配置文件允许您配置应用程序设置选项,并且每个配置选项都包含其用途的描述,因此请确保彻底探索此文件。

快速入门

假设您在路由/product-list上有一个产品列表,您需要做的只是将Distillable特性附加到您的Product模型上。

namespace App\Models

use Illuminate\Database\Eloquent\Model;
use matejsvajger\Distillery\Traits\Distillable;

class Product extends Model {
    use Distillable;
    
    protected $distillery = [
        'hidden' => [
            //
        ],
        'default' => [
            //
        ]
    ];
	
	...
}

Distillable特性添加了一个static function distill($filters = null)。在处理/product-list路由的控制器中,只需将Product模型的获取调用(例如:Product:all())替换为::distill()

class ProductListController extends Controller
{
	public function index()
	{		
		return view('product.list',[
			'products' => Product::distill()
		]);
	}
}

分页

distill()将返回15项的分页响应。这是Eloquent模型在$perPage属性上的默认值。您可以通过在模型中覆盖值或设置limit的默认值来调整它。

要添加分页链接到视图调用,请在blade模板中调用$products->links();

...
	<!-- Your existing list -->
	@foreach($products as $product)
		<tr>
			<td>{{ $product->id }}</td>
			<td>{{ $product->name }}</td>
			<td>{{ $product->description }}</td>
			<td>{{ $product->price }}</td>
		</tr>
	@endforeach
...
	<div class="text-center">
		{{ $products->links() }} <!-- Add this. -->
	</div>
...

这就是一个Product模型的分页列表。

什么?!这就像Laravel的Paginator!没错,我们还想过滤它,对吧?好吧,继续。

过滤

如果我们想通过在namedescription上的搜索查询过滤上述产品列表,我们需要为产品模型创建一个搜索过滤器。让我们创建它。

php artisan distillery:filter Search Product

这将在app/Filters/Product/Search.php中生成一个搜索过滤器。

生成的类实现了apply(Builder $builder, $value)方法,该方法接收Eloquent构建器和过滤器值。

对于上述搜索示例,我们会这样做:

namespace App\Filters\Product;

use Illuminate\Database\Eloquent\Builder;
use matejsvajger\Distillery\Contracts\Filter;

class Search implements Filter
{
    public static function apply(Builder $builder, $value)
    {
        return $builder->where(function ($query) use ($value) {
            $query
                ->where('name', 'like', "{$value}%")
                ->orWhere('description', 'like', "%{$value}%");
        });
    }
}

要将过滤器应用于前面的产品列表,只需将搜索查询字符串参数添加到URL中。

/product-list?search=socks,并且集合将自动过滤,分页链接将反映设置过的过滤器。

有关过滤器的更多示例,请查看示例部分。

工作原理

Distillery背后的想法是每个请求参数都是一个过滤器名称/值对。Distillery遍历所有请求参数,检查是否为选定的模型存在过滤器,并根据它们的值构建过滤后的资源集合。

默认情况下,Distillery预测您有

  • 模型存储在app/Models中,
  • 资源存储在app/Http/Resources中,
  • 并且过滤器位于app/Filters中。

所有值都可以通过配置文件进行配置。

过滤器名称

  • page
  • limit

是用于Laravel分页器的保留关键字。

深入了解

Artisan命令distillery:filter

Distillery附带一个Artisan生成器命令,用于为现有模型生成过滤器类。签名有两个参数

'distillery:filter {filter} {model?}'

  • {filter} 过滤器名称(必需
  • {model?} 模型类名称(可选

如果您传入模型名称,过滤器将在子命名空间中生成:App\Filters\{Model}。如果没有可选的模型参数,则过滤器在App\Filters中生成,用于在多个模型上通用。

要启用对通用过滤器的回退,您需要将'fallback' => true设置在distillery模型属性上。

在生成过程中,您可以选择一些标准过滤器模板

空白模板

生成的类返回未经修改的$builder。您需要自己编写逻辑。

排序模板

您定义一个要排序的模型字段列表,并选择默认排序字段和方向。

搜索模板

定义要搜索的模型字段。将生成一个具有"like {$value}%"的过滤器。

服务器端过滤器值

有时您可能需要在服务器端附加额外的过滤器。默认情况下,您不需要传递任何过滤器。Distilliery将从请求中提取它们。通常,您会有一个seo路由,它已经返回了部分模型而不是全部;例如,产品的分类路由:/category/summer-clothing?search=bikini

通常,您不会在参数中传递分类ID,因为它已经通过seo slug定义。

您可以通过传递一个数组到distill函数中来添加未在URI中定义的附加过滤器或覆盖它们。例如:如果您有一个接受id的Category过滤器,可以在控制器中附加它

public function list(Request $request, Category $category)
{
    return view('product.list',[
        'products' => Product::distill([
            'category' => $category->id,
        ]);
    ]);	
}

Distillery外观

Distillery包含一个外观,它允许您在不需要Distillable特性的情况下对任何模型进行蒸馏。它接受两个参数:模型完全限定名和过滤器数组。

Distillery::distill(Product::class, $filters);

模型资源

如果您将Distillery用作API端点,您可能不希望向全世界公开您的整个模型,或者您可能想附加一些附加数据。Distillery检查是否存在Eloquent资源,并将过滤后的集合映射到它们,否则返回普通模型。

如果您没有它们,只需用Artisan创建它们即可

php artisan make:resource Product

并查看文档,了解如何使用它们。

每个模型的默认过滤器值

可以按模型定义默认过滤器值。例如,如果您想为某些模型设置默认过滤器值,可以在模型本身的protected $distillery数组中设置一个'default'键。

class User extends Model {
    protected $distillery = [
        'default' => [
            'sort' => 'updated_at-desc'
        ]
    ];
}

从URI查询字符串中隐藏过滤器

在模型上有一个可用的'hidden'配置数组,可以隐藏当它们在服务器端应用时从URI中应用的过滤器。

class User extends Model {
    protected $distillery = [
        'hidden' => [
            'category' // - applied in controller; set from seo url
        ]
    ];
}

启用对通用过滤器的回退

如果模型中没有定义过滤器,则可以使用通用过滤器。

class User extends Model {
    protected $distillery = [
        'fallback' => true
    ];
}

API过滤器-分页路由

Distillery提供了一个标准的过滤路由,您可以在其中自动过滤/分页任何模型,而无需将特性附加到模型上。

此功能默认是禁用的。您需要在配置中启用它。

过滤模型的默认路由是/distill,与模型名称和查询字符串结合使用。

/distill/{model}?page=1&limit=10&search=socks

需要通过此路由进行过滤的模型需要添加到distillery.routing.models配置数组中。

    'routing' => [

        'enabled' => true,

        'path' => 'distill',

        'middleware' => [
            'web',
        ],

        'models' => [
            'product' => App\Models\Product::class,
        ]
    ],

可以在配置中更改路由路径。如果您想用Auth来保护它,例如,您还可以在配置中将自定义中间件附加到路由上。

自定义分页链接

分页链接是Laravel分页的一部分。查看Laravel文档,了解如何自定义它们。

示例

排序

对于按多个字段排序模型,您可以使用如下格式的排序过滤器: sort=field-ascsort=field-desc

php artisan distillery:filter Sort Product
class Sort implements Filter
{
    protected static $allowed = ['price', 'name', 'updated_at'];
    
    public static function apply(Builder $builder, $value)
    {
        if (Str::endsWith($value, ['-asc', '-desc'])) {
            [$field, $dir] = explode('-', $value);
            
            if (in_array($field, static::$allowed)) {
                return $builder->orderBy($field, $dir);
            }
        }

        return $builder->orderBy('updated_at', 'desc');
    }
}

要应用过滤器,只需将其添加到qs中: /product-list?search=socks&sort=price-desc

过滤关系

有时您可能想要根据模型的关系进行过滤。

假设您有一个包含多个颜色附件的Product模型

class Color implements Filter
{
    public static function apply(Builder $builder, $value)
    {
        $value = is_array($value) ? $value : [$value];
        $query = $builder->with('colors');

        foreach ($value as $colorId) {
            $query->whereHas('colors', function ($q) use ($colorId) {
                $q->where('id', $colorId);
            });
        }

        return $query;
    }
}

要应用它: /product-list?search=socks&sort=price-desc&color[]=2&color[]=5

通往1.0.0的道路

  • 增加生成标准预定义过滤器(排序、搜索等)的可能性。
  • 使能够定义要隐藏从URL查询字符串中的哪些参数。
  • 添加通用过滤器的回退,这些过滤器可以在不同的模型之间重用。
  • 编写测试。

许可

Laravel Distillery是开源软件,根据MIT许可证授权。