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 :)