Mám skvělý pocit z právě vydané verze Nette 2.2.3, protože se tam
podařilo vychytat řadu drobností, počínaje chytřejším rozpoznání chyb u nativních
funkcí, přes výstižnější chybové hlášky DI kontejneru, až po
různé novinky (viz release
notes). Už jsem ji nasadil na všechny své weby a běží výborně.
Rád bych vypíchl 3 užitečné novinky. První se týká Latte a jde o funkci
invokeFilter()
, kterou můžete volat filtr i mimo šablonu:
$latte = new Latte\Engine;
$latte->addFilter('upper', 'strtoupper');
$upper = $latte->invokeFilter('upper', array('abc')));
// obdoba {'abc'|upper} v šabloně
Druhá novinka se týká Tracy. Ta
nyní dokáže logovat chyby jako je E_NOTICE
v plné náloži
(tj. s HTML souborem), jako když loguje výjimky. Které chyby má takto
logovat nastavíte do proměnné $logSeverity
:
Tracy\Debugger::$logSeverity = E_NOTICE | E_WARNING;
Třetí novinka souvisí s bezpečností. Třída Configurator
má metodu setDebugMode()
, pomocí které určujete, zda aplikace
poběží v produkčním nebo vývojářském režimu. Raději jí nikdy
nepředávejte argument true
, může se pak snadno stát, že to
deploynete na ostrý server a máte hned bezpečnostní kráter. Správné je
jako argument předat IP adresy, pro které chcete vývojářský režim na
ostrém serveru povolit:
$configurator->setDebugMode('23.75.345.200');
Jenže IP adresy se mohou měnit a dostane ji někdo jiný. Proto je nově
možné přidat ještě pojistku v podobně cookie. Do cookie nazvané
nette-debug
si uložíte tajný řetězec (buď funkcí setcookie
nebo pomocí vývojářského nástroje prohlížeče, každopádně
nezapomeňte na příznak httpOnly), například mysecret
a
necháte Configurator, aby ověřoval i jej. Teprve sedí-li IP adresa
i hodnota v cookie, bude aktivován vývojářský režim:
$configurator->setDebugMode('mysecret@23.75.345.200');
Čtvrtá novinka ze tří se týká DI
kontejneru a je velmi dobře skrytá. Dovoluje nastavit, které třídy
vynechat z autowiringu. Typickým kandidátem je
Nette\Application\UI\Control
, kterého vám může DI kontejner
cpát třeba do konstruktoru formuláře. Seznam ignorovaných tříd předáte
metodě ContainerBuilder::addExcludedClasses()
. K té se dostanete
například v bootstrap.php
:
$configurator->onCompile[] = function($configurator, $compiler) {
$compiler->getContainerBuilder()->addExcludedClasses(array(
'stdClass',
'Nette\Application\UI\Control',
));
};
A do pětice všeho dobrého: při vývoji můžete narazit na upozornění
Possible problem: you are sending a HTTP header while already having some data in output buffer. Try OutputDebugger or start session earlier.
To se objeví, když se snažíte odeslat HTTP hlavičky, a ono to sice ještě
jde, nicméně aplikace už nějaký výstup předtím odeslala, jen ho zachytil
output buffer.
V takové situaci je nejlepší nastartovat OutputDebugger
a zjistit, odkud se výstup posílal a předejít tomu. Od verze 2.2.3 máte
také možnost toto dobře míněné upozornění potlačit pomocí proměnné
Nette\Http\Response::$warnOnBuffer
. Třeba opět z bootstrapu:
$container->getByType('Nette\Http\Response')->warnOnBuffer = false;
Poslední dobou si lámu hlavu s hledáním „byznys“ modelu pro vývoj
Nette, protože půlroční snaha o komunitní pojetí dojela na nezájem.
Co dál?
Jednak bych chtěl, aby Nette dál vzkvétalo, jde dost možná
o nejpoužívanější webový framework u nás a zná ho nejvíc
programátorů, tudíž se pokračovat musí.
Mám dojem, že firmy, které používají Nette, jeho vývoj zase tolik
nezajímá. Upgradovat na vyšší velké verze kvůli možným
nekompatibilitám bolí, ve frameworku asi moc chyb není a pokud jim něco
nevyhovuje, stejně neví, jak to udělat lépe.
Firmy spíš mají problém najít schopné programátory, i přesto, že
Nette je mainstream. Takže by ocenili co nejlepší dokumentaci, co nevíce
příkladů atd. Což je zároveň to poslední, čím bych z nějaké
vnitřní motivace trávil svůj čas.
Napadly mě dvě možnosti:
- konkrétní části vývoje frameworku nebo dokumentace financovat
crowdfundingu
- nebo najít partnera, se kterým bychom založili školu pro Nette
programátory (což je samozřejmě mnohem ambicioznější plán).
Používáte Nette a napadá vás něco dalšího? Chcete do nějakého
projektu seriozně jít? Nebo vymýšlím blbosti?
Jaké jsou best practice pro předávání závislostí
presenterům, komponentám a jiným službám v Nette?
Nejprve: nezávisle na frameworku nebo typu tříd platí vždy tohle:
- povinné závislosti předávat konstruktorem
- volitelné buď samostatnou metodou, nebo též konstruktorem
Tečka.
Nicméně existuje případ, kdy je předávání závislostí konstruktorem
problematické, tzv. constructor hell,
tedy situace, kdy předáváme závislosti konstruktorem určité třídě a
zároveň jejímu potomkovi. Tohle nastává často u presenterů, kde je
právě zvykem mít nějaký BasePresenter. Jako workaround dává DI kontejner
v Nette možnost použít v BasePresenteru místo konstruktoru metodu nazvanou
injectBase()
(případně jakkoliv jinak, jen musí začínat na
inject
).
Jde o workaround pro base presentery, takže v jiných situacích metody
inject nepoužívejte.
Dále předávání závislostí přes konstruktory nebo jiné metody je
otravné v tom, že musíte napsat nějaký rutinní kód. Nutnost psát
rutinní kód vždy ukazuje na slabé místo samotného jazyka, jedna ze šancí na
zjednodušení byla zamítnuta, nicméně některé IDE ho umí vygenerovat
a taktéž DI kontejner ve frameworku nabízí zkratku v podobě
@inject
anotací. Public (!) proměnnou doplníte anotací např.
/** @var Model\UserFacade @inject */
a framework sám do ní
vloží službu a vyhnete se psaní konstruktoru nebo inject metody.
Protože to není čisté řešení, funguje opět jen pro presentery.
Používání anotací rozhodně není best practice, ale je to sakra
pohodlné.
Doporučuji podívat se na přednášku Filipa
Procházky a přečíst článek Vojty Dobeše Tvorba komponent
s využitím autowiringu.
Asi největší revoluce v dějinách Nette, která se vás
nijak nedotkne.
Poměrně krátce po vydání velké verze 2.1, která přinesla řadu
vylepšení nejen ve formulářích, je
tu další velká verze 2.2, která přichází s úplně novou
infrastrukturou. Totiž původní repozitář Nette byl rozdělen do
19 nových samostatných komponent: Application, Bootstrap, Caching, ComponentModel, Nette Database, DI, Finder, Forms, Http, Latte, Mail, Neon, PhpGenerator, Reflection, RobotLoader, SafeStream, Security, Tokenizer, Tracy a Utils.
(Podívejte se na video Kvadratura
Nette.)
Co se tím mění pro vás, uživatele Nette Frameworku?
Takřka nic. Stále si můžete stáhnout celý framework nebo jej
nainstalovat příkazem composer require nette/nette
.
Ale zároveň máte možnost používat zcela samostatně
šablonovací systém Latte, Laděnku (neboli Tracy), databázovou vrstvu a
vlastně cokoliv.
Rozdělení frameworku do menších částí je trend, který už započalo
například Symfony nebo Zend Framework 2. Nutnou podmínkou byl vznik
respektovaného nástroje pro správu závislostí v PHP, kterým se stal
Composer. Pokud si s ním zatím netykáte, neváhejte a seznamte se, není
daleko doba, kdy se v PHP knihovny nebudou distribuovat jinak.
Nette se na rozdíl od Symfony nebo Zendu rozdělilo i fyzicky, což
znamená, že každá komponenta má vlastní repozitář, issue tracker a
číslování verzí. Zároveň každý repozitář obsahuje testy a všechny
související soubory. Podívejte se například na Forms, kde najdete příklady použití
v examples
, v adresáři src/assets
JavaScripty a
v adresáři src/Bridges
kód, který propojuje různé Nette
komponenty. V případě formulářů jde o makra pro Latte.
Stejným způsobem jsou pak strukturovány všechny repozitáře.
Rozdělení frameworku je završením dvouleté práce, s cílem zachovat
maximální kompatibilitu. Vlastně i proto zůstáváme u čísla verze
2. Jediným výrazným zásekem bylo oddělení Latte, což si vyžádalo
přepracovat systém šablon, který v Nette existuje v takřka původní
podobně od verze 0.8. Ale postupně:
Tracy
Laděnka byla přejmenována na Tracy
, nemusíte se tak trápit
s psaním šíleného Nette\Diagnostics\Debugger
, nyní stačí
Tracy\Debugger
. Původní třída je z důvodu zpětné
kompatibility stále funkční.
Pokud píšete doplňky, prefix názvů CSS tříd se změnil z
nette-
na tracy-
a třída
nette-toggle-collapsed
na dvojici
tracy-toggle tracy-collapsed
. Původní třídy jsou u starých
doplňku změněny na nové automaticky.
Latte
Šablonovací systém byl vždy poměrně úzce provázán s dalšími
částmi frameworku, zejména třídami z jmenného prostoru Nette\Templating
.
Aby bylo Latte samostatně použitelné, bylo potřeba mu vymyslet nové snadno
použitelné API, které se obejde bez těchto pomocných tříd.
A vypadá takto:
$latte = new Latte\Engine; // nikoliv Nette\Latte\Engine
$latte->setTempDirectory('/path/to/cache');
$latte->addFilter('money', function($val) { return ...; }); // dříve registerHelper()
$latte->onCompile[] = function($latte) {
$latte->addMacro(...); // when you want add some own macros, see http://goo.gl/d5A1u2
};
$latte->render('template.latte', $parameters);
// or $html = $latte->renderToString('template.latte', $parameters);
Jak vidíte, Latte si řeší samo načítání šablon a jejich kešování,
čímž pádem původní FileTemplate
a vlastně celý
Nette\Templating
z velké míry pozbývá na smyslu existence.
Tyto třídy i nadále fungují a snaží se zajistit kompatibilitu s novým
Latte, nicméně jsou zavržené. Ze stejného důvodu jsou zavržené
i třídy Nette\Utils\LimitedScope
,
Nette\Caching\Storages\PhpFileStorage
a služba
templateCacheStorage
.
Naopak Application přináší vlastní třídu Template
(nahrazující FileTemplate a zajišťují kompatibilitu) a továrnu
TemplateFactory
, která rozšiřuje možnosti, jak v presenterech
a komponentách pracovat se šablonami.
Ostatní
Třídy Nette\ArrayHash
, ArrayList
,
DateTime
, Image
a ObjectMixin
jsou nyní
součástí balíčku Utils
, proto i jejich namespace byl změněn
z Nette
na Nette\Utils
. Obdobně
Nette\Utils\Neon
se stalo součástí balíčku Neon
a
bude mít namespace Nette\Neon\Neon
. Aby změna byla
transparentní, vytváří se pro tyto a některé další třídy tiše aliasy.
Aliasy ostatních tříd vytváří Nette Loader spuštěný v
loader.php
a vypisuje přitom varování (abyste mohli svůj kód
upravit). Pokud loader.php
nepoužíváte (tj. instalujete
Nette přes Composer), můžete Nette Loader načíst ručně třeba v
bootstrap.php
. Od RC4 se Nette Loader spouští vždy.
Alternativně je možné vytvořit v bootstrap.php
rovnou
všechny aliasy a obejít tak varování. Ale jelikož PHP při vytváření
aliasů načítá zdrojový kód tříd, může to vést k mírnému snížení
výkonu:
@array_walk(Nette\Loaders\NetteLoader::getInstance()->renamed, 'class_alias');
Zavržena (tj. stále funguje, jen vyhodí E_USER_DEPRECATED) je třída
Nette\Utils\MimeTypeDetector
, která od PHP 5.3 není potřeba,
neboť ji plně nahrazuje rozšíření Fileinfo (pod Windows jej
nezapomeňte zapnout v php.ini).
Byla zrušena podpora anotace @serializationVersion
a
dohledávání tříd pro vlastní anotace – tyto věci nebyly známé ani
používané, ale měly negativní vliv na výkon.
A nakonec, chybné odkazy v šabloně nyní začínají hashem, tj. místo
error:...
se vypisuje #error:
, aby když na takový
odkaz omylem kliknete, browser nevypsal strašidelnou hlášku. Upravte si proto
CSS.
Novinky
Verze 2.2.0 přichází i s řadou novinek.
Formuláře nyní přenášejí parametr do
v POST datech,
takže nebude strašit v URL. Přibyly nové validátory Form::MIN
a Form::MAX
. A do funkcí obsluhující událost
onSuccess
se nyní jako druhý parametr předávají hodnoty
formuláře, takže ušetříte psaní
$values = $form->getValues()
.
V databázi přibyla nová funkce fetchAssoc(). Můžete se podívat na pár
příkladů
použití v testech.
Anotace @inject
nyní respektují aliasy definované pomocí
use
.
Pokud do data-
atributů třídy Html vložíte pole, bude se
serializovat do JSONu.
V souboru config.neon
můžete jednotlivým uživatelů
definovat také jejich role.
A přibyla nová třída Nette\Security\Passwords
,
která řeší hashování hesel.
Tip: nástroj
na automatické přejmenování tříd.
„Přesvědč mě, proč bych měl používat Nette Tester, v čem je lepší než
PHPUnit?“ Tyhle otázky mě vždycky trošku uvádějí do rozpaků, neboť
nemám potřebu nikoho přesvědčovat, aby Tester používal. Sám bych se bez
něj ale neobešel.
Samotné testování je poněkud zakletá věc. Pět let se na všech
konferencích stále dokola mluví o testování a přitom skoro v žádné
firmě se kód „netestuje“. Píšu to v uvozovkách, protože ve
skutečnosti všichni programátoři dnes a denně testují, co ale nedělají
je, že nepíšou testy v PHPUnit, z mnoha důvodů. Pravda je, že sám jsem
v oné krátké době, kdy byl Nette Framework testován PHPUnitem, také
ztratil chuť testovat. Přičemž testování je pro vývoj frameworku natolik
zásadní prvek, jako třeba verzovací systém.
Ale popořadě. Proč všichni programátoři testují, i když
„netestují“?
Představte si, že naprogramujete funkci foobar()
function foobar($x, $y) {
// tady se počítají nějaké věci
return $val;
}
První věc, kterou každý programátor udělá, je, že vyzkouší, jestli
to funguje:
echo foobar(10, 20);
Spustí to, vypíše to 30, což je správně, vypadá to, že to funguje a
třeba ještě vyzkouší pár jiných vstupů.
Jinými slovy funkci otestuje. Tedy testuje!
Potom následně udělá to, že testovací skript smaže. A to je
právě průšvih! Všechny ty argumenty vývojářů, že na testování
nemají čas, v tento moment padají, protože realita je taková, že na
testování čas je, dokonce jsou napsané i testy, jenže pak je
programátoři smažou. Ironie.
Testem není pouze třída v PHPUnit, testem je i tento jednořádkový
skript. Přesněji řečeno, test musí obsahovat ještě informaci, jaká je
správná návratová hodnota, takže by vypadal takto:
assert( foobar(10, 20) === 30 );
assert( foobar(-1, 5) === 4 );
...
Až někdy v budoucnu upravím implementaci funkce foobar
, nebo
do ní sáhne kolega, stačí tento skript spustit, a pokud vyhodí warning,
hned vím, že je funkce rozbitá.
A to je vše. Tohle je testování. Tak je to jednoduché. Děláme to
všichni, bohužel hodně z vás si ty testy pak maže.
Časem se nám nahromadí obrovská spousta takovýchto testovacích
skriptíků a vznikne otázka, jak je spouštět hromadně. Dá se to řešit
nějakým shell skriptem, já jsem si na to napsal PHP skript. Jeho podstatnou
výhodou je, že umí testy pouštět paralelně (běžně spouštím
40 vláken), což otestování celé sady dramaticky zrychlí. A taky
přehledně vypisuje, ve kterém souboru kde přesně došlo k selhání.
Také místo PHP funkce assert
jsem si napsal vlastní funkce (třída Assert
),
které se liší především v tom, že při selhání hezky a čitelně
vypíšou, co funkce měla vrátit a co místo toho vrátila, abych rychle
věděl, kde je problém.
A ten spouštěč, třída Assert
a ještě dalších pár
věcí tvoří zmíněný Nette Tester. Čtyři roky spolehlivě testuje Nette
Framework.
Když mi někdo nahlásí, že ve funkci foobar
je chyba, že
pro vstupy 0
a -1
vrací prázdný řetězec místo
čísla -1
, tak začnu tím, že to nejprve ověřím:
Assert::same( -1, foobar(0, -1) );
Spustím to a skutečně, vypíše se:
Failed: '' should be -1
Tedy jsem napsal failující test. Neudělal jsem to proto, že
v příručkách o testování se píše, že test musí nejdřív failovat,
nebo proto, že bych se řídil TDD, dělám to proto, že mě nenapadá, co
jiného by se dalo dělat, než prostě napsat krátký kód, který bugreport
ověří, tedy failující test.
Chyba tam vážně je a je třeba ji opravit. V IDE začnu kód krokovat a
hledám místo, kde je zakopaný pes. (O programátorech, kteří píší kód
v poznámkovém bloku, ať už se jmenuje TextMate nebo Sublime, namísto
plnohodnotného IDE, a nemohou proto kód krokovat, napíšu článek někdy
příště.) Ano, kde je chyba bych asi zjistil i bez krokování, zíráním
do kódu a umisťováním var_dump
, echo
nebo
console.log
, ale trvalo by to mnohem déle. Chci zdůraznit, že
krokování a testování nejsou alternativy, ale zcela odlišné činnosti,
které je fajn používat dohromady.
Odhalím a opravím chybu, Assert::same
je spokojený a do
repozitáře komitnu nejen opravu funkce foobar
, ale také onen
soubor s testem. Díky tomu se tahle chyba už nikdy v budoucnu nevyskytne.
A věřte mi, že chyby mají tendenci se opakovat, dokonce pro tento jev
existuje název: regrese.
Tohle povídání vám asi muselo připadat strašně samozřejmé. A to je
dobře, ono je samozřejmé a já chci bourat předsudky a obavy z testování.
Ale stále jsem neodpověděl na úvodní otázku: proč nepoužívám PHPUnit?
Protože s ním takto přímočaře pracovat neumím.
Abych mohl otestovat foobar
, musel bych napsat celou třídu,
která dědí od jiné třídy, jejíž jméno si nejsem schopen zapamatovat. No
budiž, použiji šablonu. PHPUnit neumí testy spouštět paralelně, takže
otestování celé sady trvá násobně déle. V případě Nette Frameworku
jde o 35 sekund versus 2 minuty, což už saje. Ale především, testy
psané v PHPUnitu lze spouštět jen v PHPUnitu, nejde o samostatně
spustitelné skripty. Takže není způsob, jak napsat failující test a potom
ho úplně snadno krokovat a hledat výše uvedeným způsobem chybu.
Nejjednodušší řešení proto bylo napsat si vlastní triviální
testovací udělátko. Za ty čtyři roky velmi pozvolna vyspěl
v plnohodnotný nástroj, už ho nevyvíjím sám a díky klukům z Oracle má
dnes integrovanou podporu v NetBeans 8.0.
Jelikož generuje výstup ve formátu TAP, neměl by být problém ani
s integrací do jiných nástrojů.
Nebudu vás přesvědčovat, abyste používali Nette Tester, ale rád bych
vás přesvědčil, abyste si testy, které píšete, nemazali 🙂
Otázky a stručné odpovědi pro všechny, kteří by rádi
přispěli do Nette Frameworku, ale netuší jak.
Rád
bych přispěl do Nette, ale nejsem moc dobrý programátor…
Kód je jen jedna ze šíleně mnoha částí, co tvoří framework. Do Nette
mohou přispívat lidé tím, že pomáhají vylepšit dokumentaci, píší
články, knihy, korigují naše pokusy o angličtinu, přednáší, točí
tutoriály, trpělivě odpovídají na fóru, dělí se o své nápady,
programují doplňky, testují nové verze, tvoří pro Nette nástroje,
pomáhají s Poslední sobotou, hledají prostory, natáčejí přednášky,
stříhají je, organizují a navštěvují hackathony a nebo prostě podporují
framework finančně. Určitě existuje ještě dalších 101 věcí, které
mě teď nenapadly.
Přispívání do kódu je vlastně jen jedna specifická záležitost,
o kterou mi dříve ani tolik nešlo a rozhodně bych nerad vyvolal pocit, že
každý by měl přispět řádkem 😉 Podstatné je, že něco dělat chceš,
čehož si vážím a dodávám: možností jsou mraky.
Existuje
teda nějaký seznam úkolů, které je třeba udělat?
Žádný bodový seznam v tuto chvíli nemám, byť časem třeba něco
vznikne. O seznam totiž nejde, inspiraci máš kolem sebe. Třeba když
vyřešíš nějaký zajímavý úkol v Nette, máš příležitost o tom
blognout (jako to třeba dělá Filip a jiní). Určitě tě
mnohokrát napadlo, co by se v Nette mohlo vyřešit líp, netvrď mi, že ne,
a to je příležitost napsat RFC
(česky: „zlepšovací návrh“).
Ono stačí ve věcech místo problémů vidět příležitosti. Stěžovat
si, že Nette nemá zdaleka tolik tutoriálů, co třeba Laravel či Rails
versus uvědomit si příležitost a napsat třeba seriál a udělat
si tím jméno. Stěžovat si, že v issue trackeru visí
bugy versus uvědomit si, že můžu některé vyřešit. Vidět, že
mnoho lidí bylo frustrovaných
z quickstartu versus uvědomit si možnost s tím
něco udělat. A tak dále.
Spíš mám za to, že nevědět, co se žádá,
znamená mít klapky na očích.
Dobře,
ale pokud chci přímo programovat, musím znát road map
Nejnepraktičtější frameworky jsou ty, které navrhneš tzv. „od
stolu“. Nejlepší nápady totiž přicházejí z praxe, když se snažíš
něco zjednodušit. Nebo čistě náhodou. Tyhle myšlenky pak tvoří
road map.
Sepsal jsem seznam
svých idejí, které jsem plánoval do Nette přidat. Mohou tě zaujmout a
můžeš se pokusit je realizovat, mohou tě inspirovat k novým nápadům, ale
také si jich vůbec nemusíš všímat a můžeš přijít
s čímkoliv novým.
Prostě to normálně zkus.
A co když
něco naprogramuji a pak to nebude přijato?
To se pochopitelně stát může. Sám jsem naprogramoval stovky věcí,
které jsem nakonec do frameworku nedal. Proto je vhodné s nápadem přijít
v raném stádium na fórum a sepsat
RFC. Odargumentovat nebo si zkusit věc nahrubo naprogramovat často
pomůže utřídit myšlenky. Na fóru proběhne diskuse, někdy nelehká, jindy
se záměr takřka okamžitě schválí.
A domluvili jsme se s kolegy, že budeme RFC věnovat velkou pozornost, aby
nevyšuměly.
Někdy není ideální, aby se nápad stal přímo součástí frameworku,
ale může z něj být výborný doplněk.
A to musím kvůli všemu psát
RFC?
Pochopitelně ne, u jednodušších věcí stačí poslat Pull request (návod).
Přičemž kód a commit message musí respektovat coding standards, součástí
má být test a nejlépe i zápis do dokumentace.
…což
je dost práce. Existuje nějaký nástroj na ověření coding standards?
Poprvé to asi není úplně snadné, ale chceme přece všichni používat
framework, který má vysoké nároky na kvalitu, ne? Zvládnout základy Gitu a
Githubu se ti milionkrát vrátí. (Btw, dejte prosím Nette hvězdičku!)
Nástroj na ověření coding style zatím nemáme. Osobně mi nechybí:
když přispívám do jiných projektů, kód formátuji stejně, jako vypadá
ten okolní, v logu se podívám, jak hlavní vývojáři zapisují commit
message a je to řádově snazší, než studovat coding standards či
instalovat nějaký nástroj. Ale beru, že by se mohl hodit – opět je to
příležitost takovou věc udělat.
Jakým způsobem lze psát
do dokumentace?
Celá dokumentace je na
Githubu, takže se do ní dá přispívat stejně, jako do kódu, tedy
poslat pull request. Repozitář je rozdělen do větví, dokumentace pro Nette
2.0 je ve větvi doc-2.0
, pro verzi 2.1 v doc-2.1
.
Každou změnu je záhodno udělat v českém i anglickém jazyce. Pro náhled
použijte editor.
Pokud bys chtěl (v angličtině) představit nějaký doplněk nebo
publikovat návod, je ti k dispozici i nový Nette Blog.
Proč
anglicky? Není trapné mluvit anglicky, když jsme tu samí Češi?
Já vím, ale věc se má tak, že skoro nikdo na světě neumí
česky 😉
Na rovinu, angličtina je pravděpodobně mnohem větší problém pro mě,
než pro tebe, protože jde o můj pátý jazyk, který se, když jsem byl na
základce, ani nevyučoval. Ale bojuji s tím! Psát anglicky má pár výhod:
lidi se v diskusích nemají tendenci moc rozkecávat, při psaní se
zdokonaluješ ve znalosti nejdůležitějšího jazyka a tvůj článek si
může přečíst tisíckrát více lidí.
Kde se dozvím, co se chystá a
tak?
Primárním místem je již zmiňovaný Nette Blog + Discussion on
development a RFC na fóru.
Můžeš sledovat také twitterový účet @NetteFramework či #nettefw
a samozřejmě číst tento blog.
Jinak každý měsíc pořádáme Poslední
soboty a komornější #NetteFwPivo, kde se pije převážně
kubánský rum.
A nemělo by zapadnout, že máme i Youtube kanál
s hromadou videí.
A kdo je to „my“?
Skupina samozvaných lidí, kteří prostě chtěli být u toho a chtějí
něco dělat. Přidej se!
Btw, pokud jsi napsal nějaký článek, seriál, natočil video apod, bylo
by fajn to dát na Planette. Stačí, když
mi pošleš odkaz do komentářů, s pár průvodními slovy.
Je nejvyšší čas rozseknout FUD a nejasnosti kolem
databázových vrstev.
Databázovou vrstvu dibi jsem
začal psát cca před devíti lety se záměrem shrnutým v tomto historickém článku. Šlo mi
především o to sjednotit API různorodých klientů, ošetřovat chybové
stavy, přidat uživatelsky pohodlné bindování parametrů a také dynamické
generování základních konstrukcí SQL, jako jsou například podmínky,
řazení a INSERT & UPDATE:
$db = new DibiConnection(...); // or via monostate dibi::connect(...)
$pairs = $db->fetchPairs('SELECT id, name FROM countries');
$arr = array(
'name' => 'John',
'modified%d' => time(),
);
$db->query('UPDATE users SET ', $arr, ' WHERE `id`=%i', $id);
// UPDATE users SET `name`='John', `modified`= '2005-10-12' WHERE `id` = 123
Časem se v PHP objevila nativní knihovna PDO, která v podstatě řešila polovinu
věcí, co dibi, nicméně její API pro bindování parametrů bylo
těžkopádné, neporadilo si s datumy a skládání základních konstrukcí
SQL chybělo úplně. Takže dibi nenahradilo.
V dibi jsem si hrál i s experimenty, jako DibiTable, DibiFluent nebo
DibiDataSource, ale sám jsem je nikdy nepoužíval. Jsou tam pochopitelně
i věci, které bych dnes udělal lépe, ale z hlediska zpětné kompatibility
je takřka nemožné do nich zasahovat. Třeba mám zmatek v tom, co který
modifikátor znamená – je jich příliš mnoho. (Moc se to neví, ale
místo přemýšlení, který modifikátor použít, můžete obvykle použít
otazník.)
Protože téměř v každém demu pro Nette bylo potřeba pracovat
s databází, vyžadovalo to nainstalovat dibi nebo Doctrine (jiné vrstvy se
v podstatě nepoužívají). Dnes je to díky Composeru otázka
pár úderů do klávesnice, ale tehdy neexistoval. Přemýšlel jsem proto, že
bych si v příkladech vystačil jen s čistým PDO. Jenže pokud jste
rozmlsaní z dibi, není návratu zpět. Chybí vám nejen přívětivé API,
ale i pohodlí Tracy (tj. Laděnky) pro
monitorování dotazů či chyb.
Tehdy mě napadlo, že by nebylo od věci udělat „dibi model 2010“,
nově, bez historických zátěží, založené čistě nad PDO. Vyhodit hromadu
driverů, všechny modifikátory nahradit jedním otazníkem a implementovat jen
vlastnosti, které budou skutečně potřeba.
Nette Database
Takhle vzniklo Nette Database
(NDB). Moderní ekvivalent dibi:
$db = new Nette\Database\Connection(...);
$pairs = $db->fetchPairs('SELECT id, name FROM countries');
$arr = array(
'name' => 'John',
'modified' => new DateTime,
);
$db->query('UPDATE users SET ', $arr, ' WHERE `id`= ?', $id);
Brzy jsem narazil na hromadu nedostatků PDO, nareportoval a obešel mraky
chyb a když bylo Nette Database odladěné, vyšlo v únoru 2012 jako
součást finálního Nette Framework 2.0.
Tady musím zdůraznit, že navzdory šiřitelům FUD v Nette Database
skutečně takřka žádné chyby nebyly a jediným větším problém se
ukázal bug v PDO způsobující memory
leaky, kvůli němuž musely být třídy NDB přepsány a v Nette
2.1 již Connection není potomkem PDO (dědit od PDO byla z dnešního
pohledu stejně blbost.)
Dnes nevidím důvod, proč pro nový projekt použít staré dibi namísto
NDB. Chybí asi jen:
- bohatší možnosti skládání v klauzuli WHERE (zatím se nezdá, že by
byla potřeba)
- statická obálka
dibi::
(tu v Nette nahrazuje DI
Container)
- samostatnost (vyřeší Nette 2.2)
- fetchAssoc (tu v Nette nahrazuje NDBT,
eventuálně by ji šlo
doplnit je v 2.2-dev)
A tím se dostáváme k Nette Database Table
(NDBT), prapříčině mnoha zmatků.
Nette Database Table (nyní
Explorer)
V prosinci 2010 jsem do tehdy beta verze Nette 2.0 začlenil knihovnu
Jakuba Vrány NotORM, ve kterém jsem viděl
úžasný nástroj pro dolování dat z databáze:
$pairs = $db->table('countries')->fetchPairs('id', 'name');
// SELECT `id`, `name` FROM `countries`
$name = $db->table('book')->get($id)->author->name;
// SELECT `id`, `author_id` FROM `book` WHERE `id` = 123
// SELECT `id`, `name` FROM `author` WHERE (`author`.`id` IN (456))
$arr = array(
'name' => 'John',
'modified' => new DateTime,
);
$db->table('users')->where('id', $id)->update($arr);
// UPDATE users SET `name`='John', `modified`= '2005-10-12' WHERE `id` = 123
Kód i API jsem upravil tak, aby zapadlo do koncepce Nette, v podstatě
z myšlenky využít NotORM v Latte pochází i nápad na tzv. předbíhání
budoucnosti, neboli načítání jen těch sloupců, které budou později
potřeba, taktéž s Latte může skvěle fungovat koncept NotORM 2.
A právě NotORM v NDB nese označení NDBT (nyní Nette Database
Explorer). Přičemž její použití je volitelné.
Zapojení do Nette vyvolalo o NDBT resp. NotORM velký zájem a ukázalo se,
že byť byla knihovna pro potřeby Jakuba odladěná, pro různorodější
požadavky bylo třeba odvést ještě hodně práce. Té se od poloviny roku
2011 ujal Hrach a z velké části původní NDBT přepsal a pečlivě doplnil
testy. Knihovna procházela mnohem rychlejším vývojovým cyklem než zbytek
frameworku, nicméně nebýt jeho součástí, nevyvíjí se asi vůbec.
Nette tedy má
- NDB (nyní Nette Database Core), obdobu dibi, stabilní od verze 2.0.0
- NDBT (nyní Database Explorer), obdobu NotORM, vhodnou pro produkční
nasazení až od verze 2.1
Dibi nadále udržuji, koneckonců běží mi na něm většina webů, ale
žádné novinky nechystám. V podstatě ani do NDB ne. Naopak s NDBT, jenž
pohání mimo jiné i tento blog, má Hrach ambiciózní plány.
Aktualizace 2017: Původní Nette Database Table (NDBT) nese nový název
Nette Database Explorer a samotné jádro je Nette Database Core
Jaké novinky přináší Nette
Framework 2.1 ve formulářích? Začnu perličkou: formuláře byly
představeny před sedmi lety, jaksi mimochodem, v komentářích
pod jiným článkem, a jejich kód včetně dema se vešel do 800 řádků. Už tehdy šlo
o stěžejní část frameworku, která uměla třeba vedle serverové validace
generovat i tu JavaScriptovou.
Původní návrh založený na explicitním vyjmenovávání prvků se
ukázal jako správný, zejména když propukla kauza se zranitelností Mass
Assignment, kterou trpěly weby psané v Rails a jimi inspirovaných
frameworcích. Na druhou stranu, tvorbu některých dynamických formulářů to
činilo těžkopádnou. Dlouho jsem hledal kompromis a pak to
přišlo:
Nyní lze používat i prvky, které zapíšeme pouze v šabloně a
nepřidáme je do formuláře některou z metod
$form->addXyz()
. Když například vypisujeme záznamy
z databáze a dopředu nevíme, kolik jich bude a jaké budou mít ID, a chceme
u každého řádku zobrazit checkbox nebo radio button, stačí jej nakódovat
v šabloně:
{foreach $items as $item}
<p><input type=checkbox name="sel[]" value={$item->id}> {$item->name}</p>
{/foreach}
A po odeslání hodnotu zjistíme:
$values = $form->getHttpData($form::DATA_TEXT, 'sel[]');
kde první parametr je typ elementu (DATA_FILE
pro
type=file
, DATA_LINE
pro jednořádkové vstupy jako
text
, password
, email
apod. a
DATA_TEXT
pro všechny ostatní) a druhý parametr
sel[]
odpovídá HTML atributu name
.
Podstatné je, že getHttpData()
vrací sanitizovanou
hodnotu, v tomto případě to bude vždy pole validních
UTF-8 řetězců, ať už se pokusíte serveru podstrčit cokoliv. Jde
o obdobu přímé práce s $_POST
nebo $_GET
avšak
s tím podstatným rozdílem, že vždy vrací čistá data, tak, jak jste
zvyklí u standardních prvků Nette formulářů.
CheckboxList
Nový prvek pro výběr z více možností je CheckboxList. Stejně jako
v případě selectboxů nebo radiolistů kontroluje, zda odeslané hodnoty
jsou z těch, které nabízíme:
$form = new Form;
$form->addCheckboxList('colors', 'Favorite colors:', array(
'r' => 'red',
'g' => 'green',
'b' => 'blue',
));
Multiple file upload
Najednou lze uploadovat i více souborů, všimněte si
true
:
$form = new Form;
$form->addUpload('avatar', 'Picture:', true);
Zároveň formuláře mají integrovanou kontrolu, zda nebyl překročen
povolený limit velikosti odesílaných dat.
Nové vykreslovací zbraně
Velmi snadno můžete propojit formulář s existující šablonou. Stačí
jen doplnit atributy n:name
:
function createComponentSignInForm()
{
$form = new Form;
$form->addText('user')->setRequired();
$form->addPassword('password')->setRequired();
$form->addSubmit('send');
return $form;
}
<form n:name=signInForm class=form>
<p><label n:name=user>Username: <input n:name=user size=20></label>
<p><label n:name=password>Password: <input n:name=password></label>
<p><input n:name=send class="btn btn-default">
</form>
Atribut n:name
lze používat i s elementy
<select>
, <button>
nebo
<textarea>
.
Dále můžete vykreslovat prvky jako je RadioList, Checkbox nebo nový
CheckList pěkně po jednotlivých HTML elementech. Říká se tomu partial
rendering:
{foreach $form[gender]->items as $key => $label}
<label n:name="gender:$key"><input n:name="gender:$key"> {$label}</label>
{/foreach}
Nebo lze použít klasická makra {input gender:$key}
a
{label gender:$key}
, trik je tom názvu s dvojtečkou.
S tím úzce souvisí i aktualizovaný způsob vykreslování checkboxů a
RadioListů. Místo dřívějšího
<label>...</label><input>
se nyní vykreslují v praktičtějším tvaru
<label><input>...</label>
pročež si myslím, že odpadne většina důvodů, proč jste tyto prvky
potřebovali vykreslovat po částech.
Zároveň také odpadá nutnost kreslit
checkboxy trošku jinak než jiné prvky, tj. myslet na to, aby label byl na
správném místě. Metoda getLabel()
či makro
{label}
totiž u checkboxů nyní nevrací nic a
getControl()
či {input}
vrací HTML v onom novém
tvaru. Pokud ale potřebujete staré chování, přepněte se do zmíněného
partial renderingu přidáním dvojtečky: {label checkbox:}
a
{input checkbox:}
.
Podpora pro Bootstrap
V příkladech najdete ukázky, jak nakonfigurovat vykreslování
formulářů pro Twitter
Bootstrap 2 a Bootstrap
3.
Chytřejší validátory
Validační pravidla Form::INTEGER
, NUMERIC
a
FLOAT
rovnou převádí hodnotu na integer resp. float. A dále
pravidlo Form::URL
, které akceptuje i řetězec ve tvaru např.
nette.org
, jej automaticky doplní na plnohodnotné
https://nette.org
.
Přibyla nová validační pravidla Form::BLANK
(prvek nesmí
být vyplněn) a Form::NOT_EQUAL
.
A v argumentech všech validátorů se můžete dynamicky odkazovat na
jiné prvky. Takže třeba tady prvek value
musí být v rozmezí
určeným aktuálními hodnotami prvků min
a max
:
$form->addText('min');
$form->addText('max');
$form->addText('value')
->addRule($form::RANGE, 'from %d to %d', array($form['min'], $form['max']));
Chybové zprávy
Makro {control form}
nyní vypisuje chybové zprávy přímo
vedle souvisejících prvků a nad formulářem se objeví jen ty, které
žádnému prvku nepřiřadíme (tj. když místo
$form['name']->addError()
použijeme
$form->addError()
). Je to mnohem uživatelsky příjemnější a
doporučuji, abyste stejným způsobem vykreslovali i formuláře manuálně,
třeba
takto. Pomůže vám metoda $form->getOwnErrors()
, která
vrací chybové zprávy přiřazené jen k formuláři.
Píšeme vlastní prvky
Výrazného zjednodušení doznala tvorba vlastních formulářových prvků.
Podívejte se na příklad
DateInput, což je prvek pro zadávání data. Zobrazovat se bude jako
trojice políček den, měsíc, rok a z pohledu API bude přijímat a vracet
objekt DateTime
.
Interně se datum reprezentuje jako trojice privátních proměnných
$day, $month, $year
, které metoda getValue()
převede
na požadovaný objekt DateTime
(tedy pokud půjde o platné
datum) a setValue()
naopak vstup do této trojice rozloží.
Přičemž by měla kontrolovat validitu vstupu a v případě chyby vyhodit
výjimku.
Výjimky naopak nevyhazuje loadHttpData()
, která se volá po
odeslání formuláře, a hodnoty, které uživatel odeslal, získá metodou
getHttpData()
a uloží do zmíněné trojice proměnných. Jen
pozor, tentokrát mluvím o metodě třídy BaseControl
, nikoliv
Form
. Každopádně i v tomto případě
getHttpData()
vrací očištěná data.
A nakonec metoda getControl()
generuje HTML. Pokud je prvek
reprezentován jedním HTML elementem, jeho atribut name
určí
metoda getHtmlName()
. Jenže máme prvky tři, tak za název
ještě dolepíme řetězec [day]
, [month]
a
[year]
(včetně těch hranatých závorek). Stejný postfix pak
uvádíme při volání getHttpData()
ve zmíněné
loadHttpData()
.
Co když místo obyčejného textového pole budeme chtít vykreslit
selectbox? Pak oceníte funkci
Nette\Forms\Helpers::createSelectBox()
. Prvním parametrem je pole
nabízených hodnot, druhým pole HTML atributů elementu
<option>
. V příkladu uvedené selected?
s otazníkem znamená, že atribut se uvede pouze u položky s uvedenou
hodnotou. Šlo by také uvést např.
'title:' => array(1 => 'January', 2 => ...)
s dvojtečkou, což dává možnost každé položce dát jiný
title
.
Existuje také obdobná funkce createInputList()
pro
generování skupin inputů. Té lze jako třetí parametr předat pole HTML
atributů pro element label
, taktéž podporující otazník a
dvojtečku.
Dále autoři nových prvků mohou ocenit dvě nové abstraktní třídy ChoiceControl
a MultiChoiceControl
.
A co ještě?
Pomocí $control->setOmitted()
vyjmete prvek z dat, která
vrací $form->getValues()
. To se hodí pro různé hesla pro
kontrolu, antispamové prvky atd. I všechny prvky, které označíte jako
$form->setDisabled()
, budou takto vyjmuty.
Vylepšeno bylo togglování, nyní by mělo fungovat přesně podle
očekávání. Navíc $form->getToggles()
vrátí informaci
o viditelnosti všech id.
Metoda setValue()
u jednotlivých prvků kontroluje datový typ
a dále v případě SelectBoxů a podobně vás nenechá nastavit hodnotu,
která v nabízených není.
V HTML atributech data-nette-rules
se používá čistý JSON,
takže nezapomeňte nasadit aktuální netteForms.js
.
A nakonec – u jednotlivých tlačítek můžete omezit seznam prvků,
které se mají při odeslání formuláře tímto tlačítkem validovat:
$form->addSubmit('edit')
->setValidationScope(array($form['name'], $form['password']));
Z něčeho, co má člověka bavit, se stala otročina.
(Hele, ono by to tak mohlo vypadat, ale tohle není naříkání, jen
konstatování léta známých faktů:)
Nette Framework je i po deseti letech projekt, který vymýšlím sám,
programuji sám, píšu mu sám dokumentaci, píšu všechny články, co kdy
o něm vyšly, sám spravuji a platím web. (Přeháním, vývoj DB vrstvy
převzal Honza Škrášek, pár lidí se podílelo na překladu dokumentace a
tvorbě quick startu a hodně jich dělá podporu na fóru.)
Zpětná vazba je především žádná (ze žádné z firem
používajících Nette nevím o ničem, co vylepšit) nebo negativní (občas
z těch firem prosákne, že je všechno špatně.)
Investuji do toho neuvěřitelné množství času. A pochopitelně to
negeneruje žádný příjem, jde o open source. Nestěžuji si, je skvělé
mít takový koníček.
Vím, že Nette je projekt kvalitativně srovnatelný se světovou
špičkou.
Dnes jsem vydal Nette Framework 2.0.14, který uzavírá starou větev, a
úplně novou verzi 2.1.0, se kterou jsem velmi spokojen. A mám spoustu
nápadů na nové věci.
Jenže jsem z toho začal mít regulérní deprese. Analyzuji důvody. Asi
neustálá nutnost čelit negativitě, nutnost brát ohledy na uživatele,
kteří pro framework nehnou ani prstem, to všechno mě vnitřně ničilo a
dostalo do velmi divného rozpoložení, ze kterého bych rád unikl. No a
jelikož jsem dnes vydal ty nové verze, které uzavírají dlouho etapu,
napadlo mě vydat se taky dál 🙂
Před chvílí vyšel Nette
Framework 2.1. Ačkoliv číselně jde o desetinkový posun, novinek je
hromada. K těm se překvapivě dostanu až v příštích článcích,
nyní mi půjde o kompatibilitu.
Na tu vždycky Nette Framework velmi dbal:
- nikdy mezi verzemi nebyla tlustá čára, vývoj je evoluční
- ačkoliv je psán v PHP 5.3, generovala se i verze pro PHP 5.2
- s přechodem na jmenné prostory dostali vývojáři nástroj, jenž jim
všechny třídy ve zdrojových kódech přejmenoval
Přechod na verzi 2.1 by měl být snadný. Teď si říkáte: „kilometr
dlouhý článek a snadný přechod?“ Inu, snaží se být vyčerpávající.
Mám weby, na kterých nebylo potřeba měnit nic.
Byť se pár věcí přejmenovalo, v případě tříd existují aliasy a
fungují i staré názvy metod, jen se vypíše či zaloguje upozornění.
Nicméně kvůli technikáliím doporučuji stejně těch pár tříd
přejmenovat, máte k tomu i nástroj na automatické
přejmenování tříd.
Zamáčkněte slzu, Nette Framework 2.1 opouští PHP 5.2, verzi, kterou už
3 roky nepodporuje ani samotné PHP.
Minimální požadovaná verze je tak 5.3.1 a Nette by mělo jet prakticky na
každém pětrojkovém hostingu (je testováno i na nejnovější 5.5.7).
Minimalizovaná verze se nyní generuje ve formátu PHAR, takže
v distribuci místo nette.min.php
najdete soubor
nette.phar
, se kterým se však pracuje úplně stejně.
Nette Database (NDB)
NDB společně s Dependency Injection byly čerstvé části frameworku a
bylo zřejmé, že nejvíce změn bude právě tady.
Nette\Database\Connection
již není potomkem PDO
- přejmenujte metody
exec()
→ query()
,
fetchColumn()
→ fetchField()
a
lastInsertId()
→ getInsertId()
Nette\Database\Statement
je nyní
Nette\Database\ResultSet
a též už není potomkem PDOStatement
- přejmenujte metody
rowCount()
→ getRowCount()
a
columnCount()
→ getColumnCount()
Používáte Nette Database Table (NDBT), tedy skvělou část NDB, ke které
se přistupuje přes $database->table(...)
?
- metoda
table()
byl přesunuta z Connection
do
nové třídy Nette\Database\Context
. Ta obsahuje
obsahuje všechny důležité metody pro práci s databází, takže klidně
změňte Connection
za Context
a máte hotovo.
- proměnné řádku
ActiveRow
jsou nyní read-only, pro změnu
slouží metoda $row->update(array('field' => 'value'))
.
Věřte, že dřívější chování mělo tolik úskalí, že jiná cesta
nebyla.
- změnila se tzv. backjoin syntaxe z
book_tag:tag.name
na
:book_tag.tag.name
(dvojtečka na začátku)
- místo druhého parametru
$having
v metodě
group()
použijte metodu having()
(Pokud jste používali SelectionFactory
v dev-verzi, změňte
ji také na Context
.)
Dependency Injection (DI)
- třída
Nette\Config\Configurator
→
Nette\Configurator
(původní název zněl, jako když se člověk
zakoktá)
- v konfiguračním souboru se sloučily definice
factories
a
services
do společného services
. Jen těm, co byly
původně factories, přidejte klíč autowired: no
.
- a zavedl se „odrážkový“ zápis anonymních služeb:
services:
Jmeno\Tridy: self # dříve, ukázalo se jako matoucí
- Jmeno\Tridy # nyní
Pracovat přímo s DI kontejnerem není obvykle dobrý nápad, ale pokud už
tak činíte:
- tovární metody volejte jako
$container->createService('nazevsluzby')
namísto $container->createNazevSluzby()
- zavrženy jsou všechny výchozí továrničky jako
createLatte()
, createCache()
,
createMail()
a createBasicForm()
- a ke službám přistupujte raději přes
$container->getService()
či getByType()
namísto $container->nazevSluzby
Pokud píšete vlastní rozšíření, vězte, že došlo k přejmenování
jmenných prostorů Nette\Config
→ Nette\DI
a
Nette\Utils\PhpGenerator
→ Nette\PhpGenerator
.
Oproti dev-verzi jsou anotace @inject
a metody
inject()
automaticky zpracovány jen na presenterech. Na jiných
službách je zapnete uvedením klíče inject: yes
v definici.
Používáte-li ještě stařičký Environment
, bude po vás
vyžadovat nastavenou konstantu TEMP_DIR
, kvůli výkonu.
Ufff, máme za sebou tu náročnou část. Teď už to bude brnkačka.
UI\Presenter a Control
- Presenter nyní zabraňuje, aby vám někdo podstrčil do persistentního
parametru pole. Pokud ale pole chcete, uveďte ho jako výchozí hodnotu,
- zavržené jsou metody
getService()
(použijte
getContext()->getService()
), dále getHttpContext()
a getApplication()
- magické
getParameter(null)
→
getParameters()
- místo divného
invalidateControl()
lze používat
redrawControl()
Tak to je easy, ne? Pojďme si dát Latte.
Latte
- výchozím režimem je HTML (namísto XHTML), což lze přepnout v konfiguraci
- automaticky ouvozovkuje
atributy v
<a title={$title}>
, což by nemělo způsobit
žádnou komplikaci, ale raději to zmiňuji
- atribut
n:input
se mění na n:name
, aby šel
použít nejen na <input>
, ale i label, select, form a
textarea
- zavržená jsou makra
{attr}
(nahrazuje n:attr
) a
{assign}
→ {var}
- doporučujeme místo vykřičníkového zápisu
{!$var}
přejít na {$var|noescape}
, je to zřejmější
- pokud jste v dev-verzi používali zkrácený zápis bloků
{#block}
, tak do 2.1 se nedostal, nebyl srozumitelný
V Latte je novinka, která v <a href={$url}>
automaticky
kontroluje, zda proměnná $url
neobsahuje něco jako
javascript:hackniWeb()
. Povolené jsou pouze protokoly http, https,
ftp, mailto a pochopitelně relativní cesty a kontroluje i atributy src,
action, formaction a také <object data=...>
. Pokud někde
potřebujete vypsat URL bez kontroly, použijte modifikátor
|nosafeurl
.
A nakonec: drobná změna souvisí s ručním vykreslování checkboxů,
ale o tom níže.
Přes obrovskou spoustu novinek ve formulářích je možných
nekompatibilit málo.
Checkboxy a RadioListy se nyní vykreslují v praktičtějším tvaru
<label><input>...</label>
namísto
<label>...</label><input>
. Jako důsledek
u Checkbox metoda getLabel()
či {label}
nevrací nic
a getControl()
či {input}
HTML v onom novém tvaru.
Pokud ale potřebujete staré chování, přepněte se do tzv. partial
renderingu přidáním dvojtečky: {label nazevprvku:}
a
{input nazevprvku:}
. Easy.
Makro {control form}
nyní vždy vypisuje chybové zprávy
u jednotlivých prvků a nad formulářem jsou jen ty nepřiřazené.
Doporučujeme to tak dělat i při manuálním vykreslování, třeba
takto.
setValue()
u prvků kontroluje hodnotu a v případě chyby
vyhodí výjimku namísto dřívějšího mlčení
- validační pravidla jako
Form::INTEGER
, NUMERIC
a
FLOAT
převádí hodnotu na integer resp. float
- TextArea: zrušeny výchozí hodnoty atributů
cols
a
rows
(existovaly jen proto, že to HTML4 vyžadovalo)
- prvky označené
setDisabled()
se neobjeví ve
$form->getValues()
(prohlížeč je totiž vůbec
neposílá)
- zavrženo
SelectBox::setPrompt(true)
, místo true použijte
řetězec
- přejmenováno
MultiSelectBox::getSelectedItem()
→
getSelectedItems()
- v HTML atributech
data-nette-rules
se používá JSON, takže
nezapomeňte nasadit aktuální netteForms.js
Debugger
Nette\Diagnostics\Debugger::$blueScreen
→
Debugger::getBlueScreen()
- a adekvátně
$bar
→ getBar()
,
$logger
→ getLogger()
a $fireLogger
→ getFireLogger()
- zavrženo
Nette\Diagnostics\Debugger::tryError()
,
catchError()
a také toStringException()
, místo
kterého použijte obyčený trigger_error()
- zavrženy interní
Nette\Diagnostics\Helpers::clickableDump()
a
htmlDump()
, které nahrazuje nová
třída Dumper
Mail
Zavržená metoda Nette\Mail\Message::send()
, použijte mailer,
viz dokumentace.
ostatní
- Nette nemusí fungovat s eAccelerator a minifikovaný PHAR nemusí fungovat
s APC
Nette\Utils\Finder::find($mask)
filtruje podle masky nejen
soubory, ale i adresáře
- do
Nette\Security\User
se v konstruktoru předává
autentikátor, pozor na kruhové závislosti
- v loaderu se už nenastavuje
iconv_set_encoding()
a
mb_internal_encoding()
- zavrženy konstanty
NETTE, NETTE_DIR a NETTE_VERSION_ID
- a třída
Nette\Loaders\AutoLoader
- a proměnná
Nette\Framework::$iAmUsingBadHost
- doporučujeme přestat používat
callback()
a třídu
Nette\Callback
, neboť globální funkce mohou způsobit komplikace
- přejmenoval se jmenný prostor
Nette\Utils\PhpGenerator
→
Nette\PhpGenerator
- Nette varuje hláškou „Possible problem: you are sending a cookie while
already having some data in output buffer,“ pokud se snažíte odeslat HTTP
hlavičku nebo cookie a byl již odeslán nějaký výstup – byť do bufferu.
Buffer totiž může přetéct a proto to varování.
Vyzkoušejte!
Stáhněte si verzi 2.1 a
vyzkoušejte ji! A těšte se na články o novinkách 🙂