Skip to content

Commit

Permalink
Update README.md with docblock updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Thavarshan committed Apr 12, 2024
1 parent f304b8d commit e26e139
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 21 deletions.
65 changes: 57 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ You can create a new filter class using the following Artisan command:
php artisan make:filter PostFilter
```

This command will generate a new filter class in the `app/Filters` directory. You can then customize this class to add your own filter methods.
This command will generate a new filter class in the `app/Filters` directory. You can then customise this class to add your own filter methods.

The `Filter` class is a base class that provides the core functionality for applying filters to Eloquent queries. You can extend this class to create your own filter classes tailored to your specific models. To use the `Filter` class, you first need to extend it to create your own filter class tailored to your specific model. Here's a basic example for a `Post` model:

Expand All @@ -74,6 +74,26 @@ class PostFilter extends Filter
}
```

To add a new filter, simply define a new method within your custom filter class. This method should adhere to PHP's **camelCase** naming convention and be named descriptively based on the filter's purpose. Once you've implemented the method, ensure to register its name in the `$filters` array to activate it. Here's how you can do it:

```php
namespace App\Filters;

use Filterable\Filter;

class PostFilter extends Filter
{
protected array $filters = ['last_published_at'];

protected function lastPublishedAt(int $value): Builder
{
return $this->builder->where('last_published_at', $value);
}
}
```

In this example, a new filter `lastPublishedAt` is created in the PostFilter class. The filter name `last_published_at` is registered in the `$filters` array.

### Implementing the `Filterable` Trait and `Filterable` Interface

To use the `Filter` class in your Eloquent models, you need to implement the `Filterable` interface and use the `Filterable` trait. Here's an example for a `Post` model:
Expand Down Expand Up @@ -154,11 +174,40 @@ class PostController extends Controller
}
```

### Applying Pre-Filters to run before the main filters

You can also apply pre-filters that run before the main filters. The `registerPreFilters` method sets the pre-filters that should be applied:

```php
use App\Models\Post;
use App\Filters\PostFilter;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Builder;

class PostController extends Controller
{
public function index(Request $request, PostFilter $filter)
{
$filter->registerPreFilters(function (Builder $query) {
return $query->where('published', true);
});

$query = Post::filter($filter);

$posts = $request->has('paginate')
? $query->paginate($request->query('per_page', 20))
: $query->get();

return response()->json($posts);
}
}
```

## Customization

### Adding New Filters
### Caching

To add a new filter, simply define a new method within your custom filter class. This method should adhere to PHP's **camelCase** naming convention and be named descriptively based on the filter's purpose. Once you've implemented the method, ensure to register its name in the `$filters` array to activate it. Here's how you can do it:
In your filter class, you can control caching by using the `setUseCache` method. Set the `$useCache` property to `true` to enable caching, or `false` to disable it. You can also customise the duration of the cache by modifying the `$cacheExpiration` property.`

```php
namespace App\Filters;
Expand All @@ -174,13 +223,13 @@ class PostFilter extends Filter
return $this->builder->where('last_published_at', $value);
}
}
```

In this example, a new filter `lastPublishedAt` is created in the PostFilter class. The filter name `last_published_at` is registered in the `$filters` array.

### Caching
$filter = new PostFilter(request(), cache());

Enable or disable caching by setting the `$useCache` property in your filter class. Customize the cache duration by adjusting the `$cacheExpiration` property.
// Control caching
$filter->setUseCache(true);
$filter->cacheExpiration = 1440; // Cache duration in minutes
```

## Testing

Expand Down
56 changes: 43 additions & 13 deletions src/Filterable/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

Expand Down Expand Up @@ -67,6 +68,10 @@ abstract class Filter implements FilterInterface
/**
* The pre-filters to apply to the query.
*
* These are filters to be applied before the actual filterables are executed.
* So when the Query Builder is run, the results have has already been
* filtered and then the actual filters are applied.
*
* @var Closure|null
*/
protected ?Closure $preFilters = null;
Expand Down Expand Up @@ -102,6 +107,8 @@ abstract class Filter implements FilterInterface
/**
* Extra options for the filter.
*
* These options are for the developers use and are not used internally.
*
* @var array<string, mixed>
*/
protected array $options = [];
Expand Down Expand Up @@ -155,6 +162,7 @@ public function apply(Builder $builder, ?array $options = []): Builder
$this->setOptions($options)->setBuilder($builder);

// Apply the filter for a specific user if it's set
// Basically to filter resutls by 'user_id' column
$this->applyForUserFilter();

// Apply any predefined filters
Expand All @@ -168,7 +176,7 @@ public function apply(Builder $builder, ?array $options = []): Builder
}

/**
* Apply the for user filter.
* Filter the query to only include records for the authenticated user.
*
* @return void
*/
Expand All @@ -189,7 +197,7 @@ protected function applyForUserFilter(): void
*/
protected function applyFilterables(): void
{
if (! $this->useCache) {
if (! $this->shouldUseCache()) {
$this->applyFiltersToQuery();

return;
Expand All @@ -198,7 +206,7 @@ protected function applyFilterables(): void
$this->getCacheHandler()->remember(
$this->buildCacheKey(),
Carbon::now()->addMinutes($this->getCacheExpiration()),
function () {
function (): Collection {
$this->applyFiltersToQuery();

return $this->getBuilder()->get();
Expand All @@ -207,7 +215,7 @@ function () {
}

/**
* Apply the filters to the query.
* Execute the query builder query functionality with the filters applied.
*
* @return void
*/
Expand All @@ -219,32 +227,43 @@ protected function applyFiltersToQuery(): void
&& $value !== false
&& $value !== [])
->each(function ($value, $filter) {
$this->applyFilterable($value, $filter);
$this->applyFilterable($filter, $value);
});
}

/**
* Apply a filter to the query.
*
* @param mixed $value
* @param string $filter
* @param mixed $value
*
* @return void
*/
protected function applyFilterable(mixed $value, string $filter): void
protected function applyFilterable(string $filter, mixed $value): void
{
$filter = $this->filterMethodMap[$filter]
?? Str::camel($filter);
$filter = $this->makeFilterIntoMethodName($filter);

if (! method_exists($this, $filter)) {
throw new BadMethodCallException(
sprintf('Method %s does not exist on %s', $filter, static::class)
sprintf('Method [%s] does not exist on %s', $filter, static::class)
);
}

call_user_func([$this, $filter], $value);
}

/**
* Make the filter into a method name.
*
* @param string $filter
*
* @return string
*/
protected function makeFilterIntoMethodName(string $filter): string
{
return $this->filterMethodMap[$filter] ?? Str::camel($filter);
}

/**
* Build the cache key for the filter.
*
Expand All @@ -261,17 +280,18 @@ protected function buildCacheKey(): string
}

/**
* Fetch all relevant filters from the request.
* Fetch all relevant filters (key, value) from the request.
*
* @return array<string>
*/
public function getFilterables(): array
{
$filterKeys = array_merge(
$this->filters,
$this->getFilters(),
array_keys($this->filterMethodMap ?? [])
);

// Will contains key, value pairs of the filters
$this->filterables = array_merge(
$this->filterables,
array_filter($this->request->only($filterKeys))
Expand Down Expand Up @@ -487,10 +507,20 @@ public function getCacheHandler(): Cache
*
* @return self
*/
public function setCacheHandler(Cache $cache)
public function setCacheHandler(Cache $cache): self
{
$this->cache = $cache;

return $this;
}

/**
* Get indicates if caching should be used.
*
* @return bool
*/
public function shouldUseCache(): bool
{
return $this->useCache;
}
}

0 comments on commit e26e139

Please sign in to comment.