承接 mgussekloo/laravel-facet-filter 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

mgussekloo/laravel-facet-filter

Composer 安装命令:

composer require mgussekloo/laravel-facet-filter

包简介

Simple facet filtering in Laravel projects, hassle free.

README 文档

README

Stars

Laravel Facet Filter

This package provides simple facet filtering (sometimes called Faceted Search or Faceted Navigation) in Laravel projects. It helps narrow down query results based on the attributes of your models.

  • Free, no dependencies
  • Easy to use in any project
  • Easy to customize
  • There's a demo project to get you started
  • Ongoing support (last update: july 2025)

Demo

Contributing

Please contribute to this package either by creating a pull request or reporting an issue.

Installation

This package can be installed through Composer.

composer require mgussekloo/laravel-facet-filter

Get started

Update your models

Add a Facettable trait and a facetDefinitions() method to models you'd like to filter:

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

use Mgussekloo\FacetFilter\Traits\Facettable;

class Product extends Model
{
	use HasFactory;
	use Facettable;

	public static function facetDefinitions()
	{
		// Return an array of definitions
		return [
			[
				'title' => 'Main color', // The title will be used for the parameter.
				'fieldname' => 'color' // Model property from which to get the values.
			],
			[
				'title' => 'Sizes',
				'fieldname' => 'sizes.name' // Use dot notation to get the value from related models.
			]
		];
	}
}

Build an index

In most cases you'll want to create an index to filter large datasets efficiently. (Don't want to build an index? Skip ahead to filtering collections.)

First, run the migrations:

php artisan vendor:publish --tag="facet-filter-migrations"
php artisan migrate

To build the index, create an Artisan command that queries your Facettable models. Run it periodically or whenever your data changes.

$products = Product::with(['sizes'])->get(); // get some products
$products->buildIndex(); // build the index

Get results

Within a controller, apply the facet filter to a query

$filter = request()->all(); // the filter looks like ['main-color' => ['green']]
$products = Product::facetFilter($filter)->get();

Basic frontend example

Here's a simple demo project that demonstrates a basic frontend.

<div class="flex">
	<div class="w-1/4 flex-0">
		@foreach ($products->getFacets() as $facet)
			<p>
				<h3>{{ $facet->title }}</h3>

				@foreach ($facet->getOptions() as $option)
					<a href="?{{ $option->http_query }}" class="{{ $option->selected ? 'underline' : '' }}">{{ $option->value }} ({{ $option->total }}) </a><br />
				@endforeach
			</p><br />
		@endforeach
	</div>
	<div class="w-3/4">
		@foreach ($products as $product)
			<p>
				<h1>{{ $product->name }} ({{ $product->sizes->pluck('name')->join(', ') }})</h1>
				{{ $product->color }}<br /><br />
			</p>
		@endforeach
	</div>
</div>

To see an example of a Livewire implementation, see this gist.

Facet details

$facets = $products->getFacets();

/* You can filter and sort like any regular Laravel collection. */
$singleFacet = $facets->firstWhere('fieldname', 'color');

/* Find out stuff about the facet. */
$paramName = $singleFacet->getParamName(); // "main-color"
$options = $singleFacet->getOptions();

/*
Options look like this:
(object)[
	'value' => 'Red',
	'selected' => false,
	'total' => 3,
	'slug' => 'color_red',
	'http_query' => 'main-color%5B1%5D=red&sizes%5B0%5D=small'
]
*/

Customization

Advanced indexing

Extend the Indexer to customize behavior, e.g. to save a "range bracket" value instead of a "individual price" value to the index.

class MyCustomIndexer extends \Mgussekloo\FacetFilter\Indexer {
	public function buildValues($facet, $model) {
		$values = parent::buildValues($facet, $model);

		if ($facet->fieldname == 'price') {

			if ($model->price > 1000) {
				return 'Expensive';
			}
			if ($model->price > 500) {
				return '500 - 1000';
			}
			if ($model->price > 250) {
				return '250 - 500';
			}
			return '0 - 250';
		}

		return $values;
	}
}

You may overwrite the indexer() method on your Facettable model to return an instance of your custom indexer:

use App\MyCustomIndexer;

class Product extends Model
{
	use HasFactory;
	use Facettable;

	public static function indexer()
	{
		return new MyCustomIndexer();
	}
}
$products = Products::get();
$products->buildIndex(); // uses MyCustomIndexer

Updating a larger index over time

$indexer = new Indexer();

$perPage = 1000; $currentPage = Cache::get('facetIndexingPage', 1);

$products = Product::with(['sizes'])->paginate($perPage, ['*'], 'page', $currentPage);

if ($currentPage == 1) {
	$indexer->resetIndex(); // clear entire index
}

$indexer->buildIndex($products);

if ($products->hasMorePages()) {}
	// next iteration, increase currentPage with one
}

Custom facets

Provide custom attributes and an optional custom Facet class in the facet definitions.

public static function facetDefinitions()
{
	return [
		[
			'title' => 'Main color',
			'description' => 'The main color.', // optional custom attribute, you could use $facet->description when creating the frontend...
			'related_id' => 23, // ... or use $facet->related_id with your custom indexer
			'fieldname' => 'color',
			'facet_class' => CustomFacet::class // optional Facet class with custom logic
		]
	];
}

Filtering collections

It's possible to apply facet filtering to a collection without building an index. Facettable models return a FacettableCollection, which provides an indexlessFacetFilter() method.

$products = Product::all(); // returns a "FacettableCollection"
$products = $products->indexlessFacetFilter($filter);

Pagination

Example:

$products = Product::facetFilter($filter)->paginate(10);
$pagination = $products->appends(request()->input())->links();

Notes on caching

By default Facet Filter caches some heavy operations through the non-persistent 'array' cache driver. Caches are based on the model and filter, not the query bindings or specifics. Use a cacheTag to distinguish between queries.

// if you have two facet filter queries on the same model...
Product::where('published', false)->cacheTag('unpublished')->facetFilter($filter)->get();
// ...make sure to distinguish between queries
Product::where('published', true)->cacheTag('published')->facetFilter($filter)->get();

The default Indexer clears the cache for all models when rebuilding the index. You can do it manually:

Product::forgetCache(); // clears cache for all cache tags
Product::forgetCache('unpublished'); // clears cache for only this cachetag

use Mgussekloo\FacetFilter\Facades\FacetCache;
FacetCache::forgetCache(); // clears cache for all models and cache tags

Config

You can configure a peristent cache driver through config/facet-filter.php. Be aware of any caching related issues, e.g. if you have any user specific results this may be problematic.

php artisan vendor:publish --tag=facet-filter-config
'classes' => [
	'facet' => Mgussekloo\FacetFilter\Models\Facet::class,
	'facetrow' => Mgussekloo\FacetFilter\Models\FacetRow::class,
],

'table_names' => [
	'facetrows' => 'facetrows',
],

'cache' => [
	'expiration_time' => \DateInterval::createFromDateString('24 hours'),
	'key' => 'mgussekloo.facetfilter.cache',
	'store' => 'array',
],

License

The MIT License (MIT). Please see License File for more information.

mgussekloo/laravel-facet-filter 适用场景与选型建议

mgussekloo/laravel-facet-filter 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 765 次下载、GitHub Stars 达 58, 最近一次更新时间为 2022 年 07 月 15 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「search」 「filter」 「navigation」 「laravel」 「facet」 「faceted search」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 mgussekloo/laravel-facet-filter 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 mgussekloo/laravel-facet-filter 我们能提供哪些服务?
定制开发 / 二次开发

基于 mgussekloo/laravel-facet-filter 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 765
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 58
  • 点击次数: 15
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 58
  • Watchers: 1
  • Forks: 6
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2022-07-15