data z dynamickeho formulara sa stracaju

- xr
 - Člen | 94
 
zdravim
mam formular, do ktoreho dynamicky pridavam prvky. pridavaju sa rozne inputy podla kontextu. tieto nacitam ajaxovo a vkladam do formularu.
problem je v tom, ze do obsluznej funkcie sa mi tieto data nedostanu.
	public function processEdit( AppForm $form ) {
		if ( $form['save']->isSubmittedBy() ) {
			$values = $form->getValues();
			debug::dump($values);
			debug::dump($_POST);exit;
...
POST obsahuje potrebne prvky, ale $values nie – ako je to mozne? kde sa data stracaju a ako sa tomu vyhnem?
okrem teda moznosti rucne si ich sosat z POSTu … resp. este su data
dostupne vo
$form->httpData
ale tahat ich odtial mi prijde rovnako suplikantske ako z POSTu.
dik za reakcie vopred

- xr
 - Člen | 94
 
@22:
moja metoda spociva v tom, ze mam AsyncPresenter, ktory zostavi formular na
zaklade toho, co si uzivatel zada (moze pridavat rozne objekty, ktore
maju rozne inputy – text / radiobutton / chebbox atd), z neho si zoberiem
len vnutro (t.j. len samotne inputy) a tieto ajaxom nacitam a pridam priamo
pomocou jQuery do hlavneho formulara.
jednotlive inputy patriace jednemu objektu pomenuvam takto:
[nazov_objektu]_[nazov_inputu], cize podla prefixu
[nazov_objektu] som schopny inputy rozdelit do skupin a potom
vytvarat model podla hidden inputu nesucim typ a takto ich spracovat.
napriklad ak teda pridavam dynamicky objekt s textovymi inputmi
title a description, tak do formulara pridavam input
tagy typu text s name atributom nastavenym na i123_title a
i123_description, kde i123 je unikatny
identofikator.
inak s tym obchadzanim bezpecnosti nette – je mozne na pole hodnot
inputov $dynamic (viz moj predchadzajuci post) aplikovat validaciu
ineho formularu, ako toho hlavneho, ktory prave obsluhujem? t.j. toho, ktory
tieto inputy vytvara (v async prezenteri).
a tiez, ak mi niekto poradi lepsiu metodu, tak ju rad prijmem.

- Filip Procházka
 - Moderator | 4668
 
Obcházíš bezpečnostní mechanizmus Nette. Správně je to:
- Uživatel otevře stránku s presenterem
 - actionDefault()
		
- zavolá továrničku, která sestaví formulář
			
$this['myForm']→createComponentMyForm() - naplnění výchozích hodnot formuláře
			
->setDefaults($this->myModel->find($id)) - tento krok není nutný, pokud neplníš formulář výchozími daty
 
 - zavolá továrničku, která sestaví formulář
			
 - v šabloně vykreslíš formulář 
{control myForm} - uživatel vyplní data a odešle formulář
 - actionDefault()
		
- zavolá se úplně to stejné co předtím, sestaví se stejný formulář a můžeš mít v akci i podmínku, abys zbytečně nevolal databázi kvůli výchozím datům
 
 - signál na formulář
	
$presenter->getComponent('myForm')->handleSubmit()- provede se automaticky
 - naprosto stejně sestavený formulář ti příjme data co uživatel odeslal
				
- BEZPEČNOSTNÍ MECHANIZMUS !!!!
 
 - provedou se tvoje události, kde máš k dispozici správné a všechny hodnoty
 
 
…
Takže ty vůbec nepotřebuješ šahat na nějaké httpData, ty
MUSÍŠ sestavit formulář stejně jako byl při
vykreslování. To tvoje ajaxové cosi je celé špatně a radši to smaž a
nikdy nikomu neukazuj. Až ti někdo rozjebe aplikaci, protože jsi dělal
takové kotrmelce s ajaxem, tak nechoď brečet k nám.
Nic z toho co jsem popsal ti nebrání sestavovat dynamicky formuláře. Jenom to nebudeš dělat jako prasátko, ale sestavíš formulář, připojíš ho do presenteru a vykreslíš. Potom ho sestavíš znovu, úplně stejně a přijmeš data. Ale to už se opakuju :)

- Filip Procházka
 - Moderator | 4668
 
Já nic neobcházím. To je několik různých věcí. Ty potřebuješ nadefinovat formulář a potřebuješ ho pak někde vypisovat. Jenom jsi zvolil jeden z nejhorších přístupů :)

- bazo
 - Člen | 620
 
xr napsal(a):
no a ty zase obchadzas to, co sa snazim dosiahnut – ako zrekonstruujem formular, ktory si uzivatel sam naklika na front-ende ? mam X skupin inputov, ktore si moze lubovolne umiestnit a moze ich byt neobmedzeny pocet v lubovolnom poradi.
strukturu toho formulara si asi niekde ptom ukladas, nie? tak podla toho si to aj zrekonstruujes

- xr
 - Člen | 94
 
nie, nic si neukladam. zakladny formular ma napevno zopar prvkov a ostatne sa do neho sukaju ajaxom. potom sa to posle cele a ja potrebujem dostat tie hodnoty.
ok, tak teraz otazka na expertov → ked mam pole s hodnotami, ktore som dostal nekalym sposobom, kazdu sadu hodnot vytvoril jeden formular, akurat sa z neho vykuchali vnutornosti a strcili do toho zakladneho. mozem teda nejakym sposobom spustit validaciu toho tovarnickoveho formularu ?
aby som tu len nekecal o nekonkretnych veciach…
toto je block presenter – block je ten zakladny prvok, ktory sa dynamicky
zvacsuje o nove prvky
	public function createComponentEdit( $name ) {
		$form = new AppForm($this, $name);
//		$form->addDynamicContainer('fero');
		foreach ( $this->setup->languages->codes as $lang ) {
			$item = new \Model\BlockText($this->itemId, $lang);
			$item->dbReload();
			$form->addText($this->encodeLangTitle('title', $lang), $lang . ': ' . $this->tr('Title', 'title-tit'), 80, 128)
					->setDefaultValue($item->title)
					->addRule(Form::FILLED, $this->tr('...!', 'title-req'));
			$form->addTextArea($this->encodeLangTitle('text', $lang), $lang . ': ' . $this->tr('Text', 'text-tit'), 80, 20)
					->setDefaultValue($item->text);
		}
		$item = new \Model\Block($this->itemId);
		$item->dbReload();
		$form->addText('category', $this->tr('Category', 'category-tit'), 30, 3)
				->setDefaultValue($item->category)
				->addRule(Form::INTEGER, $this->tr('Category is of integral type!', 'category-req'));
		$form->addText('unique', $this->tr('Unique descriptor', 'unique-tit'), 30, 3)
				->setDefaultValue($item->unique)
				->addRule(Form::FILLED, $this->tr('Fill in a unique block descriptor!', 'unique-req'));
		$form->addCheckbox('display', $this->tr('Visible', 'visible-tit'))->setDefaultValue($item->display - 1);
		$form->addSubmit('save', $this->tr('Save', 'save-btn'));
		$form->addSubmit('back', $this->tr('Cancel', 'cancel-btn'))->setValidationScope(NULL);
		$form->onSubmit[] = callback($this, 'processEdit');
	}
/--
toto je ta sporna metoda (handler submitu)
\--
/--php
	public function processEdit( AppForm $form ) {
		if ( $form['save']->isSubmittedBy() ) {
			$values = $form->getValues();
			$dynamic = array_diff($form->httpData, $values);
			unset($dynamic['save']);
//			debug::dump($values);
//			debug::dump($dynamic);
//			debug::dump($_POST);exit;
			// v dynamic mas dynamicky pridane prvky
			// create a base model
			$item = new \Model\Block($this->itemId);
			$item->category = $values['category'];
			$item->unique = $values['unique'];
			$item->display = $values['display'] + 1;
			$item->save();
			$mutations = $this->decodeMultiLangInput($values);
			foreach ( $mutations as $lang => $values ) {
				$item = new \Model\BlockText($this->itemId, $lang);
				$item->title = $values['title'];
				$item->text = $values['text'];
				$item->save();
			}
			$mutations = $this->decodeMultiLangInput($dynamic);
			foreach ( $mutations as $lang => $values ) {
				debug::dump($this->decodeItems($values));
				// decodeItems vracia pole skupin parov hodnot z inputov
				// array( 123 => array('text'=>'blablabla', 'obrazok'=>'/img/..'), 124 => ...)
				// tu by sa podla typu mali vytvorit jednotlive modely, prekazdu skupinu jeden.
				// naplnit a ulozit
			}
			exit;
			$this->flashMessage($this->tr('Block modified.', 'block-midif'));
		}
		$this->redirect('default');
	}
teraz toto je v Async presenteri
public function actionXY(){
...
	$form = new Form();
	$this->addItemInputs($form, $id, $number, $this->lang);
...
}
	protected function addItemInputs( Form $form, $type, $number, $lang = null, $model = null ) {
		$namePrefix = 'i' . sprintf('%03d', $number) . '_';
		switch ( $type ) {
			case \Model\Item::ITYPE_TEXT:
				$this->setView('input_text');
				$name = $namePrefix . 'text';
				if ( $lang ) {
					$name = $this->encodeLangTitle($name, $lang);
				}
				$comp = $form->addTextArea($name, $this->tr('Text', 'text-tit'), 80, 20);
				if ( !is_null($model) ) {
					$comp->setDefaultValue($model->text);
				}
				break;
			case \Model\Item::ITYPE_IMAGE:
				...
			default:
				$this->setView('empty');
				exit;
				break;
		}
		$name = $namePrefix . 'itype';
		if ( $lang ) {
			$name = $this->encodeLangTitle($name, $lang);
		}
		$form->addHidden($name, $type);
		$name = $namePrefix . 'iorder';
		if ( $lang ) {
			$name = $this->encodeLangTitle($name, $lang);
		}
		$form->addHidden($name, $number);
		return $form;
	}
tak znova tu otazku – je mozne data ziskane z toho hlavneho forumlaru v obsluhe nejako zvalidovat cez takto vytvoreny formular v Async prezenteri ? ak ano – ako? pretoze neviem. dik za rady

- Filip Procházka
 - Moderator | 4668
 
Já se snažím.. opravdu se snažím tě pochopit a pomoct ti… Ale píšeš moc abstraktně a ten kód mi moc neřekl, popravdě jsem ho prolétl a opravdu se mi to nechce studovat.
Jestli chceš vědět jak se to dělá nette-way, tak mi musíš konkrétně popsat, čeho se snažíš dosáhnout. Protože jsem to do teď nepochopil.

- Filip Procházka
 - Moderator | 4668
 
Pokud dáš do formuláře prvek, třeba
$form->addContainer('neco')->addContainer('tamto')->addText('name', 'Jméno');
a v $_POST bude
$_POST['neco']['tamto']['name'] = 'Lady Gaga';
Tak po připojení formuláře do presenteru bude
$form->values['neco']['tamto']['name'] === 'Lady Gaga'
I pokud budeš po připojení formuláře do presenteru přidávat další políčka, tak se automaticky bude načítat jejich hodnota.
Ale pokud budeš formulář sestavovat na základě $_POST a né
na základě nějaké struktury, nebo uložených metadata v nějakém
nastavení, tak je to kontraproduktivní a zbytečné, protože by si tam
uživatel zase mohl naflákat co chce.

- Ani
 - Člen | 226
 
Udělej si signál, který ti na základě požadavku uloží třeba do session, co se má do formuláře přidat.
V továrně toho formuláře koukni do session a jestli tam něco je, tak to hned v té továrně přidej do formuláře.
Zpracovat to pak můžeš normálně.
Tohle co tu máš je velká divočina :D

- frosty22
 - Člen | 373
 
Napadlo mě, zda-li by nebylo možné, aby se dosadili přijaté hodnoty ještě před validací a v případě invalidace, by se ty dané hodnoty vyhodily, což by umožnilo i ony dynamicky závislé formulářové prvky. Akorát si nejsem jist, zda-li by nemohlo dojít k bezpečnostním problémům, když by asi nemělo. Uvedu na příkladě:
<?php
protected function createComponentFooForm()
{
  $form = new Form;
  $items = $db->category()->fetchPairs(...);
  $form->addSelect("category", "Kategorie:", $items)
        ->setDefault(key($items));  // nastavení výchozí hodnoty první kategorie např.
  $items = $db->subcategory()->where("category_id = ?", $form["category"]->value)->fetchPairs(...);
  $form->addSelect("subcategory", "Podkategorie:", $items);
  ...
  return $form;
}
?>
V tomto případě, pokud by formuláře prvotně naplnili přijatými hodnotami elementy a až následně je validovali, tak by to prošlo:
- Odešle se formulář
 - Přijme se signál
 - Přidá se element category a rovnou se zvaliduje, pokud je OK tak hodnota už se naplní, pokud není OK, tak se odstraní
 - Zavolá se dotaz na podkategorie s již nově přijatým ID kategorie, čili se naplní korektně a validací projde
 
…
Aktuálně je zde problém, že se prvně složí celý formulář a až následně se validují elementy, čili se složí s tím, že ve $form[„category“]->value bude vždy výchozí hodnota a tím pádem, už se nenaplní onen závislý select korektními daty (pouze v případě stejné kategorie).
Snad si rozumíme, ale myslím si, že takto by to nemuselo být špatné řešení. Bohužel jsem zatím přímo neprošel, jak funguje vnitřně onen Forms/Container a Forms/Form, takže možná plácám kraviny.
Editoval frosty22 (31. 7. 2011 13:21)