How to pass values to filter / Filter Loader
If you need to pass a filter (also known as a helper) already defined values or database results, you can do it through anynomous function.
Static list
$genderTypes = [
'ma' => 'Male',
'f' => 'Female',
];
$this->template->addFilter('gender', function ($gender) use ($genderTypes) {
if (isset($genderTypes[$gender])) {
return $genderTypes[$gender];
}
return 'gender unknown';
});
Items list from database
$categoryList = $this->models->categories->fetchAll();
$this->template->addFilter('category', function ($categoryId) use ($categoryList) {
if (isset($categoryList[$categoryId])) {
return $categoryList[$categoryId];
}
return 'unknown';
});
Filter Loader
Another and easily extendable solution is to use your own filter loader. You can extend the class and simply test them and move to other projects.
Following example respects Dependency Injection, so it's passing only required services, you can use to access
database, predefined parameters, path to dirs temp
, app
etc. Our loader contains
filter `
profilePicture`
, which based on file name return route to profile photo, resp. to deafult “no
profile photo” file.
namespace App;
class TemplateFilters
{
/** @var string */
private $wwwDir;
/** @var Nette\Http\IRequest */
private $httpRequest;
public function __construct($wwwDir, Nette\Http\IRequest $httpRequest)
{
$this->wwwDir = $wwwDir;
$this->httpRequest = $httpRequest;
}
/**
* Method we will register as callback
* in method $template->addFilter().
*/
public function loader($helper)
{
return call_user_func_array([$this, $helper], array_slice(func_get_args(), 1));
}
/* === Following particular helpers === */
/**
* Display profile photos
*
* <code>
* <img src="{'JohnDoe.jpg'|profilePicture}">
* </code>
*
* @param string name of file with photo
* @return string route to profile photo of default picture
*/
public function profilePicture($fileName)
{
$basePath = $this->httpRequest->url->scriptPath;
if (is_file($this->wwwDir . '/photos/' . $fileName)) { // profile photo exits
return $basePath . '/photos/' . $fileName;
} else { // profile photo doesn't exist
return $basePath . '/photos/noPhoto.jpg';
}
}
}
If you need use presenter functions in filter (redirect(), link() etc.), you have to pass service
@application
through the __construct
. Presenter will be accessible through
$application->getPresenter()
during template rendering.
How to register filter loader?
Set it as a service first in application config.
services:
myTemplateFilters:
factory: App\TemplateFilters( %wwwDir% )
Than we can register Filter loader
in BasePresenter.php by callback to our method loader() into
Template::addFilter().
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
/**
* @var \App\TemplateFilters @inject
*/
public $myTemplateFilters;
public function createTemplate($class = null)
{
$template = parent::createTemplate($class);
$template->addFilter(null, [
$this->myTemplateFilters,
'loader'
]);
return $template;
}
}