<?php
namespace LiaisonTrait;
/**
* - declare and document more filters (Should I document them here or in the place where they're declared? Yes.)
* - Document examples
*
* @export(TODO.Filters)
*/
trait Filters {
protected $filters = [];
protected $filterSorters = [];
/**
* Remove unwanted array items with custom filter functions.
* To execute the filter do `$filteredItems = $lia->filter($filterName, array $itemsToFilter, ...$extraParamaters);`
*
*
* See the [Filters Test](/test/Filters.php) for a thorough example.
*
* @export(Usage.Filters.Execute)
*/
public function filter($name, array $filterable, ...$extraArgs){
$filters = $this->filters[$name] ?? null;
if ($filters==null)return $filterable;
$objs = [];
foreach ($filters as $filter){
$obj = new \Lia\Utility\FancyClosure($filter['callable'], $filter['bound']);
$objs[] = $obj;
}
$filters = $objs;
if (($origCount=count($filters))>1
&& ($sorter=
($this->filterSorters[$name] ?? false)
)
){
//call the sorter
$call = $sorter['callable'];
$bound = $sorter['bound'];
$args = array_merge($bound, [$filters]);
// print_r($args);
// exit;
$filters = $call(...$args);
if (($newCount = count($filters))!=$origCount){
throw new \Exception("Your filter sorter function for '{$name}' MUST return the same number of filters as it was passed.
Original count was '{$origCount}' and you return '{$newCount}'.");
}
}
foreach ($filters as $f){
$args = array_merge([$filterable], $extraArgs);
$filterable = $f(...$args);
}
return $filterable;
}
/**
* Routes might frequently need some filtering that can't be reliably provided by liaison, such as if you declare dynamic routes that sometimes conflict with static routes.
*
* Your filter function can accept bound arguments prior to the filterable array of items. See the [Filters Test](8-build/test/Filters.php) for a full example.
* Example:
* ```php
* $priorityBaseUrl = '/blog/';
* $lia->addFilter(Router.routes, [$yourObject, 'removeDynamicRoutes'], $priorityBaseUrl);
* //any args after the callable will be passed to your callback before the filterable array of items and subsequent paramaters that are passed when filter() is called
* ```
* Then `removeDynamicRoutes` would be:
* ```php
* public function removeDynamicRoutes($priorityBaseUrl, array $routes, $url){
* if ($url does-not-start-with $priorityBaseUrl)return $routes; //We will only filter for '/blog/' urls
* $ret = [];
* foreach ($routes as $r){
* if ($r is-a-dynamic-route)continue;
* $ret[] = $r;
* }
* if (count($ret)>0)return $ret;
* else return $routes;
* }
* ```
*
* @export(Usage.Filters.Add)
*/
public function addFilter($name, $callable, ...$boundArgs){
$this->filters[$name][] = ['callable'=>$callable,'bound'=>$boundArgs];
}
/**
* In case you have added multiple filters for the same name, you can sort the order in which they execute.
* Your callback will be like `function(...$boundArgs, array $filterObjects)`
* - The $filterObjects will be an array of `\Lia\Utility\FancyClosure` objects
* And you add the filter with `$lia->sortFilter($name, $callback, ...$boundArgs)`
* You don't have to pass bound args.
*
* See the [Filters Test](8-build/test/Filters.php) for an example.
*
* @export(Usage.Filters.Sort)
*/
public function sortFilter($name, $callable, ...$boundArgs){
$sorters = $this->filterSorters;
if (isset($sorters[$name]))throw new \Exception("You can only have one sorter for each filter name. '{$name}' is already taken.");
$this->filterSorters[$name] = ['callable'=>$callable, 'bound'=>$boundArgs];
}
}