Komponenta s přístupem do modelu

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

Zdravím,

mám další menší problém s vytvářením formuláře.

Mám formulář, jehož 3/4 část (je poměrně rozsáhlý) bude použita v několika desítkách dalších formulářů, takže si chci vytvořit komponentu carForm, kterou pak budu volat v rámci továrničky.

Do „/app/forms/CarForm.php“ jsem si vytvořil základ formuláře takto:

namespace App;

use Nette\Application\UI,
    Nette\ComponentModel\IContainer,
    Nette\Forms\Container;

class CarForm extends UI\Form
{

    /**
    * @var \App\Cars
    * @inject
    */
    public $cars;

    public function __construct(IContainer $parent = NULL, $name = NULL)
    {
        parent::__construct($parent, $name);

        $this->addSelect('brand', 'Výrobce:', $this->cars->listOfCarBrands())
                ->setPrompt('Zvolte výrobce vozidla');

	.............

a volám jej v rámci Presenteru takto:

	protected function createComponentAddCarForm()
	{

		$form = new CarForm();

		// dočasné testovací prvky formuláře
		$form->addSubmit('send', 'Odeslat formulář');

		// call method logInFormSucceeded() on success
		$form->onSuccess[] = $this->addCarFormSucceeded;
		return $form;
	}

Tohle všechno by fungovalo, ale mám problém s doplněním seznamu hodnot do Selectů tohoto formuláře, což dělám za pomocí modelu $this->cars->listOfCarBrands() (viz první část kódu).
Problém je ale v tom, že k tomu modelu zřejmě nemám přístup (což je divné), každopádně laděnka mi hlásí toto:

Call to a member function listOfCarBrands() on a non-object search►

Proč? Co dělám špatně nebo přehlížím?
Případně měl bych řešit naplnění výchozích hodnot do selectu nějak jinak? (třeba v rámci Presenteru, kde přístup do listOfCarBrands() mám).

Díky!

thunderbuff
Člen | 164
+
0
-
<?php

// formulář

class CarForm extends UI\Form
{

    /**
    * @var \App\Cars
    */
    private $cars;

    public function __construct(Cars $cars)
    {
        parent::__construct();

	$this->cars = $cars;

        $this->addSelect('brand', 'Výrobce:', $this->cars->listOfCarBrands())
                ->setPrompt('Zvolte výrobce vozidla');
     }
}



// presenter


// tady už by fungovala i anotace inject
private $carForm;

public function injectCars(CarForm $carForm) {
	$this->carForm = $carForm;
}

protected function createComponentAddCarForm()
{

    $form = $this->carForm;

    // dočasné testovací prvky formuláře
    $form->addSubmit('send', 'Odeslat formulář');

    // call method logInFormSucceeded() on success
    $form->onSuccess[] = $this->addCarFormSucceeded;
    return $form;
}

?>

… a zaregistruj si carForm jako sužbu v configu, pak to bude fungovat.

Editoval thunderbuff (10. 1. 2014 15:09)

David Matějka
Moderator | 6445
+
0
-

@thunderbuff: komponenty jako sluzbu neni spravny reseni, muze se to rozbit

@dj.kure: udelej si tovarnicku

class CarForm extends UI\Form
{

    /**
    * @var \App\Cars
    */
    private $cars;

    public function __construct(Cars $cars)
    {
        $this->cars = $cars;
        $this->addSelect('brand', 'Výrobce:', $this->cars->listOfCarBrands())
                ->setPrompt('Zvolte výrobce vozidla');
     }
}


interface CarFormFactory
{
	/**
	* @return CarForm
	*/
	public function create();
}

config.neon:

services:
	- CarFormFactory

presenter:

/**
* @var CarFormFactory
* @inject
*/
public $carFormFactory;

protected function createComponentAddCarForm()
{
	$carForm = $this->carFormFactory->create();

	.....

	return $carForm;
}
dj.kure
Člen | 70
+
0
-

Děkuji za rady, udělal jsem to podle matej21, ale stále to nefunguje, stále tento error:

Call to a member function listOfCarBrands() on a non-object
chyba je u:
$this->addSelect(‚brand‘, ‚Výrobce:‘, $this->cars->listOfCarBrands())

Pak jsem si všiml, že jsem nepředělal toto:

class CarForm extends UI\Form
{

    /**
    * @var \App\Cars
    */
    private $cars;

    public function __construct(Cars $cars)
    {
        $this->cars = $cars;
        $this->addSelect('brand', 'Výrobce:', $this->cars->listOfCarBrands())
                ->setPrompt('Zvolte výrobce vozidla');
     }
}

Takže jsem to předělal a stejně mi to hlásí následující Error:

Argument 1 passed to Nette\Application\UI\Form::__construct() must implement interface Nette\ComponentModel\IContainer, instance of App\Cars given, called in /usr/local/zend/apache2/htdocs/esk/app/forms/CarForm.php on line 21 and defined

David Matějka
Moderator | 6445
+
0
-

Call to a member function listOfCarBrands() on a non-object
to hlasit nemuze, pokud jsi postupoval, jak jsem psal. to by driv selhalo na spatnem argumentu nebo tak…

dj.kure
Člen | 70
+
0
-

Jak jsem psal, byla to moje chyba, že jsem přehlédl tebou upravený carForm :-) aktuální chyba je ta dole. Na té teď stojím.

David Matějka
Moderator | 6445
+
0
-

nevolas nahodou v konstruktoru parent::__construct($cars);?? kdyztak to smaz

dj.kure
Člen | 70
+
0
-

Ano, náhodou volám, už je to pryč:

class CarForm extends UI\Form
{

    /**
    * @var \App\Cars
    * @inject
    */
    private $cars;

    public function __construct(Cars $cars)
    {

        $this->cars = $cars;

        Container::extensionMethod('addDatePicker', function (Container $container, $name, $label = NUL
        {
            return $container[$name] = new \JanTvrdik\Components\DatePicker($label);
        });

        $this->addSelect('brand', 'Výrobce:', $this->cars->listOfCarBrands())
                ->setPrompt('Zvolte výrobce vozidla');

Chyba: Trying to get property of non-object

200:        /**
201:         * Returns form's method.
202:         * @return string get | post
203:         */
204:        public function getMethod()
205:        {
206:            return $this->element->method;
207:        }
208:
209:

A NetBeans na mě pořád křičí, že:
Parent Constructor is not Called, 0 mandatory, 2 optional parameters needed, Your objects can be wrongly initalized:

David Matějka
Moderator | 6445
+
0
-

ajo vlastne, kecam :)
zavolej parent::__construct(); ale bez parametru

a

Container::extensionMethod('addDatePicker', function (Container $container, $name, $label = NUL
       {
           return $container[$name] = new \JanTvrdik\Components\DatePicker($label);
       });

dej do bootstrapu, tady to nema co delat..

a posledni vec, i kdyz nemam rad dedeni formu, tak kdyz to delas, dej definici polozek radeji do attached (pryc z __construct). cely to bude vypadat asi takhle

class CarForm extends UI\Form
{

    /**
    * @var \App\Cars
    */
    private $cars;

    public function __construct(Cars $cars)
    {

        $this->cars = $cars;
		parent::__construct();

	}

	public function attached($presenter)
	{
		parent::attached($presenter);
		if($presenter instanceof \Nette\Application\UI\Presenter) {
      		$this->addSelect('brand', 'Výrobce:', $this->cars->listOfCarBrands())
                ->setPrompt('Zvolte výrobce vozidla');
		}
	}
dj.kure
Člen | 70
+
0
-

Už to funguje, addDatePicker jsem přehodil do Bootstrapu.
Ale teď mám takový menší jiný problém, ale to asi bude drobnost –

	protected function createComponentAddCarForm()
	{

		$form = $this->carFormFactory->create();
		$form->addSubmit('send', 'Odeslat formulář');

		// call method logInFormSucceeded() on success
		$form->onSuccess[] = $this->addCarFormSucceeded;
		return $form;
	}

Problém je v tom, že tlačítko „Odeslat formulář“ se mi vkládá do formuláře jako první, místo aby bylo úplně na konci :( Proč?

David Matějka
Moderator | 6445
+
0
-

aaaa pravda, jsem si neuvedomil, sorry :)

ok, prehod zas zpatky tu definici $this->addSelect do konstruktoru, snad se nic nerozbije :)

dj.kure
Člen | 70
+
0
-

Opraveno, děkuju moc :-) sám bych na to nepřišel ani kdybych se rozkrájel.

Já sázel na to, že ten jednoduchý Injector (jestli to nazývám správně) bude fungovat všude, ne jen v Presenterech.

Mám na mysli toto:

/**
* @var \App\Cars
* @inject
*/
private $cars;

Editoval dj.kure (10. 1. 2014 16:39)

Robyer
Člen | 74
+
0
-

@dj.kure Tady máš vysvětlení: https://forum.nette.org/…a-steroidech#…