Routování, filtery, komponenty a další
- hotline
- Člen | 41
Dobry den, chtel bych se vas zeptat na par nazoru ohledne Nette. Myslite si, ze obecne usnadnuje vyvoj nebo ho spis komplikuje tim, ze jsem omezen na to, jak je nette staveny? Jde o to, ze musim jaksi prejit pod filozofii frameworku a ridit se tim, jak je staveny.
Napriklad, routovani, ktere mam v cistem PHP vyresene za 15 minut vcetne
osetreni vsech vyjimek, duplicitnich odkazu, apod. resim v nette uz nekolik
dnu. Pritom jde o trivialni vec:
Zjednoduseny sled udalosti pri zavolani URL:
http://example.com/ –
vyreseno, jsem na indexu,
Jinak pokracuji dal:
http://example.com/[staticky
definovane stranky] (kontakt, forum, apod.) – dalsi casti (napr.
/kontakt/email) jsou reseny az v kontaktu, ktery si je pak routuje sam
Pokud neni shoda, pokracuji dal:
http://example.com/[nazev-clanku] – vyhledam v databazi
shodu na clanky
Pokud neni shoda, pokracuji na index + odpoved 404
Nette mi vnucuje <presenter>/<action>/<id>, bez <action> nelze nic, apod. Routovani typu http://example.com/[dotaz do databaze na existenci] je snad neresitelny problem.
Stejne tak napriklad, pokud chci na strance s clanky includovat header, footer, apod. To v latte snad ani nejde nebo to neni v dokumentaci zmineno. V PHP to vyresim jednou radkou, ale jak na to v nette?
Nektere veci ve frameworku opravdu reseny velmi dobre a zjednodusuji, ale celkove je to pro me spis komplikovanejsi, nez kdybych to delal cele na vlastnim reseni, kteremu bych rozumel od A do Z a nemusel resit, proc framework (ne)dela tohle a tohle a jak se dela v nette neco, co bych ve vlastnim reseni vyresil jednou radkou.
Neberte to prosim nejak spatne, spis mi jde o to, jestli jdou napriklad vyse zminovane veci nejakym zpusobem snadno osetrit tak, abych mohl opravdu rici: „ano, tohle budu delat v nette, protoze to bude rychlejsi“. Nebo jak podobne veci resite vy? Kdyz potrebujete neco, co nette neumi? V php jde vse, coz je super, ale jak to prevedu do nette? Chapu, ze vy, co v nette delate jiz nekolik let si to osetrite hned, ale vyplati se ta casova investice? Bohuzel, zde to neni tak, ze bych mohl stejne, jako v php/jquery/…, delat nejakou pro me neznamou veci z patra tim, ze se mrknu do php dokumentace a tim je neznalost ihned vyresena.
Diky za nazory.
Editoval hotline (21. 5. 2015 18:18)
- David Matějka
- Moderator | 6445
Nette mi vnucuje <presenter>/<action>/<id>, bez <action> nelze nic, apod.
vubec nevnucuje, v sandboxu je to pouze priklad. Pro staticky stranky si muzes udelat routu treba
new Route('kontakt', 'Contact:default');
pro clanek treba
new Route('<url>', 'Article:default');
do presenteru ti pak prijde parametr url
Stejne tak napriklad, pokud chci na strance s clanky includovat header, footer, apod
to das do @layout.latte
a do latte muzes inkludovat dalsi latte
soubory: https://latte.nette.org/cs/tags#…
a k samotne otazce:
Ulehcuje nette vyvoj nebo naopak?
snad nejsou lidi idioti, aby pouzivali neco, co jim ztezuje praci :)
- hotline
- Člen | 41
Diky za reakce. Tak to je mnohem snazsi, nez jsem si myslel, akorat me zmatlo par veci v dokumentaci.
Fajn, budu vam verit a ten cas tomu dam. :-) Ono je i dost srozumitelnych step-by-step tutorialu, ale je skoda, ze vetsina je starsich, ktere, pokud jsem cetl spravne, nelze pro aktualni verzi Nette brat v potaz. Pokud byste vedeli o necem, na co mohu sahnout s nejnovejsi verzi Nette, dejte prosim vedet. ;-)
Abych nedelal nic naprazdno, pokousim se prepsat jeden web do nette a docela se mi to zacina libit. Mel bych na vas jeste jednu takovou obecnou otazku na latte – v presenteru mam dotaz do databaze, ktery se pak v latte zpracovava foreach cyklem. Jenze, potreboval bych s vypsanymi udaji jeste pracovat, coz jsem byl zvykly resit vlastni php funkci. Kdyz se ted ale foreach zpracovava v latte, tak to asi nebude mozne?
Jedinou cestou je asi vlastni makro? https://latte.nette.org/cs/#…
Napadlo me jeste to, ze bych foreach spoustel v presenteru, tam vyresil potrebne veci a v latte by se foreach volal znovu. To ale asi neni uplne nejcistsi reseni. Jak takovou vec resite?
Diky za ochotu.
Editoval hotline (21. 5. 2015 22:39)
- Filip Procházka
- Moderator | 4668
Proč by to nebylo možné? Napiš konkrétně co s těmi daty chceš dělat a poradíme ti. Takhle je to moc obecně a nerad bych ti poradil něco nevhodného pro tvůj případ.
- hotline
- Člen | 41
Napriklad bych ve foreach cyklu potreboval vypsat odpoved funkce get_timeAgo, do ktere bych posilal jednu bunku z radku tabulky, kde je ulozeny timestamp.
function get_timeAgo( $ptime )
{
$estimate_time = time() - $ptime;
if( $estimate_time < 1 )
{
return 'less than 1 second ago';
}
$condition = array(
12 * 30 * 24 * 60 * 60 => 'year',
30 * 24 * 60 * 60 => 'month',
24 * 60 * 60 => 'day',
60 * 60 => 'hour',
60 => 'minute',
1 => 'second'
);
foreach( $condition as $secs => $str )
{
$d = $estimate_time / $secs;
if( $d >= 1 )
{
$r = round( $d );
return 'about ' . $r . ' ' . $str . ( $r > 1 ? 's' : '' ) . ' ago';
}
}
}
Pak treba mam funkci, ktera vraci jquery kod pro prispevek (pri nacteni skryje prebytecnou cast, kterou jde zobrazit (jedoduse tak, ze se doplni za zkraceny prispevek) kliknutim na zkracenou cast pres toggle), coz by ale melo normalne jit, pokud jsem to spravne pochopil, ale jeste jsem nezkoumal, jestli na to v nette neni nejaka pomucka.
Dale tam mam ajaxy, ale ty se mi v nette libi a jsou v dokumentaci dobre popsane, spis mi slo o to, jak muzu pro promennou v latte volat php fci nebo s ni nejak sloziteji pracovat, kdyz nechci foreach volat dvakrat.
- Oli
- Člen | 1215
Tak přesně na ten tvůj první problém se hodí filtry. A tady je popsáno, jak si vytvoříš vlastní filtr.
Ten kod v jquery by měl jít normálně vypsat, ale budeš ho muset odescapovat. Hlavně si dej pozor aby se ti nedostal do databáze nějaký záškodnický kód, protože tím, že to odeskejpuješ by se ti vykonal…
- hotline
- Člen | 41
Sypu si popel na hlavu.. Diky moc za odpovedi a omlouvam se za ten prvni prispevek, ale byl jsem trochu rozladeny z prvotniho dojmu a moji neznalosti. Tady je taky volani php funkce v latte pekne vysvetleno, jen jsem to jaksi prehledl. :-) Nette je opravdu smer, kterym se budu ubirat.
Jeste bych na vas mel jednu otazku. Jakym zpusobem resite situaci, kdy
potrebujete vypsat neco, co zavisi na odpovedi databaze, coz zavisi na udajich,
ktere se vypisi v ramci foreach v latte?
Napriklad foreach v latte mi prochazi prispevky, ktere se zobrazji na homepage
a ja ke kazdemu prispevku potrebuji ziskat ID z databaze (to mam) a na zaklade
toho ID zavolat dalsi pozadavek do databaze a podle nej vypsat odpoved. Treba
muze jit o nejake oznaceni, zda uzivatel tento prispevek uz cetl.
Chtel jsem to resit v basepresenteru tak, ze z latte do nej zavolam funkci s argumentem obsahujicim ID a returnuji vysledek. Ale muzu v baseprezenteru pouzivat databazi? Cetl jsem, ze v basepresenteru nemuzu pouzivat __construct(), tak vubec nevim, jak se k $database dostanu. (Cannot read an undeclared property App\Presenters\HomepagePresenter::$database.) A neni to spatne reseni? Nerad bych se hned ze zacatku ubyral nejakym nevhodnym smerem.
Editoval hotline (22. 5. 2015 23:51)
- filipsedivy
- Člen | 37
Ano v BasePresenteru můžeš využít databázi, ale jen pouze pokud je to nezbytně nutné. Jako každý doporučuji pro komunikaci využít modely
Nějaký model může vypadat pro vytažení databáze takto
class Clanky extends \Nette\Object{
private $db;
public function __construct(Nette\Database\Context $db){
$this->db = $db;
}
}
Ale ještě si musíš tento model zaregistrovat v konfiguračním souboru
Pokud opravdu ale, nevíš, tak doporučuji juknout do sandboxu https://github.com/nette/sandbox který je jakýsi základ podle kterého se můžeš učit
Editoval filipsedivy (23. 5. 2015 0:13)
- Blujacker
- Člen | 89
Ale jak ten model dostat do BasePresenteru? Kdyby pouzil konstruktor
v BasePreenteru, tak by musel ve vsech dalsich presenterech volat
parent::__construct(model)
(pozdeji bude potreba dostat dalsi vec
do basepresenteru a nastalo by to, cemu zde rikaji constructor hell :-)
V tomto pripade bude asi nejlepsi pouzit metodu inject*
nebo
tusim, ze knihovna Kdyby/Autowired
toto resi take.
Doporucuji precist https://phpfashion.com/…i-zavislosti
- filipsedivy
- Člen | 37
Já si zatím vystačím s injekcí v BasePresenteru
class BasePresenter extends .... {
private $db;
public function injectDatabase(Nette\Database\Context $db){
$this->db = $db;
}
public function actionDefault(){
$row = $this->db->query("SELECT * FROM clanky");
// atd...
}
}
- Petr Hudík
- Člen | 49
Pokud to není nezbytně nutné a danou „funkci“ nepoužívají
skutečně všichni potomci BasePresenteru
, tak zvaž zda ji
umístit přímo do něj či využít jinou možnost. Problém je v tom, že
BasePresenter zbytečně bobtná a nakonec dělá všechno. V současné době
to pravděpodobně není důležité, ale pokud s Nette začínáš, je IMHO
nejlepší nenaučit se špatným návykům.
Pokud vím, tak doporučený způsob předávání závislostí do
presenteru je přes anotaci /** ... @inject
– uvnitř prezenteru
stačí napsat:
<?php
/** @var Nette\Database\Context @inject */
public $db;
?>
- hotline
- Člen | 41
Dekuji za rady, nejlepsi se mi zda inject pres anotaci, tak jsem to pouzil.
V souvislosti s BasePresenterem ted resim jeste ajax pro akci, ktera je
dostupna globalne na vsech strankach v ramci headeru.
Situace: V @layout.latte mam header, ve kterem je formular pro login
(zatim neni upraveny do podoby Nette Forms, ale o to tu ted nejde). To je na
kazde strance. Login resim ajaxem, tak se ho snazim prepsat do Nette, ale
narazil jsem hned v uvodu. Vychazim z navodu Simple ajax example a
snazim se presne to same zprovoznit u sebe. 1. cast (Setup) bych mel mit
v poradku, cast In presenter – v ukazce se pouziva konkretni presenter, ale
co kdyz bych to potreboval pouzivat globalne? Je i pro tento pripad
basepresenter vhodnou volbou? Zkousim to pres nej, ale nemuzu tam
pouzivat funkci
renderDefault()
, tak jsem to udelal takhle:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
public function handleChangeVariable()
{
$this->anyVariable = 'changed value via ajax';
if ($this->isAjax()) {
$this->invalidateControl('ajaxChange');
}
}
protected function createTemplate($class = NULL)
{
$template = parent::createTemplate($class);
$this->anyVariable = 'default value';
}
}
Ale ladenka mi hlasi chybu:
PHP User Warning: Invalid link: No route for PostDetail:default(do=changeVariable) in
<a class="ajax" href="<?php echo Latte\Runtime\Filters::escapeHtml($_control->link("changeVariable!"), ENT_COMPAT) ?>
Pouzivana routa je:
$router[] = new Route(‚<url>‘, ‚PostDetail:default‘);
Ale nefunguje ani $router[] = new Route(‚<url>/<action>‘,
‚PostDetail:default‘);
Tak nevim, jestli na to nejdu uplne spatne nebo jestli musim jeste neco resit v route. Anebo jestli neresim ajax pro vsechny stranky nevhodne. Libi se mi tohle reseni pres snippety, pokud jsem to pochopil spravne, tak nemusim pouzivat extra latte sablonu pro kazdou akci.
Moc diky za rady.
Editoval hotline (23. 5. 2015 17:00)
- filipsedivy
- Člen | 37
Pokud používáte changeVariable!
, tak se nejedná o výstup
presenteru, ale jedná se o handler, který je nutné v daném presenteru
registrovat. Tedy pokud máte tento handler na všech stránkách zvolte
BasePresenter.
public function handlerChangeVariable()
Tímto si registrujete handler
- hotline
- Člen | 41
V @layout (pouziva se na vsech strankach) mam:
<a n:href="changeVariable!" class="ajax">Change variable!</a>
V basepresenteru jsem mel:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
public function handleChangeVariable()
{
$this->anyVariable = 'changed value via ajax';
if ($this->isAjax()) {
$this->invalidateControl('ajaxChange');
}
}
}
Tak jsem zmenil hanldeChangeVariable() na handlerChangeVariable(), ale to mi dava chybu:
Invalid link: Unknown signal 'changeVariable', missing handler App\Presenters\PostDetailPresenter::handlechangeVariable()
Tak nevim, jestli jsme se spatne pochopili nebo porad delam neco spatne. Kazdopadne diky za ochotu.
Jeste jsem prisel na to, ze na homepage ($router[] = new Route('',
‚Homepage:default‘);) mi to error nedava, odkaz Change variable! obsahuje
get parametr (?do=changeVariable), ale po kliknuti se nic nedeje. Kdyz na ten
odkaz jdu manualne, dostanu:
Cannot write to an undeclared property App\Presenters\PostDetailPresenter::$anyVariable
.
Editoval hotline (23. 5. 2015 20:01)
- hotline
- Člen | 41
Diky, to jsem tam mel, tak nevim, kde by mohla byt chyba. Vychazim z navodu, ktery je pro Nette 2.0, tak se treba neco zmenilo. V aktualni dokumentaci je spis popsany manualni postup namisto chytre obnovy snippetu. Snad jsem muj postup popsal pochopitelne, kdyz tak se prosim zeptejte, ja si s tim fakt nevim rady uz.
Zjistil jsem, ze tady nekdo resil stejny problem a musel to obejit tak, jak ja nemuzu. Pouzivate nekdo funkcni ajax v ramci snippetu v Nette 2.3 nebo na to musim jinak?
Editoval hotline (23. 5. 2015 20:38)
- Unlink
- Člen | 298
No toto asi tak jednoducho možné nebude, ja by som skôr spravil na to
komponentu.
https://doc.nette.org/…n/components
Ale to závisí od toho, čo potrebuješ dosiahnuť.
- hotline
- Člen | 41
Aha. No je to docela jednoduche, potrebuji na kazde strance formular na prihlaseni a registraci, ktery bude fungovat ajaxove. Tak to je skoda, bez nette na to stacilo par radek jQuery (posilani udaju z formulare jsonem do externiho php scriptu, ktery jen odpovidal). Asi to tedy takto rucne udelam i v nette, nechci to moc komplikovat, kdyz to jde jednoduse, ale je to skoda, myslel jsem, ze na ajax je tu nejake chytre „udelatko“ (aneb po odeslani nerefreshuj celou stranku, ale jen stanoveny snippet).
Editoval hotline (23. 5. 2015 21:05)
- filipsedivy
- Člen | 37
(aneb po odeslani nerefreshuj celou stranku, ale jen stanoveny snippet)
Ale přesně to Nette dělá :)
- hotline
- Člen | 41
Ja vim, ale musim jit po komponente, takze to neni tak jednoduche, jak to zni
v dokumentaci pro ajax :-) 2 hodiny jsem se marne pokousel zprovoznit
(jakkoli, kdekoli) priklad na komponenty nette/examples/Fifteen, abych vedel, co
to vlastne vubec dela. Nebezi to nekde online? (edit: aha, bezi)
Pokusim se tedy bez prikladu jit na to pres dokumentaci, protoze v tom prikladu
je i nejaka jina souborova struktura, nez mam ja v nejnovejsi verzi (pritom to
vypada, ze je aktualni, jsem z toho zmateny), takze na to radsi koukat vubec
nebudu. Popravde jsem necekal, ze zprovozneni trivialniho ajaxu bude tak ohodne
obtiznejsi, nez bez frameworku.
Tak nevim, jestli se pro zacatek spis nepodivat treba na cakephp, u nej si pri velmi specifickem dotazu do googlu vybirate, jestli se podivate na 1 z xx tutorialu, youtube tutorial nebo precizni dokumentaci. U nette jsem rad, kdyz najdu alespon priblizne podobnou problematiku, ale vetsinou je stejne pro neaktualni verzi a nemuzu tak dane vysvetleni pouzit. To me na nette mrzi, verim, ze je to dobry framework, ale nedostatecna dokumentace tvori velkou barieru.
Editoval hotline (23. 5. 2015 23:23)
- Caine
- Člen | 216
Dokumentace je skutecne na dve veci (a to je imho i hlavni problem, proc ma problem prorazit do sveta), ale muzu te ubezpecit, ze kdyz prekonas tu silenou prvotni barieru (coz i dost casto zmanena reverse engineering), tak ti Nette spoustu veci velice usnadni a to vcetne psani AJAX aplikaci.. Kazdopadne to vyzaduje trpelivost (za me to bylo mesic, dva, nez jsem do toho trosku vice proniknul), a pokud se ji neobrnis, mozna bude lepsi zkusit jiny, lepe zdokumentovany, framework (laravel, symfony)… I kdyz, casem te stejne u kazdeho frameworku zacne zajimat, jak a proc to vevnitr vlastne funguje… ;)
- hotline
- Člen | 41
Myslim si, ze jsem docela trpelivy, kdyz jsem zacinal v uplne jinem jazyku, nevadilo mi resit cele dny neco, co ted mam za 10 minut. :D
Koukam tedy na komponenty. Pro zacatek mi bude stacit, kdyz komponenta vypise promennou.
Vytvoril jsem si slozku app/components a v ni:
LoginControl.php:
<?php
use Nette\Application\UI\Control;
class LoginControl extends Control
{
public function render()
{
$template = $this->template;
$template->setFile(__DIR__ . '/LoginControl.latte');
// vložíme do šablony nějaké parametry
$template->param = "neco";
// a vykreslíme ji
$template->render();
}
}
LoginControl.latte:
{$param}
V https://doc.nette.org/…s/form-reuse jsem nasel, ze musim provest registraci do configu jako service, coz se zda byt spravnym resenim, prestoze, se to vztahuje k postupu pro „UI\Form“ a ja postupuju podle dokumentace pro komponenty, kde je to reseno na urovni „UI\Control“, u ktereho se uvadi registrace do „factories“.
No nic, do neon configu jsem pridal service:` - LoginControl`. Pokud zmenim nazev tridy „LoginControl“ na neco jineho, vyhodi to chybu o tom, ze trida „LoginControl“ nebyla nalezena, takze se to zda byt jako spravne reseni.
Uz jsem ale nedohledal, co mam delat v presenterech, idealne v basepresenteru. Jakym zpusobem tam prosim vas komponentu nactu? V dokumentaci se uz navazuje na to, ze je nacteno – v casti „signaly“ se pise o HandleClick, ale to uz zase nenavazuje na prvni priklad s komponentou, tam nic o clicku neni. Tak jsem se v tom trochu ztratil. Prijde mi, jako kdyby to bylo psano jako rychly prehled pro ty, kteri chapou, jak cely framework funguje. Asi si budu muset zajit na skoleni, ale radsi bych tu castku venoval na lepsi a podrobnejsi dokumentaci od A do Z. Pokud by byla nejaka sbirka pro nekoho, kdo by se toho ujal, muzete s mym prispevkem pocitat. Verim, ze by to zvysilo i zajem o framework, a tim padem by vznikla dokonala symbioza, hodne veci by se pak dalo vyresit beznym dotazem do googlu.
- Blujacker
- Člen | 89
Do (base)presenteru se komponenta musi dostat konstruktorem nebo injectnutim, pridat tedy neco jako
function __construct(\KomponentyNamespace\LoginControl $loginControl){
$this->loginControl = $loginControl;
}
A ted v latte ktery se vykresluje spolecne s presenterem musis pridat
{control loginControl}
a do presenteru pridat metodu pro vytvoreni komponenty
protected function createComponentLoginControl(){
return $this->loginControl;
}
- David Matějka
- Moderator | 6445
@hotline v presenteru si vytvoris createComponent* metodu, kde
vytvoris instanci ty komponenty – bud rucne, nebo pomoci tovarny (jak je to
v tom tutorialu). Jen je na pla.nette deprecated info, ze se to ma uvest do
sekce factories
, ma se to napsat do sekce services
,
jinak bude postup stejny – tedy createComponentXXXX metoda, injectnuti
tovarny a vytvoreni instance komponenty.
komponenty samotne ale nikdy neregistruj jako sluzby, zpusobi ti to driv nebo pozdeji problemy – pouzivej tovarny
edit: jeste par relevatnich odkazu do doc:
- hotline
- Člen | 41
Diky, ale podle toho co jsem cetl, tak v basepresenteru nemuzu pouzivat konstruktor. Jak to prosim injectnu?
Muj basepresenter ted vypada takto:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
/** @var Nette\Database\Context @inject */
public $database;
protected function createComponentLoginControl(){
return $this->loginControl;
}
protected function createTemplate($class = NULL)
{
$template = parent::createTemplate($class);
}
}
//edit: psano pred tvym prispevkem, Davide, diky, mrknu se na to
Editoval hotline (24. 5. 2015 17:22)
- hotline
- Člen | 41
Dobre, diky, zkousim zprovoznit postup z pla.nette (ten druhy – https://doc.nette.org/…s/form-reuse#…). Postupoval jsem takto:
LoginControl.php
<?php
use Nette\Application\UI\Control;
class CategoryForm extends Control
{
private $database;
public $onCategorySave;
public function __construct(Nette\Database\Connection $database)
{
parent::__construct();
$this->database = $database;
}
protected function createComponentForm()
{
$form = new UI\Form;
// mohu použít $this->database
$form->addSubmit('send', 'Odeslat');
$form->onSuccess[] = $this->processForm;
return $form;
}
public function processForm($form)
{
// mohu použít $this->database
// zpracování formuláře, např. změním údaje upravované kategorie
// $category je nějaký řádek tabulky (entita), kterou zpracováváme
$this->onCategorySave($this, $category);
}
}
/** rozhranní pro generovanou továrničku */
interface ICategoryFormFactory
{
/** @return \CategoryForm */
function create();
}
basepresenter.php
<?php
namespace App\Presenters;
use Nette,
App\Model;
/**
* Base presenter for all application presenters.
*/
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
/** @var Nette\Database\Context @inject */
public $database;
/** @var \ICategoryFormFactory @inject */
public $categoryFormFactory;
protected function createTemplate($class = NULL)
{
$template = parent::createTemplate($class);
$teplate->test = $categoryFormFactory;
}
}
Services:
services:
- App\Model\UserManager
- App\Forms\SignFormFactory
router: App\RouterFactory::createRouter
- ICategoryFormFactory
Nyni dostavam chybu: Undefined variable: categoryFormFactory
V basepresenteru ale jeste chybi:
protected function createComponentCategoryForm()
{
$control = $this->categoryFormFactory->create();
$control->onCategorySave[] = function(CategoryControl $control, $category) {
$this->redirect('this');
// nebo například přesměrujeme na detail dané kategorie
// $this->redirect('detail', array('id' => $category->id));
}
return $control;
}
Tam mi totiz radka return $control; dava syntax error.
Nevite kde jsem udelal chybu? Diky.
- David Matějka
- Moderator | 6445
Nyni dostavam chybu: Undefined variable: categoryFormFactory
na tridni property se nemuzes takto, viz php doc
Tam mi totiz radka return $control; dava syntax error.
za tou closurou chybi strednik, uz jsem poslal pr s opravou: https://github.com/…ll/300/files
- hotline
- Člen | 41
Aha, diky, toho jsem si nevsiml. Tak ted mam:
namespace App\Presenters;
use Nette,
App\Model;
/**
* Base presenter for all application presenters.
*/
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
/** @var Nette\Database\Context @inject */
public $database;
/** @var \ICategoryFormFactory @inject */
public $categoryFormFactory;
protected function createComponentCategoryForm()
{
$control = $this->categoryFormFactory->create();
$control->onCategorySave[] = function(CategoryControl $control, $category) {
$this->redirect('this');
// nebo například přesměrujeme na detail dané kategorie
// $this->redirect('detail', array('id' => $category->id));
};
return $control;
}
protected function createTemplate($class = NULL)
{
$template = parent::createTemplate($class);
}
}
Ale porad nerozumim tomu, jak tu komponentu dostanu do presenteru. Nebo uz jen neco dopsat do latte (v dokumentaci je ke komponente i samostatny latte soubor, v tomto tutorialu ne, tak nevim)? Bohuzel vubec nerozumim tomu, co jsem ted udelal, spis bych to rad zprovoznil a sledoval, co a jak se deje v jake promenne, apod., abych pochopil. Jen jsem tupe zkopiroval kod, aby mi komponenta cokoli vypsala. Timhle dokumentace i tutorial konci, opravdu tedy nevim, muzes mi prosim poradit, co jeste schazi? Jde mi opravdu jen o zprovozneni jakekoli komponenty od zacatku do konce, abych s tim pak mohl nejak pracovat.
- David Matějka
- Moderator | 6445
Timhle dokumentace i tutorial konci
nikoliv, pokracuje nasledovne:
V šabloně je možné získat a vykreslit komponentu pomocí makra {control}. Není proto potřeba manuálně komponenty předávat do šablony.
<h2>Editační formulář</h2>
{control editForm}
- Unlink
- Člen | 298
No do layoutu si tu komponentu zobrazíš
@layout.latte
{control categoryForm}
potom si spravíš layout pre tú komponentu
categoryForm.latte a umiestniš ju do zložky s tou
triedou
obsah
{control form}
potom do CategoryForm pridáš metodu render
public function render()
{
$this->template->setFile(__DIR__.'/categoryForm.latte');
$this->template->render();
}
Ono tá vlastná šablóna je v tomto prípade zbytočná a stačí ísť prvým spôsobom, no na druhej strane, teraz do tej šablóny komponenty môžeš pridať aj niečo iné ako obyčajný formulár.
Editoval Unlink (24. 5. 2015 21:08)
- hotline
- Člen | 41
Dekuji, ono se o tom pise jeste v dokumentaci presenteru, toho jsem si nevsiml. Sablonu jsem si udelal taky, abych pro priste vedel, dobry napad.
Komponenta ted vypada takto:
<?php
use Nette\Application\UI\Control;
class CategoryForm extends Control
{
private $database;
public $onCategorySave;
public function __construct(Nette\Database\Connection $database)
{
parent::__construct();
$this->database = $database;
}
protected function createComponentForm()
{
$form = new UI\Form;
// mohu použít $this->database
$form->addSubmit('send', 'Odeslat');
$form->onSuccess[] = $this->processForm;
return $form;
}
public function processForm($form)
{
// mohu použít $this->database
// zpracování formuláře, např. změním údaje upravované kategorie
// $category je nějaký řádek tabulky (entita), kterou zpracováváme
$this->onCategorySave($this, $category);
}
public function render()
{
$this->template->setFile(__DIR__.'/categoryForm.latte');
$this->template->render();
}
}
/** rozhranní pro generovanou továrničku */
interface ICategoryFormFactory
{
/** @return \CategoryForm */
function create();
}
A na radce $form = new UI\Form;
se vyskytla chyba:
Class 'UI\Form' not found
Neni tam jeste neco neaktualniho nebo jsem nekde udelal chybu? :(
Editoval hotline (24. 5. 2015 21:25)
- hotline
- Člen | 41
Diky moc, vse se podarilo a splnil jsem tak vcerejsi ukol – vypsat cokoli z komponenty. :D Prakticky jsem temer celou aplikaci prepsal do Nette a musim uznat, ze uspora casu je videt dost vyrazne. Jedine, co mi vsak chybi, jsou formulare a ajaxy. To tedy musim resit pres komponenty, se kterymi trochu zapasim a nepodarilo se mi do nich proniknout.
Moje opsana komponenta vypada nasledovne. Rad bych ji ted upravil do ajaxoveho formulare, ktery vypise do urciteho divu nebo snippetu vysledek pozadavku (vyplnte jmeno, vyplnte heslo, udaje se neshoduji, apod.) a bude provadet operace uvnitr (overovani, prihlaseni, presmerovani). Predpokladam, ze pro tento ucel je komponenta porad idealni volbou.
<?php
use Nette\Application\UI\Control;
class CategoryForm extends Control
{
private $database;
public $onCategorySave;
public function __construct(Nette\Database\Connection $database)
{
parent::__construct();
$this->database = $database;
}
protected function createComponentForm()
{
$form = new \Nette\Application\UI\Form();
// mohu použít $this->database
$form->addSubmit('send', 'Odeslat');
$form->onSuccess[] = $this->processForm;
return $form;
}
public function processForm($form)
{
$this->onCategorySave($this, $category);
}
public function render()
{
$this->template->setFile(__DIR__.'/categoryForm.latte');
$this->template->render();
}
}
/** rozhranní pro generovanou továrničku */
interface ICategoryFormFactory
{
/** @return \CategoryForm */
function create();
}
protected function createComponentForm()
– toto tlacitko na
odeslani (resp. formular) se v sablonach vykresluje diky snippetu
{control categoryForm}
. Ale jak Nette vi, ze ma pri vykresleni
volat metodu createComponentForm()
? Vubec nikde neni jeji nazev
uvedeny, vazne nikde. Chapu, ze zacatecni nazev „createComponent“ muze byt
bran jako nejaky standard Nette, ale presto, nikde neni uvedeno volani
„Form“.
Naopak metoda render()
se zrejme vubec nepouziva, protoze uvedeny
soubor latte neexistuje a chybu to nikde nedava (az po odeslani, ale to je
pochopitelne – nebo ten soubor slouzi pro vykresleni odpovedi?). Pokud chci
na kazde strance vykreslovat login formular, tak vlastni latte soubor asi ani
nebudu potrebovat, jen v layoutu zavolam snippet {control nazev}, aby se
vykresila komponenta.
Nebo jsem „zivotni cyklus“ komponenent vubec nepochopil?
Po odeslani formulare se vola metoda processForm(), ale ta taky nikde neni
definovana. Opet jde o nejaky standard?
Pokud bych rad pochopil i princip, muzu se zeptat, proc se vola zrovna
metoda createComponentForm()
?
V basepresenteru mam:
/** @var \ICategoryFormFactory @inject */
public $categoryFormFactory;
protected function createComponentCategoryForm()
{
$control = $this->categoryFormFactory->create();
$control->onCategorySave[] = function(CategoryControl $control, $category) {
$this->redirect('this');
// nebo například přesměrujeme na detail dané kategorie
// $this->redirect('detail', array('id' => $category->id));
};
return $control;
}
Nevite, proc je akce po odeslani resena na dvou mistech? V komponente je ulozeni dat a tady presmerovani.
Asi to bude slozitejsi, tak bych se spis podival na prednasku https://www.youtube.com/watch?… (zatim jsem koukal jen na
prvni minuty a vypada to velmi srozumitelne), ale chtel bych se nejdriv zeptat,
jestli tam nejsou nejake vetsi rozdily co se tyce prezentovane verze 2.0 a mou
verzi 2.3.0.
Moc si cenim vasich trpelivych odpovedi, verim, ze mnoho zacatecniku ma podobne
otazky jako ja a bude jim take vlakno prinosne.
Editoval hotline (25. 5. 2015 15:42)
- David Matějka
- Moderator | 6445
uvedeny soubor latte neexistuje
musis ho vytvorit, ten navod pocita
s nejakou znalosti komponent, tak to tam ani neuvadi. Proste udelej
categoryForm.latte s obsahem {control form}
Po odeslani formulare se vola metoda processForm(), ale ta taky nikde neni definovana
je, v komponente je metoda public function processForm($form)
,
tam nejdriv ulozis do databaze a pak zavolas udalost onCategorySave
Nevite, proc je akce po odeslani resena na dvou mistech? V komponente je ulozeni dat a tady presmerovani.
dela se to kvuli snadne znovupouzitelnosti komponent. Tu komponentu pak muzes pouzit kdekoliv jinde a v presenteru jen zmenis, co se ma stat po odeslani.
ale chtel bych se nejdriv zeptat, jestli tam nejsou nejake vetsi rozdily co se tyce prezentovane verze 2.0 a mou verzi 2.3.0.
ten zaklad je porad stejny. od 2.1 tu akorat jsou generovany tovarny (ten interface), ale to je takovy bonus :)
- hotline
- Člen | 41
Diky, ten video tutorial je super.
Ale od doby, co jsem pridal nejake formulare vzdy dostavam v ladence User Warning (ktery muzu preskocit a zda se to byt funkcni). Nevite kde by mohl byt problem? Kdyz formular smazu, vse je ok.
Invalid link: No route for Prispevek:default()
Pouzita routa:
new Route('<url>', 'Prispevek:default');
Tracy bar ukazuje spravnou shodu v route.
Matches - yes Route <url>
presenter = Prispevek
action = default
Prispevek:default
url = nazev-prispevku
Vyskytuje se na radce latte pro Prispevek, kde je snippet {control registrationForm}. Dany presenter obsahuje toto:
<?php
namespace App\Presenters;
use Nette,
App\Model;
/**
* Prispevek presenter.
*/
class PrispevekPresenter extends BasePresenter
{
public $database;
public function __construct(Nette\Database\Context $database)
{
$this->database = $database;
}
protected function createComponentRegistrationForm()
{
$form = new Nette\Application\UI\Form ;
$form->addText('name', 'Jméno:');
$form->addPassword('password', 'Heslo:');
$form->addSubmit('login', 'Registrovat');
$form->onSuccess[] = array($this, 'registrationFormSucceeded');
return $form;
}
// volá se po úspěšném odeslání formuláře
public function registrationFormSucceeded(Nette\Application\UI\Form $form, $values)
{
// ...
$this->flashMessage('Byl jste úspěšně registrován.');
$this->redirect('Homepage:');
}
}
Stejny problem byl jsem mel i kdyz jsem komponentu vytvarel v app/components, zaregistroval ji jako service a injectoval ji do presenteru. Ted jsem jen zkusil zakladni formular, jestli jsem predtim neudelal nekde chybu. Pritom vse v tento komponente je funkcni, probehne i presmerovani se zobrazenim flash message.
Diky za rady.
Editoval hotline (26. 5. 2015 20:20)
- David Matějka
- Moderator | 6445
To je takove trochu nette-wtf, jak vytvari odkazy na this
. Aby
parametr url
(ktery mas v route jako povinny) zustal pri
odkazovani na this
, je nutne aby bud:
- byl persistentnim parametrem
- byl uveden jako parametr v signature prislusne action/render metody (jako to muzes videt treba tady)
takze staci, kdyz pridas do tveho presenteru:
public function actionDefault($url) //nebo klidne renderDefault
{
}
- Tomáš Kolinger
- Člen | 136
Tohle vlákno není o tom, zda Nette ulehčuje vývoj či naopak, ale o tom, že se to vůbec nesnažíš pochopit či si dohledat informace sám. Třeba hned první dotaz o routování – vše by ses dozvěděl, kdyby sis přečetl dokumentaci a zapojil do toho trochu logického uvažování.
Připadá mě, že někam furt spěcháš a chceš to honem napsat. Což je naprosto nevhodný, protože očividně s Nette nemáš žádný zkušenosti a potřebuješ čas, aby si překonal tu prvotní informační bariéru. Což znamená si číst dokumentaci či příklady a pomalu experimentovat s tou danou částí aplikace. Pokud potřebuješ teď něco rychle realizovat, tak to radši realizuj v tom, co znáš.
- kalatalabnik
- Člen | 35
- Filip Procházka
- Moderator | 4668
@hotline otvírej prosím nová témata na jednotlivé problémy (nikoliv jedno další téma na 10 dalších problémů), tohle ja chaos, ve kterém se už nikdo nikdy nevyzná a nikomu dalšímu kromě tebe to nepomůže. Díky.
Zamknuto a přesunuto do začátečníci. A strašně mě iritoval ten titulek, tak jsem ho taky změnil.