Fix compatibility with Nette 2.4

Právě v těchto dnech přichází další významná minor verze Nette balíčků do vašich vendorů. Událo se velké množství změn a to zejména pod kapotou. To si však s sebou nese určitou daň a tou je potřeba učinit pár úprav v kódu, které zajistí kompatibilitu. Těchto úprav není mnoho. A když už jsou, tak na ně Nette upozorní třeba prostřednictvím E_USER_DEPRECATED. Pokud však pracujete se složitější aplikací, která třeba nebyla původně postavená na Nette, může být taková úprava docela lopota.

Zde se tedy nedočtete co je v Nette nového, ale jak co upravit a na co jsem narazil, když jsem tuto kompatibilitu re­šil.

Úpravy v Latte

Jelikož pracuji na starším projektu, který je původem non-Nette, tak je zvykem používat PHP konstanty. Všude. Zatímco dříve stačilo používat {=NAZEV_KONSTANTY}, teď je nutné konstantu přímo označit {=constant('NAZEV_KONSTANTY')}, aby bylo jednoznačně jasné, že se jedná skutečně o konstantu. Jedna z velmi užitečných vlastností Latte bylo to, že nebyl problém napsat PHP kód do klasických PHP tagů <?php. Existovalo makro {?, ale dnes je doporučované pouze {php ...}. Toto je zároveň jediná věc, která mě štve, protože dříve bylo převádění externích šablon do Latte velmi jednoduché. Tímto se vše komplikuje.

Velké změny jsou pod kaptou Latte. Pokud máte vlastní Template objekt (a tedy i vlastní TemplateFactory, protože to jinak udělat nejde), doporučuji udělat aktualizaci podle masteru. Asi nejzásadnější změna je právě v TemplateFactory při naplňování šablony:

// default parameters
$template->user = $this->user;
$template->baseUri = $template->baseUrl = $this->httpRequest ? rtrim($this->httpRequest->getUrl()->getBaseUrl(), '/') : NULL;
$template->basePath = preg_replace('#https?://[^/]+#A', '', $template->baseUrl);
$template->flashes = [];
if ($control) {
    $template->control = $control;
    $template->presenter = $presenter;
    $latte->addProvider('uiControl', $control);
    $latte->addProvider('uiPresenter', $presenter);
    $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($control));
}
$latte->addProvider('cacheStorage', $this->cacheStorage);

Nově se používají tzv. providery, které lze získat takto: $template->getLatte()->getProviders(). Pokud tedy máte např. vlastní Latte makra, tak ty je zapotřebí změnit v tomto duchu: z $_control->link(... na $this->global->uiControl->link(....

Úpravy v Nette

Relativně nedávnou změnou je absence metody Nette\Utils\Html::add. Ta je nahrazena kombinací addText resp. addHtml. Touto změnou by se mělo zajistit, že programátor nepošle do šablony HTML kód o kterém si myslí, že je escapovaný, ale on ve skutečnosti není.

Asi největší myšlenkový obrat způsobila změna chování rout. Konkrétně Route::SECURED. Od samého začátku co dělám s Nette jsem tento příznak chápal blbě a nejsem sám. Nově Nette zachovává takový protokol, s kterým uživatel přišel. Pokud potřebujete aplikaci na HTTPS, tak správné řešení je nastavit toto chování na úrovni serveru, třeba takto:

RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Pokud i přesto potřebujeme generovat odkazy v aplikaci s HTTPS (k čemuž byl určen Route::SECURED příznak), můžeme tak učinit vepsáním protokolu do masky routy. Dva příklady řeknou více než tisíc slov:

$router[] = new Route('rss/novinky.php', 'Front:Rss:novinky'); //celý web je na HTTP
$this->link('//:Front:Rss:novinky'); //vygeneruje: http://example.com/rss/novinky.php

$router[] = new Route('https://%host%/rss/novinky.php', 'Front:Rss:novinky'); //celý web je stále na HTTP
$this->link('//:Front:Rss:novinky'); //vygeneruje: https://example.com/rss/novinky.php

Ve stejném smyslu je zapotřebí upravit i vlastní routery. Takže zpátky z šicím strojům opravit si aplikace… :)

Pár dalších drobností a postřehů

Místo Nette\Object je teď možné používat traitu Nette\SmartObject. Tato traita se od svého předchůdce liší v několika drobnostech. Více informací je rozepsáno v tomto vláknu na fóru. S tím se váže to, že občas je potřeba změnit podobné zápisy: z $this->reflection na $this->getReflection(). Drtivá část věcí se snad odladila, takže není třeba nic řešit. Jsou však místa (jako ta reflexe), kdy si to raději změním ve svém kódu.

Jak se na fóru dočtete, tak Nette\SmartObject nepodporuje extension methods. To se často využívá u vlastních formulářových prvků. Náhrada je opět jednoduchá a logická:

BaseControl::extensionMethod('addHelp', function (... //původně
ObjectMixin::setExtensionMethod(BaseControl::class, 'addHelp', function (... //nově

S čím jsem měl trošku problémy byla Tracy. Jedna z rad byla vypnout debugger, ale toto by již mělo být vyřešené:

session:
    debugger: no

Pokud se vám tedy načítá stránka bez zjevného důvodu dlouho, vyzkoušejte vypnout tento panel. Asi nejvíce problémy budou dělat knihovny třetích stran. Zejména Kdyby mi dělá největší vrásky na čele. Bohužel autor nemá čas tyto věci řešit, takže celý internet čeká… :) Zároveň se např. v Kdyby/Doctrine (dev-master kde je lecos již opravené) oddělilo několik komponent do vlastních repozitářů. To se ukázalo jako překvapivě velký BC break, který nemá jednoduché řešení. Například zatímco dříve měl Testbench Doctrine jako volitelnou závislost, tak dnes musí mít navíc i kdyby/doctrine-dbal-batchimport. To je pro uživatele velmi nepříjmené, protože na to musí myslet. Zatím nevím co s tím…

Dočasná vhodná kombinace (pro zajištění kompatibility s Nette 2.4) pro Kdyby balíčky, které používám já je tato:

{
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/mrtnzlml/Events"
    }
  ],
  "require": {
    "kdyby/console": "^2.5",
    "kdyby/doctrine": "dev-master",
    "kdyby/doctrine-cache": "dev-master",
    "kdyby/doctrine-dbal-batchimport": "dev-master",
    "kdyby/events": "dev-patch-1 as 3.0.x-dev",
    "kdyby/fake-session": "^2.0",
    "kdyby/monolog": "^1.2",
  }
}

Z toho důvodu bych možná raději doporučoval chvíli počkat, protože je s tím velké (a hlavně zbytečné) trápení. A když už jsem se opřel i o Testbench. I zde se z důvodu kompatibility ukáže BC break. Mock linky se budou generovat v jiném formátu (kompatibilním s Testerem).

Máte při přechodu ještě nějaký problém?

  • V komentářích jsou povolené HTML tagy <a href=""> <blockquote> <code> <em> <strong>
  • Kódy programů zapisujte takto pomocí <pre><code>alert('XSS');</code></pre>