„Pseudo“ dynamický formulář – pls help me
- mr.mac
- Člen | 87
Už fakt asi blnu, ale nevím, kam jsem si zakopal psa. Dělám na průvodci
importu dat z CSV do DB. Mám jednoduchý formulář, který bohužel musí
mít určitý předem neznámý počet listboxů pro přiřazení sloupců
z načteného CSV polím v DB (nevím totiž kolik má uploudnutý CSV
sloupců). Udělal jsem si to takto (viz kod níže).
Problém je, že formulář s listboxy normálně načtu – funguje, jakmile
hod dám odeslat, tak při zpracování funkcí **checkFormSubmitted **se
nemůžu na dynamicky přidaná pole listbox dostat – chyba, že neexistují.
Tzn. že takto jednoduše nelze pole do formulářů gnerovat? proč? V PHP
s tím nemám problém (kdosi mi tu nedávno psal, že to je jen PHP…?). Je
pravda, že tam mohu mít chyb, kterou už FAKT nevidím.
Díky za radu – pomoc.
//deklarované pole DB polí (seznam) pro přiřazení
private $npole = array( 'code' => 'Kód',
'nazev' => 'Název',
'cislo' => 'Číslo',
'cena' => 'Cena [Kč/ks]',
'mnozstvi' => 'Množství {ks]');
//továrna na formulář
protected function createComponentCheckForm()
{
$form = new Form;
$i=0;
//dynamický formulář - dle počtu sloupců CSV;
foreach($this->head as $pole => $v){
$i++;
$form->addSelect('mpole'.$i, $v.' »-> ', $this->npole)
->setPrompt('[zvolte pole]');
}
$form->addHidden('sloupcu'); // zde si posílám počet listboxů/sloupců CSV
$form->addSubmit('save', 'Importovat')->setAttribute('class', 'default');
$form->addSubmit('cancel', 'Storno')->setValidationScope(NULL);
$form->onSuccess[] = callback($this, 'checkFormSubmitted');
$form->addProtection(self::MESS_PROTECT);
return $form;
}
public function checkFormSubmitted(Form $form)
{if ($form['save']->isSubmittedBy()) {
$fields = array();
$cols = $form['sloupcu']->getValue();
for ($i = 1; $i<=$cols; $i++) {
//TADY to havaruje, hlasí, že pole mpole1 ve formuláři neexistuje
//když to dumpnu tak tam fakt žádný prvek mpole není!!!!
**$fields[$i] = $form['mpole'.$i]->value;**
}
dump($fields);
$this->flashMessage('Data BY byla importována.');
$file = $form['file']->getValue();
$this->redirect('confirm',$file);
} else {
$this->flashMessage('Import byl stornován.','exclamation');
$this->redirect('default');
}
- Filip Procházka
- Moderator | 4668
Promiň, ale vůbec nechápu o co se snažíš… Možná by ti pomohlo addDynamic?
A to $i
se mi tam vůbec nelíbí, koukni na Containery
- mr.mac
- Člen | 87
HosipLan napsal(a):
Promiň, ale vůbec nechápu o co se snažíš…
Na addDynamic jsem taky myslel, ale považoval jsem to za zbytečné (ještě ho nemám vyzkoušený). Kód mi připadá vcelku srozumitelný – ale asi jen pro mě. Jde mi je o to, že v rámci jednoho formuláře (s jedním tlačítke submit) potřebuji zobrazit 1 .. n listboxů se stejnými možnostmi výběru a pak po jeho odeslání si sestavím inserty pro načtení dat do DB – tedy, aybch věděl která data z kterého sloupce CSV budu insertovat do kterého příslušného pole DB. Je to jen krok přiřazení každému sloupci odpovídající pole z tabulky DB. Ani contejer si myslím pro toto není potřeba. A neboto jde udělat jednoduše, ale jsem lama a nedám to…
- Filip Procházka
- Moderator | 4668
Nejde o to, že container není potřeba. Ono je to s ním lepší, protože výsledný data jsou lépe strukturovaný
protected function createComponentCheckForm()
{
$form = new Nette\Application\UI\Form;
$presenter = $this;
//dynamický formulář - dle počtu sloupců CSV;
$mpole = $form->addContainer('mpole');
foreach(array_values($this->head) as $i => $v){
$mpole->addSelect($i, $v . ' »-> ', $this->npole)
->setPrompt('[zvolte pole]');
}
$form->addSubmit('save', 'Importovat')
->setAttribute('class', 'default')
->onClick[] = callback($this, 'checkFormSaveClicked');
$form->addSubmit('cancel', 'Storno')
->setValidationScope(NULL)
->onClick[] = function ($button) use ($presenter) {
$presenter->flashMessage('Import byl stornován.','exclamation');
$presenter->redirect('default');
};
$form->addProtection(self::MESS_PROTECT);
return $form;
}
public function checkFormSaveClicked(Form $form)
{
$fields = $form['mpole']->values;
// nemusíš nic přerozdělovat, jenom díky tomu, že jsi použil container už máš pole ve tvaru
// array(0 => 'code', 1 => 'cena', ...)
dump($fields);
$this->flashMessage('Data BY byla importována.');
$file = $form['file']->getValue();
$this->redirect('confirm', $file);
}
Nějak jsem nepochopil, jak se ti tam zamíchalo to file
, soubor
nejde přenáše mezi requesty formulářem. Musíš ho nahrát, uložit do
nějaké složky a přenášet si, třeba jeho jméno, v session.
- mr.mac
- Člen | 87
HosipLan napsal(a):
Nejde o to, že container není potřeba. Ono je to s ním lepší, protože výsledný data jsou lépe strukturovaný
EDIT: Container je funkční, díky. Pole se záhlavím sloupců se mezi requesty ztrácí i nadále. Asi cache? Jak? Nebylo by „nakopnutí“?
EDIT2: Tak a je to – cache jsem se zbytečně bál – ukládám si jen jméno file a data hlavičky csv do cache v MODELU a mám 2 metody jak je precist a pak je použiji v prezenteru a factory. To to bolelo ach jo!!! Den v pr****.
Díky za čas a práci – pokusím se to tak udělat. Díky více
listboxům mám následný problém s tím, že se mi po submitu data
ztratí – resp. hodnoty zvolné v listboxech mají NULL, ostatní hiden a
checkbox jsou ok. Nevím, zda bych obsah pole pro listboxy neměl cachovat –
jenomže to jsem zase „jako začátečník“ nepobral – zdá se mi, že
bych potřeboval mít cache v presenteru, jenomže jak jsem se dočetl měla by
být v modelu tak s tím bojuji. Ucelený příklad použití jsem bohužel
nenašel – ostatně jako mnoho jiného. Pro nováčky je to šílená dřina.
Když jsem před 2 lety začínal s PHP (klasicky) měl jsem první web za
měsíc – tohle je zase od začátku – na OOP taky nejsem moc zvyklý (no
ale k věci).
Jo a ten „file“ je jen název uploadnutého souboru. Jak jsem psal –
dělám na průvodci importu dat z CSV do DB – takže v předchozím kroku
uploadnutý soubor posílám do dalšího formuláře přes Hidden, abych ho
„cestou k finálním potvrzení“ neztratil. Možná by se na to ta cache
taky hodila, ale nevím jak si ji podržet mezi presentery (myslím
cache->save($key, $data) a jinde cache->load($key)). No mám v tom
pěknou bramboračku.
Editoval mr.mac (22. 10. 2011 22:50)
- mr.mac
- Člen | 87
HosipLan napsal(a):
Ještě jsem narazil na drobnost. Container vrací ArrayHash (viz dump):
Nette\ArrayHash(5) {
0 => "cena" (4)
1 => "nazev" (5)
2 => NULL
3 => NULL
4 => NULL
}
A já potřebuji ověřit, zda byla vyplněná alespoň 3 povinná pole (mám jejich seznam), v submit proceduře jsem si napsal toto (v poli $nrequired mám seznam oněch tří povinných):
...
foreach($nrequired as $req){
if (!in_array($req, $fields)) {
$form['save']->addError('Nejsou přiřazena všechna povinná pole: Kód, Název, Množství');
return ;
}
}
A vyskakuje mi chyba, že $fields není pole. Nevím proč, ale konverze na „nohash“ nefunguje, mám ji napsanou takto:
protected function getNoHashFormFields($hashData)
{
//když dostane hash pole
$data = \Nette\ArrayHash::from($hashData);
//vrátí zase hash :-(((
return $data;
}
Nevíte někdo, prosím co s tím? Dokonce se mi zdálo, že mi to v minulosti fungovalo a teď najednou nic, není to pole z Contejneru nějaké jiné??
- Filip Procházka
- Moderator | 4668
ArrayHash
se dá snadno přetypovat.
$hash = Nette\ArrayHash::from(array(
0 => "cena",
1 => "nazev",
2 => NULL,
3 => NULL,
4 => NULL,
)); // objekt
$values = (array)$hash; // pole
// array(0 => "cena", 1 => "nazev", ...)
Já si myslím, že se ztácíš v tom, že formulář špatně znovu vytváříš. Funguje to tak, že formulář vytvoříš, vykreslíš, uživatel ho vyplní a odešle. Ty ho potom musíš znovu sestavit tak, jako poprvé, jinak ty pole, která v něm nebudou, vůbec nepřijme. Je to bezpečnostní opatření.
Takže to tvoje $this->head
musí mít ty správné hodnoty
při prvním requestu, ale při druhém! Jinak se ti to vůbec
nesestaví a formulář ty data prostě zahodí.
Ty si tedy můžeš ty sloupce z toho souboru buď přečíst znovu, nebo si je uložíš do session.
A cache v presenteru ničemu nevadí (jenom se to v určitých situacích dělá jinak)
- mr.mac
- Člen | 87
HosipLan napsal(a):
ArrayHash
se dá snadno přetypovat.
Díky za velmi rychlou reakci. Jak jsem psal v #5 (EDIT2) problém s druhým
vykreslením jsem odstranil – naučil jsem se další novinku – použití
cache (v modelu) – uložil jsem si hlavičky do cache a po odeslání se
formulář korektně naplní a vykreslí neboť si data s cache znovu
obnovím.
Přetypování $data = (array) $hash mě fakt dostalo –
vracím se k základům PHP, jdu si číst manual. To je ostuda :-(!!
Díky moc za pomoc.
- mr.mac
- Člen | 87
22 napsal(a):
..data formuláře patří imho do session a ne do cache.
Asi máš pravdu, až budu mít čas tak to předělám, teď ale musím finišovat na další části aplikace. Import z CSV do MSSQL mi chodí – nečekal jsem to, že s tím budu válčit 2 dny – to jsou ty těžké začátky v novém prostředí… Hodně se musí pátrat/hledat – mnoho návodů je neaktuálních, ale to už je obehraná písnička.
Editoval mr.mac (23. 10. 2011 17:11)