phpFashion

Na navigaci | Klávesové zkratky

PhpStorm a napovídání nad $this->template

Jak se zbavit upozorňování PhpStormu na „undefined fields“ a aktivovat napovídání u objektu $this->template v presenterech?

Tedy jak změnit tento pohled s podtrženým abc a prázdným napovídacím okénkem:

Na tento?

Jednoduše. Stačí do presenteru (například BasePresenter) doplnit tuto anotaci:

/**
 * @property-read \Nette\Bridges\ApplicationLatte\Template|\stdClass $template
 */
abstract class BasePresenter extends Nette\Application\UI\Presenter

Aby fungovalo i napovídání dynamicky přidaných proměnných, které je dostupné po dvojím stisknutí Ctrl+Space, je potřeba šablonu uložit do lokální proměnné:


Nette lišta dává tipy na zajímavé články, videa, události

Web Nette prochází redesignem a první vlaštovkou je zbrusu nová horní lišta.

Na ní podobně jako ve vysílání ČT 24 nebo CNN běží tipy na zajímavé články, knihovny, videa, události atd. Díky ní by vám nemělo uniknout nic zajímavého, co se kolem Nette děje.

Pošlete tipy na články, doplňky, videa!

Jakmile administrátoři tip schválí, objeví se na všech webech Nette.

Napsali jste článek, natočili video? Šup tam s ním. Budete mít reklamu na všech webech Nette.


Jak správně updatovat Nette

Potřebujete aktualizovat projekt běžící na Nette 2.0 na nejnovější verzi? Tady je pár tipů, jak na to.

Stoupejte po jednotlivých verzích

Tj. nejprve aktualizujte na Nette 2.1, poté 2.2, a tak dále. Důvod je ten, že pokud se v Nette nějaká vlastnost změní nebo odstraní, děje se tak v postupných krocích trvajících i několik let. Nejprve je vlastnost jako deprecated jen označena v kódu (silently deprecated), v další velké verzi emituje hlášku E_USER_DEPRECATED, ale funkčnost je zachována, a teprve ve třetí verzi je odstraněna.

Nette se snaží, aby ony hlášky byly maximálně srozumitelné a návodné (např. Syntax {!$var} is deprecated, use {$var|noescape} on line 123), abyste mohli zastaralé věci snadno nahradit.

Pokud byste přeskočili několik verzí, mohli byste přijít o tuto důležitou fázi.

Začínejte bez E_USER_DEPRECATED

Před nasazováním nové verze je vhodné nejprve vypnout hlášení chyb E_USER_DEPRECATED:

$configurator->enableDebugger();
error_reporting(~E_USER_DEPRECATED); // všimněte si ~

Nyní můžete vyzkoušet, zda vše funguje jak má, bez upozorňování na zapovězené věci. Pokud vše funguje, hlášky zase povolte a upravte podle nich kód.

Čtěte dokumentaci

Všechny migrační návody najdete v dokumentaci. Pokud byste ve firmě potřebovali s aktualizací pomoci, jsem vám k dispozici.


Nette 2.4: už je za rohem!

Za pár týdnů vyjde nová verze Nette 2.4, nejnabušenější Nette všech dob. Postupně budu přidávat články, kde se dozvíte o všech novinkách, ale ještě předtím…

…by bylo skvělé, kdybyste otestovali, jestli pod ním běží vaše aplikace. Na všech svých webech už mám testovací 2.4 nasazenou a pochopitelně jsem přitom odhalil řadu chybiček, které bylo potřeba opravit. Tak prosím ověřte, jak jsou na tom vaše weby, než vyjde stable.

Verze 2.4 by měla být na 99 % kompatibilní s verzí 2.3. Zároveň upozorňuje, pokud používáte konstrukce, se kterými se už nepočítá do Nette 3.0. Může se stát, že něco z toho je pro vás důležité a chtěli byste funkčnost zachovat. Stačí o tom dát vědět. Ale samozřejmě co nejdříve.

Podrobné vysvětlení všech případů, kdy Nette generuje upozornění, a několika nekompatibilit mezi 2.3 a 2.4 najdete v tomto vláknu na fóru. A velmi stručný přehled novinek můžete zkouknout ve videu z poslední Poslední soboty.


Co nevíte o output bufferingu v PHP

A co se ani v dokumentaci nedočtete, včetně záplaty na bezpečnostní díru a rady, jak zrychlit odezvu serveru a naopak ji nezbrzdit.

Output buffering umožňuje, aby výstup PHP skriptu (především funkcí echo) nebyl okamžitě odeslán do prohlížeče nebo terminálu, ale byl uchováván v paměti (tj. bufferu). Což se hodí k celé řadě věcí.

Zabránění vypisování na výstup:

ob_start();  // zapne output buffering
$foo->bar();  // veškerý výstup jde pouze do bufferu
ob_end_clean();  // buffer smaže a ukončí buffering

Zachytávání výstupu do proměnné:

ob_start();  // zapne output buffering
$foo->render();  // výstup jde pouze do bufferu
$output = ob_get_contents();  // obsah bufferu uloží do proměnné
ob_end_clean();  // buffer smaže a ukončí buffering

Dvojici ob_get_contents() a ob_end_clean() lze nahradit jedinou funkcí ob_get_clean(), z jejíhož názvu se sice vytratilo end, ale skutečně output buffering i vypíná:

$output = ob_get_clean();  // obsah bufferu uloží do proměnné a vypne buffering

V uvedených příkladech se obsah bufferu na výstup vůbec nedostal. Pokud jej naopak na výstup poslat chci, namísto ob_end_clean() jej ukončím funkcí ob_end_flush() . Pro současné získání obsahu bufferu, odeslání na výstup a ukončení bufferování existuje opět zkratka (i včetně chybějícího end v názvu): ob_get_flush().

Buffer lze kdykoliv vyprázdnit i bez nutnosti jej ukončit, a to pomocí ob_clean() (smaže jej) a nebo ob_flush() (pošle jej na výstup):

ob_start();  // zapne output buffering
$foo->bar();  // veškerý výstup jde pouze do bufferu
ob_clean();  // smažu obsah bufferu, ale buffering zůstává aktivní
$foo->render(); // výstup jde stále do bufferu
ob_flush(); // buffer posílám na výstup
$none = ob_get_contents();  // obsah bufferu je nyní prázdný řetězec
ob_end_clean();  // vypne output buffering

Do bufferu se posílá i výstup zapisovaný na php://output, naopak buffery lze obejít zápisem na php://stdout (nebo do STDOUT), což je k dispozici pouze pod CLI, tedy při spouštění skriptů z příkazové řádky.

Zanoření

Buffery je možné zanořovat, takže zatímco je jeden buffer aktivní, dalším voláním ob_start() se aktivuje buffer nový. Tedy ob_end_flush() a ob_flush() neposílají obsah bufferu na výstup, ale do nadřazeného bufferu. A teprve když žádný nadřazený není, posílá se obsah na skutečný výstup, tj. do prohlížeče nebo terminálu.

Proto je důležité buffering ukončit, a to i v případě, že v průběhu nastane výjimka:

ob_start();
try {
    $foo->render();
} finally {  // finally existuje od PHP 5.5
    ob_end_clean(); // nebo ob_end_flush()
}

Velikost bufferu

Buffer může také zrychlit generování stránky tím, že se do prohlížeče nebude odesílat každé jednotlivé echo, ale až větší objem dat (například 4kB). Stačí na začátku skriptu zavolat:

ob_start(null, 4096);

Jakmile velikost bufferu překročí 4096 bajtů (tzv. chunk size), automaticky se provede flush, tj. buffer se vyprázdní a odešle ven. Téhož se dá dosáhnout i nastavením direktivy output_buffering. V CLI režimu se ignoruje.

Ale pozor, spuštění bufferingu bez uvedení velikosti, tedy prostým ob_start(), způsobí, že se stránka nebude neodesílat průběžně, ale až se vykreslí celá, takže server bude naopak působit velmi líně!

HTTP hlavičky

Output buffering nemá žádný vliv na odesílání HTTP hlaviček, ty se zpracovávají jinou cestou. Nicméně díky bufferingu je možné odeslat hlavičky i poté, co se vypsal nějaký výstup, jelikož se stále drží v bufferu. Ovšem jde o vedlejší efekt, na který neradno spoléhat, protože není jistota, kdy výstup překročí velikost bufferu a odešle se.

Bezpečnostní díra

Při ukončení skriptu se všechny neukončené buffery vypíší na výstup. Což lze považovat za nepříjemnou bezpečnostní díru, pokud si například v bufferu připravujete citlivá data, která nejsou určená pro výstup a dojde přitom k chybě. Řešením je použít vlastní handler:

ob_start(function () { return ''; });

Handlery

Na output buffering lze navázat vlastní handler, tj. funkci, která obsah paměti zpracuje před odesláním ven:

ob_start(
    function ($buffer, $phase) { return strtoupper($buffer); }
);
echo 'Ahoj';
ob_end_flush(); // na výstup se dostane AHOJ

I funkce ob_clean() nebo ob_end_clean() vyvolají handler, ale výstup zahodí a ven neposílají. Přičemž handler může zjistit, která funkce je volána a reagovat na to. Používá se k tomu druhý parametr $phase, což je bitová maska (od PHP 5.4):

  • PHP_OUTPUT_HANDLER_START při otevření bufferu
  • PHP_OUTPUT_HANDLER_FINAL při ukončení bufferu
  • PHP_OUTPUT_HANDLER_FLUSH při volání ob_flush() (ale nikoliv ob_end_flush() nebo ob_get_flush())
  • PHP_OUTPUT_HANDLER_CLEAN při volání ob_clean(), ob_end_clean()ob_get_clean()
  • PHP_OUTPUT_HANDLER_WRITE při automatickém flush

Fáze start, final a flush (resp. clean) mohou klidně nastat současně, rozliší se pomocí binárního operátoru &:

if ($phase & PHP_OUTPUT_HANDLER_START) { ... }
if ($phase & PHP_OUTPUT_HANDLER_FLUSH) { ... }
elseif ($phase & PHP_OUTPUT_HANDLER_CLEAN) { ... }
if ($phase & PHP_OUTPUT_HANDLER_FINAL) { ... }

Fáze PHP_OUTPUT_HANDLER_WRITE nastává jen tehdy, pokud má buffer velikost (chunk size) a ta byla překročena. Jedná se tedy o zmíněný automatický flush. Jen pozor, konstanta PHP_OUTPUT_HANDLER_WRITE má hodnotu 0, proto nelze použít bitový test, ale:

if ($phase === PHP_OUTPUT_HANDLER_WRITE) { .... }

Handler nemusí podporovat všechny operace. Při aktivaci funkcí ob_start() lze jako třetí parametr uvést bitovou masku podporovaných operací:

  • PHP_OUTPUT_HANDLER_CLEANABLE – lze volat funkce ob_clean() a související
  • PHP_OUTPUT_HANDLER_FLUSHABLE – lze volat funkci ob_flush()
  • PHP_OUTPUT_HANDLER_REMOVABLE – buffer lze ukončit
  • PHP_OUTPUT_HANDLER_STDFLAGS – je kombinací všech tří flagů, výchozí chování

Tohle se týká i bufferingu bez vlastního handleru. Například pokud chci zachytávat výstupu do proměnné, nenastavím flag PHP_OUTPUT_HANDLER_FLUSHABLE a buffer tak nebude možné (třeba omylem) poslat na výstup funkcí ob_flush(). Nicméně lze tak učinit pomocí ob_end_flush() nebo ob_get_flush(), takže to poněkud ztrácí smysl.

Obdobně by měla absence flagu PHP_OUTPUT_HANDLER_CLEANABLE zamezit mazání bufferu, ale opět to nefunguje.

A nakonec absence PHP_OUTPUT_HANDLER_REMOVABLE činní buffer uživatelsky neodstranitelný, vypne se až při ukončení skriptu. Příkladem handleru, který je vhodné takto nastavit, je ob_gzhandler, který komprimuje výstup a tedy snižuje objem a zvyšuje rychlost datového přenosu. Jakmile se tento buffer otevře, odešle HTTP hlavičku Content-Encoding: gzip a veškerý další výstup musí být komprimovaný. Odstranění bufferu by rozbilo stránku.

Správné použití je tedy:

ob_start(
    'ob_gzhandler',
    16000, // bez chunk size by server data neodesílal průběžně
    PHP_OUTPUT_HANDLER_FLUSHABLE // ale ne removable nebo cleanable
);

Komprimaci výstupu můžete aktivovat také direktivou zlib.output_compression, která zapne buffering s jiným handlerem (netuším, v čem konkrétně se liší), bohužel chybí příznak, že má být neodstranitelný. Protože je vhodné komprimovat přenos všech textových souborů, nejen v PHP generovaných stánek, je lepší kompresi aktivovat přímo na straně HTTP serveru.




Nette Pro: úplně bez obalu

Blíží se spuštění Nette Pro. Chemix sepsal, o co jde, a já dokončuji web, kde bude vysvětleno, co to přinese. Protože jsem zaznamenal i nějaké obavy, rád bych je rozptýlil a zkusím proto Nette Pro popsat zcela bez obalu.

Například Martin Zlámal se ptal: „chci o frameworku přednášet na školách. Baví mě to – a hodně. Mění se tím pro mě něco? Můžu to vůbec dělat?“ a v tu chvíli jsem si uvědomil, že Nette Pro obestírá jakýsi závoj neporozumění. Takže postupně:

Co je cílem všeho toho snažení? No je jím přesně to, po čem všichni voláme:

  • chceme nové verze plné novinek
  • chceme perfektní release management
  • chceme, aby se řešily hlášené issues nebo pull requesty
  • chceme lepší dokumentaci reflektující novinky
  • chceme stabilitu a minimum BC breaků
  • chceme blog o tom, co se chystá
  • chceme vylepšit web a fórum
  • chceme tutoriály, příklady, videa, podcasty, tipy, triky, řešení
  • chceme ten obsah i v angličtině, protože
  • chceme, aby se o Nette psalo v zahraničí, aby se o něm přednášelo
  • chceme, aby Nette hodně dlouho fungovalo, protože na něm děláme weby

Některé cíle jsou idealistické, jiné velmi hmatatelné, podstatné je, že všechny vám určitě rezonují. Martinova ochota přednášet o Nette na školách do toho pochopitelně zapadá.

Co je důvodem vzniku Nette Pro? Bez obalu: získat peníze na uskutečnění toho všeho.

A proč jsou potřeba peníze? Protože potřebujeme zaplatit lidi.

A proč potřebujeme zaplatit lidi? Protože nemáme dobrovolníky.

Jako že jich je málo? Současná komunita nestačí?

Na rovinu: na Nette pracují vlastně 3 lidé:

  • Milo, který vymýšlí, vyvíjí, opravuje, dokumentuje a píše na blog o Nette Testeru, taktéž spravuje hosting pro nette.org. Dělá to jako dobrovolník ve volném čase mimo zaměstnání a výchovu malého dítěte.
  • Chemix, který organizuje a moderuje Poslední soboty, zajišťuje sponzory, prostory, přednášející. Dělá to jako dobrovolník, jinak působí jako kreativec na volné noze. Neumí anglickou gramatiku tak, aby si troufl vydávat články.
  • já, David, který vymýšlí, vyvíjí, opravuje a releasuje Tracy, Latte a vlastně celé Nette, taky dibi a Texy, psal dokumentaci, udržuje web nette.org a fórum. Dělá to jako dobrovolník v podstatě už veškerý svůj čas. Neumí anglickou gramatiku tak, aby si troufl vydávat články.

A řekl bych, že nás všechny to baví. Jenže to neškáluje :-)

A taky bych řekl, že nás dost nebaví, když (zejména ti velmi dobře obeznámení se situací a možnostmi) nás hejtujou, že vysoká očekávání neplníme.

Z téhle trojky už víc vymáčknout nepůjde a dnes už víme, že na příliv nových sil nelze spoléhat. Zkoušeli jsme leccos včetně hazardérství, ale nic nezabralo. Místo čekání, jestli se někdo chopí třeba vylepšování dokumentace, je lepší si prostě copywritera najít a normálně mu těch několik měsíců práce zaplatit.

Samozřejmě nechci připravit o kredit kluky, kteří věnují čas fóru, což je fakt důležitá činnost.

Jen jsme narazili na hranici toho, co lze na čistě dobrovolné bázi uskutečnit. A hledáme způsob, jak jí překonat. Potřebujeme angažovat i „nedobrovolníky“.

Proč se tito lidé nezaplatí z příjmů Nette? Bez obalu: Nette generuje příjem v řádu tisícikorun měsíčně.

Tudíž potřebujeme ty příjmy zvýšit. Mnohanásobně. Což vůbec není sranda. Ano, Nette je zřejmě nejpopulárnějším webových frameworkem u nás, běží na něm řada nesmírně výdělečných projektů, jenže z toho automaticky neplyne příjem pro Nette. Firmy jsou nemilosrdné, a pokud jim nenabídnete nějakou přidanou hodnotu, korunu nepustí.

A tou přidanou hodnotou (především) pro firmy má být právě Nette Pro.

Svým způsobem přidanou hodnotou je i to, že chceme dělat Nette pro fesionálně.

Samo o sobě to však nestačí. Vyrazili jsme proto do firem a ptali se jich, bez obalu, jak si můžeme být prospěšní. „My potřebujeme peníze, protože bez nich by Nette jen přešlapovalo na místě. Co vám můžeme za ně nabídnout?“ Někdo se chtěl zviditelnit. Někdo chtěl vyřešit issues. Někdo jen chtěl, aby se Nette dál vyvíjelo. Tak jsme myšlenky přetavili do balíčků.

Ony balíčky jsou tedy tím, o čem lidé prohlásili: „jo, tohle dovedu u nás ve firmě prosadit.“

Nebo řekli: „jo, tohle by se nám fakt hodilo.“ Ať už programátorům, nebo třeba HR či marketingu, protože to pomůže zviditelnit firmu nebo najít zaměstnance.

Takže dobrovolníci už nejsou potřeba? Jsou! Setsakramentsky moc!

V Nette bylo a bude téměř vše tvořeno dobrovolníky. Nette Pro je jen záplata jejich chronického/ochromujícího nedostatku.

Doufám, že když se peníze z Nette Pro použijí na vylepšení webu, dokumentace, tutoriálů, že ten tvůrčí kvas povzbudí komunitu k aktivitě. Potřebujeme Martiny, kteří budou jezdit po školách. Potřebujeme autory tutoriálů a doplňků, kteří si tímto způsobem udělají jméno. Potřebujeme nadšence, co o Nette budou psát články do zahraničních magazínů, aby se přitáhla i světová komunita. Nette Pro zaplatí překladatele. Ale práci dobrovolníků nenahradí.

A kdy se to spustí? Během pár dní.


Dibi 3.0 je venku, Texy na cestě

Zmodernizoval jsem kód knihoven Dibi a Texy, třídy přenesl do jmenných prostorů a využil syntaxe PHP 5.4. Zároveň jsem doplnil mechanismus, aby knihovny fungovaly i s existujícím kódem, který používá původní názvy tříd.

Výsledkem je Texy 2.8 (release notes) a Dibi 3.0 (release notes).

Dibi mělo nést původně označení 2.4, protože krom vnitřního refactoringu jsem nechtěl přidávat nebo měnit jakoukoliv funkčnost, jako u Texy 2.8, ale nakonec jsem pár vychytávek přidal a výsledkem je právě verze 3.0:

  • nové výjimky Dibi\ConstraintViolationException, ForeignKeyConstraintViolationException, NotNullConstraintViolationExceptionUniqueConstraintViolationException
  • MySQL: sloupec TIME se převádí na objekty DateInterval namísto DateTime (BC break)
  • SqlsrvDriver: doplněna podpora pro LIMIT & OFFSET
  • vylepšen Dibi\Fluent při použití limit & offset

Zmizely ovladače pro SQLite 2 a MsSqlDriver, které nejsou od PHP 5.3 podporované, a MsSql2005Driver se nyní jmenuje SqlsrvDriver (funguje i starý název). Statická třída dibi zůstává mimo jmenné prostory. Pokud si píšete vlastní ovladač, došlo ke změně v rozhraní u metod escape() & unescape() (viz).

Minimální požadovaná verze PHP je 5.4.4, obě knihovny jsou plně funkční i pod PHP 7. Minifikovaná verze je ve formě archívu PHAR.

Dibi postupně pokrývám testy. Jelikož nepoužívám MS SQL Server, je tento driver víceméně v rukou komunity. Pokud jej používáte, zkuste prosím zjistit, proč neprocházejí testy používané pro jiné servery a co je potřeba změnit.

Velmi pozvolna vzniká i Texy 3.0, ze kterého zmizí dnes už překonané funkce, jako je třeba podpora jiného kódování než UTF-8, jiného formátu než HTML5 atd.


Jak vyvíjet komfotrněji?

Nová verze Nette 2.3.7 přináší spoustu vylepšení, jedno z nich si ale rychle zamilujete. Jsou to chybové hlášky, které se vám pokusí napovědět, pokud uděláte překlep.

Určitě jste už někdy narazili na podobnou chybu:

Chcete v šabloně vykreslit komponentu a ona prý neexistuje. Může to mít celou řadu příčin, od nějakého opomenutí na straně presenteru, až po chybu v šabloně. Nebo se komponenta jmenuje jinak?

Nejhorší ze všeho jsou triviální přelkepy, které nevidíte, takže několikrát prověříte všechny možnosti a strávíte na tom dost času, než chybu odhalíte.

Nejnovější verze Nette má ale šikovnější chybovou hlášku:

Did you mean ‚signInForm‘? Aha! Hned je jasné, že na vině byl překlep a můžete ho rovnou opravit.

Pokud jste se někdy dlouze zasekli na velikosti písmenek, tj. že vám {control MyComponent} hlásil chybu Component with name ‚MyComponent‘ does not exist, o to více oceníte dovětek did you mean ‚myComponent‘?.

Pojďme k Nette\Database. Chybka v názvu databázového sloupce? Opět ji dostanete na stříbrném podnose:

Mimochodem, stejná feature bude i v příští verzi dibi, kterou prosím před vydáním otestujte.

Nette napovídá překlepy v názvech funkcí, metod, proměnných atd. Pokud vyvíjíte v IDE, neměly by se vám podobné chyby stávat, na druhou stranu málokteré IDE dokáže plnohodnotně napovídat třeba v šablonách. Ať už se spletete v názvu filtru nebo makra:

Případně v názvu proměnné:

Hláškou did you mean novinky zvyšující pohodlí nekončí. Nette vás nově upozorní na celou řadu dalších, dříve špatně odhalitelných, chyb. Jako například chybějící []

$myForm->onSuccess = [$this, 'myFormSucceeded'];
// namísto správného
$myForm->onSuccess[] = [$this, 'myFormSucceeded'];

nebo chybějící ()

{foreach $form->getErrors as $error}
// namísto správného
{foreach $form->getErrors() as $error}

či docela nebezpečné opomenutí, jelikož $user->isLoggedIn je vždy truthy:

{if $user->isLoggedIn} ... něco tajného ... {/if}
// namísto správného
{if $user->isLoggedIn()} ... něco tajného ... {/if}

To nyní povede k varování Did you forget parentheses after isLoggedIn?

Poznámka: pokud záměrně píšete v kódu metodu bez závorek, tj. $cb = $obj->getItems, protože chcete využít vlastnosti Nette\Object, která takto do $cb uloží callback na metodu getItems, a objeví se varování, použijte prosím standardní PHP zápis, tj. $cb = [$obj, 'getItems']. Při korektních běžných použitích se varování nezobrazuje.

Dále Latte vás upozorní, když použijete modifikátor na místě, kde se ignoruje, jako například:

{if $var |filter}

Did you mean „komfortněji“?

Nová verze Nette je tu od toho, aby vám usnadnila a zpříjemnila vývoj. A jak je to napovídání boží si doopravdy uvědomíte, až to vyzkoušíte.


phpFashion © 2004, 2017 David Grudl | o blogu

Pokud není uvedeno jinak, podléhá obsah těchto stránek licenci Creative Commons BY-NC-ND Creative Commons License BY-NC-ND

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.