phpFashion

Na navigaci | Klávesové zkratky

Rubrika PHP

Jak zprovoznit https na localhost?

Abych si přiblížil vývoj na lokálním počítači tomu ostrému, zprovoznil jsem si lokální https. Jak na to?

Nejsnazší cesta

V komentářích padla zmínka o aplikaci mkcert, která následující postup udělá za vás. Ale pokud máte rádi ruční práci, čtěte dál :)

Vygenerujeme SSL certifikát

K tomu použijeme program openssl, který určitě na počítači najdete, třeba jako součást Gitu na C:\Program Files\Git\usr\bin\openssl.exe nebo jinde. Následující příkaz vygeneruje klíč do souboru rootCA.key. Bude to po vás chtít vymyslet nějaké heslo, které si uložte.

openssl genrsa -des3 -out rootCA.key 2048

Další příkaz z klíče vygeneruje kořenový SSL certifikát a uloží ho do souboru rootCA.pem. Jeho platnost bude 2000 dní (tedy pět let), ale číslo klidně změňte:

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 2000 -out rootCA.pem

Uvěříme certifikátu

Teď oznámíme operačnímu systému, aby certifikát považoval za důvěryhodný. Postup pro Mac jsem našel třeba tady, pro Windows je pěkně obrázek za obrázkem sepsaný zde a pro české Windows jsem vám jej přeložil:

  • spustit mmc
  • v menu Soubor > Přidat nebo odebrat moduly snap-in
  • doubleclick na Certifikáty v levém okně
  • zvolte Účet počítače a Další
  • ponechte Místní počítač a Dokončit
  • zavřete okno tlačítkem OK
  • v levém okně zvolte Certifikáty, v pravém Důvěryhodné kořenové certifikační autority
  • pravé tlačítko a v kontextovém menu Všechny úkoly > Importovat
  • objeví se Průvodce importem certifikátu, dejte Další
  • vyberte soubor rootCA.pem a odklikejte průvodce na konec

Ufff, jsme v půlce. Pokračujeme v Konzoli:

  • opět v menu Soubor > Přidat nebo odebrat moduly snap-in
  • doubleclick na Editor objektů zásad skupiny
  • stiskněte Dokončit a zavřete okno tlačítkem OK
  • v levém okně otevřete Místní počítač – zásady > Konfigurace počítače > Nastavení systému Windows > Nastavení zabezpečení > Zásady veřejných klíčů
  • doubleclick na Nastavení ověření cesty certifikátů
  • zatrhněte Definovat tato nastavení, Povolit ověřování certifikátů … a Povolit uživatelům důvěřovat certifikátum …
  • potvrďte tlačítkem OK

Hotovo, zavřete Konzoli.

Všichni už certifikátu věří, akorát Firefox chce ještě popostrčit:

  • ve Firefoxu otevřete stránku about:config
  • odklikejte všechna varování
  • vyhledejte položku security.enterprise_roots.enabled
  • doubleklikem změňte hodnotu na true
  • zavřete stránku

Vyrobíme certifikát pro webový server

Klikačku máme za sebou, teď vyrobíme certifikáty pro server. Vytvoříme soubor server.csr.cnf s tímto obsahem:

[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C = CZ
ST = Random
L = Random
O = Random
OU = Random
emailAddress = example@example.com
CN = localhost

A dále soubor v3.ext, kde bude uveden seznam všech domén, které na localhostu provozujete:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost
DNS.2 = texy.l
DNS.3 = *.texy.l
DNS.4 = nette.l
DNS.5 = *.nette.l
DNS.6 = navlnachekg.l

Jak vidíte, lokální verze webů provozuji na doménách, které končí na .l, u vás to třeba bude jinak. Ty jednotlivé klíče DNS.1 apod. je potřeba fakt jako idiot postupně očíslovat.

Následujícím krokem vygenerujeme soubory server.key aserver.csr:

openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config server.csr.cnf

A konečně vygenerujeme SSL certifikát pro server do server.crt (teď to bude po vás chtít zadat heslo, které jste si vymysleli na začátku):

openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext

Všechny dosud vytvořené soubory včetně hesla si někam uložte. Ať se totiž změní domény, které provozujete lokálně, jen upravíte v3.ext a posledním příkazem znovu vygenerujete certifikát pro server.

Konfigurace webového serveru

Zbývá povolit https na serveru. Tj. nakonfigurovat server tak, aby naslouchal na portu 443, na kterém běží https, a používal vygenerovaný certifikát.

Používám Apache, do jehož konfiguračního soubor httpd.conf jsem přidal následující řádky s cestou k souborům server.key aserver.crt:

Listen 443
SSLCertificateFile "C:\Apache24\ssl\server.crt"
SSLCertificateKeyFile "C:\Apache24\ssl\server.key"

Konfiguraci virtuál hostů možná řešíte úplně jinak než já, těžko říct, ale v mém případě zprovoznění obnášelo ke každému virtuálu jako je

<VirtualHost *>
    ServerName localhost
    DocumentRoot "W:/"
</VirtualHost>

doplnit ještě druhý:

<VirtualHost *:443>
    ServerName localhost
    DocumentRoot "W:/"
    SSLEngine on
</VirtualHost>

V nginx by mělo stačit do konfiguračního souboru nginx.conf doplnit pro každý server něco takového:

server {
	listen 443 ssl;
	ssl_certificate     path/to/server.crt;
	ssl_certificate_key   path/to/server.key;
}

A to je vše. Docela mazec, co? Otevřete v prohlížeči https://localhost a jestli se stránka zobrazí, je to důvod k oslavě.


Fight jazyků: co obnášejí dvě mutace Nette?

Stránky Nette existují ve dvou jazykových verzích: české a anglické. Udržovat tak obsáhlý projekt ve dvou mutacích vyžaduje dost práce, ale vidím v tom smysl.

Plnohodnotná česká dokumentace a fórum je totiž výhodou pro zdejší začínající programátory, protože žádný jiný framework ničím takovým nedisponuje. Samozřejmě ideální by bylo, kdyby každý Čech už od základní školy uměl plynně anglicky, ušetřilo by to hodně práce, ale není úkolem frameworku tohle suplovat. Nicméně angličtina není v žádném případě druhotným jazykem. Naopak. Posuďte sami:

Dokumentace. Její současná velikost čítá 3 MB textů (pro srovnání celé dílo Shakespeare má 5 MB). Anglická a česká jsou přitom zcela identické. Nejsem si vědom, že by jeden jediný odstavec existoval třeba v české verzi a anglické chyběl. Případně by se v jedné verzi objevil mnohem dříve než v druhé. Obě verze jsou neustále synchronizované. Pokud byste na nesoulad narazili, vytvořte prosím issue na GitHubu.

Anglické forum bylo spuštěno v roce 2008. Na českém až do minulého týdne svítila zpráva: „Chcete se zdokonalovat v angličtině? Zkuste psát do anglického fóra. I když by to bylo s chybami – těmi se člověk učí.“, takže i mnoho Čechů používá anglické fórum.

Nette Blog v tuto chvíli čítá 34 článků v angličtině a 19 v češtině. Rozhodně doporučuji blog sledovat, třeba přes RSS, stává se z něj hlavní zdroj informací o novinkách.

Diskuse na GitHubu jsou výhradně v angličtině. Tuším od roku 2012 je to oficiální podmínka. Jedinou výjimkou jsou diskuse o české dokumentaci, což je snad pochopitelné.

V celém kódu se nikdy neobjevilo jediné české slovo. Kód je od prapočátků pouze v angličtině, včetně všech chybových hlášek, komentářů atd. Tuším jen jednou se v něm vyskytlo slovo fuck :-)

Dále je tu oficiální Twitter kanál, který je od počátku kompletně anglicky.

Co naopak anglicky není? Tak především jsou to videa z Posobot a facebooková stránka Nette Framework CZ/SK, která slouží zejména k informování o lokálních akcích, jako je právě Posobota nebo NettePivo. A taky kanál na Slacku Péhápkaři, což tedy není oficiální součást Nette.

Ještě pár technických záležitostí: pokud přijdete na úvodní stránku webu, fóra či blogu, nejspíš vás to přesměruje na českou verzi. Je to pouze proto, že máte v prohlížeči nastavený jako preferovaný jazyk češtinu nebo jste se už někdy v minulosti do české mutace přepnuli. Jinak samozřejmě přesměrovává na anglickou verzi.

Taktéž je určitý rozdíl mezi výpisem článků či příspěvků na českém a anglickém fóru. Web zkrátka předpokládá, že český uživatel anglicky číst umí, takže českým uživatelům se například u nejnovějších příspěvků vypisují i ty anglické nebo na českém blogu i anglické články, u který neexistuje českých překlad. Zahraniční uživatel tento mix nevidí.

Česká verze je zkrátka přidaným komfortem. Ale rozhodně preferujeme tvořit obsah v angličtině.

před 4 lety v rubrice PHP



Jak správně nastavit CSP a script-src

Content Security Policy (CSP) je dodatečný bezpečnostní prvek, který prohlížeči říká, jaké další zdroje může stránka načítat a jak může být zobrazena. Chrání tak před vkládáním škodlivého kódu a útokům jako je XSS. Odesílá se v podobě hlavičky sestavené z řady direktiv. Jeho nasazení ale není vůbec triviální.

Obvykle chceme používat JavaScriptové knihovny umístěné na různých místech mimo náš server, například měřící kód Google Analytics, reklamní systémy, captchy atd. A tady bohužel první verze CSP selhává. Vyžaduje přesnou analýzu načítaného obsahu a nastavení správných pravidel. Tedy vytvořit whitelist, výčet všech domén, což není snadné, jelikož některé skripty dynamicky dotahují další skripty z jiných domén, nebo jsou na jiné domény přesměrované atd. A i když si dáte práci a seznam vytvoříte ručně, nikdy nevíte, co se může v budoucnu změnit, takže musíte neustále sledovat, jestli je seznam stále aktuální a opravovat ho. Analýza Google ukázala, že i to pečlivé ladění ve finále vede k tomu, že povolíte tak široký přístup, že celý smysl CSP padá, jen posíláte s každým požadavek mnohem větší hlavičky.

CSP level 2 už k problému přistupuje jinak, pomocí nonce, nicméně teprve třetí verze řešení dotáhla do konce. Bohužel zatím (rok 2019) nemá dostatečnou podporu u prohlížečů.

O tom, jak sestavit direktivy script-src a style-src, aby správně fungovaly i ve starších prohlížečích a přitom s tím bylo co nejméně práce, jsem sepsal podrobný článek v partnerské sekci Nette. V zásadě výsledná podoba může vypadat nějak takto:

script-src 'nonce-XXXXX' 'strict-dynamic' * 'unsafe-inline'
style-src 'nonce-XXXXX' * 'unsafe-inline'

Příklad použití v PHP

Vygenerujeme nonce a odešleme hlavičku:

$nonce = base64_encode(random_bytes(16));

header("Content-Security-Policy: script-src 'nonce-$nonce' 'strict-dynamic' * 'unsafe-inline'");

A vložíme nonce do HTML kódu:

<script nonce="<?=$nonce?>" src="..."></script>

Příklad použití v Nette

Protože Nette má vestavěnou podporu pro CSP a nonce od verze 2.4, stačí v konfiguračním souboru uvést:

http:
	csp:
		script-src: [nonce, strict-dynamic, *, unsafe-inline]
		style-src: [nonce, *, unsafe-inline]

A v šablonách pak používat:

<script n:nonce src="..."></script>
<style n:nonce>...</style>

Monitoring

Než nastavíte nová pravidla pro CSP, vyzkoušejte si je nejprve nanečisto pomocí hlavičky Content-Security-Policy-Report-Only. Ta funguje ve všech prohlížečích podporujících CSP. Při porušení pravidel prohlížeč nezablokuje skript, ale jen pošle notifikaci na URL uvedené v direktivě report-uri. K příjmu notifikací a jejich analýze můžete použít třeba službu Report URI.

http:
	cspReportOnly:
		script-src: [nonce, strict-dynamic, *, unsafe-inline]
		report-uri: https://xxx.report-uri.com/r/d/csp/reportOnly

Můžete zároveň používat obě hlavičky a v Content-Security-Policy mít ověřené a aktivní pravidla a zároveň v Content-Security-Policy-Report-Only si testovat jejich úpravu. Samozřejmě i selhání ostrých pravidlech si můžete nechat monitorovat.

před 4 lety v rubrice PHP


Typed properties v PHP 7.4 jsou cool, ale ne jak si myslíte?

Po dvou verzích PHP, které nepřinesly nic moc zajímavého, se blíží verze, pro kterou bude mít opět smysl aktualizovat knihovny. Jde o PHP 7.4 a hlavním tahákem jsou typed properties, které uzavírají mnohaletý posun ke striktně typovanému jazyku, což PHP zvýhodňuje oproti jiným webovým jazykům.

Ve zkratce, tahle novinka vám umožní deklarovat typy přímo u proměnných třídy:

class Config
{
	public string $dsn;
	public ?string $user;
	public ?string $password;
	public bool $debugger = true;
}

Příklad použití najdete i v dokumentaci Nette Schema, které je na ně už dnes připravené.

Je potřeba říct, že pokud jste si navykli používat privátní proměnné a přistupovat k nim přes typehintované metody (což je správně), tak vlastně o žádnou killer feature nejde. Druhotná kontrola typů je zbytečná a vlastně jen zpomaluje kód. Diametrálně jiná situace se týká public/protected proměnných, kde dosud neexistoval žádný způsob, jak mít jejich hodnotu (a dokonce existenci) pod kontrolou. Až dosud.

Což nevyhnutelně povede k otázce:

Je nutné dál psát settery a gettery?

Sice veškerý boilerplate kód nám dnes na kliknutí generují editory, ale určitě vypadá hezky, když tohle:

class Circle
{
	private $radius;

	function setRadius(float $val)
	{
		$this->radius = $val;
	}

	function getRadius(): float
	{
		return $this->radius;
	}
}

nahradíte za:

class Circle
{
	public float $radius;
}

Nehledě na to, že i užití objektu je stručnější $circle->radius = $x vs $circle->setRadius($x).

Problém ale je, že velkou spoustu setterů a getterů nelze jednoduše nahradit. Třeba zrovna v uvedeném příkladu by se hodilo ještě ověřit, že poloměr není záporné číslo:

	function setRadius(float $val)
	{
		if ($val < 0) {
			throw new InvalidArgumentException;
		}
		$this->radius = $val;
	}

A v ten moment už nelze kód zredukovat do veřejné proměnné.

Jindy zase chceme, aby jednou nastavená hodnota byla neměnná, což nelze u public proměnné zajistit.

Nebo vůbec nechceme dávat k dispozici getter, protože nepatří do veřejného API třídy.

Anebo chceme mít setter či getter součástí rozhraní.

Atd, atd.

Zkrátka někdy bude možné použít typované veřejné proměnné místo metod, jindy ne, rozdíl bude dost často otázkou vnitřní implementace třídy a pro uživatele neprůhledný. Což je cesta v nekonzistentnímu API, kdy jednou se používá proměnná, jindy metoda a uživatel v tom nevidí logiku. (Podobně jako třeba metoda PDOStatement::errorInfo() vs. proměnná PDOException::$errorInfo).

Prohlubování nekonzistence ale nechceš. Raději konzistentní setrvání u metod, privátních proměnných a všeho toho boilerplate kódu. A pro privátní proměnné, jak jsem zmiňoval v úvodu, je přínos typehintů sporný. Nebo ne?

V čem je tedy výhoda?

Vlastně je výhod dost, i když v jiných oblastech. Typované proměnné budou užitečné pro kompilátor kvůli optimalizacím, pro práci s reflexí nebo nástroje analyzující kód. Důležité budou v šedé zóně protected proměnných. Umožňují zapsat prostředky jazyka to, co se dosud obcházelo komentářem. A navíc přinášejí do jazyka nový příznak neinicializovaného stavu, jakousi obdobu undefined z JavaScriptu.


Nette spouští ambiciozní program

Nette spouští nový crowdfundingový program, jehož cílem je získat finanční prostředky pro vývoj frameworku. Hlavní změnou je, že místo jednorázových příspěvků je zaměřen na pravidelnou měsíční podporu. Ta může přicházet jak od jednotlivců, tak od firem, kterým nabízí možnost zviditelnit se na webu Nette a inzerovat na fóru nebo přímo v dokumentaci, tedy na místech s nejlepším zásahem cílové skupiny programátorů.

Každý, kdo staví na Nette, má zájem, aby se framework aktivně vyvíjel. Aby podporoval nové verze PHP. Aby se opravovaly chyby. Aby přicházel s dalšími novinkami, které usnadní práci nebo ušetří čas a peníze. Aby framework měl skvělou dokumentaci a existoval kolem něj užitečný obsah, ať už ve formě článků, návodů nebo videí.

Řada částí Nette představuje světovou špičku a chceme, aby tomu tak bylo nadále.

Bez adekvátního financování se nic z toho nedá zajistit. Přitom abyste se mohli spolehnout, že vyjdou další verze, stačí docela málo: abyste jej každý měsíc podpořili byť jen malou finanční částkou.

Pojďte do toho a staňte se partnerem Nette!

Používá vaše firma Nette?

Pokud pracujete ve firmě, které Nette vydělává peníze, vysvětlete prosím svému šéfovi, že je dobrý nápad se stát partnerem a zajistit tak zdravé fungování projektu, na který spoléháte. Zvýšíte prioritu řešení vašich issues a zároveň zviditelníte svoji společnost v komunitě a přilákáte k sobě vývojáře.

Partnerství totiž přichází s exkluzivními výhodami. Například s uvedením vašeho loga na webu Nette, možností vkládat pracovní nabídky, inzerovat na fóru (ukázka) nebo v dokumentaci (ukázka), tedy na místech se zcela nejlepším zásahem do skupiny Nette vývojářů.

Partnerům vystavujeme faktury, aby si mohli podporu dát do nákladů, a to buď měsíčně, čtvrtletně, půlročně nebo ročně.

Používáte Nette soukromě?

Stojíme také o vaši podporu. Přihlaste se k pravidelným donations přes PayPal. Vaše jméno bude vidět na webu Nette.

Kolik peněz je potřeba?

V tuto chvíli máme stanoveny tři cíle, kterých chceme dosáhnout.

Prvním cílem je 64.000 Kč měsíčně, které zajistí, že se vývoji bude věnovat jeden programátor na půl úvazku. Další vývoj Nette tak bude pokračovat, nicméně polovičním tempem než dosud, což není úplně ideální. Při dosažení hranice 128.000 Kč získá framework full-time vývojáře a nové verze mohou přicházet každý rok.

Náklady jsou tak nízké proto, že nepotřebujeme kanceláře a hlavně pracujeme na něčem, co nás baví.

Při dosažení třetí mety 196.000 Kč měsíčně budeme moci přizvat další spolupracovníky a vylepšovat tak web, dokumentaci, vytvářet nový obsah a nechat jej překládat do angličtiny. A tak oslovit zahraniční komunitu. Čtvrtá meta dává možnost zapojit druhého programátora, což by vývoj a správu issues značně zrychlilo.

Jakmile se dosáhne tohoto milníku, připravíme další cíle, které by počítaly s více programátory, mohly by vznikat nové užitečné nástroje a knihovny. Pak třeba vznikne i kniha o Nette.


Viz také Freelo.cz: 14 důvodů, proč podpořit Nette


How to Mock Final Classes?

How to mock classes that are defined as final or some of their methods are final?

Mocking means replacing the original object with its testing imitation that does not perform any functionality and just looks like the original object. And pretending the behavior we need to test.

For example, instead of a PDO with methods like query() etc., we create a mock that pretends working with the database, and instead verifies that the correct SQL statements are called, etc. More e.g. in the Mockery documentation.

And in order to be able to pass mock to methods that use PDO type hint, it is necessary for the mock class to inherit from the PDO. And that can be a stumbling block. If the PDO or method query() were final, it would not be possible.

Is there any solution? The first option is not to use the final keyword at all. This, of course, does not help with the third-party code that it uses, but mainly detracts from the important element of the object design. For example, there is dogma that every class should be either final or abstract.

The second and very handy option is to use BypassFinals, which removes finals from source code on-the-fly and allows mocking of final methods and classes.

Install it using Composer:

composer require dg/bypass-finals --dev

And just call at the beginning of the test:

require __DIR__ . '/vendor/autoload.php';

DG\BypassFinals::enable();

Thats all. Incredibly black magic :-)

BypassFinals requires PHP version 5.6 and supports PHP up to 7.2. It can be used together with any test tool such as PHPUnit or Mockery.


This functionality is directly implemented in the „Nette Tester“: https://tester.nette.org version 2.0 and can be enabled this way:

require __DIR__ . '/vendor/autoload.php';

Tester\Environment::bypassFinals();

Jak mockovat final třídy?

Jak mockovat třídy, které jsou definované jako final nebo některé z jejich metod jsou final?

Mockování znamená nahrazení původního objektu za jeho testovací imitaci, která neprovádí žádnou funkci a jen se tváří jako původní objekt. A předstírá chování, které potřebujeme kvůli testování.

Takže například místo objektu PDO s metodami jako query() apod. vytvoříme jeho mock, který práci s databází jen předstírá, a místo toho ověřuje, že se volají ty správné SQL příkazy atd. Více třeba v dokumentaci Mockery.

A aby bylo možné mock předávat metodám, které mají type hint PDO, je potřeba, aby i třída mocku dědila od PDO. A to může být kámen úrazu. Pokud by totiž třída PDO nebo metoda query() byla final, už by to nebylo možné.

Existuje nějaké řešení? První možnost je final vůbec nepoužívat. To ovšem nepomůže s kódem třetích stran, který final používá, ale hlavně se tím ochuzujeme o důležitý prvek objektového návrhu. Existuje dogma, že každá třída by měla být buď final, nebo abstract.

Druhou a velmi šikovnou možností je použít Nette Tester, který od verze 2.0 disponuje vychytávkou, která odstraňuje z kódu klíčové slovo final on-the-fly. Stačí na začátku testu zavolat:

require __DIR__ . '/vendor/autoload.php';

Tester\Environment::bypassFinals();

A je to. Je za tím ukrytá neskutečně černá magie ?

Pokud nepoužíváte Nette Tester, ale třeba PHPUnit, nebudete ochuzeni, stačí si nainstalovat BypassFinals:

composer require dg/bypass-finals --dev

A na začátku skriptu zavoláte:

require __DIR__ . '/vendor/autoload.php';

DG\BypassFinals::enable();

Jak souhrnně nazývat třídy a rozhraní?

Názvoslovný oříšek: jak souhrnně označovat třídy a rozhraní? Jak třeba nazvat proměnnou, která může obsahovat jak název třídy, tak rozhraní? Co zvolit místo $class?

Dá se tomu říkat type ($type), nicméně to je zase příliš obecné, protože typem je i řetězec nebo pole. Z pohledu jazyka jím může být i něco komplikovanějšího, třeba ?array. Navíc je sporné, co je v případě objektu jeho typ: je jím název třídy, nebo je to object?

Nicméně souhrnné označení pro třídy a rozhraní skutečně existuje: je jím slovo třída.

Cože?

  1. Z pohledu deklarace je interface hodně ořezaná třída. Může obsahovat jen veřejné abstraktní metody. Což také implikuje nemožnost vytvářet objekty. Rozhraní jsou tedy podmnožinou tříd. A pokud je něco podmnožinou, tak to můžeme označovat názvem nadmnožiny. Člověk je savec, stejně jako rozhraní je třída.
  2. Nicméně je tady ještě pohled užití. Třída může dědit jen od jedné třídy, ale může implementovat vícero rozhraní. Nicméně tohle je omezení týkající se tříd, samotné rozhraní za to nemůže. Obdobně: třída nemůže dědit od final třídy, ale přitom final třídu pořád vnímáme jako třídu. A také pokud třída může implementovat víc rozhraní (tj. tříd, viz 1.), stále je vnímejme jako třídy.

A co traity? Ty sem vůbec nepatří, z hlediska OOP jednoduše neexistují.

Tedy problém se společným pojmenováním tříd a rozhraní je vyřešen. Říkejme jim prostě třídy.

classes + interfaces = classes

No jo, ale vznikl tady problém nový. Jak říkat třídám, které nejsou rozhraní? Tedy jejich doplňku. Tomu, co se ještě na začátku článku nazývalo třídy. Nerozhraní? Nebo implementations:-)

To je ještě větší oříšek. To je pořádný ořech. Víte co, raději zapomeňme na to, že rozhraní jsou také třídy, a tvařme se opět, že každý OOP identifikátor je buď třída, nebo rozhraní. Bude to snazší.


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

Jak se zbavit upozorňování PhpStormu, NetBeans nebo dalších IDE 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

Pozn.: v nejnovějších verzích Nette 2.4 až je tato anotace přímo v kódu.

Třída šablony

Třída stdClass v anotaci je workaround pro PhpStorm, který jinak všechny proměnné považuje za nedefinované. Nicméně zajímavější je si vytvořit třídu se seznamem skutečných proměnných, které šablona má, včetně jejich typů. Může vypadat třeba takto:

class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
	/** @var string */
	public $lang;
	/** @var int */
	public $page;
	/** @var string[] */
	public $menu;
	/** @var Model\Page */
	public $article;
}

a potom ji v anotaci konkrétního presenteru uvedeme namísto stdClass:

/**
 * @property-read ArticleTemplate $template
 */
final class ArticlePresenter extends Nette\Application\UI\Presenter

Od této chvíle je napovídání perfektní:

Aktualizace: Latte plugin už podporuje napovídání přímo v šablonách. Stačí přidat {templateType App\Presenters\ArticleTemplate} na začátek šablony.


phpFashion © 2004, 2024 David Grudl | o blogu

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