Ako napísať registráciu v súlade s PDO?

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

Prečítal som si toto vlákno ale to ma neuspokojilo. Skončilo to tam pri porovnávaní konkrétneho kódu pre mysql:

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 */ }

Ale ako napísať takú kontrolu, ktorá by bola v súlade s používaním PDO, teda univerzálnu. Dá sa to vôbec tak napísať?
Ma napadlo pri výskyte akejkoľvek chyby testovať následne existenciu mena v tabuľke.

catch(Exception e)
{
	if($this->database->table(users)->where('name = ?', $values['name'])->fetch())
	{
		$form->addError('Meno je už obsadené');
		$this->redirect('this');
	}
	else
	{
		'tuto neviem presne čo mám vyhodiť';
	}
}

Ale moc elegantne mi to nepripadá. Dá sa to napísať lepšie?

Jan Suchánek
Člen | 404
+
0
-

Takto?

public function registrationProccess(Form $form)
{
	$values = $form->getValues();
	try {
		$this->registerFacade->register($values); // možná v tvém případě stačí nějaký repositář, aby to nebyl takovej špageťák
		$this->redirect("this"); // todo redirect na spravné místo
	} catch(\MyInvalidException $e){ // vytvoř si sbírku vyjímek a neodchytávej pouze Exception
		$form->addError('Sorry, this name "'. $values->name .'" already exists.');
	}
}

Video o vyjímkách od Honzy Tvrdíka.

Editoval jenicek (8. 7. 2014 11:52)

David Kudera
Člen | 455
+
0
-

Třeba kdyby/doctrine vyhodí Kdyby\Doctrine\DuplicateEntryException, tu si hned v nějaké např. přidávací metodě pro uživatele odchytávám. Zkontroluji, jestli se jedná o duplikaci na emailu nebo někde jinde (třeba nějaký username) a podle toho dál vyhodím svou App\DuplicateEmailException nebo App\DuplicateUsernameException apod. Jinak nechám vyhodit zpět původní exception z kdyby.

try {
	$dao->save($user);
} catch (\Kdyby\Doctrine\DuplicateEntryException $e) {
	if (checkSomehowIfExceptionIsBecauseOfDuplicateEmail($e)) {
		throw new \App\DuplicateEmailException($user, $e);
	} else {
		throw $e;
	}
}

No a ve formu si odchytávám už přímo tyhle moje výjimky.

Ono když je totiž jen kontrola podle toho, jestli už ten záznam v db není a má jít pak i editovat, tak je ta kontrola hned složitější. Při přeuložení bez změny by mi totiž form hodil chybu, že email už existuje.

Šaman
Člen | 2666
+
0
-

Ty při aktualizaci záznamů znovu insertuješ? Při update samozřejmě unikátní index nevadí a nic nevyhazuje…

Čamo
Člen | 798
+
0
-

Ale mňa zaujíma hlavne kód tej metódy register(). Ale díky za to video.

Editoval Čamo (8. 7. 2014 13:19)

Čamo
Člen | 798
+
0
-

Potreboval by som vidieť tú implementáciu v kdyby/doctrine. Pošlite mi niekto odkaz ak môžte na ich dokumentáciu. Ja to idem skúsiť pohľadať, ale tie systémy vôbec nepoznám, tak netušim ani kde…

Editoval Čamo (8. 7. 2014 13:29)

David Kudera
Člen | 455
+
0
-

@Šaman nene neinsertuji. Jen jsem to asi špatně napsal. Pokud by při editaci nechal jen tuhle kontrolu:

if($this->database->table(users)->where('name = ?', $values['name'])->fetch())
{
    $form->addError('Meno je už obsadené');
    $this->redirect('this');
}

tak formulář ukáže chybu, že jméno je obsazené, když ho nijak nezměním. Musel bych tu podmínku rozšířit a když těch „unikátních“ sloupců bude víc, tak se to zesložití a pro vkládání to bude jinak a pro editaci jinak. Proto mi přijde unique určitě lepší (spolu s tím, že do db to můžu vložit přímo atd…)

David Kudera
Člen | 455
+
0
-

@Čamo tady je dokumentace a tady je ten kód z kdyby/doctrine, ale taky koukám, že to je na mysql, asi… možná.....

á.. tak je to ještě trochu jinak.. je tam ještě tahle třída a např. její metoda isUniqueConstraintViolation pro kontrolu podle jednotlivých kódů

Edit: trochu jsem se do toho asi zamotal, tady by někdo znalejší poradil víc určitě jak to vlastně funguje

Editoval David Kudera (8. 7. 2014 13:50)

David Matějka
Moderator | 6445
+
0
-

@Šaman

Při update samozřejmě unikátní index nevadí a nic nevyhazuje…

?? unikatni index se bere v potaz i pri update

David Kudera
Člen | 455
+
0
-

@matej21 myslím, že šlo jen o nedorozumění. Tuším, že @Šaman myslel, že jsem psal unique klíči a tom, že to vyhodí chybu, když provedu update a unique sloupec nijak neupravím. Já ale myslel ne-unique sloupec a kontrolu jen podle podmínky, zda záznam už v db existuje. Ta by totiž při editaci ve formu chybu zobrazila

Jan Suchánek
Člen | 404
+
0
-

To záleží jaké metody v repository používaš a jakou db používáš. Pokud Nette Database Context tak něco jako:

	$this->dbContext->table("user")->insert($values);

Editoval jenicek (8. 7. 2014 15:45)

Filip Procházka
Moderator | 4668
+
0
-

DuplicateEntryException bys neměl chytat, ale měl bys jí předcházet https://github.com/…cs/en/dao.md#…

Čamo
Člen | 798
+
0
-

David Kudera
Díky za odkaz, ale to nemám šancu rozkryť. Nechám to tak ako to je aj keď to bude zložitejšie pri väčšom počte unique indexov.

Editoval Čamo (8. 7. 2014 20:22)

David Kudera
Člen | 455
+
0
-

@FilipProcházka ahá, díky moc, tohle jsem nějak ve čtení asi přeskočil

Čamo
Člen | 798
+
0
-

Tak som to nakoniec zbastlil takto:

try
{
	$row = $this->database->table('users')->insert($arr);
	$this->flashMessage('Boli ste zaregistrovaní. Môžete sa prihlásiť');
	$this->redirect('Sign:');
}
catch(\Exception $e)
{
	$db = $this->database;
	if($db->table('users')->where('username', $values['username'])->fetch() && !isset($row) )
	{
		$this->flashMessage('Meno '.$values['username'].' je už obsadené. Vyberte si prosím iné.');
		$this->redirect('this');
	}
	elseif($db->table('users')->where('email', $values['email'])->fetch() && !isset($row) )
	{
		$this->flashMessage('Email '.$values['email'].' je už obsadený.');
		$this->redirect('this');
	}
	else
	{
		throw $e;
	}
}

Síce ak nastane nejaká iná výnimka(než duplicate entry) a zároveň už existuje daný uživateľ(čo by bola duplicate entry), hodí to chybne duplicate enty error a neošetrí tú skutočnú výnimku. Ale po opravení mena/mailu sa aj tá neošetrená vyhodí/zaloguje(ak teda ešte je čo logovať). Ale zase je to hádam dosť nepravdepodobné. Na viac zatiaľ nevydalo.

Editoval Čamo (9. 7. 2014 1:14)

David Kudera
Člen | 455
+
0
-

Akorát to má tu nevýhodu, že u dalšího formu můžeš třeba zapomenout na to, že aby prošel redirect, musíš pak vyhodit všechny ostatní výjimky. Jasně dojde ti to, jakmile zjistíš, že redirect neprošel a throw $e hned doplníš. Ale co třeba za měsíc? Co za delší dobu? Osobně vím, že bych pak koukal, co to je, proč to tak je a k čemu to je. Je to prostě trochu takové...... ehm.. chápeš ne?

Asi bych to fakt raději přesunul do nějaké modelové metody, v ní chytal ty výjimky a převáděl je na svoje vlastní DuplicateEmailException, DuplicateNameException apod. Máš to znovupoužitelný a formulář se ti krásně zjednoduší, protože hned od pohledu budeš vědět, co znamená třeba catch (DuplicateEmailException $e)

Čamo
Člen | 798
+
0
-

Ešte mám jednu takú kacírsku otázku na všetkých. Čo si myslíte o použití

if(preg_match('/duplicate.+entry/i', $e->errorMessage)){...}

Nieje udržovanie aktuálnych kódov pre duplicate entry to isté ako udržovanie aktuálnych error mesidžov???

Čamo
Člen | 798
+
0
-

David Kudera:
Ešte som vlastné vínimky nepísal. Kam by som takú triedu pre vínimku uložil? Do modelu? A ako taká trieda vyzerá? Nemáš nejaký príklad? Ale myslím si, že toto by mala ošetriť vrstva nette database.

Editoval Čamo (9. 7. 2014 10:00)

David Kudera
Člen | 455
+
0
-

Spíš myslím, že radši ty kódy, přijde mi to takový jistější. Zkus znovu mrknout na to video o výjimkách, co je nahoře. Myslím, že tam se o tom taky mluvilo

David Kudera
Člen | 455
+
0
-

Opět video o výjimkách. A když už jsme se bavili o kdyby/doctrine, tak tady je ukázka, jak ty exceptiony vypadají. Ale je to celkem na tobě, tady jsou např. všechny v jednom souboru, někdo je ale dává jako jedna exception == jeden soubor apod. A uložení? Je to taky na tobě.. Pokud chceš mít např. v app/models/něco, tak klidně