fenom/src/Fenom.php

1247 lines
37 KiB
PHP
Raw Permalink Normal View History

2013-01-25 18:36:16 +04:00
<?php
2013-04-28 11:33:36 +04:00
/*
2013-06-28 11:53:53 +04:00
* This file is part of Fenom.
2013-04-28 11:33:36 +04:00
*
* (c) 2013 Ivan Shalganov
*
2013-04-28 18:08:57 +04:00
* For the full copyright and license information, please view the license.md
2013-04-28 11:33:36 +04:00
* file that was distributed with this source code.
*/
2016-06-09 14:24:35 +03:00
use Fenom\Error\CompileException;
2023-02-05 23:59:04 +03:00
use Fenom\Provider;
2013-08-01 01:05:19 +04:00
use Fenom\ProviderInterface;
2023-02-05 23:59:04 +03:00
use Fenom\Render;
2013-08-01 01:05:19 +04:00
use Fenom\Template;
2013-01-25 18:36:16 +04:00
2013-01-25 19:18:09 +04:00
/**
2013-06-28 11:53:53 +04:00
* Fenom Template Engine
2013-07-04 01:28:10 +04:00
*
2014-10-31 10:55:58 +03:00
*
2013-07-04 01:28:10 +04:00
* @author Ivan Shalganov <a.cobest@gmail.com>
2013-01-25 19:18:09 +04:00
*/
2013-07-29 14:58:14 +04:00
class Fenom
{
2023-02-20 00:14:08 +03:00
const VERSION = '3.0';
const REV = 2;
2013-07-20 21:25:32 +04:00
/* Actions */
2013-07-29 14:58:14 +04:00
const INLINE_COMPILER = 1;
2014-05-06 14:22:58 +04:00
const BLOCK_COMPILER = 5;
const INLINE_FUNCTION = 2;
2014-05-06 14:22:58 +04:00
const BLOCK_FUNCTION = 7;
2013-01-25 18:36:16 +04:00
2013-07-03 12:10:50 +04:00
/* Options */
2014-05-06 14:22:58 +04:00
const DENY_ACCESSOR = 0x8;
const DENY_METHODS = 0x10;
2013-07-29 14:58:14 +04:00
const DENY_NATIVE_FUNCS = 0x20;
2014-05-06 14:22:58 +04:00
const FORCE_INCLUDE = 0x40;
const AUTO_RELOAD = 0x80;
const FORCE_COMPILE = 0x100;
const AUTO_ESCAPE = 0x200;
const DISABLE_CACHE = 0x400;
const FORCE_VERIFY = 0x800;
const AUTO_TRIM = 0x1000; // reserved
2014-11-05 16:07:50 +03:00
const DENY_PHP_CALLS = 0x2000;
2014-05-08 12:56:37 +04:00
const AUTO_STRIP = 0x4000;
2014-11-05 16:07:50 +03:00
/**
* Use DENY_PHP_CALLS
* @deprecated
*/
const DENY_STATICS = 0x2000;
2013-07-24 19:37:07 +04:00
2013-07-03 12:10:50 +04:00
/* Default parsers */
2013-06-28 11:53:53 +04:00
const DEFAULT_CLOSE_COMPILER = 'Fenom\Compiler::stdClose';
2014-05-06 14:22:58 +04:00
const DEFAULT_FUNC_PARSER = 'Fenom\Compiler::stdFuncParser';
const DEFAULT_FUNC_OPEN = 'Fenom\Compiler::stdFuncOpen';
const DEFAULT_FUNC_CLOSE = 'Fenom\Compiler::stdFuncClose';
const SMART_FUNC_PARSER = 'Fenom\Compiler::smartFuncParser';
2013-01-25 18:36:16 +04:00
2013-07-29 14:58:14 +04:00
const MAX_MACRO_RECURSIVE = 32;
2013-07-29 14:53:21 +04:00
const ACCESSOR_CUSTOM = null;
const ACCESSOR_VAR = 'Fenom\Accessor::parserVar';
const ACCESSOR_CALL = 'Fenom\Accessor::parserCall';
const ACCESSOR_PROPERTY = 'Fenom\Accessor::parserProperty';
const ACCESSOR_METHOD = 'Fenom\Accessor::parserMethod';
2016-04-19 12:35:25 +03:00
const ACCESSOR_CHAIN = 'Fenom\Accessor::parserChain';
2015-06-01 23:42:47 +03:00
2023-02-20 00:14:08 +03:00
public static string $charset = "UTF-8";
2015-06-03 00:19:40 +03:00
2016-06-10 15:51:23 +03:00
/**
* @var int maximum length of compiled filename (use sha1 of name if bigger)
*/
2023-02-20 00:14:08 +03:00
public static int $filename_length = 200;
2016-06-10 15:51:23 +03:00
2013-01-25 18:36:16 +04:00
/**
2013-05-19 02:04:52 +04:00
* @var int[] of possible options, as associative array
* @see setOptions
2013-01-25 18:36:16 +04:00
*/
2023-02-20 00:14:08 +03:00
private static array $_options_list = [
2014-05-06 14:22:58 +04:00
"disable_accessor" => self::DENY_ACCESSOR,
"disable_methods" => self::DENY_METHODS,
2013-07-24 19:37:07 +04:00
"disable_native_funcs" => self::DENY_NATIVE_FUNCS,
2014-05-06 14:22:58 +04:00
"disable_cache" => self::DISABLE_CACHE,
"force_compile" => self::FORCE_COMPILE,
"auto_reload" => self::AUTO_RELOAD,
"force_include" => self::FORCE_INCLUDE,
"auto_escape" => self::AUTO_ESCAPE,
"force_verify" => self::FORCE_VERIFY,
"auto_trim" => self::AUTO_TRIM,
2014-11-05 16:07:50 +03:00
"disable_php_calls" => self::DENY_PHP_CALLS,
2014-05-06 14:22:58 +04:00
"disable_statics" => self::DENY_STATICS,
2014-05-08 12:56:37 +04:00
"strip" => self::AUTO_STRIP,
2023-02-05 23:59:04 +03:00
];
2013-01-25 18:36:16 +04:00
2013-08-01 01:05:19 +04:00
/**
* @var callable[]
*/
2023-02-20 00:14:08 +03:00
protected array $pre_filters = [];
2013-08-01 01:05:19 +04:00
/**
* @var callable[]
*/
2023-02-20 00:14:08 +03:00
protected array $filters = [];
2013-08-01 01:05:19 +04:00
/**
* @var callable[]
*/
2023-02-20 00:14:08 +03:00
protected array $tag_filters = [];
/**
* @var string[]
*/
2023-02-20 00:14:08 +03:00
protected array $call_filters = [];
2013-08-01 01:05:19 +04:00
/**
* @var callable[]
*/
2023-02-20 00:14:08 +03:00
protected array $post_filters = [];
2013-08-01 01:05:19 +04:00
2013-01-28 16:34:34 +04:00
/**
2013-06-28 11:53:53 +04:00
* @var Fenom\Render[] Templates storage
2013-01-28 16:34:34 +04:00
*/
2023-02-05 23:59:04 +03:00
protected array $_storage = [];
2013-08-01 01:05:19 +04:00
2013-01-25 18:36:16 +04:00
/**
* @var string compile directory
*/
2023-02-05 23:59:04 +03:00
protected string $_compile_dir = "/tmp";
2013-01-25 18:36:16 +04:00
/**
* @var string compile prefix ID template
*/
2023-02-20 00:14:08 +03:00
protected string $_compile_id = "";
/**
* @var string[] compile directory for custom provider
*/
2023-02-05 23:59:04 +03:00
protected array $_compiles = [];
2013-01-25 18:36:16 +04:00
/**
* @var int masked options
*/
2023-02-05 23:59:04 +03:00
protected int $_options = 0;
2013-01-25 18:36:16 +04:00
/**
* @var ProviderInterface
*/
2023-02-05 23:59:04 +03:00
private ProviderInterface $_provider;
/**
2013-06-28 11:53:53 +04:00
* @var Fenom\ProviderInterface[]
*/
2023-02-05 23:59:04 +03:00
protected array $_providers = [];
2013-01-25 18:36:16 +04:00
/**
2013-05-19 02:04:52 +04:00
* @var string[] list of modifiers [modifier_name => callable]
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
protected array $_modifiers = [
2014-05-06 14:22:58 +04:00
"upper" => 'strtoupper',
"up" => 'strtoupper',
"lower" => 'strtolower',
"low" => 'strtolower',
2013-06-28 11:53:53 +04:00
"date_format" => 'Fenom\Modifier::dateFormat',
2014-05-06 14:22:58 +04:00
"date" => 'Fenom\Modifier::date',
"truncate" => 'Fenom\Modifier::truncate',
"escape" => 'Fenom\Modifier::escape',
"e" => 'Fenom\Modifier::escape', // alias of escape
"unescape" => 'Fenom\Modifier::unescape',
"strip" => 'Fenom\Modifier::strip',
"length" => 'Fenom\Modifier::length',
"iterable" => 'Fenom\Modifier::isIterable',
"replace" => 'Fenom\Modifier::replace',
"ereplace" => 'Fenom\Modifier::ereplace',
"match" => 'Fenom\Modifier::match',
"ematch" => 'Fenom\Modifier::ematch',
"split" => 'Fenom\Modifier::split',
"esplit" => 'Fenom\Modifier::esplit',
"join" => 'Fenom\Modifier::join',
2014-07-11 12:11:51 +04:00
"in" => 'Fenom\Modifier::in',
2016-05-06 23:04:08 +03:00
"range" => 'Fenom\Modifier::range',
2023-02-05 23:59:04 +03:00
];
2013-01-25 18:36:16 +04:00
/**
* @var array of allowed PHP functions
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
protected array $_allowed_funcs = [
2014-05-06 14:22:58 +04:00
"count" => 1,
"is_string" => 1,
"is_array" => 1,
"is_numeric" => 1,
"is_int" => 1,
'constant' => 1,
"is_object" => 1,
"strtotime" => 1,
"gettype" => 1,
"is_double" => 1,
"json_encode" => 1,
"json_decode" => 1,
"ip2long" => 1,
"long2ip" => 1,
"strip_tags" => 1,
"nl2br" => 1,
"explode" => 1,
"implode" => 1
2023-02-05 23:59:04 +03:00
];
2013-01-25 18:36:16 +04:00
/**
* @var string[] the disabled functions by `disable_functions` PHP's option
*/
2023-02-05 23:59:04 +03:00
protected array $_disabled_funcs = [];
2013-01-25 18:36:16 +04:00
/**
2013-05-19 02:04:52 +04:00
* @var array[] of compilers and functions
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
protected array $_actions = [
'foreach' => [ // {foreach ...} {break} {continue} {foreachelse} {/foreach}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::foreachOpen',
'close' => 'Fenom\Compiler::foreachClose',
2023-02-05 23:59:04 +03:00
'tags' => [
2013-06-28 11:53:53 +04:00
'foreachelse' => 'Fenom\Compiler::foreachElse',
2014-05-06 14:22:58 +04:00
'break' => 'Fenom\Compiler::tagBreak',
'continue' => 'Fenom\Compiler::tagContinue',
2023-02-05 23:59:04 +03:00
],
'float_tags' => ['break' => 1, 'continue' => 1]
],
'if' => [ // {if ...} {elseif ...} {else} {/if}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::ifOpen',
2013-06-28 11:53:53 +04:00
'close' => 'Fenom\Compiler::stdClose',
2023-02-05 23:59:04 +03:00
'tags' => [
2013-06-28 11:53:53 +04:00
'elseif' => 'Fenom\Compiler::tagElseIf',
2014-05-06 14:22:58 +04:00
'else' => 'Fenom\Compiler::tagElse'
2023-02-05 23:59:04 +03:00
]
],
'switch' => [ // {switch ...} {case ..., ...} {default} {/switch}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::switchOpen',
'close' => 'Fenom\Compiler::switchClose',
2023-02-05 23:59:04 +03:00
'tags' => [
2014-05-06 14:22:58 +04:00
'case' => 'Fenom\Compiler::tagCase',
2013-09-02 17:40:58 +04:00
'default' => 'Fenom\Compiler::tagDefault'
2023-02-05 23:59:04 +03:00
],
'float_tags' => ['break' => 1]
],
'for' => [ // {for ...} {break} {continue} {/for}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::forOpen',
'close' => 'Fenom\Compiler::forClose',
2023-02-05 23:59:04 +03:00
'tags' => [
2014-05-06 14:22:58 +04:00
'forelse' => 'Fenom\Compiler::forElse',
'break' => 'Fenom\Compiler::tagBreak',
2013-06-28 11:53:53 +04:00
'continue' => 'Fenom\Compiler::tagContinue',
2023-02-05 23:59:04 +03:00
],
'float_tags' => ['break' => 1, 'continue' => 1]
],
'while' => [ // {while ...} {break} {continue} {/while}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::whileOpen',
'close' => 'Fenom\Compiler::stdClose',
2023-02-05 23:59:04 +03:00
'tags' => [
2014-05-06 14:22:58 +04:00
'break' => 'Fenom\Compiler::tagBreak',
2013-06-28 11:53:53 +04:00
'continue' => 'Fenom\Compiler::tagContinue',
2023-02-05 23:59:04 +03:00
],
'float_tags' => ['break' => 1, 'continue' => 1]
],
'include' => [ // {include ...}
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-06-28 11:53:53 +04:00
'parser' => 'Fenom\Compiler::tagInclude'
2023-02-05 23:59:04 +03:00
],
'insert' => [ // {include ...}
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-09-02 17:40:58 +04:00
'parser' => 'Fenom\Compiler::tagInsert'
2023-02-05 23:59:04 +03:00
],
'var' => [ // {var ...}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::setOpen',
'close' => 'Fenom\Compiler::setClose'
2023-02-05 23:59:04 +03:00
],
'set' => [ // {set ...}
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::setOpen',
'close' => 'Fenom\Compiler::setClose'
2023-02-05 23:59:04 +03:00
],
'add' => [ // {add ...}
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::setOpen',
'close' => 'Fenom\Compiler::setClose'
2023-02-05 23:59:04 +03:00
],
'do' => [ // {do ...}
2016-05-08 18:26:01 +03:00
'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagDo'
2023-02-05 23:59:04 +03:00
],
'block' => [ // {block ...} {parent} {/block}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::tagBlockOpen',
'close' => 'Fenom\Compiler::tagBlockClose',
2023-02-05 23:59:04 +03:00
'tags' => ['parent' => 'Fenom\Compiler::tagParent'],
'float_tags' => ['parent' => 1]
],
'extends' => [ // {extends ...}
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-06-28 11:53:53 +04:00
'parser' => 'Fenom\Compiler::tagExtends'
2023-02-05 23:59:04 +03:00
],
'use' => [ // {use}
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-06-28 11:53:53 +04:00
'parser' => 'Fenom\Compiler::tagUse'
2023-02-05 23:59:04 +03:00
],
'filter' => [ // {filter} ... {/filter}
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::filterOpen',
2013-06-28 11:53:53 +04:00
'close' => 'Fenom\Compiler::filterClose'
2023-02-05 23:59:04 +03:00
],
'macro' => [
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::macroOpen',
2013-06-28 11:53:53 +04:00
'close' => 'Fenom\Compiler::macroClose'
2023-02-05 23:59:04 +03:00
],
'import' => [
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-06-28 11:53:53 +04:00
'parser' => 'Fenom\Compiler::tagImport'
2023-02-05 23:59:04 +03:00
],
'cycle' => [
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-07-03 12:10:50 +04:00
'parser' => 'Fenom\Compiler::tagCycle'
2023-02-05 23:59:04 +03:00
],
'raw' => [
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagRaw'
2023-02-05 23:59:04 +03:00
],
'autoescape' => [ // deprecated
2014-05-08 12:56:37 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::escapeOpen',
'close' => 'Fenom\Compiler::nope'
2023-02-05 23:59:04 +03:00
],
'escape' => [
2014-05-08 12:56:37 +04:00
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::escapeOpen',
'close' => 'Fenom\Compiler::nope'
2023-02-05 23:59:04 +03:00
],
'strip' => [
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
2014-05-08 12:56:37 +04:00
'open' => 'Fenom\Compiler::stripOpen',
'close' => 'Fenom\Compiler::nope'
2023-02-05 23:59:04 +03:00
],
'ignore' => [
'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::ignoreOpen',
'close' => 'Fenom\Compiler::nope'
2023-02-05 23:59:04 +03:00
],
'unset' => [
2014-06-28 22:15:30 +04:00
'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagUnset'
2023-02-05 23:59:04 +03:00
],
'paste' => [ // {include ...}
2016-04-11 20:19:31 +03:00
'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagPaste'
2023-02-05 23:59:04 +03:00
],
];
2013-01-25 18:36:16 +04:00
2014-04-12 01:00:58 +04:00
/**
* List of tests
* @see https://github.com/bzick/fenom/blob/develop/docs/operators.md#test-operator
* @var array
*/
2023-02-05 23:59:04 +03:00
protected array $_tests = [
2014-05-06 14:22:58 +04:00
'integer' => 'is_int(%s)',
'int' => 'is_int(%s)',
'float' => 'is_float(%s)',
'double' => 'is_float(%s)',
'decimal' => 'is_float(%s)',
'string' => 'is_string(%s)',
'bool' => 'is_bool(%s)',
'boolean' => 'is_bool(%s)',
'number' => 'is_numeric(%s)',
'numeric' => 'is_numeric(%s)',
'scalar' => 'is_scalar(%s)',
'object' => 'is_object(%s)',
2014-04-12 01:00:58 +04:00
'callable' => 'is_callable(%s)',
'callback' => 'is_callable(%s)',
2014-05-06 14:22:58 +04:00
'array' => 'is_array(%s)',
2014-04-12 01:00:58 +04:00
'iterable' => '\Fenom\Modifier::isIterable(%s)',
2014-05-06 14:22:58 +04:00
'const' => 'defined(%s)',
2014-04-12 01:00:58 +04:00
'template' => '$tpl->getStorage()->templateExists(%s)',
2014-05-06 14:22:58 +04:00
'empty' => 'empty(%s)',
'set' => 'isset(%s)',
'_empty' => '!%s', // for none variable
'_set' => '(%s !== null)', // for none variable
'odd' => '(%s & 1)',
'even' => '!(%s %% 2)',
'third' => '!(%s %% 3)'
2023-02-05 23:59:04 +03:00
];
2014-04-12 01:00:58 +04:00
2023-02-05 23:59:04 +03:00
protected array $_accessors = [
'get' => 'Fenom\Accessor::getVar',
'env' => 'Fenom\Accessor::getVar',
'post' => 'Fenom\Accessor::getVar',
'request' => 'Fenom\Accessor::getVar',
'cookie' => 'Fenom\Accessor::getVar',
'globals' => 'Fenom\Accessor::getVar',
'server' => 'Fenom\Accessor::getVar',
'session' => 'Fenom\Accessor::getVar',
'files' => 'Fenom\Accessor::getVar',
'tpl' => 'Fenom\Accessor::tpl',
'version' => 'Fenom\Accessor::version',
'const' => 'Fenom\Accessor::constant',
2016-04-11 19:44:59 +03:00
'php' => 'Fenom\Accessor::call',
'call' => 'Fenom\Accessor::call',
'tag' => 'Fenom\Accessor::Tag',
2016-04-11 19:44:59 +03:00
'fetch' => 'Fenom\Accessor::fetch',
2016-04-12 12:28:57 +03:00
'block' => 'Fenom\Accessor::block',
2023-02-05 23:59:04 +03:00
];
2013-02-13 20:51:27 +04:00
/**
* Just factory
*
2013-06-28 11:53:53 +04:00
* @param string|Fenom\ProviderInterface $source path to templates or custom provider
2013-02-13 20:51:27 +04:00
* @param string $compile_dir path to compiled files
2014-06-19 20:44:18 +04:00
* @param int|array $options
2013-02-13 20:51:27 +04:00
* @throws InvalidArgumentException
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-02-13 20:51:27 +04:00
*/
2023-02-05 23:59:04 +03:00
public static function factory(
string|Fenom\ProviderInterface $source,
string $compile_dir = '/tmp',
int|array $options = 0
2023-02-23 23:50:12 +03:00
): static
2013-07-29 14:58:14 +04:00
{
if (is_string($source)) {
2013-06-28 11:53:53 +04:00
$provider = new Fenom\Provider($source);
2013-02-13 20:51:27 +04:00
} else {
2023-02-22 00:09:00 +03:00
$provider = $source;
2013-02-13 20:51:27 +04:00
}
2013-06-28 11:53:53 +04:00
$fenom = new static($provider);
$fenom->setCompileDir($compile_dir);
2013-07-29 14:58:14 +04:00
if ($options) {
2013-06-28 11:53:53 +04:00
$fenom->setOptions($options);
2013-01-25 18:36:16 +04:00
}
2013-06-28 11:53:53 +04:00
return $fenom;
2013-01-25 18:36:16 +04:00
}
/**
2013-06-28 11:53:53 +04:00
* @param Fenom\ProviderInterface $provider
*/
2013-07-29 14:58:14 +04:00
public function __construct(Fenom\ProviderInterface $provider)
{
$this->_provider = $provider;
}
/**
* Set compile directory
2013-05-19 02:04:52 +04:00
*
* @param string $dir directory to store compiled templates in
2013-09-06 15:56:37 +04:00
* @throws LogicException
2023-02-05 23:59:04 +03:00
* @return $this
*/
2023-02-05 23:59:04 +03:00
public function setCompileDir(string $dir): static
2013-07-29 14:58:14 +04:00
{
2014-02-27 16:30:44 +04:00
if (!is_writable($dir)) {
2013-09-06 15:56:37 +04:00
throw new LogicException("Cache directory $dir is not writable");
}
2013-01-25 18:36:16 +04:00
$this->_compile_dir = $dir;
return $this;
}
/**
* Set compile prefix ID template
*
* @param string $id prefix ID to store compiled templates
2023-02-05 23:59:04 +03:00
* @return $this
*/
2023-02-05 23:59:04 +03:00
public function setCompileId(string $id): static
{
$this->_compile_id = $id;
return $this;
}
/**
*
* @param callable $cb
2023-02-05 23:59:04 +03:00
* @return $this
*/
2023-02-05 23:59:04 +03:00
public function addPreFilter(callable $cb): static
2013-07-29 14:58:14 +04:00
{
2013-08-01 01:05:19 +04:00
$this->pre_filters[] = $cb;
return $this;
}
2023-02-05 23:59:04 +03:00
/**
* @return callable[]
*/
public function getPreFilters(): array
2013-08-02 21:50:04 +04:00
{
2013-08-01 01:05:19 +04:00
return $this->pre_filters;
}
/**
*
* @param callable $cb
2023-02-05 23:59:04 +03:00
* @return $this
*/
2023-02-05 23:59:04 +03:00
public function addPostFilter(callable $cb): static
2013-07-29 14:58:14 +04:00
{
2013-08-01 01:05:19 +04:00
$this->post_filters[] = $cb;
return $this;
}
2023-02-05 23:59:04 +03:00
/**
* @return callable[]
*/
public function getPostFilters(): array
2013-08-02 21:50:04 +04:00
{
2013-08-01 01:05:19 +04:00
return $this->post_filters;
2013-01-25 18:36:16 +04:00
}
/**
* @param callable $cb
2013-08-01 01:05:19 +04:00
* @return self
*/
2023-02-05 23:59:04 +03:00
public function addFilter(callable $cb): static
2013-07-29 14:58:14 +04:00
{
2013-08-01 01:05:19 +04:00
$this->filters[] = $cb;
return $this;
}
2023-02-05 23:59:04 +03:00
public function getFilters(): array
2013-08-02 21:50:04 +04:00
{
2013-08-01 01:05:19 +04:00
return $this->filters;
}
2013-01-25 18:36:16 +04:00
/**
* @param callable $cb
* @return self
*/
2023-02-05 23:59:04 +03:00
public function addTagFilter(callable $cb): static
{
$this->tag_filters[] = $cb;
return $this;
}
2023-02-05 23:59:04 +03:00
public function getTagFilters(): array
{
return $this->tag_filters;
}
2013-01-25 18:36:16 +04:00
/**
* Add modifier
*
2013-05-19 02:04:52 +04:00
* @param string $modifier the modifier name
2018-07-20 15:31:17 +03:00
* @param callable $callback the modifier callback
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addModifier(string $modifier, callable $callback): static
2013-07-29 14:58:14 +04:00
{
2013-01-25 18:36:16 +04:00
$this->_modifiers[$modifier] = $callback;
return $this;
}
/**
2013-02-20 18:09:24 +04:00
* Add inline tag compiler
*
* @param string $compiler
2013-02-20 18:09:24 +04:00
* @param callable $parser
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addCompiler(string $compiler, callable $parser): static
2013-07-29 14:58:14 +04:00
{
2013-01-25 18:36:16 +04:00
$this->_actions[$compiler] = array(
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-01-25 18:36:16 +04:00
'parser' => $parser
);
return $this;
}
/**
* @param string $compiler
* @param string|object $storage
* @return $this
*/
2023-02-05 23:59:04 +03:00
public function addCompilerSmart(string $compiler, string|object $storage): static
2013-07-29 14:58:14 +04:00
{
if (method_exists($storage, "tag" . $compiler)) {
$this->_actions[$compiler] = array(
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_COMPILER,
2013-07-29 14:58:14 +04:00
'parser' => array($storage, "tag" . $compiler)
);
}
2013-03-04 12:40:32 +04:00
return $this;
}
2013-01-25 18:36:16 +04:00
/**
2013-02-20 18:09:24 +04:00
* Add block compiler
*
* @param string $compiler
2013-02-20 18:09:24 +04:00
* @param callable $open_parser
2023-02-05 23:59:04 +03:00
* @param callable $close_parser
2013-01-25 18:36:16 +04:00
* @param array $tags
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addBlockCompiler(
string $compiler,
callable $open_parser,
callable $close_parser = self::DEFAULT_CLOSE_COMPILER,
array $tags = []
): static
{
2013-01-25 18:36:16 +04:00
$this->_actions[$compiler] = array(
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
'open' => $open_parser,
2013-07-29 14:58:14 +04:00
'close' => $close_parser ? : self::DEFAULT_CLOSE_COMPILER,
2014-05-06 14:22:58 +04:00
'tags' => $tags,
2013-01-25 18:36:16 +04:00
);
return $this;
}
2013-03-04 12:40:32 +04:00
/**
2023-02-05 23:59:04 +03:00
* @param string $compiler
* @param string|object $storage
2013-03-04 12:40:32 +04:00
* @param array $tags
* @param array $floats
* @throws LogicException
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-03-04 12:40:32 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addBlockCompilerSmart(
string $compiler,
string|object $storage,
array $tags,
array $floats = []
): static
2013-07-29 14:58:14 +04:00
{
$c = array(
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_COMPILER,
"tags" => array(),
"float_tags" => array()
);
2013-07-29 14:58:14 +04:00
if (method_exists($storage, $compiler . "Open")) {
2013-09-14 11:24:23 +04:00
$c["open"] = array($storage, $compiler . "Open");
} else {
throw new \LogicException("Open compiler {$compiler}Open not found");
}
2013-07-29 14:58:14 +04:00
if (method_exists($storage, $compiler . "Close")) {
2013-09-14 11:24:23 +04:00
$c["close"] = array($storage, $compiler . "Close");
} else {
throw new \LogicException("Close compiler {$compiler}Close not found");
}
2013-07-29 14:58:14 +04:00
foreach ($tags as $tag) {
if (method_exists($storage, "tag" . $tag)) {
2013-09-14 11:24:23 +04:00
$c["tags"][$tag] = array($storage, "tag" . $tag);
2013-07-29 14:58:14 +04:00
if ($floats && in_array($tag, $floats)) {
$c['float_tags'][$tag] = 1;
}
} else {
throw new \LogicException("Tag compiler $tag (tag{$compiler}) not found");
}
}
$this->_actions[$compiler] = $c;
2013-03-04 12:40:32 +04:00
return $this;
}
2013-01-25 18:36:16 +04:00
/**
* @param string $function
* @param callable $callback
2023-02-05 23:59:04 +03:00
* @param callable $parser
2013-06-28 11:53:53 +04:00
* @return Fenom
*/
2023-02-05 23:59:04 +03:00
public function addFunction(string $function, callable $callback, callable $parser = self::DEFAULT_FUNC_PARSER): static
2013-07-29 14:58:14 +04:00
{
$this->_actions[$function] = array(
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_FUNCTION,
'parser' => $parser,
'function' => $callback,
);
return $this;
}
/**
* @param string $function
* @param callable $callback
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addFunctionSmart(string $function, callable $callback): static
2013-07-29 14:58:14 +04:00
{
2013-01-25 18:36:16 +04:00
$this->_actions[$function] = array(
2014-05-06 14:22:58 +04:00
'type' => self::INLINE_FUNCTION,
'parser' => self::SMART_FUNC_PARSER,
2013-01-25 18:36:16 +04:00
'function' => $callback,
);
return $this;
}
/**
2013-02-20 18:09:24 +04:00
* @param string $function
* @param callable $callback
2023-02-05 23:59:04 +03:00
* @param callable $parser_open
* @param callable $parser_close
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addBlockFunction(
string $function,
callable $callback,
callable $parser_open = self::DEFAULT_FUNC_OPEN,
callable $parser_close = self::DEFAULT_FUNC_CLOSE
): static
2014-10-15 01:01:55 +04:00
{
2013-01-25 18:36:16 +04:00
$this->_actions[$function] = array(
2014-05-06 14:22:58 +04:00
'type' => self::BLOCK_FUNCTION,
'open' => $parser_open,
'close' => $parser_close,
2013-07-29 14:58:14 +04:00
'function' => $callback,
2013-01-25 18:36:16 +04:00
);
return $this;
}
/**
* @param array $funcs
2013-06-28 11:53:53 +04:00
* @return Fenom
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addAllowedFunctions(array $funcs): static
2013-07-29 14:58:14 +04:00
{
2013-01-25 18:36:16 +04:00
$this->_allowed_funcs = $this->_allowed_funcs + array_flip($funcs);
return $this;
}
2014-04-12 01:00:58 +04:00
/**
* Add custom test
* @param string $name test name
2023-02-05 23:59:04 +03:00
* @param string $code test PHP code. Code may contain placeholder %s, which will be replaced by test-value. For example: is_callable(%s)
2014-04-12 01:00:58 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addTest(string $name, string $code): static
2014-04-17 23:27:59 +04:00
{
2014-04-12 01:00:58 +04:00
$this->_tests[$name] = $code;
2023-02-05 23:59:04 +03:00
return $this;
2014-04-12 01:00:58 +04:00
}
/**
* Get test code by name
* @param string $name
2023-02-05 23:59:04 +03:00
* @return string
2014-04-12 01:00:58 +04:00
*/
2023-02-05 23:59:04 +03:00
public function getTest(string $name): string
2014-04-17 23:27:59 +04:00
{
2023-02-05 23:59:04 +03:00
return $this->_tests[$name] ?? "";
2014-04-12 01:00:58 +04:00
}
2013-01-25 18:36:16 +04:00
/**
2013-02-20 18:09:24 +04:00
* Return modifier function
*
2013-07-24 19:37:07 +04:00
* @param string $modifier
2023-02-05 23:59:04 +03:00
* @param Template|null $template
2023-02-20 00:14:08 +03:00
* @return callable|null
2013-01-25 18:36:16 +04:00
*/
2023-02-20 00:14:08 +03:00
public function getModifier(string $modifier, Fenom\Template $template = null): ?callable
2013-07-29 14:58:14 +04:00
{
if (isset($this->_modifiers[$modifier])) {
2013-01-25 18:36:16 +04:00
return $this->_modifiers[$modifier];
2013-07-29 14:58:14 +04:00
} elseif ($this->isAllowedFunction($modifier)) {
2013-01-25 18:36:16 +04:00
return $modifier;
} else {
2013-07-24 19:37:07 +04:00
return $this->_loadModifier($modifier, $template);
2013-01-25 18:36:16 +04:00
}
}
/**
2014-04-09 18:03:49 +04:00
* Modifier autoloader
2013-07-24 19:37:07 +04:00
* @param string $modifier
2023-02-07 01:49:54 +03:00
* @param Template $template
* @return string|null
2013-07-24 19:37:07 +04:00
*/
2023-02-07 01:49:54 +03:00
protected function _loadModifier(string $modifier, Fenom\Template $template): ?string
2013-07-29 14:58:14 +04:00
{
2023-02-07 01:49:54 +03:00
return null;
2013-07-24 19:37:07 +04:00
}
/**
* Returns tag info
*
* @param string $tag
2023-02-05 23:59:04 +03:00
* @param Template|null $template
* @return array|null
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function getTag(string $tag, Template $template = null): ?array
2013-07-29 14:58:14 +04:00
{
if (isset($this->_actions[$tag])) {
2013-07-24 19:37:07 +04:00
return $this->_actions[$tag];
2013-01-25 18:36:16 +04:00
} else {
2013-07-24 19:37:07 +04:00
return $this->_loadTag($tag, $template);
2013-01-25 18:36:16 +04:00
}
}
2013-07-24 19:37:07 +04:00
/**
2014-04-09 18:03:49 +04:00
* Tags autoloader
* @param string $tag
2013-07-24 19:37:07 +04:00
* @param Fenom\Template $template
2023-02-05 23:59:04 +03:00
* @return array|null
2013-07-24 19:37:07 +04:00
*/
2023-02-05 23:59:04 +03:00
protected function _loadTag(string $tag, Template $template): ?array
2013-07-29 14:58:14 +04:00
{
2023-02-05 23:59:04 +03:00
return null;
2013-07-24 19:37:07 +04:00
}
2013-02-20 18:09:24 +04:00
/**
* Checks if is allowed PHP function for using in templates.
*
* @param string $function the function name
2013-02-20 18:09:24 +04:00
* @return bool
*/
2023-02-05 23:59:04 +03:00
public function isAllowedFunction(string $function): bool
2013-07-29 14:58:14 +04:00
{
2022-06-12 11:46:43 +03:00
$allow = ($this->_options & self::DENY_NATIVE_FUNCS)
? isset($this->_allowed_funcs[$function])
: function_exists($function);
2023-02-05 23:59:04 +03:00
return $allow && !in_array($function, $this->_getDisabledFuncs(), true);
2022-06-12 11:46:43 +03:00
}
/**
* Returns the disabled PHP functions.
*
* @return string[]
*/
2023-02-05 23:59:04 +03:00
protected function _getDisabledFuncs(): array
2022-06-12 11:46:43 +03:00
{
return $this->_disabled_funcs;
2013-01-25 18:36:16 +04:00
}
2013-02-26 23:56:06 +04:00
/**
* @param string $tag
* @return array
*/
2023-02-05 23:59:04 +03:00
public function getTagOwners(string $tag): array
2013-07-29 14:58:14 +04:00
{
2023-02-05 23:59:04 +03:00
$tags = [];
2013-07-29 14:58:14 +04:00
foreach ($this->_actions as $owner => $params) {
if (isset($params["tags"][$tag])) {
2013-01-25 18:36:16 +04:00
$tags[] = $owner;
}
}
return $tags;
}
2013-02-20 18:09:24 +04:00
/**
* Add source template provider by scheme
*
* @param string $scm scheme name
2013-06-28 11:53:53 +04:00
* @param Fenom\ProviderInterface $provider provider object
2023-02-05 23:59:04 +03:00
* @param string|null $compile_path
2013-09-02 17:40:58 +04:00
* @return $this
2013-02-20 18:09:24 +04:00
*/
2023-02-05 23:59:04 +03:00
public function addProvider(string $scm, ProviderInterface $provider, string $compile_path = null): static
2013-07-29 14:58:14 +04:00
{
$this->_providers[$scm] = $provider;
2014-02-27 16:30:44 +04:00
if ($compile_path) {
$this->_compiles[$scm] = $compile_path;
}
2013-09-02 17:40:58 +04:00
return $this;
2013-01-28 16:34:34 +04:00
}
2013-01-25 18:36:16 +04:00
/**
2013-07-25 02:05:44 +04:00
* Set options
2013-01-25 18:36:16 +04:00
* @param int|array $options
2013-09-02 17:40:58 +04:00
* @return $this
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function setOptions(int|array $options): static
2013-07-29 14:58:14 +04:00
{
if (is_array($options)) {
2013-07-23 11:32:31 +04:00
$options = self::_makeMask($options, self::$_options_list, $this->_options);
2013-01-25 18:36:16 +04:00
}
2013-02-20 18:09:24 +04:00
$this->_storage = array();
2013-01-25 18:36:16 +04:00
$this->_options = $options;
2013-09-02 17:40:58 +04:00
return $this;
2013-01-25 18:36:16 +04:00
}
/**
* Get options as bits
* @return int
*/
2023-02-05 23:59:04 +03:00
public function getOptions(): int
2013-07-29 14:58:14 +04:00
{
2013-01-25 18:36:16 +04:00
return $this->_options;
}
/**
* Add global accessor ($.)
* @param string $name
* @param callable $parser
* @return Fenom
*/
2023-02-05 23:59:04 +03:00
public function addAccessor(string $name, callable $parser): static
{
$this->_accessors[$name] = $parser;
return $this;
}
/**
2016-06-09 13:44:43 +03:00
* Add global accessor as PHP code ($.)
* @param string $name
* @param mixed $accessor
2015-06-01 23:42:47 +03:00
* @param string $parser
* @return Fenom
*/
2023-02-05 23:59:04 +03:00
public function addAccessorSmart(string $name, mixed $accessor, string $parser = self::ACCESSOR_VAR): static
2016-06-09 13:44:43 +03:00
{
2015-06-01 23:42:47 +03:00
$this->_accessors[$name] = array(
"accessor" => $accessor,
2016-06-09 13:44:43 +03:00
"parser" => $parser,
);
return $this;
}
/**
* Add global accessor handler as callback ($.X)
* @param string $name
* @param callable $callback
* @return Fenom
*/
2023-02-05 23:59:04 +03:00
public function addAccessorCallback(string $name, callable $callback): static
2016-06-09 13:44:43 +03:00
{
$this->_accessors[$name] = array(
"callback" => $callback
2015-06-01 23:42:47 +03:00
);
return $this;
}
/**
* Remove accessor
* @param string $name
* @return Fenom
*/
2023-02-05 23:59:04 +03:00
public function removeAccessor(string $name): static
{
unset($this->_accessors[$name]);
return $this;
}
/**
* Get an accessor
* @param string $name
2023-02-05 23:59:04 +03:00
* @param string|null $key
2023-02-20 00:14:08 +03:00
* @return callable|array|null
*/
2023-02-20 00:14:08 +03:00
public function getAccessor(string $name,string $key = null): mixed
2016-06-09 13:44:43 +03:00
{
if(isset($this->_accessors[$name])) {
2016-06-09 13:44:43 +03:00
if($key) {
return $this->_accessors[$name][$key];
} else {
return $this->_accessors[$name];
}
} else {
2023-02-05 23:59:04 +03:00
return null;
}
}
/**
* Add filter for $.php accessor.
* Uses glob syntax.
* @param string $pattern
* @return $this
*/
2023-02-05 23:59:04 +03:00
public function addCallFilter(string $pattern): static
2016-06-09 13:44:43 +03:00
{
$this->call_filters[] = $pattern;
return $this;
}
/**
2023-02-05 23:59:04 +03:00
* @param string|null $scm
* @return ProviderInterface
* @throws InvalidArgumentException
*/
2023-02-05 23:59:04 +03:00
public function getProvider(string $scm = null): Fenom\ProviderInterface
2013-07-29 14:58:14 +04:00
{
if ($scm) {
if (isset($this->_providers[$scm])) {
return $this->_providers[$scm];
} else {
throw new InvalidArgumentException("Provider for '$scm' not found");
}
} else {
return $this->_provider;
}
}
2013-02-20 18:09:24 +04:00
/**
* Return empty template
*
2013-06-28 11:53:53 +04:00
* @return Fenom\Template
2013-02-20 18:09:24 +04:00
*/
2023-02-05 23:59:04 +03:00
public function getRawTemplate(Template $parent = null): Template
2013-07-29 14:58:14 +04:00
{
2016-10-09 23:40:37 +03:00
return new Template($this, $this->_options, $parent);
2013-02-13 20:51:27 +04:00
}
2013-01-25 18:36:16 +04:00
/**
* Execute template and write result into stdout
*
* @param string|array $template name of template.
* If it is array of names of templates they will be extended from left to right.
2013-02-20 18:09:24 +04:00
* @param array $vars array of data for template
2023-02-20 00:14:08 +03:00
* @return array
2023-02-05 23:59:04 +03:00
* @throws CompileException
2013-01-25 18:36:16 +04:00
*/
2023-02-20 00:14:08 +03:00
public function display(string|array $template, array $vars = array()): array
2013-07-29 14:58:14 +04:00
{
2013-01-25 18:36:16 +04:00
return $this->getTemplate($template)->display($vars);
2013-01-28 16:34:34 +04:00
}
2013-01-25 18:36:16 +04:00
/**
*
2023-02-05 23:59:04 +03:00
* @param array|string $template name of template.
* If it is array of names of templates they will be extended from left to right.
2013-02-20 18:09:24 +04:00
* @param array $vars array of data for template
2013-01-25 18:36:16 +04:00
* @return mixed
2023-02-05 23:59:04 +03:00
* @throws Exception
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function fetch(array|string $template, array $vars = array()): mixed
2013-07-29 14:58:14 +04:00
{
2013-01-28 16:34:34 +04:00
return $this->getTemplate($template)->fetch($vars);
}
2013-01-25 18:36:16 +04:00
2013-07-03 12:10:50 +04:00
/**
2014-05-06 14:22:58 +04:00
* Creates pipe-line of template's data to callback
2014-05-06 15:27:31 +04:00
* @note Method not works correctly in old PHP 5.3.*
2023-02-05 23:59:04 +03:00
* @param array|string $template name of the template.
* If it is array of names of templates they will be extended from left to right.
2014-05-06 14:22:58 +04:00
* @param callable $callback template's data handler
2013-07-03 12:10:50 +04:00
* @param array $vars
2023-02-05 23:59:04 +03:00
* @param int $chunk amount of bytes of chunk
2013-07-20 21:25:32 +04:00
* @return array
2023-02-05 23:59:04 +03:00
* @throws CompileException
2013-07-03 12:10:50 +04:00
*/
2023-02-05 23:59:04 +03:00
public function pipe(array|string $template, callable $callback, array $vars = array(), int $chunk = 1_000_000): array
2013-07-29 14:58:14 +04:00
{
2014-05-06 14:22:58 +04:00
ob_start($callback, $chunk, PHP_OUTPUT_HANDLER_STDFLAGS);
2013-07-20 21:25:32 +04:00
$data = $this->getTemplate($template)->display($vars);
2013-07-03 12:10:50 +04:00
ob_end_flush();
2013-07-20 21:25:32 +04:00
return $data;
2013-07-03 12:10:50 +04:00
}
2013-01-25 18:36:16 +04:00
/**
2013-05-19 02:04:52 +04:00
* Get template by name
2013-01-25 18:36:16 +04:00
*
2023-02-05 23:59:04 +03:00
* @param string|array $template template name with schema
2013-05-19 02:04:52 +04:00
* @param int $options additional options and flags
2023-02-05 23:59:04 +03:00
* @return Fenom\Render
* @throws CompileException
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function getTemplate(string|array $template, int $options = 0): Render
2013-07-29 14:58:14 +04:00
{
2013-07-22 18:03:43 +04:00
$options |= $this->_options;
2014-02-27 16:30:44 +04:00
if (is_array($template)) {
2016-06-09 16:00:18 +03:00
$key = $options . "@" . implode(",", $template);
} else {
$key = $options . "@" . $template;
}
2013-07-29 14:58:14 +04:00
if (isset($this->_storage[$key])) {
/** @var Fenom\Template $tpl */
$tpl = $this->_storage[$key];
if (($this->_options & self::AUTO_RELOAD) && !$tpl->isValid()) {
2023-02-23 23:50:12 +03:00
$this->compile($template, true, $options);
return $this->_storage[$key] = $this->_load($template, $options);
2013-01-25 18:36:16 +04:00
} else {
return $tpl;
2013-01-25 18:36:16 +04:00
}
2023-02-23 23:50:12 +03:00
} elseif ($this->_options & (self::FORCE_COMPILE | self::DISABLE_CACHE)) {
2015-08-13 10:33:39 +03:00
return $this->compile($template, !($this->_options & self::DISABLE_CACHE), $options);
2013-01-25 18:36:16 +04:00
} else {
2013-07-29 14:58:14 +04:00
return $this->_storage[$key] = $this->_load($template, $options);
2013-01-25 18:36:16 +04:00
}
2013-01-28 16:34:34 +04:00
}
2013-01-25 18:36:16 +04:00
/**
2013-07-20 21:25:32 +04:00
* Check if template exists
* @param string $template
* @return bool
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function templateExists(string $template): bool
2013-07-29 14:58:14 +04:00
{
$key = $this->_options . "@" . $template;
if (isset($this->_storage[$key])) { // already loaded
return true;
}
2013-07-29 14:58:14 +04:00
if ($provider = strstr($template, ":", true)) {
if (isset($this->_providers[$provider])) {
2013-07-20 21:25:32 +04:00
return $this->_providers[$provider]->templateExists(substr($template, strlen($provider) + 1));
}
} else {
return $this->_provider->templateExists($template);
}
return false;
2013-01-25 18:36:16 +04:00
}
/**
2013-05-19 02:04:52 +04:00
* Load template from cache or create cache if it doesn't exists.
2013-01-25 18:36:16 +04:00
*
2023-02-20 00:14:08 +03:00
* @param string[]|string $template
* @param int $opts
2013-06-28 11:53:53 +04:00
* @return Fenom\Render
2023-02-05 23:59:04 +03:00
* @throws CompileException
2013-01-25 18:36:16 +04:00
*/
2023-02-20 00:14:08 +03:00
protected function _load(array|string $template, int $opts): Render
2013-07-29 14:58:14 +04:00
{
2016-06-09 13:44:43 +03:00
$file_name = $this->getCompileName($template, $opts);
2023-02-23 23:50:12 +03:00
$tpl = null;
if (!is_file($this->_compile_dir . "/" . $file_name)) {
$tpl = $this->compile($template, true, $opts);
}
2013-08-23 00:55:53 +04:00
if (is_file($this->_compile_dir . "/" . $file_name)) {
2013-09-02 17:40:58 +04:00
$fenom = $this; // used in template
2014-05-06 14:22:58 +04:00
$_tpl = include($this->_compile_dir . "/" . $file_name);
2013-09-02 17:40:58 +04:00
/* @var Fenom\Render $_tpl */
2016-05-30 14:29:14 +03:00
if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD)
&& $_tpl instanceof Fenom\Render
&& $_tpl->isValid()) {
2013-08-23 00:55:53 +04:00
return $_tpl;
2023-02-23 23:50:12 +03:00
} else if ($tpl) {
return $tpl;
2013-08-23 00:55:53 +04:00
}
2013-01-28 16:34:34 +04:00
}
2023-02-23 23:50:12 +03:00
throw new CompileException("failed to store cache of " . var_export($template, true) .
" to {$file_name}");
2013-01-28 16:34:34 +04:00
}
2013-01-25 18:36:16 +04:00
/**
* Generate unique name of compiled template
*
2016-06-09 13:44:43 +03:00
* @param string|string[] $tpl
* @param int $options additional options
2013-01-25 18:36:16 +04:00
* @return string
*/
2023-02-05 23:59:04 +03:00
public function getCompileName(array|string $tpl, int $options = 0): string
2013-07-29 14:58:14 +04:00
{
2016-05-30 14:29:14 +03:00
$options = $this->_options | $options;
2014-02-27 16:30:44 +04:00
if (is_array($tpl)) {
$hash = implode(".", $tpl) . ":" . $options;
2014-02-27 16:30:44 +04:00
foreach ($tpl as &$t) {
2016-06-10 15:51:23 +03:00
$t = urlencode(str_replace(":", "_", basename($t)));
}
2016-06-10 15:51:23 +03:00
$tpl = implode("~", $tpl);
} else {
$hash = $tpl . ":" . $options;
2016-06-10 15:51:23 +03:00
$tpl = urlencode(str_replace(":", "_", basename($tpl)));
}
if($tpl > self::$filename_length) {
$tpl = sha1($tpl);
}
2016-06-10 15:51:23 +03:00
return $this->_compile_id . $tpl . "." . sprintf("%x.%x.php", crc32($hash), strlen($hash));
2013-01-25 18:36:16 +04:00
}
/**
* Compile and save template
*
2023-02-05 23:59:04 +03:00
* @param array|string $tpl
* @param bool $store store template on disk
2013-04-04 10:56:44 +04:00
* @param int $options
2023-02-05 23:59:04 +03:00
* @return Template
2016-06-09 14:24:35 +03:00
* @throws CompileException
*/
2023-02-05 23:59:04 +03:00
public function compile(array|string $tpl, bool $store = true, int $options = 0): Template
2013-07-29 14:58:14 +04:00
{
2014-02-27 16:30:44 +04:00
if (is_string($tpl)) {
$template = $this->getRawTemplate()->load($tpl);
} else {
$template = $this->getRawTemplate()->load($tpl[0], false);
for($i = 1; $i < count($tpl); $i++) {
$template->extend($tpl[ $i ]);
}
}
2013-07-29 14:58:14 +04:00
if ($store) {
2016-06-09 13:44:43 +03:00
$cache_name = $this->getCompileName($tpl, $options);
2016-05-30 14:25:08 +03:00
$compile_path = $this->_compile_dir . "/" . $cache_name . "." . mt_rand(0, 100000) . ".tmp";
if(!file_put_contents($compile_path, $template->getTemplateCode())) {
2016-06-09 14:24:35 +03:00
throw new CompileException("Can't to write to the file $compile_path. Directory " . $this->_compile_dir . " is writable?");
}
2016-05-30 14:25:08 +03:00
$cache_path = $this->_compile_dir . "/" . $cache_name;
if (!rename($compile_path, $cache_path)) {
unlink($compile_path);
2016-06-09 14:24:35 +03:00
throw new CompileException("Can't to move the file $compile_path -> $cache_path");
}
}
2013-01-25 18:36:16 +04:00
return $template;
}
/**
2014-10-15 01:01:55 +04:00
* Flush internal template in-memory-cache
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function flush(): void
2013-07-29 14:58:14 +04:00
{
2023-02-05 23:59:04 +03:00
$this->_storage = [];
2013-05-19 02:04:52 +04:00
}
2013-01-25 18:36:16 +04:00
/**
2013-05-19 02:04:52 +04:00
* Remove all compiled templates
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function clearAllCompiles(): void
2013-07-29 14:58:14 +04:00
{
2023-02-05 23:59:04 +03:00
Provider::clean($this->_compile_dir);
2014-10-15 01:01:55 +04:00
$this->flush();
2013-01-25 18:36:16 +04:00
}
/**
* Compile code to template
*
* @param string $code
* @param string $name
2013-06-28 11:53:53 +04:00
* @return Fenom\Template
2013-01-25 18:36:16 +04:00
*/
2023-02-05 23:59:04 +03:00
public function compileCode(string $code, string $name = 'Runtime compile'): Template
2013-07-29 14:58:14 +04:00
{
2013-07-25 02:05:44 +04:00
return $this->getRawTemplate()->source($name, $code);
2013-01-25 18:36:16 +04:00
}
2013-02-21 22:51:24 +04:00
/**
* Create bit-mask from associative array use fully associative array possible keys with bit values
* @static
* @param array $values custom assoc array, ["a" => true, "b" => false]
* @param array $options possible values, ["a" => 0b001, "b" => 0b010, "c" => 0b100]
* @param int $mask the initial value of the mask
* @return int result, ( $mask | a ) & ~b
2023-02-05 23:59:04 +03:00
* @throws \RuntimeException if key from custom assoc doesn't exist into possible values
2013-02-21 22:51:24 +04:00
*/
2023-02-05 23:59:04 +03:00
private static function _makeMask(array $values, array $options, int $mask = 0): int
2013-07-29 14:58:14 +04:00
{
2013-07-23 11:32:31 +04:00
foreach ($values as $key => $value) {
if (isset($options[$key])) {
if ($value) {
$mask |= $options[$key];
2013-02-21 22:51:24 +04:00
} else {
$mask &= ~$options[$key];
2013-02-21 22:51:24 +04:00
}
} else {
throw new \RuntimeException("Undefined parameter $value");
}
}
return $mask;
}
2023-02-20 00:14:08 +03:00
/**
* @return array
*/
public function getCallFilters(): array
{
return $this->call_filters;
}
2013-01-25 18:36:16 +04:00
}