NetteExtension aneb konfigurace všeho v Nette pomocí config.neon
- David Grudl
- Nette Core | 8218
Aktuální informace jsou udržovány v dokumentaci.
Drtivou většinu parametrů Nette Frameworku lze nyní ovlivnit pomocí
konfiguračního souboru. Konfigurace se zapisuje do sekce nette
,
ta se nachází pod hlavní sekcí common
(pokud ji
používáte):
Sessions
Lze nastavovat všechny PHP direktivy (ve formátu camelCase). Nastavení
autoStart
na hodnotu smart
automaticky nastartuje již
vytvořenou session, doporučil bych používat.
nette:
session:
autoStart: true # výchozí je smart
expiration: 10 days
name: ...
...
Application
nette:
application:
debugger: true # panel v bluescreen
catchExceptions: ...
errorPresenter: ...
Routování
Tohle je zatím spíše experimentální záležitost.
nette:
routing:
debugger: true # panel v Debugger baru
routes:
index.php: Dashboard:default
'<presenter>/<action>[/<id>]': Dashboard:default
Security
Uvedením pole users
vytvoříme SimpleAuthenticator, uvedením
polí roles
nebo resources
vytvoříme autorizátor
Nette\Security\Permission.
nette:
security:
debugger: true # panel v Debugger baru
frames: ... # hodnota hlavičky X-Frame-Options
users:
frantisek: tajneheslo
roles:
guest:
member:
admin: [member] # admin dědí od membera
resources:
file:
Maily
Standardní mailer je SendmailMailer, uvedením smtp
aktivujeme
SmtpMailer.
nette:
mailer:
smtp: ...
# dále lze uvést host, port, username, password, secure, timeout
Pro vytvoření emailové zprávy můžeme použít
$container->nette->createMail()
.
Databáze
Můžeme vytvořit více připojení, které uvedeme pod klíčem
database
. Takto vytvoříme spojení nazvané default
a dostupné pod $container->nette->database->default
.
nette:
database:
default:
dsn: "sqlite2:%appDir%/models/demo.db"
user: ...
password: ...
options: [PDO::MYSQL_ATTR_COMPRESS = true]
debugger: false # panel v Debugger baru
explain: false # explain dotazů v Debugger baru
reflection: discovered # nebo conventional nebo název třídy
Framework tak vytvoří nejen objekt Nette\Database\Connection
,
ale nastavují mu i pomocné objekty jako reflection & cache a ve
vývojářském režimu přidá panel do Debugger baru.
V rámci konfiguračního souboru se můžeme ke službě dostat přes
autowiring (@Nette\Database\Connection
), přes název služby
(@nette.database.default
) nebo si vytvořit alias a ten
používat:
services:
database: @nette.database.default
authorizator: Auth(@database)
Formuláře
V konfiguračním souboru lze změnit výchozí chybové hlášky.
nette:
forms:
messages:
EQUAL: 'Please enter %s.'
FILLED: 'Please complete mandatory field.'
MIN_LENGTH: 'Please enter a value of at least %d characters.'
Pro vytvoření formuláře vhodného pro použití mimo presentery můžeme
použít $container->nette->createBasicForm()
.
Šablony
Lze přepínat HTML a XHTML režim šablon:
nette:
xhtml: no # výchozí je true
Základní nakonfigurovanou šablonu s helpery a Latte vyrobí
$container->nette->createTemplate()
.
DI
nette:
container:
debugger: true # aktivuje panel v Debugger baru
Debugger
Lze konfigurovat některé parametry Nette\Diagnostics\Debugger
a nastavovat panely do Debugger baru.
nette:
debugger:
email: %webmasterEmail%
strictMode: TRUE
editor: ...
browser: ...
bar: [IncludePanel, XDebugHelper('myIdeKey') ]
blueScreen: [] # panely do blue-screen obrazovky
Cache
Objekt pro přístup ke keši vyrobí
$container->nette->createCache($namespace = NULL)
.
Low-level úpravy
Všechny tyto nastavení ovlivňují podobu výsledného systémového DI
kontejneru. Oproti přímému zápisu do sekcí
services či factories
nabízejí srozumitelnější a
stručnější syntax. Nicméně zůstává možnost si jednotlivé služby
ještě „doladit“ na nižší úrovni:
services:
nette.mailer:
class: MySmtpMailer
factories:
nette.mail:
setup:
- addHeader('X-Mailer', 'Nette Framework 2.0')
Nebo vytvořit nové služby poděděním existujících: (přidá metodu
$container->createSecuredForm()
)
factories:
securedForm < nette.basicForm:
setup:
- addProtection()
- nanuqcz
- Člen | 822
David Grudl napsal(a):
Databáze
…
Chápu to správně, že tyto dva konfigurační soubory budou pracovat obdobně?
nette:
database:
default:
dsn: "sqlite2:%appDir%/models/demo.db"
user: ...
password: ...
services:
database: @nette.database.default
parameters:
database:
dsn: "sqlite2:%appDir%/models/demo.db"
user: ...
password: ...
services:
database: Nette\Database\Connection(%database.dsn%, %database.user%, %database.password%)
A bude mi při použití prvního způsobu fungovat v presenterech
$this->getService('nette.database.default')
? Takže bych ani
nemusel definovat službu database
v services
?
- ViPEr*CZ*
- Člen | 817
xxxObiWan napsal(a):
A bude mi při použití prvního způsobu fungovat v presenterech$this->getService('nette.database.default')
? Takže bych ani nemusel definovat službudatabase
vservices
?
Ano bude… když to bude v nette, tak to nemusí být v services. A je to dostupné takto:
$container->nette->database->default
- Felix
- Nette Core | 1196
David Grudl napsal(a):
Šablony
Lze přepínat HTML a XHTML režim šablon:
nette: xhtml: no # výchozí je true
Základní nakonfigurovanou šablonu s helpery a Latte vyrobí
$container->nette->createTemplate()
.
bud delam neco blbe, ale zkousel jsme xhtml: no i xhtml: false a porad to generuje xhmtl
EDIT: jsem blbec, aktualizoval jsem nette a uz to jede, jsem si nevsim, ze uz to je opraveny..
Editoval Felix (26. 1. 2012 13:24)
- David Grudl
- Nette Core | 8218
xxxObiWan napsal(a):
Chápu to správně, že tyto dva konfigurační soubory budou pracovat obdobně?
V jednom případě vytváříš službu sám, ve druhém případě ti ji vytvoří NetteExtension, který vytvoří i panel do Debugger baru atd. Obě cesty jsou možné.
hAssassin napsal(a):
Je nějaká možnost jak nakonfigurovat připojení k
dibi
novým způsobem, nebo musím zůstat u starého, klasického? Dík.
Nevím, co přesně myslíš novým a starým způsobem,
každopádně jakýkoliv objekt/službu můžeš vytvořit klasicky v PHP
(třeba bootstrapu) a uložit do containeru, zápisem v poli services
(dibi: DibiConnection(...)
) a pokud pro knihovnu existuje nějaká
CompilerExtension, tak i vytvořením vlastní sekce v configu.
Pro dibi existuje DibiNetteExtension. Připojíme ji v bootstrapu:
$configurator = new Nette\Config\Configurator;
$configurator->onCompile[] = function($configurator, $compiler) {
$compiler->addExtension('dibi', new DibiNetteExtension); // nazev sekce bude dibi
};
a přidáme sekci v config.neon:
dibi:
driver : mysqli
host : localhost
username : root
password : xxx
database : dibi
Službu pak najdeme v $container->dibi->connection
.
- hAssassin
- Člen | 293
@David Grudl: Aha, takhle se na to musí. Zkusim.
Díky. Jinak tím klasickým způsobem jsem myslel definici sluzby
dibi
v config.neon
:
services:
dibi:
class: \DibiConnection
arguments: ['%database%']
...
parameters:
database:
driver : mysql
host : localhost
username : root
password : xxx
database : dibi
Problém právě je, že při aktualizaci na Nette RC1 a Dibi 2.0 přestane fungovat panel v debug baru.
- hAssassin
- Člen | 293
RiskyNet napsal(a):
hAssassin napsal(a):
…Zkus přidat do parametru databaze
profiler: TRUE
To ja tam samozrejmne mam, ale stejne to nefunguje. Proble je totiz zde, pokud smazu ten parametr FALSE, tak to uz panel zobrazi v pohode, jinak se to do ty podminky nedostane. Problem asi bude v tom ze to registruju pres sluzbu tak jak sem psal vyse.
- RiskyNet
- Člen | 20
hAssassin napsal(a):
RiskyNet napsal(a):
hAssassin napsal(a):
…Zkus přidat do parametru databaze
profiler: TRUE
To ja tam samozrejmne mam, ale stejne to nefunguje. Proble je totiz zde, pokud smazu ten parametr FALSE, tak to uz panel zobrazi v pohode, jinak se to do ty podminky nedostane. Problem asi bude v tom ze to registruju pres sluzbu tak jak sem psal vyse.
Uz to vidim, me to totiz funguje (taky registruju pres sluzbu) ale pouzivam ted min verzi, tam ten FALSE neni sorry
Editoval RiskyNet (26. 1. 2012 17:42)
- dakota
- Člen | 148
Chcem sa spýtať či je v neon podporovaný len tento zápis
services:
nette.mailer:
class: MyFileMailer
pretože pôvodne mi fungoval aj zápis
services:
mailer:
class: MyFileMailer
pričom ten teraz vyhodí chybu
Nette\DI\ServiceCreationException
Service 'nette.mail': Multiple services of type Nette\Mail\IMailer found: nette.mailer, mailer
- David Grudl
- Nette Core | 8218
Je to tím, že ve starší revizi mi chybělo u v názvu služby
nette.
. Správně je první zápis.
- Milo
- Nette Core | 1283
hAssassin napsal(a):
RiskyNet napsal(a):
hAssassin napsal(a):
…Zkus přidat do parametru databaze
profiler: TRUE
To ja tam samozrejmne mam, ale stejne to nefunguje. Proble je totiz zde, pokud smazu ten parametr FALSE, tak to uz panel zobrazi v pohode, jinak se to do ty podminky nedostane. Problem asi bude v tom ze to registruju pres sluzbu tak jak sem psal vyse.
Problém je v tom, že se DibiConnection.php
includuje přes
RobotLoader
a ne přes dibi.php
ve kterém se loaduje
třída DibiNettePanel
pro panel. Když odstraníš to FALSE,
RobotLoader
ti automaticky natáhne i
DibiNettePanel
.
- Filip Procházka
- Moderator | 4668
Předpokládám, že v dokumentaci se takový přehled bude lépe udržovat: https://doc.nette.org/cs/configuring
- uestla
- Backer | 799
Je to opravdu super.
Nicméně routování v konfigu (ač experimentální) je takové svázané, neboť se nedají předávat flagy (jednosměrky, chráněné routy, …).
Plánuje se tato funkčnost přidat? Myslím, že by to mohla být jediná věc, která by experimentálnost přesunula k plnohodnotnému využití – nebo něco přehlížím?
Díky!
- David Grudl
- Nette Core | 8218
uestla napsal(a):
Nicméně routování v konfigu (ač experimentální) je takové svázané, neboť se nedají předávat flagy (jednosměrky, chráněné routy, …).
Nedá se měnit ani třída atd. Chce to vymyslet nějakou pěknou syntax.
- Vyki
- Člen | 388
Chtěl bych jenom upozornit na jednu maličkost.
services:
database: @Nette\Database\Connection
authenticator: Authenticator( @database::table(users) )
myService:
class: MyServiceClass(@database, ClassWithParams('id', '%s_id', '%s'), ClassWithoutParams())
Pokud jako parametr volím třídu, která nemá v konstruktoru povinné paramatry, tedy PHP zápis
$class = new ClassWithoutParams;
musím v neon zápisu stejně použít prázdné závorky
ClassWithoutParams()
za názvem třídy. Jinak se to přeloží
jako 'ClassWithoutParams'
a ne new ClassWithoutParams
.
Dává to logiku, protože je to asi jediný způsob jak to v tom neon zápisu
odlišit od řetězce, jenom se potřeba si to ohlídat.
Editoval Vyki (8. 2. 2012 12:04)
- ViPEr*CZ*
- Člen | 817
Juan napsal(a):
ViPErCZ napsal(a):
Tohle
$class = new ClassWithoutParams;
bych úplně vyhodil… kompilátor c++ by na tomhle řval.
Vyhodil odkud? Z PHP? :D
A co sem taháte C++ a Javascript?
Ano myšleno z PHP. Jen jsem chtěl vyjádřit souhlas se správností syntaxe s používáním závorek u bezparametrického konstruktoru.
- David Grudl
- Nette Core | 8218
Nicméně chápu, že to, na co upozornil Vyki, může být matoucí. Jednak instance se vytváří pomocí závorek, ale u specifikace
class:
se píše jen řetězcovité jméno třídy (čili bez závorek).
Protože class
je skutečně jméno třídy, tedy řetězec. Má
smysl jej uvádět pouze v situacích, kdy se volá nějaká továrna a není
známo, co vrací. Obecné doporučení by asi mělo být používat vždy
factory.
- Vyki
- Člen | 388
Ještě bych si dovolil jednu poznámku ohledně
[...]
routes:
index.php: Dashboard:default
'<presenter>/<action>[/<id>]': Dashboard:default
[...]
Na definici jednoduchých rout je to super. I kdyby to z Nette zmizelo ve
svém FW si to nechám. Má to ale jednu vadu na kráse – nelze definovat
FLAG
. Osobně jsem si ve svém Extension
dodělal
podporu, která umožňuje psát toto:
[...]
routes:
index.php: [Homepage:default, ONE_WAY]
'<presenter>/<action>[/<id>]': Homepage:default
[...]
Oproti původnímu kódu v NetteExtension vypadá můj kód následovně.
[...]
if(is_array($action))
$router->addSetup('$service[] = new Nette\Application\Routers\Route(?, ?, ?)', array($mask, $action[0], constant("Nette\Application\Routers\Route::{$action[1]}")));
else
$router->addSetup('$service[] = new Nette\Application\Routers\Route(?, ?)', array($mask, $action));
[...]
To s tím constant tam mám kvůli tomu, že jsem si nedovedl představit,
jak budu psát jako FLAG
v konfiguračním souboru celou cestu
k té konstantě. To by asi moc hezké nebylo tam psát
Nette\Application\Routers\Route::ONE_WAY
Asi to není úplně ideální, ale minimálně u jedné routy v každé
aplikaci ten FLAG
napsat potřebuji.
- Vyki
- Člen | 388
uestla napsal(a):
Koukni 3 dny zpátky ;-)
Tak to sorry za spam, toho jsem si nevšiml.
Chtěl jsem se ještě zeptat jestli někdo neví, jakým způsobem si lze
jednoduše pomocí nové konfigurace zaregistrovat vlastní makro. Mám již
vytvořenou třídu potomka MacroSet
, která ovšem chce ve
statické metodě install instanci Nette\Latte\Compiler
a netuším
jak se k ní snadno v při konfiguraci dostat. Dříve jsem to řešil
přetížením metody Presenter::templatePrepareFilters
v
BasePresenteru
, ale to samé potom musím udělat i v
BaseControl
, tak mě napadlo zda by to nyní nešlo
elegantněji.
- Filip Procházka
- Moderator | 4668
@**Vyki**: něco jako
services:
nette.latte:
setup:
- MyMacroSet::install($service->compiler)
Editoval HosipLan (10. 2. 2012 7:39)
- Vyki
- Člen | 388
HosipLan napsal(a):
@**Vyki**: něco jako …
Když dám místo service factory tak už se blížím k úspěchu a do
těla té továrničky mi to vloží to MyMacroSet::install
.
Nevypořádá se to ale s tím ($service->compiler)
vypíše to
Unexpected '>compiler)' on line 51, column 41
, takže jsem šel
zatím cestou rozšíření Nette\Latte\Engine
.
Edit: Koukám, že lze také využít makro {use MacroSet}
, ale
to se mi moc nelíbí dávat tuto logiku do šablony.
Editoval Vyki (10. 2. 2012 11:18)
- martyx
- Člen | 5
Pokouším se přepsat konfiguraci session do neonu. Poradil by mi někdo z nette pardálů, jestli jde nastavit nějakým způsobem cookiePath, tak aby vedla k projektu, zanořeném ve více složkách? V bootstrapu to řeším takto:
$container->session->setCookieParameters($container->httpRequest->url->scriptPath, $_SERVER['SERVER_NAME']);
Něco jako tohle, což mi nejde:
nette:
session:
autoStart: smart
expiration: +14days
cookie_path: @httpRequest.uri.scriptPath
Bez toho mám část konfigurace v neonu a část v bootstrapu, což bych rád měl na jednom místě. Díky za pomoc.
- martyx
- Člen | 5
mkoubik napsal(a):
Nevím jestli není plus speciální znak, zkus to dát do uvozovek:
expiration: '+14days'
.
Díky, ale v tom problém není, to funguje dobře. Ostatně je to podle Davidova vzoru z úvodu tohodle topicu. Jedná se mi o to cookie_path, resp. jak mu nastavit cestu. Můžu to tam samozřejmě dát ručně na tvrdo, ale pohodlnější by pro mě bylo dynamické načtení cesty. Zkusil jsem jen odhadem @httpRequest.uri.scriptPath, ovšem to je nejspíš blbost. Třeba existuje nějaká možnost.
- martyx
- Člen | 5
RiskyNet napsal(a):
Já si taky střelím :) dle „Lze nastavovat všechny PHP direktivy (ve formátu camelCase)“
zkusil jsi
cookiePath: @httpRequest.uri.scriptPath
Zkusil. V tom taky problém není. Nejde o název vlastnosti, ale její hodnotu. Pokud tam zapíšu ručně
session:
autoStart: smart
expiration: +14days
cookie_path: /projects/project
tak je to v pohodě, viz dump session:
Nette\Http\Session(4) {
regenerationNeeded private => NULL
options private => array(16) {
cookie_domain => "localhost" (9)
cookie_secure => NULL
cookie_path => "/projects/project" (17)
gc_maxlifetime => 1209600
cookie_lifetime => 1209600
...
}
ale můj pokus s
session:
autoStart: smart
expiration: +14days
cookie_path: @httpRequest.uri.scriptPath
končí laděnkou s hláškou
Reference to missing service 'httpRequest.uri.scriptPath'
Zajímavý je, že když tam dám jen službu httpRequest
session:
autoStart: smart
expiration: +14days
cookie_path_test: @httpRequest
tak to projde, viz dump session:
Nette\Http\Session(4) {
regenerationNeeded private => NULL
options private => array(16) {
cookie_domain => "localhost" (9)
cookie_secure => NULL
cookie_path_test => Nette\Http\Request(9) {
method private => "GET" (3)
url private => Nette\Http\UrlScript(10) { ... }
query private => array(0)
post private => array(0)
files private => array(0)
cookies private => array(7) { ... }
headers private => array(9) { ... }
remoteAddress private => "127.0.0.1" (9)
remoteHost private => NULL
}
gc_maxlifetime => 1209600
cookie_lifetime => 1209600
...
}
Nejspíš je pravděpodobný, že jsem tele a nechápu něco důležitýho. Např. něco s životním cyklem. Třeba v době sestavování kontejneru, ve chvíli zpracovávání mojí session, ještě není nastavana služba httpRequest.
- uestla
- Backer | 799
Co vím, tak NEON zatím neumí zřetězené volání metod na službě, čili nejde
@httpRequest::getUrl()::getScriptPath() # nebo něco na ten způsob
Co ale jde, je udělat si pomocnou službu na UrlScript a na ní pak volat
getScriptPath()
:
nette:
session:
autoStart: smart
expiration: '+ 14 days'
cookie_path: @urlScript::getScriptPath()
services:
urlScript:
factory: @httpRequest::getUrl()
Nezkoušel jsem, píši to z paty, snad bude fungovat …
- martyx
- Člen | 5
uestla napsal(a):
Co vím, tak NEON zatím neumí zřetězené volání metod na službě, čili nejde
Díky, to zkusím. K tomu řetězení mě navedlo dibi, resp. @dibi.connection. Protože takhle mi to funguje.
services:
sitemapModel: \Models\Sitemap\SitemapModel(@dibi.connection)
...
Tak jsem to zkusil i na tento případ. Ale ta pomocná služba je dobrej nápad. To by mělo jít.