Ukladanie jedneho formulara do dvoch tabuliek

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

Zdravim, mam otazku.
v modeli ukladam formular do DB,
v presenteri vytvaram formular pomocou nette forms, podla dokumentacie a
v latte formular vykreslujem, cez jQuery chcem spravit „viac-krokovy formular“

Otazne je ale, ci sa da formular spravit tak, aby ukladal nejake hodnoty do jednej tabulky a nejake hodnoty do druhej tabulky, po stlaceni Submit buttonu.

Dakujem velmi pekne za vsetky odpovede :)

Editoval majo1 (1. 2. 2016 10:59)

CZechBoY
Člen | 3608
+
0
-

https://componette.org/…orms-wizard/
Můžeš zkusit jestli by se ti to nelíbilo.

majo1
Člen | 103
+
0
-

neviem, či je to tým, že som v nette začiatočník, ale ten komponent sa mi nepodarilo rozbehať :/

class Wizard extends WebChemistry\Forms\Wizard\Component {

ide píše undefined namespace, nenašiel som spôsob, ako tú cestu upraviť.

Editoval majo1 (1. 2. 2016 11:21)

CZechBoY
Člen | 3608
+
0
-

Nainstaloval si doplněk přes composer?

David Matějka
Moderator | 6445
+
0
-

Jakou chybu to presne pise? kdyztak ukaz i s ladenkou

majo1
Člen | 103
+
0
-

http://oi66.tinypic.com/xbzng6.jpg
instalovane cez composer, – WebChemistry\Forms\Controls\DI\WizardExtension mam v configu

Editoval majo1 (1. 2. 2016 11:48)

David Matějka
Moderator | 6445
+
0
-

hm, ono v dokumentaci chybi, ze musis v presenteru vytvorit tovarnu na ten wizard, neco jako

protected function createComponentWizard()
{
	return new Wizard(); //se spravnym namespacem
}
majo1
Člen | 103
+
0
-

pardon, toto je screen, ktory som chcel poslat: http://oi63.tinypic.com/dpea20.jpg

David Matějka napsal(a):

hm, ono v dokumentaci chybi, ze musis v presenteru vytvorit tovarnu na ten wizard, neco jako

protected function createComponentWizard()
{
	return new Wizard(); //se spravnym namespacem
}
pata.kusik111
Člen | 78
+
0
-

Používáš namespace v souboru, kte vytváříš tu svoji komponentu. Jednoduchá oprava je na řádku 13 za „extends“ před jestu k extendované class přidat lomítko.

majo1
Člen | 103
+
0
-

po pridani lomitka tracy oznamuje:
Class ‚WebChemistry*Forms***Wizard**\Component‘ not found

pozrel som strukturu pricinkov..
vo vendors/webchemistry/forms/src nie je subor Wizard.php
je ale vo vendors/webchemistry/forms-wizard/src

David Matějka
Moderator | 6445
+
+1
-

vypada to, ze ta trida se spravne jmenuje \WebChemistry\Forms\Controls\Wizard

majo1
Člen | 103
+
0
-

vyzera to tak, ze ano :)
no po uprave mi tracy zas oznamuje: Nette\Application\BadRequestException #404
Cannot load presenter ‚Reservationform‘, class ‚App\Presenters\ReservationformPresenter‘ is not Nette\Application\IPresenter implementor

David Matějka
Moderator | 6445
+
+1
-

vypada to, ze nededis nejaky BasePresenter nebo UI\Presenter

majo1
Člen | 103
+
0
-

ach.. asi zostanem pri povodnom plane → na formular vykresleny v latte aplikovat tento script :)

a dalej upravit v modeli tento dopyt na databazu (neviem presne kvoli dokumentacii, ako na to)

    public function saveReservationform($reservationform)
    {
        if (!$reservationform[self::COLUMN_ID])
            $this->database->table(self::TABLE_NAME)->insert($reservationform);
    }
David Matějka
Moderator | 6445
+
0
-

ach.. asi zostanem pri povodnom plane

no to se ti nic nezmeni na tom, ze reservationformpresenter bude muset dedit od presenteru

a dalej upravit v modeli tento dopyt na databazu (neviem presne kvoli dokumentacii, ako na to)

a ja nevim, na co se ptas. hlasi to nejakou chybu?

premek_k
Člen | 172
+
0
-

Takto se ale asi poslední chyby nezbavíš. Dědí ti ten ReservationformPresenter od UI\Presenter?

EDIT: David je sakra rychlý, z mobilu jsem to nestihl… :-)

Editoval premek_k (1. 2. 2016 13:04)

CZechBoY
Člen | 3608
+
0
-

@majo1 Ten js plugin ti jen rozkouskuje 1 formulář. Tzn neděláš 4× POST jako v případě vícekrokovýho formuláře (jak jsem ti posílal odkaz na Nette plugin), ale jen pomocí js jinak zobrazíš 1 formulář.

majo1
Člen | 103
+
0
-

moja chyba je, ze som nezacal s hlavnym problemom, najpodstatnejsou vecou.
ide mi v principe o toto:

mam nasledujuci model:

<?php

namespace App\Model;

use App\Model\BaseManager;
use Nette\Database\Table\IRow;
use Nette\Database\Table\Selection;
use Nette\Utils\ArrayHash;

class ReservationformManager extends BaseManager
{
    const
            TABLE_NAME = 'reservations',
            COLUMN_ID = 'idreservation',
        CUSTOMERSTABLE_NAME = 'customers',
        CUSTOMERSCOLUMN_ID = 'idcustomer',
            SKIBUSTABLE_NAME = 'skibuses',
            SKIBUSCOLUMN_ID = 'idskibus',
        STATIONTABLE_NAME = 'stations',
        STATIONCOLUMN_ID = 'idstation',
            CENTERTABLE_NAME = 'centers',
            CENTERCOLUMN_ID = 'idcenter';

    public function saveReservationform($reservationform)
    {
        $this->database->table(self::TABLE_NAME)->insert($reservationform);
    }

    public function getCenter()
    {
        return $this->database->table(self::CENTERTABLE_NAME)->order(self::CENTERCOLUMN_ID . ' ASC');
    }

    public function getStation()
    {
        return $this->database->table(self::STATIONTABLE_NAME)->order(self::STATIONCOLUMN_ID . ' ASC');
    }

    public function getSkibus()
    {
        return $this->database->table(self::SKIBUSTABLE_NAME)->order(self::SKIBUSCOLUMN_ID . ' DESC')->limit(10);
    }
}

nasledujuci presenter:

<?php

namespace App\Presenters;

use App\Model\ReservationformManager;
use App\Presenters\BasePresenter;
use Nette\Application\BadRequestException;
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
use Nette\Database\UniqueConstraintViolationException;


class ReservationformPresenter extends BasePresenter
{

    protected $reservationformManager;


    public function __construct(ReservationformManager $reservationformManager)
    {
        parent::__construct();
        $this->reservationformManager = $reservationformManager;
    }


    public function renderDefault()
    {

    }

    protected function createComponentEditorForm()
    {
        $form = new Form;
        $form->addHidden('idreservation');
        $form->addHidden('datetime');
        $form->addText('numAdult', 'Počet dospelých:')
            ->addRule(Form::RANGE, 'Musí byť v rozsahu %d až %d', array(0, 100))
            ->setDefaultValue('0')
            ->setType('number')->setRequired();
        $form->addText('numJunior', 'Počet juniorov:')
            ->addRule(Form::RANGE, 'Musí byť v rozsahu %d až %d', array(0, 100))
            ->setDefaultValue('0')
            ->setType('number')->setRequired();
        $form->addText('numKid', 'Počet detí:')
            ->addRule(Form::RANGE, 'Musí byť v rozsahu %d až %d', array(0, 100))
            ->setDefaultValue('0')
            ->setType('number')->setRequired();
        $form->addText('numTransportOnly', 'Len doprava:')
            ->addRule(Form::RANGE, 'Musí byť v rozsahu %d až %d', array(0, 100))
            ->setDefaultValue('0')
            ->setType('number')->setRequired();

        $result = $this->reservationformManager->getCenter();
        $centers = $result->fetchPairs('idcenter', 'centerName');
        $form->addSelect('center_idcenter', 'Stredisko:', $centers);

        $result = $this->reservationformManager->getStation();
        $stations = $result->fetchPairs('idstation', 'city');
        $form->addSelect('station_idstation', 'Zastávka:', $stations);

        $result = $this->reservationformManager->getSkibus();
        $skibus = $result->fetchPairs('idskibus', 'departureDatetime');
        $form->addSelect('skibus_idskibus', 'Skibus:', $skibus);

        $form->addText('name', 'Meno:')
            ->setType('text')->setRequired();
        $form->addText('surename', 'Priezvisko:')
            ->setType('text')->setRequired();
        $form->addText('telephone', 'Telefónne číslo:')
            ->setType('text')->setRequired();
        $form->addText('email', 'E-mail:');

        $form->addSubmit('submit', 'Rezervovať skibus');
        $form->onSuccess[] = [$this, 'editorFormSucceeded'];
        return $form;
    }

    public function editorFormSucceeded($form, $values)
    {
        try {
            $this->reservationformManager->saveReservationform($values);
            $this->flashMessage('Rezervácia bola úspešná.');
            $this->redirect(':Reservationform:', $values->idreservation);
        } catch (UniqueConstraintViolationException $ex) {
            $this->flashMessage('Rezervácia s týmto ID už existuje!');
        }
    }
}
majo1
Člen | 103
+
0
-

a latte

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <link rel="stylesheet" href="{$basePath}/bootstrap/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
  <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
  <link rel="stylesheet" href="{$basePath}/dist/css/AdminLTE.min.css">
  <link rel="stylesheet" href="{$basePath}/dist/css/skins/skin-blue.min.css">
  <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
  <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->
</head>
<body>






    <form n:name=editorForm class=form>
    <div n:if="$form->hasErrors()" class="callout callout-warning">
        <h4>Chyba!</h4>
        <p n:foreach="$form->errors as $error">{$error}</p>
    </div>

    <div class="form-group">
       <label n:name=center_idcenter>Stredisko*</label>
       <select n:name=center_idcenter class="form-control">
             <option></option>
       </select>
     </div>
     <div class="form-group">
       <label n:name=skibus_idskibus>Skibus*</label>
       <select n:name=skibus_idskibus class="form-control">
             <option></option>
       </select>
     </div>
     <div class="form-group">
       <label n:name=station_idstation>Zastávka*</label>
       <select n:name=station_idstation class="form-control">
             <option></option>
       </select>
     </div>


     <div class="input-group">
       <label n:name=numAdult>Počet dospelých*
         <div class="input-group">
         <input type="number" min="0" max="100" class="form-control" n:name=numAdult>
         <div class="input-group-addon">
             <i class="fa fa-child"></i>
           </div>
         </div>
       </label>
     </div>
     <div class="input-group">
       <label n:name=numJunior>Počet juniorov*
         <div class="input-group">
         <input type="number" min="0" max="100" class="form-control" n:name=numJunior>
         <div class="input-group-addon">
             <i class="fa fa-child"></i>
           </div>
         </div>
       </label>
     </div>
     <div class="input-group">
       <label n:name=numKid>Počet detí*
         <div class="input-group">
         <input type="number" min="0" max="100" class="form-control" n:name=numKid>
         <div class="input-group-addon">
             <i class="fa fa-child"></i>
           </div>
         </div>
       </label>
     </div>
     <div class="input-group">
       <label n:name=numTransportOnly>Len doprava*
         <div class="input-group">
         <input type="number" min="0" max="100" class="form-control" n:name=numTransportOnly>
         <div class="input-group-addon">
             <i class="fa fa-bus"></i>
           </div>
         </div>
       </label>
     </div>


     <div class="input-group">
        <label n:name=name>Meno*
          <div class="input-group">
          <input class="form-control" n:name=name>
          <div class="input-group-addon">
              <i class="fa fa-user"></i>
            </div>
          </div>
        </label>
     </div>
     <div class="input-group">
         <label n:name=surename>Priezvisko*
           <div class="input-group">
           <input class="form-control" n:name=surename>
           <div class="input-group-addon">
               <i class="fa fa-user"></i>
             </div>
           </div>
         </label>
     </div>
     <div class="input-group">
        <label n:name=telephone>Telefón*
          <div class="input-group">
          <input class="form-control" n:name=telephone>
          <div class="input-group-addon">
              <i class="fa fa-phone"></i>
            </div>
          </div>
        </label>
     </div>
     <div class="input-group">
         <label n:name=email>E-mail
           <div class="input-group">
           <input class="form-control" n:name=email>
           <div class="input-group-addon">
               <i class="fa fa-envelope"></i>
             </div>
           </div>
         </label>
     </div>

    <p><input n:name=submit class="btn btn-primary"></p>
    </form>






   <script src="http://momentjs.com/downloads/moment.min.js"></script>
    <script src="{$basePath}/plugins/jQuery/jQuery-2.1.4.min.js"></script>
    <script src="{$basePath}/bootstrap/js/bootstrap.min.js"></script>
    <script src="{$basePath}/plugins/datatables/dataTables.bootstrap.min.js"></script>
    <script src="{$basePath}/dist/js/app.min.js"></script>
    <script src="{$basePath}/dist/js/demo.js"></script>
    <link rel="stylesheet" href="{$basePath}/plugins/timepicker/bootstrap-timepicker.min.css">
    <script src="{$basePath}/plugins/timepicker/bootstrap-timepicker.min.js"></script>

    <link href="//cdn.rawgit.com/Eonasdan/bootstrap-datetimepicker/e8bddc60e73c1ec2475f827be36e1957af72e2ea/build/css/bootstrap-datetimepicker.css" rel="stylesheet">
    <script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment-with-locales.js"></script>
    <script src="//cdn.rawgit.com/Eonasdan/bootstrap-datetimepicker/e8bddc60e73c1ec2475f827be36e1957af72e2ea/src/js/bootstrap-datetimepicker.js"></script>
    <script type="text/javascript">
        $(function () {
            $('#datetimepicker2').datetimepicker({
                locale: 'sk',
                useCurrent: true,
                format: 'YYYY-MM-DD HH:mm'
            });
        });
    </script>
    <script>
      $(function () {
        //Timepicker
        $(".timepicker").timepicker({
          showInputs: false,
          showMeridian: false,
          minuteStep: 1,
          defaultTime: 'current',
          format: 'HH:mm'
        });
      });
    </script>

</body>
</html>

screen latte: tu
screen tracy po odkliknuti tlacidla: tu

neviem formular upravit tak, aby sa udaje o zakaznikovi (stlpce name, surename, telephone, mail) ukladali do tabulky customers a nie do tabulky reservations.
resp. tabulky reservations a customers maju spolu vztah 1:n

latte budem upravovat, je tam kopu zbytocnosti.. v podstate ide o formular a k nemu administraciu (ktora by mala byt funkcna)

zaroven potrebujem, aby sa pri zvoleni strediska (centers) vyfiltrovali zastavky (stations) a skibusy (skibuses) len pre to urcite stredisko.

dakujem

Editoval majo1 (1. 2. 2016 14:55)

majo1
Člen | 103
+
0
-

prosim vas, vedeli by ste mi s tym pomoct? dat nejaky example, alebo postup?
vopred dakujem velmi pekne :)

David Matějka
Moderator | 6445
+
+1
-

a kde je problem? proste nektery prvky z toho pole (resp hash mapy) vlozis do jedny tabulky, nektery do druhy. Pro logicky rozdeleni formulare muzes pouzit containery a ve $values budes mit ty data rozdeleny

majo1
Člen | 103
+
0
-

vytvoril som containery v presenteri.
bude treba ale upravit latte, pretoze mi k poliam tracy pise:

Component with name ‚xyz‘ does not exist.

ako mam latte upravit, ked robim manualne vykreslovanie?

David Matějka
Moderator | 6445
+
+2
-

@majo1 jako nazev toho inputu pouzijes nazev kontejneru a nazev inputu oddeleny pomlckou, tedy treba
{input address-name} resp. <input n:name="address-name"/> kde address je nazev kontejneru a name nazev inputu

majo1
Člen | 103
+
0
-

dakujem, uz to funguje,
v modeli som insertol data takto:
29: $this->database->table(self::TABLE_NAME)->insert($reservationform->resdetail);
30: $this->database->table(self::TABLE_NAME)->insert($reservationform->custdetail);

len som asi zle vytvoril tabulky alebo zle insertujem :D

tracy:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (nitransform.reservations, CONSTRAINT fk_reservation_customer1 FOREIGN KEY (customer_idcustomer) REFERENCES customers (idcustomer) ON DELETE NO ACTION ON UPDATE NO ACTION)

David Matějka
Moderator | 6445
+
0
-

proc to vkladas do stejne tabulky? ukaz strukturu db

majo1
Člen | 103
+
0
-

takto https://unsee.cc/gusedami/ vyzera moja db.
nenapada mi, ako to spravne vlozit.

pri insertnuti informacii o zakaznikovi by sa malo jeho auto-incrementnute id niekde zapamatat a nasledne insertnut do rezervacie
neviem, ako na to :/

Editoval majo1 (2. 2. 2016 15:10)

David Matějka
Moderator | 6445
+
0
-

vloz do tabulky customers a to ti vrati radek s prirazenym ID, ktery muzes pouzit pro insert do reservations

majo1
Člen | 103
+
0
-

moj model:

const
            TABLE_NAME = 'reservations',
            COLUMN_ID = 'idreservation',
        CUSTOMERSTABLE_NAME = 'customers',
        CUSTOMERSCOLUMN_ID = 'idcustomer',

    public function saveReservationform($reservationform)
    {
        $this->database->table(self::CUSTOMERSTABLE_NAME)->insert($reservationform->custdetail);
        $this->database->table(self::TABLE_NAME)->insert($reservationform->resdetail);
    }

, tracy pise stale
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (nitransform.reservations, CONSTRAINT fk_reservation_customer1 FOREIGN KEY (customer_idcustomer) REFERENCES customers (idcustomer) ON DELETE NO ACTION ON UPDATE NO ACTION)

pricom odkazuje chybu pri inserte $reservationform->resdetail :/

majo1
Člen | 103
+
0
-

viete prosim, kde robim chybu? :/

premek_k
Člen | 172
+
0
-

Ten první insert ti vrátí právě uložená data, a to včetně nově vygenerovaného ID. Proto si to přiřaď do proměnné a před tím druhým insertem si z ní vytáhni to ID a doplň do parametru druhého insertu tak, aby ti seděl cizí klíč.

majo1
Člen | 103
+
0
-

už som to vyriešil :) pri inserte mi vynechávalo jeden FK. preto ta chyba…

teraz sa snazim zisit, co by bolo lepsie.
vo formulari je select box a od neho zavisi, ake udaje sa budu do DB nahravat.

asi pomocou uz spomenuteho https://componette.org/…orms-wizard/
len akosi to neviem rozbehat.. :/ chcelo by to nejaky priklad

CZechBoY
Člen | 3608
+
+1
-

Jakej priklad? Na ty strance, co si poslal, priklad je.

majo1
Člen | 103
+
0
-

ten priklad neviem vo svojom projekte implementovat :/

v configu mam spomenuty extension pridany,

toto je moj presenter WizardPresenter.php

<?php

namespace App\Presenters;

use App\Presenters\BasePresenter;
use Nette\Application\BadRequestException;
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
use Nette\Database\UniqueConstraintViolationException;

class WizardPresenter extends \WebChemistry\Forms\Controls\Wizard {

    protected function finish() {
        $values = $this->getValues();
    }

    protected function createStep1() {
        $form = $this->getForm();

        $form->addText('name', 'Uživatelské jméno')
            ->setRequired();

        $form->addSubmit(self::NEXT_SUBMIT_NAME, 'Další');

        return $form;
    }

    protected function createStep2() {
        $form = $this->getForm();

        $form->addText('email', 'Email')
            ->setRequired();

        $form->addSubmit(self::PREV_SUBMIT_NAME, 'Zpět');
        $form->addSubmit(self::FINISH_SUBMIT_NAME, 'Registrovat');

        return $form;
    }
}

toto moje latte Wizard/default.latte

<div n:wizard="wizard">
    <ul n:if="!$wizard->isSuccess()">
        <li n:foreach="$wizard->steps as $step" n:class="$wizard->isDisabled($step) ? disabled, $wizard->isActive($step) ? active"><a n:tag-if="$wizard->useLink($step)" n:href="changeStep! $step">{$step}</a></li>
    </ul>

    {step 1}
        {control $form}
    {/step}

    {step 2}
        {control $form}
    {/step}

    {step success}
        Úspěšně jste se registroval/a.
    {/step}
</div>

a po otvoreni stranky wizard, mi pise chybu:
Nette\Application\BadRequestException #404
Cannot load presenter ‚Wizard‘, class ‚App\Presenters\WizardPresenter‘ was not found.
chyba na: $container->getByType(‚Nette\Application\Application‘)->run();

premek_k
Člen | 172
+
+2
-

Ten kód, co máš v Presenteru má být v komponentě. Ten předek toho Presenteru je taky špatně.

Myslím, že by sis měl projít alespoň dokumentaci, abys měl aspoň trochu přehled. Copy&paste programování bez znalosti základů nikam nepovede…