Jak při registraci ověřit existujícího uživatele?

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

Mám v presenteru po odesláni registračního formuláře tuto metodu

    public function registerFormSubmitted(UI\Form $form) {
        $values = $form->getValues();
        $uzivEmail = $this->getParameter('email');
        $uzivatel = $this->database->table('uzivatele')->get($uzivEmail);
        if (!$uzivatel) {
                $this->flashMessage('Uzivatel uz existuje', 'warning');
                $this->redirect('this');
        }
        else
        {
            $this->database->table('uzivatele')->insert(array(
                'email' => $values->email,
                'heslo' => $values->password,
            ));
            $this->flashMessage('Registrace proběhla úspěšně. Nyní se můžete přihlásit.', 'success');
            $this->redirect('this');
        }
    }

Ale nefunguje mě to tak jak bych si představoval. Konkrétně podmínka:

if (!$uzivatel)

na to, jestli uživatel se zadaným emailem už v databázi existuje.
Pokud ano, chci to prostě jen vypsat na stránku, ne abych skončil s errorem v debuggeru.
Dělám to dobře nějakou takovou podmínkou nebo se to musí přes nějaké try?
Pokud ano, jak se dostanu zpět na stejnou stránku a s informací, že se před tím registrace nepodařila?
Díky

Oli
Člen | 1215
+
-2
-

Dej na sloupec v db s emailem unique a zpracuj to v try bloku. Pokud ti to odchytne tak zavolej místo flash Message, $form->addError(…); return; jinak Normálně uložíš do db.

icanjan
Člen | 30
+
0
-

Díky, a pro úplnost pro případné další čtenáře.
Moje řešení:

        try {
            $uzivatel = $this->database->table('uzivatele')->get($emailm);
            $this->database->table('uzivatele')->insert(array(
                'email' => $values->email,
                'heslo' => $values->password,
            ));

            $this->flashMessage('Registrace proběhla úspěšně. Nyní se můžete přihlásit.', 'success');
            $this->redirect('this');
        } catch (Exception $e) {
            $form->addError($e->getMessage());
        }

a na začátek presenteru použít

use Exception;

A pak vypsání chyby v .latte pod formulářem (obšlehnuto z jiného dotazu):

{form registerForm}
...
      {if $form->hasErrors()}
          <div n:foreach="$form->errors as $errorMessage" class="alert alert-danger">
              <button type="button" class="close" data-dismiss="alert">&times;</button>
              {$errorMessage}
          </div>
      {/if}
{/form}
Oli
Člen | 1215
+
0
-

Bych to i vypsal, ale jsem jen na mobilu.

@icanjan Neodchytavej jen exeption. Může se stát cokoli jiného. Odchytni si jeste konkrétní kód. Z hlavy Nevim, střílím ze by to mohlo byt 27000, ale to už si někde najdeš :)

icanjan
Člen | 30
+
0
-

No, se ukázalo, že to furt tak jasný není.
Mám teď v catch tento kód:

        } catch (Exception $e) {
            if ($e->getCode() == 23000) { // puvodne tady bylo ===
                // pokud je chyba v duplicitě klíče, přidáme chybu do formu
                $form->addError($e->getMessage()."Registrace se nezdařila.");
            } else {
                $form->addError($e->getMessage()." - JINA CHYBA.".$e->getCode());
		// pokud jde o jinou chybu, necháme ji probublat výš
               // throw $e;
            }
	}

Za prvné: mě zajímá, proč mě to do catch leze i když to žádnou vyjímku nevyhodí? Při úspěšném vložení do databáze to stejně do catch vleze, konkrétně do else větve.
Dále: V příkladu jsem našel, že na porovnání s chybou se používá operátor ===. Ale ten mě nefunguje, leze to pak do else. Musel jsem použít ==. Nechápu. Vysvětlí někdo?

Předem díky.

Editoval icanjan (6. 7. 2014 15:05)

Mysteria
Člen | 797
+
0
-
try {
...
} catch(\PDOException $e) { // SQL chyba
	if ((int)$e->errorInfo[1] === 1062) { // SQL kód pro narušení unikátního klíče
		/* Nick je obsazen, vyber si jinej */
	} else { /* Jiná SQL chyba */ }
} catch (\Exception $e) { /* Jakákoliv obecná chyba */ }

Tři === porovnávají i datový typ, tzn. "16" === 16 bude FALSE, protože jedno je string a druhý int,
takže musíš přetypovat (int)"16" === 16 bude TRUE stejně jako "16" == 16.

Editoval Mysteria (6. 7. 2014 16:12)

Čamo
Člen | 798
+
0
-

Mysteria:
Ten kód 1062 platí pre všetky databázy? Nejako sa ku tomu nemôžem cez Google dohrabať.

Majkl578
Moderator | 1364
+
0
-

@Čamo: Ne.

Majkl578
Moderator | 1364
+
+3
-

Osobně si myslím, že formulář by měl mít validaci na existující jméno mimo submit handler. Tzn. vlastní pravidlo, něco takového:

$form->addText('email')
	->...
	->addRule(function (IControl $control) {
		return !$this->usersRepository->isEmailRegistered($control->getValue());
	}, 'E-mail je již registrován.');

To je samozřejmě optimistická validace, která ale v 99% funguje. Pro pesimistickou verzi je unikátní klíč v databázi (a i tady můžeš někde v modelu chytat a analyzovat výjimku, kterou převedeš např. na EmailAlreadyRegisteredException a v submit handleru explicitně odchytíš).

Mysteria
Člen | 797
+
0
-

Určitě platí pro MySQL, jinou databázi nepoužívám, takže je mi to fuk, jak je to jinde.

Oli
Člen | 1215
+
0
-

Tohle je samozrejme uzivatelsky příjemnější. Moje řešení zase 100%. Nejlepsi je mít (jak píšeš v 2. odstavci) oboje :)