Closed sleuthhound closed 9 years ago
Дошло, тут получается надо самостоятельно разбирать токены.
Да, глобальная переменная обрабатывается во время компиляции. То есть accessor коллбек возвращает PHP код (строка), который будет выполнен во время отрисовки шаблона. Если вам надо вызвать некую функцию то можно написать следующее:
$fenom->addAccessor('array', function (Fenom\Tokenizer $tokens) {
return 'my_accessor_array("'.$tokens->next()->getAndNext().'")';
});
// $.array.key вызовет my_accessor_array("key")
Подробней о том что в коде выше произошло:
$.array.key
это токены $
, .
, array
, .
, key
. Причем токены $
, .
, array
разбираются системой, а далее предлагается самим разобрать токены .
, key
. Так как Вы не использовали оставшиеся токены то Fenom выбросил ошибку после разбора тега, так как не разобранных токенов не должно быть, все должно быть при деле.
Так как нас токен .
не интересует то мы его пропускаем методом ->next()
и берем следующий токен key
сдвигая указатель в массиве токенов на следующий элемент методом ->getAndNext()
, показывая что мы обработали свои токены, остальное нас не интересует.
В случае массива будет
$fenom->addAccessor('array', function (Fenom\Tokenizer $tokens) {
return '$array["'.$tokens->next()->getAndNext().'"]';
});
Надеюсь объяснение помогло
Да, пока просто выстраиваю цепочку вызовов методов и свойств без проверок:
$fenom->addAccessor('object', function (Fenom\Tokenizer $tokens) {
while ($tokens->valid()) {
if ($tokens->is('.')) {
$callable[] = "['". $tokens->skip('.')->getAndNext() ."']";
} else {
$callable[] = $tokens->getAndNext();
}
}
return 'Class::$object'. join('', $callable);
});
И далее, например, использую:
{$.object->set('array', array('key' => 'value'))->get('array').key}
или
{$.object->array.key}
Просто, у меня есть уже определенные объекты, например сайт, раздел, которые не подлежат изменению, потому решил сделать их доступными через глобальную переменную, и потом просто выводить название текущего сайта, раздела или какие-то другие свойства:
{$.site->title} {$.section->title}
Вот еще бы foreach воспринимал глобальную переменную, чтобы так работало:
{foreach $.site->section()->findMany() as $section}
{$section->title}
{/foreach}
сейчас приходиться заранее определять переменную и потом ее перебирать:
{set $sections = $.site->section()->findMany()}
то что foreach не воспринимает — баг, буду править
В 2.5 теперь foreach воспринимает глобальную переменную
Спасибо!
Подскажите, как правильно сформировать вывод в функции, обрабатывающей пользовательский акцессор, когда глобальная переменная используется в условных операторах. Например:
{if $.myAccesor ?}
...
{/if}
Моем случае пока формируется примерно такая каша:
if($object->myAccesor?) { ?>
В теории, понимаю, что надо получить на выходе:
if(!empty($object->myAccesor)) { ?>
Следовательно, надо отследить токен ?
и каким то образом, произвести модификацию.
Рекомендую глянуть сюда — https://github.com/fenom-template/fenom/blob/master/src/Fenom/Accessor.php#L41
Это обработка глобальных типа $.get
, $.post
и тд
Токен ?
будет переменной сам в глобальной переменной. Но глобальная переменная не воспринимается парсером как переменная, а как некий набор действий, поэтому он не может применить к ним empty
и по этой причине нельзя задавать значение глобальной переменной то есть $.get.one = 1
работать не будет.
Пока изменил предыдущий вариант https://github.com/fenom-template/fenom/issues/149#issuecomment-75248814 на такой:
$fenom->addAccessor('object', function ($tokens, $tpl) {
$body = 'Class::$object';
while ($tokens->valid()) {
if ($tokens->is('.')) {
$body = $tpl->parseVariable($tokens, $body);
} elseif ($tokens->is('|')) {
$body = $tpl->parseModifier($tokens, $body);
} elseif ($tokens->is('?') || $tokens->is('!')) {
$body = $tpl->parseTernary($tokens, $body, true);
} elseif ($tokens->is('->')) {
$body = $tpl->parseChain($tokens, $body);
} else {
$body .= $tokens->getAndNext();
}
}
return $body;
});
С первого взгляда вроде получилось, то что нужно. Можно применять модификаторы и использовать в условных операторах.
ну Вы немного перестарались) Но Ваш вариант работоспособен. Однако Вам достаточно
$fenom->addAccessor('object', function ($tokens, $tpl) {
return 'Class::$object';
});
Остальное распарсит сам шаблонизатор (точку, модификаторы, условные операторы и тд), то есть будут работать:
$.object->a
$.object->a->b->c
$.object.a
$.object.a->b ?: $c
и прочие операции над значением, которые существуют в Fenom
Ах, стоп. Я Вас ввел в заблуждение, данная возможность еще в разработке, когда шаблонизатору можно сказать самому допарсить по правилам.
Хм, у меня ошибку выдает. Я почему этот сыр бор то и затеял, что ругается Unexpected token '->' in ... . Значит можно в скором времени свои костылики убрать, это хорошо). Ждем.
Да, я написал о своей оплошности выше. Вариант, который я описал будет доступен в следующей версии
будущий вариант будет иметь 3ий аргумент в методе addAccessor, который укажет парсеру что надо распаристь самостоятельно и как
Однако, отчасти я прав в том что когда вами будет обработана глобальная переменная, то парсер сам спарсит модификаторы и условные операторы. То есть parseModifier и parseTernary лишние
Ага, вы правы. Переделал так:
$fenom->addAccessor('object', function ($tokens, $tpl) {
$body = 'Class::$object';
$body = $tpl->parseChain($tokens, $body);
$body = $tpl->parseVariable($tokens, $body);
return $body;
});
вроде работает. Спасибо.
Подскажите, так и должно быть?
На выходе получаем: