Dvojí vložení (insert) vložení záznamu do DB

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

Udělal jsem si v Nette svoji první aplikaci, která vychází z první výukové aplikace v dokumentaci. Při ručním plnění dat na produkčním serveru do DB se mi čas od času (ne pravidelně) stane, že se vkládaný záznam vloží 2×. Natvrdo jsem si zapnul laděnku a zde je krásně vidět že se vše provede 2x:

screen zde: http://prnt.sc/dt39yv

Připadá mi, že se tak stane vždy, když zpracování dotazu po odeslání formuláře trvá o něco déle než obvykle.

Poraďte prosím, jak postupovat při odhalení, v čem je problém.
Děkuji

CZechBoY
Člen | 3608
+
0
-

Těžko říct, bez kodu jenom věštění z koule.
Pošli presenter + cestu (zdrojáky) ke vkládání do databáze.

andros
Člen | 145
+
0
-

Snad bude stačit toto:

protected function createComponentPostForm()
    {
        //$form = new Form;
        $form = $this->form();
        $form->addText('title', 'Titulek:')
            ->setRequired("vz=y");

        $category = array();
        $select = $this->database->table('category')->select('id')->select('name')->fetchAll();
        foreach ($select as $id => $row) {
            $category[$id] = $row['name'];
        }

        $form->addSelect('category', 'Kategorie:', $category)
            ->setPrompt('Zvolte kategorii')
            ->setRequired("Zadejte kategorii");
        $form->addText('year','Rok')
            ->setRequired('Rok výroby je potřeba vyplnit');
        $form->addText('csfd_id','Id ČSFD');
        $form->addTextArea('content', 'Obsah:',NULL, 10);

        $form->addSubmit('send', 'Uložit a publikovat');
        $form->onSuccess[] = [$this, 'postFormSucceeded'];

        return $form;
    }

    public function postFormSucceeded($form, $values)
    {
        if (!$this->getUser()->isLoggedIn()) {
            $this->error('Pro vytvoření, nebo editování příspěvku se musíte přihlásit.');
        }

        $postId = $this->getParameter('postId');

        if ($postId) {
            $post = $this->database->table('posts')->get($postId);
            $post->update($values);
        } else {
            $post = $this->database->table('posts')->insert($values);
        }

        $this->flashMessage('Příspěvek byl úspěšně publikován.', 'success');
        $this->redirect('Homepage:default');
    }
CZechBoY
Člen | 3608
+
0
-

Tahle cast vypada ok.
Co se dela v $this->form();?

andros
Člen | 145
+
0
-

Tady je celý presenter:

<?php
namespace App\Presenters;

use Nette;
use Nette\Application\UI\Form;


class PostPresenter extends BasePresenter
{
    /** @var Nette\Database\Context */
    private $database;

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

    protected function form() {
        $form = new Form;

        $renderer = $form->getRenderer();
        $renderer->wrappers['controls']['container'] = NULL;
        $renderer->wrappers['pair']['container'] = 'div class=form-group';
        $renderer->wrappers['pair']['.error'] = 'has-error';
        $renderer->wrappers['control']['container'] = 'div class=col-sm-8';
        $renderer->wrappers['label']['container'] = 'div class="col-sm-1 control-label"';
        $renderer->wrappers['control']['description'] = 'span class=help-block';
        $renderer->wrappers['control']['errorcontainer'] = 'span class=help-block';
// make form and controls compatible with Twitter Bootstrap
        $form->getElementPrototype()
            ->class('form-horizontal page-form')
            ->role('form');

        $form->onRender[] = function ($form) {
            foreach ($form->getControls() as $control) {
                $type = $control->getOption('type');
                if ($type === 'button') {
                    $control->getControlPrototype()->addClass('btn btn-primary');
                    $usedPrimary = TRUE;
                } elseif (in_array($type, ['text', 'textarea', 'select'], TRUE)) {
                    $control->getControlPrototype()->addClass('form-control');
                } elseif (in_array($type, ['checkbox', 'radio'], TRUE)) {
                    $control->getSeparatorPrototype()->setName('div')->addClass($type);
                }
            }
        };
        return $form;
    }

    public function renderShow($postId)
    {

        $post = $this->database->table('posts')->get($postId);
        if (!$post) {
            $this->error('Stránka nebyla nalezena');
        }

        $this->template->post = $post;
        $this->template->comments = $post->related('comment')->order('created_at');

    }

    protected function createComponentCommentForm()
    {
        $form = new Form; // means Nette\Application\UI\Form

        $form->addText('name', 'Jméno:')
            ->setRequired();

        $form->addEmail('email', 'Email:');

        $form->addTextArea('content', 'Komentář:')
            ->setRequired();

        $form->addSubmit('send', 'Publikovat komentář');

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

        return $form;
    }

    public function commentFormSucceeded($form, $values)
    {
        $postId = $this->getParameter('postId');

        $this->database->table('comments')->insert([
            'post_id' => $postId,
            'name' => $values->name,
            'email' => $values->email,
            'content' => $values->content,
        ]);

        $this->flashMessage('Děkuji za komentář', 'success');
        $this->redirect('this');
    }

    protected function createComponentPostForm()
    {
        //$form = new Form;
        $form = $this->form();
        $form->addText('title', 'Titulek:')
            ->setRequired("Vložte titulek stránky");

        $category = array();
        $select = $this->database->table('category')->select('id')->select('name')->fetchAll();
        foreach ($select as $id => $row) {
            $category[$id] = $row['name'];
        }

        $form->addSelect('category', 'Kategorie:', $category)
            ->setPrompt('Zvolte kategorii')
            ->setRequired("Zadejte kategorii");
        $form->addText('year','Rok')
            ->setRequired('Rok výroby je potřeba vyplnit');
        $form->addText('csfd_id','Id ČSFD');
        $form->addTextArea('content', 'Obsah:',NULL, 10);

        $form->addSubmit('send', 'Uložit a publikovat');
        $form->onSuccess[] = [$this, 'postFormSucceeded'];

        return $form;
    }

    public function postFormSucceeded($form, $values)
    {
        if (!$this->getUser()->isLoggedIn()) {
            $this->error('Pro vytvoření, nebo editování příspěvku se musíte přihlásit.');
        }

        $postId = $this->getParameter('postId');

        if ($postId) {
            $post = $this->database->table('posts')->get($postId);
            $post->update($values);
        } else {
            $post = $this->database->table('posts')->insert($values);
        }

        $this->flashMessage('Příspěvek byl úspěšně publikován.', 'success');
        $this->redirect('Homepage:default');
    }

    public function actionEdit($postId)
    {

        if (!$this->getUser()->isLoggedIn()) {
            $this->redirect('Sign:in');
        }

        $post = $this->database->table('posts')->get($postId);
        if (!$post) {
            $this->error('Příspěvek nebyl nalezen');
        }
        $this['postForm']->setDefaults($post->toArray());
    }

    public function actionCreate($title, $rok, $csfd)
    {
        if (!$this->getUser()->isLoggedIn()) {
            $this->redirect('Sign:in');
        }

        $this['postForm']->setDefaults([
            'title' => $title,
            "year" => $rok,
            'csfd_id' => $csfd
        ]);
    }
}
cvak
Člen | 1
+
0
-

Mě se stává něco podobného. Jako příčinu jsem identifikoval skutečně dvojité odeslání formuláře uživatelem, čili 2× klikne na tlačítko, případně stiskně Enter a zárověň klikne na tlačítko.
Formulář se pak zpracuje, a něž se stihne přesměrovat, zpracuje se ještě jednou.

S tím souvisí můj dotaz – lze nějak zabránit tomu, aby došlo k druhému zpracování formuláře ještě předtím, než se stihne přesměrovat? Řešil to někdo? Je na to nějaký trik?

Díky

CZechBoY
Člen | 3608
+
0
-

@cvak jo, javascriptem, nedávno se to tu řešilo
https://forum.nette.org/…ni-formulare