Formulář jako komponenta a DI

admin@easyweb4u.cz
Backer | 143
+
0
-

Vytvořil jsem si komponentu formuláře App/Forms/TherapyForm.php, přes presenter ji posílám do šablony. Vše funguje, až na to, že do té komponenty chci injektovat službu /** @var \App\Model\TherapyService @inject */, kterou normálně používám v jiném presenteru. V komponentě App/Forms/TherapyForm.php to ale hlásí chybu: Call to a member function getTimeSelect() on null. Jak na to?

CZechBoY
Člen | 3608
+
0
-

Ukaz komponentu a jak ji vytvaris.

admin@easyweb4u.cz
Backer | 143
+
0
-
<?php

namespace App\Forms;

use Nette;
use Nette\Application\UI;

class TherapyForm
{
    /** @var Nette\Database\Context */
    private $database;

    /** @var \App\Model\TherapyService @inject */
    public $therapy;

    public function __construct(Nette\Database\Context $database) {
            $this->database = $database;
    }

    public function create($id)
    {
        $form = new UI\Form;

		....
?>
David Matějka
Moderator | 6445
+
+2
-

@inject anotace funguje defaultne pouze v presenterech, jinde zavislosti predavej pres konstruktor (stejne jako to delas s databazi)

admin@easyweb4u.cz
Backer | 143
+
0
-

Ok, dík. Jdu na to.

CZechBoY
Člen | 3608
+
0
-

btw doporucuju tu tridu prejmenovat – pridat suffix Factory, proro formular vytvari, neni to tedy formular jako takovy.

admin@easyweb4u.cz
Backer | 143
+
0
-

Přejmenováno, funguje.

<?php

namespace App\Forms;

use Nette;
use Nette\Application\UI;
use App\Model;

class TherapyFormFactory
{
    /** @var Nette\Database\Context */
    private $database;

    /** @var Model\TherapyService */
    private $therapyService;

    public function __construct(Nette\Database\Context $database, Model\TherapyService $service) {
            $this->database = $database;
            $this->therapyService = $service;
    }
?>
MajklNajt
Člen | 470
+
0
-

a ešte úplne ideálne by si mal presunúť prácu s databázou práve do tej servisy

h4kuna
Backer | 740
+
+2
-

Taky by bylo optimální, aby jsi si udělal Factory na Form a tuto továrnu poslal přes kontruktor TherapyFormFactory.

A namísto

$form = new UI\Form;

dělat

$form = $this->formFactory->create();

Do budoucna ti to umožní:

  • globálně přidat překladač
  • mít více metod, třeba s aktivovaným csrf a bez něj, get vs post atd
  • když použiješ FormFactory tak v ní můžeš teprve navěsit Extension methods, pomocí Utils\ObjectMixin::setExtensionMethod a není potřeba to dělat v requestech kde nejsou formuláře

EDIT: Stejně jako je v sanboxu

Editoval h4kuna (9. 11. 2018 11:06)

admin@easyweb4u.cz
Backer | 143
+
0
-

To je všechno pěkné, ale teď jsem se zasekl na následujícím:

V presenteru mám:

<?php
    protected function createComponentTherapyForm()
    {
        $form = $this->therapyFormFactory->create($this->id);
        $form->onSuccess[] = function (UI\Form $form) {

        };
        return $form;
?>

posílám z presenteru do formulářové komponenty parametr $this->id, abych do formuláře mohl načíst defaultní hodnoty.

<?php
    public function create($id)
    {
        $form = new UI\Form;

        $form->addProtection();

        $row = $this->database->table('calendar')->get($id);

		...

        $form->addSubmit('send', 'Odeslat')
                ->setAttribute('class', 'btn btn-success');

        $form->getElementPrototype()->class('ajax');

        $form->onSuccess[] = [$this, 'processTherapyForm'];

        return $form;
	}
?>

(Formulář se má odeslat přes AJAX)

Formulář se načte, ale po odeslání se objeví noticka Trying to get property ‚day‘ of non-object, do dotazu se načte id = 0. Při znovunačtení formuláře už se nepřenese z presenteru $id. Zkoušel jsem to přes konstruktor, ale zatím se mi nic nedaří…

PS: pokud formulář mám normálně v presenteru, vše funguje jak má

h4kuna
Backer | 740
+
0
-

A ten ajaxový request (konkrétně url) vypadá jak?

David Matějka
Moderator | 6445
+
0
-

jak vypada presenter? konkretne cast, kde pracujes s tim id?

admin@easyweb4u.cz
Backer | 143
+
0
-

h4kuna napsal(a):

A ten ajaxový request (konkrétně url) vypadá jak?

No na tohle asi neumím odpovědět … url requestu …

localhost/projekt/calendar/default/1/10

to je poslední url po odeslání toho formuláře (id = 10)

Editoval admin@easyweb4u.cz (9. 11. 2018 14:40)

admin@easyweb4u.cz
Backer | 143
+
0
-

David Matějka napsal(a):

jak vypada presenter? konkretne cast, kde pracujes s tim id?

<?php

namespace App\Presenters;

use Nette\Application\UI;

class CalendarPresenter extends BasePresenter {

    /** @var \App\Model\CalendarService @inject */
    public $calendar;

    /** @var \App\Forms\TherapyFormFactory @inject */
    public $therapyFormFactory;


    /** @var int */
    public $id;

    public function startup() {
        parent::startup();

        $id = intval($this->request->getParameter('id'));

        $this->id = $id;

		....

	}

    protected function createComponentTherapyForm()
    {
        $form = $this->therapyFormFactory->create($this->id);
        $form->onSuccess[] = function (UI\Form $form) {
            //$this->redirect('this');
        };
        return $form;
    }

    public function renderDefault() {
        $this->template->id = $this->id;
	}

?>

Ale jak jsem psal to řešení, pokud je v presenteru normálně funguje. Přes komponentu to řeším kvůli vícero použití.

h4kuna
Backer | 740
+
+1
-

admin@easyweb4u.cz napsal(a):

No na tohle asi neumím odpovědět … url requestu …

localhost/projekt/calendar/default/1/10

To jsi vyčetl z konsole nebo jsi odhadl? Opravdu to ověř, že to tak je. V chrome zmačkni f12 záložka Network a když vyvoláš ajaxový požadavek ukáže se ti url. Případně si můžeš udělat dump toho id a vypíše se ti jako odpověď ze servru.

Jelikož id není persistentní, není uvedený ani v render metodě, tak si myslím že se nedostane do atributu action v tagu form, tzn. prostě se ti ztratí z požadavku.

Pokud to tak je, tak by mělo pomoci

class CalendarPresenter extends BasePresenter {

    /**
	 * @var int
     * @persistent
     */
    public $id;
}

nebo

public function renderDefault($id) {
    $this->template->id = $this->id;
}

Dokumentace k persistentním parametrům

Editoval h4kuna (9. 11. 2018 15:34)

admin@easyweb4u.cz
Backer | 143
+
0
-

Jo jo, stačilo nastavit $id @persistent. Dík