komponenta s formularem pro pridavani do zbozi kosiku

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

Zdravim,

zasekl jsem se temer pred koncem dopsani sve komponenty, do te doby, nez jsem potreboval redirect a flashMessage vse fungovalo podle me predstavy tak jak melo.
Zkousel jsem procist par temat, jak to resi ostatni a to me neni asi uplne nejcistsi reseni, tak prosim o nejake rady.

Jedna se o komponentu vykreslujici formular pod produktem pro pridani poctu kusu do kosiku s vyberem objemu.
Pouze jednou v EshopPresenter mam

public function createComponentProduct(){
	return new Product();
}

Volani komponenty pouzivam timto zpusobem:
Chtel jsem, predavat parametry primo pri renderovani, abych se vyhnul tomu, ze bych mel v presenteru 20× new Product($count, $product1, $product2);

{control product, 1, $productsTable[30], $productsTable[14]}
{control product, 9, $productsTable[29], $productsTable[13]}

Komponenta:

<?php
use Nette\Application\UI;

final class Product extends UI\Control
{

	private $order;

    public function render($count = 1, $pObject1 = null, $pObject2 = null)
    {
		$this->order = $this->presenter->getService("session")->getSection("order");

        $this->template->setFile(__DIR__ . '/default.latte');
		if(is_object($pObject1) && count($pObject1) == 1)
			$this->template->pObject1 = $pObject1;
		if(is_object($pObject2) && count($pObject2) == 1)
			$this->template->pObject2 = $pObject2;
		$this->template->kartonCount = $count;

		if(is_object($pObject1) && count($pObject1) == 1){
			$form = new Nette\Forms\Form("product$pObject1->id");
			if($pObject2)
				$form->addSelect("id", null, array(
						$pObject1->id => "0,7l",
						$pObject2->id => "1l",
					)
				)
				->setAttribute("class", "eshop-product")
				->setAttribute("data-price1", number_format($pObject1->price, 2, ',', ' '))
				->setAttribute("data-price1-vat", number_format($pObject1->price*(1+($pObject1->vat/100)), 2, ',', ' '))
				->setAttribute("data-price2", number_format($pObject2->price, 2, ',', ' '))
				->setAttribute("data-price2-vat", number_format($pObject2->price*(1+($pObject1->vat/100)), 2, ',', ' '));
			else
				$form->addHidden("id", $pObject1->id)->addRule($form::INTEGER, 'Chyba, pokus o podstrčení neplatných údajů!');
			$form->addText("count", "počet:")->setDefaultValue(1)->addRule($form::INTEGER, 'Počet musí být číslo')->addRule($form::RANGE, 'Počet musí být od %d do %d', array(1, 99));
			$form->addSubmit("send", "do košíku");

			// $form->onSuccess[] = array($this, "productFormSubmitted");

			/*
			if($form->isSuccess()){
				$v = $form->values;
				if(isset($this->order[$v->id]))
					$this->order[$v->id] += $v->count;
				else
					$this->order[$v->id] = $v->count;
				$this->flashMessage("Zboži bylo úspěšně přidáno do košíku");
				$this->presenter->redirect("this");

			}*/

			$this->template->form = $form;
		}

        $this->template->render();
    }

	public function productFormSubmitted($form){
		echo "test";
	}

}

Sablona komponenty:

{ifset $pObject1}
<div>
	{form $form}
		<span>
		{if $pObject2}
			{if $kartonCount > 1}Karton / {$kartonCount}ks{else}Vyberte prosím objem{/if}:
		{else}
			{if $kartonCount > 1}Karton / {$kartonCount}ks{else}Objem{/if}: 0,7l
		{/if}
			{input id}
			<span>{label count /} {input count}</span>
		</span>

		<p>
			Cena <span class="price-no-vat">{$pObject1->price|number:2:',':' '}</span> Kč
			s DPH: <span class="price-vat">{$pObject1->price*(1+($pObject1->vat/100))|number:2:',':' '}</span> Kč
			{input send}
		</p>
	{/form}
</div>
{/ifset}

Pri odesilani a naslednem zpracovani formulare jsem narazil hned na nekolik problemu – productFormSubmitted() se vubec neprovede, dale v if($form->isSuccess()){ .. se neda redirectovat ani pouzivat flashMessage, protoze to je nutne volat jeste pred renderovanim.

Napada me, prepsat cely form a dat ho do tovarnicky, ale netusim, jak mu predat potrebne 2 objekty s produkty ($pObject1 a $pObject2), na zaklade kterych se dynamicky generuje. Pokud bych se vydal touto cestou, asi bych je musel predavat v konstruktoru komponenty Product hned pri vytvareni (cemuz jsem se chtel odzacatku vyhnout, protoze pro kazdy produkt bych musel vytvaret novou komponentu). Take nevim jestli by to bylo uplne ciste reseni a tak bych poprosil o radu nekoho zkusenejsiho jakym smerem se ubirat.

Jan Endel
Člen | 1016
+
0
-

Pro začátek formulář určitě do samostatné subkomponenty, pak bych taky nastudoval Multiplier. A vůbec z celého toho tvého kódu jsem dost zmatený.

  • co má být v proměnných $pObject1 a 2?
Jan Mikeš
Člen | 771
+
0
-

pilec napsal(a):

  • co má být v proměnných $pObject1 a 2?

Jsou to fetchnute radky z tabulky s produkty, kde jsou jen potrebne informace – id, cena, dph
Tyto objekty 100% potrebuji nejak do formu dostat, protoze je vypisuji primo v komponente. Dalsi moznost je predavat pouze id a fetchovat produkty az primo v komponente, ale nevim co je lepsi reseni.

Na multiplier kouknu

Jan Mikeš
Člen | 771
+
0
-

Potrebuji nejak do komponenty v multiplieru dostat 2 parametry a ne jen jeden, v idealnim pripade kdyby to slo pres {control form-$id1-$id2} pripadne {control form-$id1, $id2} ale nemuzu nic najit.

public function createComponentProductForm($item2Id = false){ // bude toto fungovat? Jak ho ale predat skrz anonymni funkci do formu?
		$that = $this;
		return new UI\Multiplier(function ($item1Id) use ($that) {
			 $item1 = $that->productsTable[$item1Id];
			// kvuli tomuto potrebuji dostat i druhy parametr, kazdy formular je pro 2 produkty najednou, 0,7l a 1l objemove varianty
			 //if($item2Id)
				 //$item2 = $that->productsTable[$item2Id];

			$form = new Nette\Application\UI\Form;
			... // zbytek uz funguje
			$form->onSuccess[] = array($that, "productFormSubmitted");
			return $form;
		});
	}
Jan Mikeš
Člen | 771
+
0
-

Tak jsem se nakonec pomoci Multiplieru dopracoval k funkcnimu reseni.
EshopPresenter:

protected function startup() {
	$this->order = $this->getService("session")->getSection("order");
	$this->products = $this->template->products = $this->context->eshop->getAllProducts();
}
public function createComponentProductForm(){
	return new ProductForm($this->order);
}

Eshop:default

{control productForm, 1, $products[30], $products[14]}
{control productForm, 9, $products[29], $products[13]}

ProductForm.php:

<?php

use Nette\Application\UI;

final class ProductForm extends UI\Control
{

	public $order;
	public $item1;
	public $item2;

	public function __construct($orderSection){
		parent::__construct();
		$this->order = $orderSection;
	}

	public function createComponentProductForm(){
		$that = $this;
		return new UI\Multiplier(function($item1Id) use ($that) {
			$item1 = $that->item1;
			$item2 = $that->item2;
			$form = new UI\Form;
			if($item2)
				$form->addSelect("id", null, array(
						$item1->id => "0,7l",
						$item2->id => "1l",
					))
					->setDefaultValue($item1->id)
					->setAttribute("class", "eshop-product")
					->setAttribute("data-price1", number_format($item1->price, 2, ',', ' '))
					->setAttribute("data-price1-vat", number_format($item1->price*(1+($item1->vat/100)), 2, ',', ' '))
					->setAttribute("data-price2", number_format($item2->price, 2, ',', ' '))
					->setAttribute("data-price2-vat", number_format($item2->price*(1+($item1->vat/100)), 2, ',', ' '));
			else
				$form->addHidden("id", $item1Id);
			$form->addText("count", "počet:")->setDefaultValue(1)->setRequired("Musíte vyplnit počet!")->addRule($form::INTEGER, 'Počet musí být číslo!')->addRule($form::RANGE, 'Počet musí být v rozmezí od %d do %d!', array(1, 99));
			$form->addSubmit("send", "do košíku");
			$form->onSuccess[] = array($that, "productFormSubmitted");
			return $form;
		});
	}

    public function render($count = 1, $item1 = false, $item2 = false)
    {
		$this->template->item1 = $this->item1 = $item1;
		$this->template->item2 = $this->item2 = $item2;

        $this->template->setFile(__DIR__ . '/default.latte');
		$this->template->count = $count;
        $this->template->render();
    }

	public function productFormSubmitted($form){
		$v = $form->values;
		if(isset($this->order[$v->id]))
			$this->order[$v->id] += $v->count;
		else
			$this->order[$v->id] = $v->count;
		$this->presenter->flashMessage("Zboží bylo úspěšně přidáno do košíku!");
		$this->presenter->redirect("this");
	}

}

default.latte (komponenty):

<div n:if="$item1">
	{form productForm-$item1->id}
		<span>
			{if $item2}
				{if $count > 1}Karton / {$count}ks{else}Vyberte objem{/if}:
			{else}
				{if $count > 1}Karton / {$count}ks{else}Objem{/if}: 0,7l
			{/if}
			{input id}
			<span>{label count /} {input count}</span>
		</span>
		<p>
			Cena <span class="price-no-vat">{$item1->price|number:2:',':' '}</span> Kč
			s DPH: <span class="price-vat">{$item1->price*(1+($item1->vat/100))|number:2:',':' '}</span> Kč
			{input send}
		</p>
	{/form}
</div>

Zda se mi to mnohem lepsi nez to puvodni reseni a mam z toho i lepsio pocit. Presto bych poprosil nekoho zkusenejsiho, aby mi ten kod zkritizoval, pripadne poradil jeste co a jak vylepsit.

Editoval Lexi (26. 6. 2012 13:36)

mfajfr
Člen | 26
+
0
-

Ahoj,
řeším momentálně podobnou situaci, kdy potřebuji na vstup dvě proměnné, čili Multiplier mi ne zcela pomůže.
Chtěl bych se zeptat, co se tedy stane po odeslání formuláře. Já totiž do vytvoření formuláře vkládám dva objekty a ty poté neexistují a tím to padá.
Vidím, že ty to řešíš, že je dáš na false, ale to se ten formulář nemůže znovu vykreslit, ne?

Předem díky.