Routování, filtery, komponenty a další

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
hotline
Člen | 41
+
-7
-

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
+
+8
-

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 :)

Felix
Nette Core | 1247
+
0
-

Myslim, ze ze zacatku, je to trochu obtizne. Pokud clovek nezna syntaxy a dalsi veci. Ale urcite te to v budoucnu neomezuje a ani nespomaluje.

hotline
Člen | 41
+
0
-

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
+
+3
-

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
+
0
-

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
+
+2
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
-1
-

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
+
0
-

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)

Caine
Člen | 216
+
+2
-

public function handleChangeVariable()

hotline
Člen | 41
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

(aneb po odeslani nerefreshuj celou stranku, ale jen stanoveny snippet)

Ale přesně to Nette dělá :)

hotline
Člen | 41
+
0
-

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
+
0
-

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… ;)

Namespace
Člen | 81
+
+4
-

Já jsem s dokumentací celkem spokojen. Důležité věci tam jsou a podrobnosti najdeš v api.nette.org.

hotline
Člen | 41
+
0
-

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
+
-3
-

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
+
0
-

@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
+
0
-

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)

Azathoth
Člen | 495
+
0
-

v base presenteru injectuj vždycky pomocí @inject anotace do public proměnné.

David Kudera
Člen | 455
+
0
-

nejen v base ;-)

hotline
Člen | 41
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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)

Blujacker
Člen | 89
+
0
-

Spatny namespace, bud se na zacatek musi pridat use Nette\Application\UI\Form; nebo pouzit $form = new \Nette\Application\UI\Form;

Unlink
Člen | 298
+
0
-

Problém bude v namespace
Trieda je v \Nette\Application\UI\Form

Takže buď to prepíš na new \Nette\Application\UI\Form()

alebo si pridaj use

čiže nejako takto to bude vyzerať:

use Nette\Application\UI\Control,
    Nette\Application\UI;

Editoval Unlink (24. 5. 2015 21:32)

hotline
Člen | 41
+
0
-

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
+
0
-

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
+
0
-

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
+
+1
-

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:

  1. byl persistentnim parametrem
  2. 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
{

}
hotline
Člen | 41
+
0
-

Aha, diky moc za radu. Ja uz tam mel renderDefault metodu, akorat jsem tedy pridal argument $url a warningy zmizely. :)

Tomáš Kolinger
Člen | 136
+
+15
-

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
+
+2
-

Taky se @hotline můžeš stavit na posobotě (tuto sobotu) a zúčasnit se workshopu pro začátečníky…

newPOPE
Člen | 648
+
+2
-

Zavrite to tu uz!

Filip Procházka
Moderator | 4668
+
+5
-

@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.