rozšíření Todolistu z quickstartu o editaci úkolů

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

Zdravím,
s frameworkem se učím teprve krátce a jelikož mi příliš nepomáhá opisovat zdrojáky z tutorialu a uznávat že až na pár nepřesností to funguje, potřebuji něco „vymyslet sám“. Řekl jsem si že rozšířit základní aplikaci z quickstartu o editaci by nemělo být nic složitého, ale zasekl jsem se na předvyplnění formuláře hodnotamy z tabulky.

Do souboru TodolistPresenter.php jsem přidal funkce

public function actionEdit($id) {
}

public function renderEdit()	{
}

A ještě před ně o poznání důležitější

public function createComponentEditForm($id)	{
    $todo = $this->model->findTodo($id);
    $form = new Nette\Application\UI\Form;
    $form->addText('text', 'Úkol', 60, 100)
	->addRule(Form::FILLED, 'Musíte vyplnit text!')->setDefaultValue($todo->text);
    $form->addSubmit('save', 'Uložit');
    $form->addSubmit('back', 'Zpět')->setValidationScope(NULL);

    $form->onSuccess[] = callback($this, 'processEditForm');

    return $form;
  }

Samozřejmě jsem si vytvořil ještě soubor edit.phtml a přidal ještě odpovídající akce.

V případě že spustím editační formulář však obdržím hlášku že na řádku kde je setDefaultValue dělám objekt z proměnné která objekt není. To mi nehrálo a tak jsem tam zkusil jako základní hodnotu vložit jen samotné $id, abych věděl jestli se dobře předává proměnná – a ve formuláři mám místo předaného id v políčku s textem nápis „editForm“.

Na editační formulář odkazuji pomocí kódu

<a href="{link edit $todo->id}">editovat</a>

tento odkaz je v souboru show.phtml.

Poradí mi někdo co dělám špatně? Určitě to bude nějaká nad slunce jasná začátečnická chyba…

22
Člen | 1478
+
0
-

čau, problém, který vidím na první pohled je tady:

public function createComponentEditForm($id) {}

Komponentě takto nelze předat parametr, protože v konstruktoru očekáva něco jiného viz. API

takže id tam musíš dopravit jinak, z hlavy mě napadají minimálně tyto 2 možnosti

  • naplnit data do formu v action metodě:
public function actionEdit($id) {
	$todo = $this->model->findTodo($id);
	$form = $this->getComponent('editForm');
	$form['text']->setValue($todo->text);
}
  • získat id z URL
public function createComponentEditForm()    {
    $todo = $this->model->findTodo($this->getParam('id'));

    $form = new Nette\Application\UI\Form;
    $form->addText('text', 'Úkol', 60, 100)
        ->addRule(Form::FILLED, 'Musíte vyplnit text!')->setDefaultValue($todo->text);
    $form->addSubmit('save', 'Uložit');
    $form->addSubmit('back', 'Zpět')->setValidationScope(NULL);

    $form->onSuccess[] = callback($this, 'processEditForm');

    return $form;
}

Editoval 22 (7. 9. 2011 2:54)

powercz
Člen | 12
+
0
-

Zdravím,

už továrničku máš špatně napsanou, použij:

protected function createComponentEditForm()

22 napsal(a):

dovolil bych si trochu upravit tvé řešení:

public function actionEdit($id) {
        $todo = $this->model->findTodo($id);
        $this->getComponent('editForm')->setDefaults($todo);
}

případně

public function createComponentEditForm()    {
    $todo = $this->model->findTodo($this->getParam('id'));

    $form = new Nette\Application\UI\Form;
    $form->addText('text', 'Úkol', 60, 100)
        ->addRule(Form::FILLED, 'Musíte vyplnit text!');
    $form->addSubmit('save', 'Uložit');
    $form->addSubmit('back', 'Zpět')->setValidationScope(NULL);

    $form->onSuccess[] = callback($this, 'processEditForm');

    $form->setDefaults($todo);

    return $form;
}
honorguard
Člen | 9
+
0
-

Díky všem, jedn z popsaných metod určitě použiju. Aspoň vím jak se proměnné předávají a nepředávají.

Co znamená to „protected“ před slovem function? Mám to použít i u vkládacího formuláře a proč?

Mám v php napsané své vlastní CMS a programoval jsem ho (bohužel) úplně jiným stylem a tak mám v MVS a Nette vůbec trošku hockey. Snad jednou přijde doba kdy taky budu moct lidem poradit, ale asi to bude chvilku trvat…

VaKvas
Začátečník | 111
+
0
-

honorguard napsal(a):

Co znamená to „protected“ před slovem function? Mám to použít i u vkládacího formuláře a proč?

Udava se tim pristupnost.
Protected znamena, ze na jeji metody a atributy muze jen samotna trida a jeji pribuzni (potomci, predci).

Pak je jeste private a to to muze jen samotna trida. No a public je pro vsechny..

powercz
Člen | 12
+
0
-

honorguard napsal(a):

Public, protected a private je viditelnost tříd, proměnných a metod. Něco si o tom můžeš přečíst např.: Živě.cz

honorguard
Člen | 9
+
0
-

Význam slov public a private jsem znal, ale protected pro mě bylo záhadou, děkuji.

Zcela „nečekaně“ jsem se zasekl hned u dalšího kroku – uložení hodnot do databáze.

V souboru TodoManager mám funkci

public function editTodo(Todo $todo)	{
	return dibi::query('UPDATE [tasks]', (array) $todo);
}

Dibi je pro mě taky novinka, netuším proč je jméno tabulky v hranatých závorkách, ani co znamená slovo array v závorce, je to víceméně upravená jiná funkce z quickstartu a zaručeně je tam něco zásadního špatně, protože mi to píše chybu SQL syntaxe.

//EDIT
za název tabulky jsem přidal ještě slovo SET a žádná chyba – ale zase se mi změnily všechny záznamy v tabulce :-D. Možná je na čase si přečíst něco o tom jak se používá dibi…

//EDIT
Takže kód jsem upravil následovně

public function editTodo(Todo $todo)	{
	return dibi::query('UPDATE [tasks] SET', (array) $todo, 'WHERE [id]=%i', $todo->id);
}

Když $todo->id natvrdo nahradím číslem funguje to, jediný problém je jak správně předat id, protože tento zápis nefunguje (chyba Undefined property: todo::$id), ale text se normálně předá a uloží – napadá někoho kde je problém?
Předem dík

Editoval honorguard (7. 9. 2011 15:24)

powercz
Člen | 12
+
0
-

honorguard napsal(a):
netuším proč je jméno tabulky v hranatých závorkách…

Kvůli různým databázím, pro MySQL se vygeneruje dotaz

// UPDATE `tasks` SET...

pro ODBC

// UPDATE [tasks] SET...

(array) znamená přetypování, object $todo se přetypuje na pole, aby jej bylo možné uložit do databáze. Mrkni se do Dibi dokumentace

A proč se ti změnily všechny záznamy v tabulce? :D Neurčil jsi, který řádek se má updatovat (WHERE), tak se updatují všechny :)

honorguard
Člen | 9
+
0
-

Aaaa, dibi umí pracovat s více typy databází :-D. Dobrá vychytávka, že jsem to nepoužíval dřív… teď už jen vědět jak tam dostat to id, ale možná už chápu proč je tam ta chyba – jestli se todo přetypovalo na pole tak to totiž není objekt… pokud je teda moje teorie správná :-D.

čili, jak správně předat do dotazu id?

powercz
Člen | 12
+
0
-

honorguard napsal(a):
čili, jak správně předat do dotazu id?

Předpokládám že máš id upravovaného řádku uložené v $todo, vyřešil bych to takto:

public function editTodo(Todo $todo)    {
	$todo = (array) $todo;
        return dibi::query('UPDATE [tasks] SET', $todo, 'WHERE todo_id=%i',$todo['todo_id']);
}

Pokud ne, tak si předej $todo_id do metody editTodo(Todo $todo, $todo_id) …

hAssassin
Člen | 293
+
0
-

@honorguard > zdravim, jak vytvaris ten objekt Todo, ktery pak posilas do ty metody editTodo? Resp. jak zjistis jeho ID? Jelikoz ve formulari zadny hidden s id nemas a metodu processEditForm jsi neuvedl. Takze jestli chyba neni tady, ale spis jen tipuju.

honorguard
Člen | 9
+
0
-

Zkoušel jsem to udělat tak jak radí Powercz, ale neuspěl jsem, nakonec jsem to vyřešil předáním id v argumentech v metodě processEditForm, kterou uvádím níže pro doplnění:

public function processEditForm(Nette/Application/UI/Form $form)	{
	if($form['save']->isSubmitedBy())	{
		$this->flashmessage('Úkol byl změněn.');
		$values = $form->getValues();

		$todo = new Todo;
		$todo->text = $values['text'];
		$todo_id = $this->getParam('id')	//tady získám id z adresy
		$this->model->editTodo($todo, $todo_id);
	}
	$this->redirect('Todolist:show');
}

S tím získáním $id z adresy a předáním v argumentech to funguje výborně, takže všem díky za pomoc.

Ještě jeden začátečnický dotaz – jak v následujícím příkladu v metodě onmouseover použít makro pro předání proměnné $basePath?

<img src="{$basePath}/images/adresa_obrazku.gif" onmouseover="this.src='{$basePath}/images/obrazek.gif'" />

Zkoušel jsem nastavit podle quickstartu dvojitý zápis závorek, ale vždycky se mi kolem té adresy v $basePath objeví nějaké znaky se slovy quote. Jak vyřešit tento zápis? Případně má Nette nějaké vlastní prostředky jak změnit obrázek po najetí myší a při odjetí zase na jiný obrázek?

Předem díky