Novinky v Nette 3.1 je venku!
- David Grudl
- Nette Core | 8218
Nette 3.1 je venku! Novinky zanáším do dokumentace a chystám články na blog, v tomhle postu si je chci postupně sumarizovat.
Všechny informace o tom, že je něco přejmenované, chápejte prosím tak, že původní varianta stále funguje, nejde o žádné BC breaky.
Obecně
- Minimální požadovaná verze je PHP 7.2
- Pokračuje odstraňování prefixu
I
z názvů rozhraní (o důvodech chystám článek)
Nette Application
- novinky jsem už dříve sepsal tady
- dále catchExceptions is always true on production mode
- router se může v konfigu uvádět bez toho ‚router:‘ (viz)
- v konfigu zrušena volba
application > routeClass
- volba
application > scanFilter
je nyní maska s podporou wildchars a výchozí hodnota je*Presenter
- do
flashMessage($obj)
můžete nyní předat vlastní objekt zprávy, musí být potomkem stdClass - značka
{control name, x: 1, y: 2}
podporuje syntax pojmenovaných parametrů - Form::disableSameSiteProtection() replaced with allowCrossOrigin()
Bootstrap
- kvůli konzistenci se třída
Nette\Configurator
přesouvá do namespace, takže jeNette\Bootstrap\Configurator
- metoda
addParameters()
má aliasaddStaticParameters()
, který je srozumitelnější ve dvojici saddDynamicParameters()
- a parametry které předáváme již nemohou obsahovat další
parametry, tj.
addParameters(['path' => '%appDir%/temp')
nebude fungovat. Že to funguje asi nikdo netušil a vznikaly kvůli tomu občas problémy. - úplně s Bootstrapem to nesouvisí, ale v Sandboxu a WebProjectu jsem
vyslyšel žádosti a přesunul složku
config/
o úroveň výš
Database
- po mnoha letech hledání názvu pro Nette Database Explorer (pamatujete NDBT, Selection, Table, ufff) to vypadá, že jsme na konci a Nette Database Explorer funguje dobře, takže i třída Nette\Database\Context je nyní Nette\Database\Explorer
- elegantní způsob práce s transakcí nabízí metoda transaction(), které předáme callback, který se vykoná v transakci. Pokud během vykonávání dojde k vyhození výjimky, transakce se zahodí, pokud vše proběhne v pořádku, transakce se potvrdí. Metoda transaction() vrací návratovou hodnotu callbacku.
$id = $database->transaction(function () use ($database) {
$database->query('DELETE FROM ...');
$database->query('INSERT INTO ...');
// ...
return $database->getInsertId();
});
- Translator SQL příkazů je o něco opatrnější a lépe kontroluje vstupy
- MySqlDriver driver uses subqueries https://github.com/…ase/pull/265
Forms
Hlavní změna se týká getValues() a parametru $values předávaného do handlerů onSuccess, onClick:
- jen zvalidované prvky se předávají do values (aby nedocházelo k typovým chybám při mapování do tříd s properties s typy)
- setValidationScope() omezuje prvky, které se validují, a nově tedy i prvky předané do $values
- volání
$form->getValues()
u nevalidního formuláře vyvolá warning - pro získání všech hodnot, i nevalidních, je tu nová metoda
$form->getUntrustedValues()
.
A dále:
- při standalone použití formulář kontroluje sameSite cookie kvůli
ochraně před CSRF. Odeslání cookie zajišťuje
Form::initialize()
. - pravidlo Form::URL doplní
example.org
nahttps://example.org
místo dřívějšíhohttp
- FormMacros: už nevytváří deprecated proměnné $_form
- Guess first parameter for event by type hint (#219)
- Validator::validateEqual returns false if control value is empty array (BC break) [Closes #257]
- Container::getValues($obj) to hydrate object
- Validator Form::URL autocompletes https:// instead of http:// (BC break)
- Checkbox: added getContainerPrototype()
- Container: addImage() renamed to addImageButton()
Http
- všechny cookies se defaultně posílají se SameSite=Lax, včetně session id
- všechny cookies se na HTTPS spojení defaultně posílají s příznakem Secured
- cookie pro detekci útoku se z
nette-samesite
přejmenovala na_nss
- v konfiguraci jsou nové volby
http > cookiePath
ahttp > cookieDomain
, naopak deprecated jesession > cookieSecure
protože její hodnota se přebírá zhttp > cookieSecure
- SessionSection: nyní je možné číst data číst i ve chvíli, kdy se session uzavřela
FileUpload::getName()
je přejmenovaný na více odstrašujícígetUntrustedName()
Latte
- Latte 2.6 s volitelným zřetězením a uživatelskými funkcemi
- Latte 2.7: typy kam se podíváš a batch
- Latte 2.8 přinášející opevnění uvnitř šablony
- Latte 2.9: to nejlepší nakonec
Neon
- běží už jen v UTF-8 režimu
PhpGenerator
- viz článek na blogu o verzi 3.4
- dále ve verzi 3.5 doplněna podpora pro PHP 8 (constructor property promotion, PHP 8 attributes, union types, …)
Schema
- nový systém generování chybových hlášek. Hlášky jsou objekty doplněné všemi informacemi, lze je tak snadno třeba překládat.
- lze generovat i varování, například že položka je deprecated
- structure() může být označena jako volitelná, i když je v ní povinný prvek
- pomocí
mergeDefaults()
je možné vypnout mergování polí, které bylo pro řadu uživatelů kontraintuitívní
Security
- třída Identity je přejmenovaná na SimpleIdentity. Důvod je uvolnit si do dalekého budoucna název Identity pro rozhraní.
- v konfiguraci je deprecated
security > roles
asecurity > resources
. Používali jste to někdo? Dejte mi vědět. IAuthenticator
se jmenujeAuthenticator
, ale obě varianty se lehce liší. U té nové se jméno a heslo už nepředávají v poli- nové rozhraní Nette\Security\UserStorage nahrazuje dřívější IUserStorage a zároveň jsou v k dispozici dvě implementace. Jedna, která ukládá informace o přihlášeném uživateli do session (jako původní) a nová druhá, která si vystačí čistě s cookie. Tedy bezsessionové přihlašování. (Mimochodem, forum a web Nette tak běží odjakživa). Hledejte security > authentication > storage
- tedy
getUser()->getStorage()
nyní vrací nový storage, ale můžete v konfiguraci vynutit i původní:
services:
security.userStorage: false
- jak nejsnáze aktualizovat identitu po načtení ze session? Třeba v ní
aktualizovat role? Stačí aby autentikátor implementoval rozhraní
Nette\Security\IdentityHandler
.
class Authenticator implements Nette\Security\Authenticator, Nette\Security\IdentityHandler
{
public function authenticate(string $username, string $password): SimpleIdentity
{
...
}
public function wakeupIdentity(IIdentity $identity): SimpleIdentity
{
// aktualizace $identity
}
Kromě metody wakeupIdentity()
je tam ještě
sleepIdentity(IIdentity $identity): IIdentity
s opačnou úlohou,
tady připravit identitu ke serializaci.
Pokud použijete uložiště
security > authentication > storage: cookie
, tak právě tyto
dvě metody jsou klíčové, protože identita se do session
neukládá vůbec.
Tracy
Zcela zbrusu nový neskutečně vylepšený dump(). K tomu bude samostatný článek.
- neskutečně rychlé
- vizuálně propracované
- generování pomocí JavaScriptu
- dark mode
- podpora nativních objektů pro DOM, ArrayObject, atd
- rozklikávání do hloubky přes Alt-click
- zobrazuje reference mezi proměnnými
- rozlišení uninitialized proměnných
- informace o délce řetězce v bytech / znacích
- přehledné zobrazování víceřádkových řetězců
- a mnoho dalšího
Utils
- renamed Nette\Utils\IHtmlString → Nette\HtmlStringable
- nová třída Nette\Utils\Floats
- Image: added detectTypeFromFile() and detectTypeFromString()
- Arrays: searchKey() renamed to getKeyOffset()
- Reflection: added getReturnTypes(), getParameterTypes() and getPropertyTypes() pro union typy
- ApliTax
- Bronze Partner | 2
Ahoj Davide,
Tohle mi trošku komplikuje život:
IAuthenticator se jmenuje Authenticator, ale obě varianty se lehce liší. U té nové se jméno a heslo už nepředávají v poli
Vyhovovalo mi pole, protože jsem u několika aplikací nepotřeboval předávat z přihlašovacího formuláře jen login a heslo, ale i další parametry např. typ uživatele (dodavatel / subdodavatel / dopravce).
Uživatelé byli z uloženi v různých tabulkách s rozdílnou strukturou a měli přístup do odlišných částí aplikace.
Karel
- David Grudl
- Nette Core | 8218
Pomohlo by ti, kdyby tady
bylo $authenticator->authenticate(...func_get_args())
, tedy by
se do authenticate() poslaly všechny argumenty?
- Jan Tvrdík
- Nette guru | 2595
Možná jsem to úplně nepochopil, ale neměl by CookieStorage tu cookie kryptograficky podepisovat (HMAC typicky)?
- jAkErCZ
- Člen | 322
Ahoj,
Já jsem používal
security:
roles:
guest:
member: [guest]
technik: [guest]
lead: [member]
admin: [lead]
A teď mám problém jak opět zprovoznit viz Problém s rolemi v nette 3
Díky za případnou radu 😊
- David Grudl
- Nette Core | 8218
@JanTvrdík ano, to je ukol pro IdentityHandler::sleepIdentity() vrátit UID, které se pak uloží do cookie, a wakeupIdentity() z totoho UID zase vytvoří původní identitu.
@jAkErCZ aha, no já tam objevil problém, ze kterého jsem pochopil, že to nikdy nefungovalo (ale teď si zaboha nevzpomenu jakej…). Takže to fungovalo?
- jAkErCZ
- Člen | 322
David Grudl napsal(a):
@JanTvrdík ano, to je ukol pro IdentityHandler::sleepIdentity() vrátit UID, které se pak uloží do cookie, a wakeupIdentity() z totoho UID zase vytvoří původní identitu.
@jAkErCZ aha, no já tam objevil problém, ze kterého jsem pochopil, že to nikdy nefungovalo (ale teď si zaboha nevzpomenu jakej…). Takže to fungovalo?
Ano u mě to normálně fungovalo 😊
- David Grudl
- Nette Core | 8218
Příklad toho IdentityHandler pro cookies. V db vytvořím sloupec
token
, ve kterém bude mít každý uživatel náhodný
alphanumerický řetězec o dostatečné délce (minimálně 13 znaků).
final class Authenticator implements Nette\Security\Authenticator, Nette\Security\IdentityHandler
{
public function authenticate(string $username, string $password): SimpleIdentity
{
// po přihlášení klasicky vytvořím identitu z údajů z databáze
$row = $this->db->fetch('SELECT * FROM user WHERE username = ?', $username);
...
return new SimpleIdentity($row->id, null, (array) $row);
}
public function sleepIdentity(IIdentity $identity): SimpleIdentity
{
// Příprava identity k uložení do storage po přihlášení.
// Do cookie storage se ukládá jen $identity->getId(), takže vrátím
// novou identitu, kde jako id předám token.
return new SimpleIdentity($identity->token);
}
public function wakeupIdentity(IIdentity $identity): ?SimpleIdentity
{
// Obnovení identity ze storage při každém požadavku.
// Cookie storage vrátí identitu s tokenem, podle něj dohledám uživatele.
$row = $this->db->fetch('SELECT * FROM user WHERE token = ?', $identity->getId());
return $row
? new SimpleIdentity($row->id, null, (array) $row) // a vrátím identitu jako authenticate()
: null;
}
}
- David Grudl
- Nette Core | 8218
@jAkErCZ už jsem na to přišel! Ty si můžeš nadefinovat role a resources, ale úplně tam chybí možnost definovat pravidla allow() a deny(). Bez toho mi to nedávalo smysl.
Jestli to chápu dobře, ty sis následně pravidla nadefinoval v setup?