Latte 2'den Latte 3'e geçiş
Latte 3, tamamen yeniden yazılmış bir derleyiciye ve biçimsel olarak iyi tanımlanmış bir gramere sahiptir. Bunun Latte 2 ile olabildiğince örtüşmesi gerekir, ama küçük düzeltmeler isteyen bazı yapılar vardır.
Pratikte şablonların büyük çoğunluğunun hiçbir değişiklik gerektirmediği ve Latte 3'te de Latte 2'deki gibi çalıştığı ortaya çıkıyor. Peki uyumsuzluklar nasıl saptanır?
Önce geçiş sürümü Latte 2.11'i kurun.
Bu sürüm yeni bir özellik getirmez, yalnızca yeni Latte'nin desteklemeyeceğini bildiği durumlar için E_USER_DEPRECATED ile uyarı verir ve daha da önemlisi onları nasıl düzelteceğinizi söyler. Tüm şablonları gözden geçirip uyumlu olup olmadıklarını sınamak için konsoldan çalıştırdığınız Linter aracını kullanabilirsiniz:
vendor/bin/latte-lint <path>
Olası uyumsuzlukları giderdikten sonra Latte 3.0'a yükseltin. Ve yeni katı ayrıştırıcının gerçekten tüm şablonları anladığından emin olmak için Linter'ı yeniden çalıştırın.
API değişiklikleri
API değişiklikleri yalnızca özel etiket eklemeyi ilgilendirir. API'nin geri kalanı 2. sürümdeki gibi kalır; yani şablonları render etme, parametre aktarma, filtre kaydetme aynı şekildedir.
İstisna, artık addFilter() metodu kullanılarak bir sınıf aracılığıyla kaydedilen
filtrelerin üstlendiği dinamik filtre Engine::addFilter(null, ...)'dır. Özgün
Engine::addFilterLoader() metodu geçici bir çözüm olarak hâlâ vardır, ama kullanımdan
kaldırılmıştır.
Özel etiket eklemenin API'si tamamen farklıdır, bu yüzden Latte 2 için tasarlanmış eklentiler onunla çalışmaz. Ayrıca bkz. Eklentilerin güncellenmesi.
Sözdizimi değişiklikleri
Değişiklikler şunlardır:
- filtreler parametre ayırıcı olarak virgül kullanır; önceden
|filter: arg : argolan artık|filter: arg, arg {label foo}...{/label}etiketi her zaman çifttir, tek olan{label /}diye yazılmalıdır- buna karşılık
{_'text'}etiketi her zaman tektir, çift olan{_}...{/}'nin yerini yeni{translate}...{/translate}almıştır {block foo-$var}gibi sözde dizeler tırnak içinde{block "foo-$var"}yazılmalı ya da bileşik parantez eklenmelidir{block foo-{$var}}- bu, nitelikler için de geçerlidir; yani
n:block="foo-$var"yerinen:block="foo-{$var}"kullanın. - Latte 3'te filtrelerde büyük-küçük harfe duyarlı olmak gerekir
{do ...}veya{php ...}etiketi yalnızca ifade içerebilir; herhangi bir PHP kullanmak için RawPhpExtension kaydedin.
Ve birkaç uç durum daha:
n:inner-xxx,n:tag-xxxven:ifcontentnitelikleri void HTML elemanlarında kullanılamazn:inner-snippetniteliği inner- olmadan yazılmalıdır</script>ve</style>etiketleri kapatılmalıdır- sihirli
$iterationsdeğişkeni kaldırıldı ($iteratorile karıştırmayın!) {includeblock file.latte}etiketini{include file.latte with blocks}veya{import}ile değiştirin{include "abc"},"abc"bir nokta içermedikçe ve bunun bir dosya olduğu açık olmadıkça{include file "abc"}diye yazılmalıdır
Eklentilerin güncellenmesi
Ayrıştırıcının tamamen yeniden yazılmasıyla özel etiket yazma biçimi de tamamen değişti. Latte için oluşturulmuş özel etiketleriniz varsa, onları 3. sürüm için yeniden yazmanız gerekecek; bkz. dokümantasyon.
Etiket ekleyen yabancı bir eklenti kullanıyorsanız, yazarın Latte 3 için bir sürüm yayımlamasını beklemeniz
gerekecek. nette/application, nette/caching ve nette/forms kütüphaneleri
3.1 sürümünde, ayrıca Texy da güncellendi ve hem Latte 2 hem Latte 3 ile çalışıyor.
nette/application
Nette'i olağan şekilde kullanırken bu uzantı otomatik ayarlanır ve bir şey değiştirmeye gerek yoktur.
Latte 2 için eski kod:
$latte->onCompile[] = function ($latte) {
Nette\Bridges\ApplicationLatte\UIMacros::install($latte->getCompiler());
};
$latte->addProvider('uiControl', $control);
$latte->addProvider('uiPresenter', $control->getPresenter());
Latte 3 için yeni kod:
$latte->addExtension(new Nette\Bridges\ApplicationLatte\UIExtension($control));
UIExtension; n:href, {link}, {control}, {snippet} vb. ekler. Snippet
etiketleri böylece Latte'nin kendisinden nette/application kütüphanesine taşınmış olur. Latte 3'te
presenter'ın templatePrepareFilters() metodu artık çağrılmaz.
nette/forms
Nette'i olağan şekilde kullanırken bu uzantı otomatik ayarlanır ve bir şey değiştirmeye gerek yoktur.
Latte 2 için eski kod:
$latte->onCompile[] = function ($latte) {
Nette\Bridges\FormsLatte\FormMacros::install($latte->getCompiler());
};
Latte 3 için yeni kod:
$latte->addExtension(new Nette\Bridges\FormsLatte\FormsExtension);
nette/caching
Nette'i olağan şekilde kullanırken bu uzantı otomatik ayarlanır ve bir şey değiştirmeye gerek yoktur.
Latte 2 için eski kod:
$latte->onCompile[] = function ($latte) {
$latte->getCompiler()->addMacro('cache', new Nette\Bridges\CacheLatte\CacheMacro);
};
$latte->addProvider('cacheStorage', $cacheStorage);
Latte 3 için yeni kod:
$latte->addExtension(new Nette\Bridges\CacheLatte\CacheExtension($cacheStorage));
Tracy
Tracy paneli de artık bir uzantı olarak etkinleştirilir.
Latte 2 için eski kod:
$latte = new Latte\Engine;
Latte\Bridges\Tracy\LattePanel::initialize($latte);
Latte 3 için yeni kod:
$latte = new Latte\Engine;
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
Çeviriler
TranslatorExtension; {_'text'} çeviri etiketlerini, yeni çift {translate}...{/translate} etiketini
ve |translate filtresini ekler.
Latte 2 için eski kod:
$latte->addFilter('translate', [$translator, 'translate']);
Latte 3 için yeni kod:
$latte->addExtension(new Latte\Essential\TranslatorExtension($translator));
Presenter'larda, $template->setTranslator($translator) metoduyla şablona çevirmen ayarlanarak otomatik
etkinleştirilir. Bu olmadan çeviri etiketleri erişilebilir olmaz ve uzantıyı elle ya da bir yapılandırma dosyasıyla
kaydetmeniz gerekir.
Yapılandırma dosyası
Latte 2'de yeni etiketler yapılandırma
dosyasıyla latte › macros bölümünde kaydedilebiliyordu. 3. sürümde bu yolla uzantıların tamamı
eklenir:
latte:
extensions:
- App\Templating\LatteExtension
- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
Latte için eklenti mi geliştiriyorsunuz?
Kütüphanenizde Latte'nin her iki sürümü için desteği aynı anda bulundurabilirsiniz. Sürümü saptamak için,
onCompile[] ve addMacro() kullanımını yeni addExtension()'dan ayırmak üzere
Latte\Engine::VERSION sabitini kullanmak en iyisidir:
if (version_compare(Latte\Engine::VERSION, '3', '<')) {
// Latte 2 hazırlığı
$this->latte->onCompile[] = function ($latte) {
$latte->addMacro(/* ... */);
};
} else {
// Latte 3 hazırlığı
$this->latte->addExtension(/* ... */);
}
Örnek olarak, Latte 2 için tasarlanmış şu kodu Latte 3 biçimine yeniden yazmayı deneyelim:
// Latte 2 için eski kod
$this->latte->onCompile[] = function (Latte\Engine $latte) {
$set = new Latte\Macros\MacroSet($latte->getCompiler());
$set->addMacro('foo', 'echo %escape(MyClass:myFunc(%node.word, %node.array))');
};
Latte 3, uzantılarla genişletilir. foo etiketini
ekleyen önemsiz bir uzantı şöyle görünürdü:
// Latte 3 için yeni kod
class FooExtension extends Latte\Extension
{
public function getTags(): array
{
return [
'foo' => [FooNode::class, 'create'], // FooNode sınıfını birazdan ekleyeceğiz
];
}
}
// kayıt
$this->latte->addExtension(new FooExtension);
Yeni derleyici daha sağlamdır, önceki kısayolları içermez, bu yüzden bir makro yazmak biraz daha fazla satır kod ister. Örneğin Latte 2'deki gibi doğrudan bir PHP kodu dizesi aktaramayız, onun yerine bir fonksiyon oluştururuz. Latte 2'de fonksiyonun aşağı yukarı şöyle görüneceğini hatırlayın:
// Latte 2
$set->addMacro('foo', function (Latte\MacroNode $node, Latte\PhpWriter $writer) {
return $writer->write('echo %escape(MyClass:myFunc(%node.word, %node.array))');
});
Yine de Latte 3 buna büyük ölçüde aynı şekilde yaklaşır; yalnızca MacroNode'un adı
Latte\Compiler\Tag, PhpWriter'ın adı ise Latte\Compiler\PrintContext'tir. Ama en
önemlisi, fazladan bir ara adım vardır: fonksiyon doğrudan PHP kodu döndürmez, bir düğüm, yani sonradan AST ağacının
parçası olan bir StatementNode çocuğu döndürür. Ve bu düğümün, PHP kodunu döndüren bir
print(Latte\Compiler\PrintContext $context): string metodu vardır:
// Latte 3
class FooNode extends Latte\Compiler\Nodes\StatementNode
{
public static function create(Latte\Compiler\Tag $tag): self
{
$node = new self;
return $node;
}
public function print(Latte\Compiler\PrintContext $context): string
{
return $context->format('echo ...'); // PHP kodu döndürür
}
}
Ayrıca $context->format() içindeki maskede artık %node.*** kısaltmaları yoktur; önce etiketin içeriğini ayrıştırdığınız
varsayılır. Yani içeriği değişkenlere (alt düğümlere) ayrıştırmak için ayrıştırıcıyı kullanır, sonra da
yazdırırız:
use Latte\Compiler\Nodes\Php\Expression\ArrayNode;
use Latte\Compiler\Nodes\Php\ExpressionNode;
class FooNode extends Latte\Compiler\Nodes\StatementNode
{
public ExpressionNode $subject;
public ArrayNode $args;
public static function create(Latte\Compiler\Tag $tag): self
{
$node = new self;
// etiketin içeriğinin ayrıştırılması
$node->subject = $tag->parser->parseUnquotedStringOrExpression();
$tag->parser->stream->tryConsume(',');
$node->args = $tag->parser->parseArguments();
return $node;
}
public function print(Latte\Compiler\PrintContext $context): string
{
return $context->format(
'echo %escape(MyClass:myFunc(%node, %node));',
$this->subject,
$this->args,
);
}
}
Son olarak, dolaşma
sırasında alt düğümlerin dolaşılabilmesi için getIterator() metodunu ekleyeceğiz:
class FooNode extends Latte\Compiler\Nodes\StatementNode
{
...
public function &getIterator(): \Generator
{
yield $this->subject;
yield $this->args;
}
}