Předání parametru z Action do komponenty formuláře (pro zpracování formuláře)
- Croc
- Člen | 270
Zdravím,
řeším takový drobný refactoring presenterů a formulářů. Chtěl bych se
zeptat, jestli a jak je možné předat parametr z action pro vytvoření
formuláře v komponentě do zpracování formuláře.
Příklad:
Presenter:
class ItemPresenter extends BasePresenter
{
/** @var FormFactory
* @inject
*/
public $formFactory;
protected function createComponentForm()
{
$form = $this->formFactory->create();
$form->onSuccess[] = function ($form) {
if ($this->id_item)
$form->getPresenter()->redirect('.....');
else
$form->getPresenter()->redirect('.....');
};
return $form;
}
public function actionForm($guid)
{
if(!$this->user->isLoggedIn()) {
$this->redirect('Sign:in');
}
if ($guid) { //pokud GUID existuje jedná se o edit existujícího, je nutné načíst data do formu
$this->id_item = $this->itemRepository->getItemID($guid);
if (!$this->id_item) {
throw new BadRequestException;
}
if (!$this->itemManager->authenticateItemOwner($this->id_item)) {
$this->error('Toto není Váš předmět!');
}
$values = $this->itemRepository->getItemFormData($this->id_item);
$this['form']->setDefaults($values);
}
}
}
FormFactory:
class FormFactory extends Nette\Object
{
/** @var Nette\Security\User */
public $user;
/** @var \App\Model\ItemManager */
public $itemManager;
protected $translator;
public $id_item;
public function __construct($id_item = NULL, Nette\Security\User $user, Model\ItemManager $itemManager, \Kdyby\Translation\Translator $translator)
{
$this->id_item = $id_item;
$this->user = $user;
$this->itemManager = $itemManager;
$this->translator = $translator;
}
public function create()
{
$form = new Form;
//....
$form->onSuccess[] = array($this, 'formSucceeded');
return $form;
public function formSucceeded($form, $values)
{
if(!$this->user->isLoggedIn()) {
$this->getPresenter()->redirect('Sign:in');
}
if($this->id_item){ // zde si potřebuji sáhnout na $this->id_item z actionForm ItemPresenteru
if(!$this->itemManager->authenticateItemOwner($this->id_item)){
$this->error('Toto není Váš předmět!');
}
$this->ItemManager->update($this->id_item, $values);
}
else {
$this->ItemManager->add($values);
}
}
Aktuálně ho předávám do create formuláře pošlu ho jako hidden pole. Následně jsem zkoušel výše uvedený postup, ale bohužel se ID nepřenese… Prosím tedy o radu co dělám špatně. Díky moc
Editoval Croc (6. 11. 2015 10:20)
- F.Vesely
- Člen | 369
Ja to delam takhle:
class EditItemControl extends Control
{
public $onSave = [];
/** @var Nette\Security\User */
protected $user;
/** @var \App\Model\ItemManager */
protected $itemManager;
protected $translator;
protected $id_item;
public function __construct($id_item = NULL, Nette\Security\User $user, Model\ItemManager $itemManager, \Kdyby\Translation\Translator $translator)
{
$this->id_item = $id_item;
$this->user = $user;
$this->itemManager = $itemManager;
$this->translator = $translator;
}
public function render()
{
$this['form']->render();
}
protected function createComponentForm()
{
$form = new Form;
//....
$form->onSuccess[] = array($this, 'formSucceeded');
$values = $this->itemRepository->getItemFormData($this->id_item);
$form->setDefaults($values);
return $form;
}
public function formSucceeded($form, $values)
{
if(!$this->user->isLoggedIn()) {
$this->getPresenter()->redirect('Sign:in');
}
if($this->id_item){ // zde si potřebuji sáhnout na $this->id_item z actionForm ItemPresenteru
if(!$this->itemManager->authenticateItemOwner($this->id_item)){
$this->error('Toto není Váš předmět!');
}
$this->ItemManager->update($this->id_item, $values);
}
else {
$this->ItemManager->add($values);
}
$this->onSave();
}
}
interface IEditItemControlFactory
{
/**
* @return EditItemControl
*/
public function create($id_item = null);
}
class ItemPresenter extends BasePresenter
{
/** @var IEditItemControlFactory
* @inject
*/
public $formFactory;
protected function createComponentForm()
{
$form = $this->formFactory->create($this->id_item);
$form->onSave[] = function () {
if ($this->id_item)
$this->redirect('.....');
else
$this->redirect('.....');
};
return $form;
}
public function actionForm($guid)
{
if(!$this->user->isLoggedIn()) {
$this->redirect('Sign:in');
}
if ($guid) { //pokud GUID existuje jedná se o edit existujícího, je nutné načíst data do formu
$this->id_item = $this->itemRepository->getItemID($guid);
if (!$this->id_item) {
throw new BadRequestException;
}
if (!$this->itemManager->authenticateItemOwner($this->id_item)) {
$this->error('Toto není Váš předmět!');
}
}
}
}
- Croc
- Člen | 270
Díky za tip, mám ale ještě otázku.
Jak jsem uvedl v příkladu výše, když volám metodu
$values = $this->itemRepository->getItemFormData($this->id_item);
,
tak tyto data použiju pro naplnění formu, ale 3 parametry zobrazuju také
v té šabloně (součást nadpisu) a hlavně 2 parametry potřebuji už při
vytváření formu pro načtení hodnot do dvou selectů ve fromuláři.
Pokud přemístím toto volání do createComponentForm()
ve
třídě EditItemControl
tak mi ty data budou chybět v šabloně
a při vytváření formuláře pro selecty. Musel bych tedy volat DB znovu
v action presenteru pro získání těchto hodnot.
Data z metody getItemFormData($this->id_item)
tedy použiji
celkem 3x:
- V šabloně jako nadpis
- Při vytvoáření formu pro načtení hodnot do dvou selectů
- Pro vyplnění defaultních hodnot formu
Existuje tedy i jiné řešení této situace?
Editoval Croc (6. 11. 2015 14:19)
- Croc
- Člen | 270
Bohužel mi dle výše uvedeného způsobu nejde předat ID ani všechny data, evidentně dělám něco špatně. Zde je můj kód:
ItemFormFactory.php
namespace App\Forms;
use Nette,
Nette\Application\UI\Control,
Nette\Application\UI\Form,
App\Model,
App\Repository;
class ItemFormControl extends Control
{
public $onSave = [];
/** @var Nette\Security\User */
protected $user;
/** @var \App\Model\UtilsManager */
protected $utilsManager;
/** @var \App\Repository\TypeRepository */
protected $typeRepository;
/** @var \App\Model\ItemManager */
protected $itemManager;
protected $translator;
protected $item = NULL;
protected $category = 'xy';
public function __construct($category = 'xy', $item = NULL, Nette\Security\User $user, Model\UtilsManager $utilsManager, Model\ItemManager $itemManager, Repository\TypeRepository $typeRepository, \Kdyby\Translation\Translator $translator)
{
$this->item = $item;
$this->category = $category;
$this->user = $user;
$this->utilsManager = $utilsManager;
$this->itemManager = $itemManager;
$this->typeRepository = $typeRepository;
$this->translator = $translator;
}
public function render()
{
$this['itemForm']->render();
}
public function createComponentItemForm()
{
$form = new Form;
$form->setTranslator($this->translator->domain('forms'));
//...
$form->addSelectize('id_category', 'labels.category_name', $this->utilsManager->loadCategory($this->translator->getLocale(), $this->category));
//....
$form->addSelectize('param', 'labels.param_name', $this->typeRepository->getTypesPairs($this->category));
$form->addProtection('forms.time_limit');
$form->addSubmit('send', 'buttons.send');
$form->onSuccess[] = array($this, 'formSucceeded');
$this['itemForm']->setDefaults($this->item);
return $form;
}
public function formSucceeded($form, $values)
{
if(!$this->user->isLoggedIn()) {
$this->getPresenter()->redirect('Sign:in');
}
if($this->item){
if(!$this->itemManager->authenticateItemOwner($this->item->id_item)){
$form->getPresenter()->redirect('Homepage:');
}
}
$this->itemManager->addItem($values, $this->item->id_item);
$this->onSave();
}
}
interface IItemFormControl
{
/**
* @return ItemFormControl
*/
public function create($category = 'xy', $item = null);
}
ItemPresenter.php
<?php
namespace App\Presenters;
use Nette,
App\Form,
App\Forms\IItemFormControl;
class ItemPresenter extends BasePresenter
{
/** @var IItemFormControl
* @inject
*/
public $itemFactory;
private $database;
private $item;
private $guid;
private $id_item;
private $category;
public function __construct(Nette\Database\Context $database)
{
$this->database = $database;
}
protected function createComponentItemForm()
{
$form = $this->itemFactory->create($this->category, $this->item);
$form->onSave[] = function ($form) {
if ($this->guid)
$form->getPresenter()->redirect('Item:profile', array('guid' => $this->guid));
else
$form->getPresenter()->redirect('User:items');
};
return $form;
}
public function actionForm($guid, $category)
{
if(!$this->user->isLoggedIn()) {
$this->redirect('Sign:in');
}
if ($guid) {
$this->id_item = $this->itemRepository->getItemID($guid);
if (!$this->id_item) {
throw new BadRequestException;
}
if (!$this->itemManager->authenticateItemOwner($this->id_item)) {
$this->error('Toto není Váš předmět!');
}
$values = $this->itemRepository->getItemFormData($this->id_item);
$this->item = $values;
$this->guid = $values['guid'];
$this->category = $values['category'];
if ($values['id_type']) {
$row = $this->itemRepository->getItem($this->id_item);
$this->type_name = $row['type_name'];
} else {
$this->type_name = $values['type_name'];
}
} else {
$this->category = $category;
}
}
public function renderForm()
{
$this->template->item = $this->item;
$this->template->type_name = $this->type_name;
$this->template->category = $this->category;
}
}
Uvedený kód se vůbec neprovede. Stránka se chvilku načítá a pak prohlížeč (ne Tracy) napíše „Spojení bylo přerušeno – Spojení se serverem bylo v průběhu načítání stránky ukončeno“.
Prosím nevíte kde bych mohl mít chybu? Díky moc
EDIT: Kód upraven dle aktuálního stavu. Dodávám kód šablony:
item/form.latte
{block content}
<div class="page-header">
{if $item}
<h3>{$item->item_name} {$item_abb}</h3>
{else}
{if $category == 'xy'}
<h3>......</h3>
{else}
<h3>.....</h3>
{/if}
{/if}
</div>
{control itemForm, $item, $category} //zkoušel jsem toto
{control itemForm} //zkoušel jsem i toto
{/block}
Editoval Croc (7. 11. 2015 0:42)
- Croc
- Člen | 270
- přidáno do předchozího postu
- opraveno
- aha, to je dobrá zpráva :) opraveno → předpokládám že hodnota se
získá:
$this->translator->getLocale()
Hele, když je formulář jako komponenta, nemá mít náhodou vlastní šablonu ve které se definuje vykreslení jednotlivých prvků?
Všechny změny jsem provedl do předchozího postu.
EDIT: Upravil jsem nastavení localhostu dle tohoto tématu, a Tracy promluvila.
Fatal Error
Maximum execution time of 30 seconds exceeded
Formulář se načítal pořád dokola ve smyčce než po 30s padnul. Mohl za to tento řádek:
$this['itemForm']->setDefaults($this->item);
// po tom co jsem ho změnil na:
if($this->item) {
$form->setDefaults($this->item);
}
// se formulář načte bez problému!
A předávání parametru také funguje. Super, díky za rady :)
Editoval Croc (7. 11. 2015 11:20)