jak na vyjímky Exception, nebo jak je odchytávat

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

Prosím nekamenujte mě rovnou, ale doopravdy to nevím / nechápu.

<?php
namespace FrontModule\Forms;

use Nette\Application\AppForm, Nette\Forms\Form, Nette\Environment, Nette\Forms
    \IFormControl, Nette\Web\Html, Model\User;

class UserRegistraceForm extends AppForm
{
    public function __construct($parent, $name)
    {
        parent::__construct($parent, $name);

        $this->addProtection('Prosím odešlete údaje znova (vypršela platnost bezpečnostního tokenu).');
        // získání dat uživatele
        $user = $this->getPresenter()->getUser();

        $this->addText('name', 'Jméno:')->
            addRule(Form::FILLED, 'Prosím zadajte svoje jméno.');
        $this->addText('email', 'Email:')->setEmptyValue('@')
        ->addRule(Form::FILLED, 'Prosím zadajte svůj email.')
        ->addRule(Form::EMAIL, 'Zadaná hodnota není Emailová adresa.');
        $this->addPassword('password', 'Heslo:')->addRule(Form::FILLED,
            'Zadejte heslo')->addRule(Form::MIN_LENGTH,
            'Zadané heslo je příliš krátké, zvolte si heslo alespoň o %d znacích', 3);
        $this->addPassword('password2', 'Heslo (ověření):')->addRule(Form::
            FILLED, 'Zadejte heslo ještě jednou, pro kontrolu')->addRule(Form::EQUAL,
            'Zadané hesla se neshodují', $this['password']);

        $this->addSubmit('send', 'Uložit');
        $this->addSubmit('reset', 'Vymazat')->setValidationScope(null);
        $this->onSubmit[] = array($this, 'formSubmited');
    }

    public function formSubmited($form)
    {
        try {
            if ($form['reset']->isSubmittedBy()) {
                // vrátím se zpět na editaci
                $this->getPresenter()->redirect("UserRegistrace:");
            } else {
            	// zde dodělat registraci....
                // + kontrola, zda zadaný email již neexistuje
                $values = $form->getValues();

		$row = User::findByEmail($values["email"]);

		if ($row) {

			throw new Exception("Zadaný email je již použit");
		}

                */
                // redirectnu zpět na registraci
                $this->getPresenter()->redirect('UserRegistrace:');
            }
        }
        catch (Exception $e) {
            $form->addError($e->getMessage());
        }
    }
}
?>

jak mám vypsat blbě hlášku, že zadaný email je již použit, použití fleshmessage umím, ale chtěl jsem to dávat přez nějakou tu throw new Exception(„Zadaný email je již použit“); ale toto mě nefunguje… Používám Nette 5.3 namespace a nějak v tom plavu :-(, protože když tohle použiju, hodí mě to laděnku: Class ‚FrontModule\Forms\Exception‘ not found. Co si mám usednout :-(

natrim
Člen | 73
+
+1
-

Namespacy…

<?php
throw new \Exception("Zadaný email je již použit");
?>

a

<?php
catch (\Exception $e)
?>
h4kuna
Backer | 740
+
+1
-

nebo na začátek přidej

<?php
use Exception;
?>
tatyalien
Člen | 239
+
0
-

Díky ;)

dubak
Člen | 41
+
0
-

Zdravim,
ja mam velmi podobny problem, ale akosi som to nedokazal rozchodit. Mam model, v ktorom mam metodu na odosielanie mailov:

<?php
public function newsletterSend(array $values, array $_FILES)
{
  try{
    // vstup do DB, odosielanie mailu pomocou $mail = new Mail; triedy
  }catch(Exception $e){
    return false;
  }
}
?>

a chcem docielit, aby ak sa vyskytne nejaka chyba pocas procesu odosielania, tak aby po zachyteni chyby vratila metoda false, aby som to mohol adekvatne v presenteri osetrit.
Skusal som toto:

<?php
use Exception;
?>

Ale hadze toto:

<?php
The use statement with non-compound name 'Exception' has no effect
?>

Pozeral som este toto vlakno:
https://forum.nette.org/…as-no-effect
ale nerozumiem preco teda „tatyalien“ napisal, ze dekuje, teda mu to asi funguje.
Rozmyslal som este aj, ze pouzijem napr.: InvalidStateException ale ta je urcena asi iba pre urcite pripady a mne sa moze vyskytnut chyba, ktoru tato vynimka nezachytava.

Vdaka za rady

Aurielle
Člen | 1281
+
0
-

Tvůj první kód by měl fungovat, jen nechápu princip použití array $_FILES… use Exception není nutné, pokud nemáš PHP 5.3 verzi.

dubak
Člen | 41
+
0
-

gmvasek napsal(a):

Tvůj první kód by měl fungovat, jen nechápu princip použití array $_FILES… use Exception není nutné, pokud nemáš PHP 5.3 verzi.

Pouzivam toto
PHP 5.3.1
Server Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l mod_autoindex_color PHP/5.3.1 mod_apreq2–20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
Nette Framework 2.0-dev
Co sa tyka tej funkcnosti, bohuzial nefunguje, preto to riesim. K tomu principu

do metody modelu si z presenteru predam po odoslani formulara jeho hodnoty + zoznam priloh. Mam totiz formular urobeny tak, ze mi JavaScript generuje nove policka na prilozenie dalsich priloh, aby uzivatel mohol pripadne poslat ich aj viac.
No a rozmyslal som, ako osetrit pripadnu chybku, lebo ak dobre rozumiem, napr. trieda Mail pri zlyhani odoslania nevracia nic, ale hadze tiez vynimky, ak zadam napr. odosielatela v zlom tvare.Rovnako pouzivam na tahanie z DB PDO a to mi tiez vyhodi vynimku ak sa nieco stane.

Cize len pre prehlad:

<?php
//zaciatok skriptu modelu
use Exception;
use Nette\Mail\Mail;
class NewsletterModel extends BaseModel
{
  public function newsletterSend(array $values, array $_FILES)
  {
    try{
      // vstup do DB, odosielanie mailu pomocou $mail = new Mail; triedy
    }catch(Exception $e){
    return false;
    }
  }

}
?>

No a tento kod vyhadzuje tu chybu: The use statement with non-compound name ‚Exception‘ has no effect
**
Ten priklad s namespacy ako uvadzal **natrim
som nejako nepochopil, ako kam zapisat to throw new?

<?php
throw new \Exception("Zadaný email je již použit");
?>

Hmmmmmm?

dubak
Člen | 41
+
0
-

Tak aby som to uzavrel, vyriesil som to takto. Pouzil som spatne lomitko pri use:

<?php
use \Exception;
use Nette\Mail\Mail;
class NewsletterModel extends BaseModel
{
  public function newsletterSend(array $values, array $_FILES)
  {
    try{
      // vstup do DB,
      if($list = $this -> getNewsletterList() == false){
	return false;
      }
      // ... odosielanie mailu pomocou $mail = new Mail; triedy ...

    }catch(Exception $e){
    return false;
    }
  }

}
?>

v samotnej metode „newsletterSend“ mam tiez zachytavanie vynimky, ale urobil som to takto:

<?php
private function getNewsletterList(){
  // SQL dopyt
  try{
    //nacitam vysledok do pola
    foreach($this->pdo_db -> query($sql) as $row){
      //vlozi cely riadok "$row" do pola "$pole"
	$pole[] = $row;
    }
  }
  catch(PDOException $e) {
    //throw new Exception($e->getMessage());
    return false;
  }
  return $pole;
}
?>

v testovacej prevadzke je teda dobre nechat vyhadzovat vynimky, aspon clovek vie, kde sa co stalo. No a potom v ostrej prevadzke tam radsej vracat false a osetrit to potom v presenteri nejako cez flashMessages.

<?php
if($this->newsletterModelManager)
{
  $this->flashMessage('Faktúra bola úspešne zverejnená.');
  $this->redirect('this');
}else{
  $this->flashMessage('CHYBA.', 'error');
  $this->redirect('this');
}
?>

Inak cital som peknu diskusiu ako riesit vynimky, teda ako ich osetrovat a vyhadzovat na strankach Jakuba Vrany, tuto: http://php.vrana.cz/…-vyjimky.php
a hned na zaciatku Jakub Vrana pise:

Ptám se proto, že jsem stejné otázky v osobním rozhovoru položil hlavnímu vývojáři významného českého frameworku a jeho odpovědi se mi zrovna dvakrát nelíbily.
Predpokladam ze pisal o Davidovi Grudlovi. Takze celkom sranda tieto vynimky.

Napisal som to sem, aby ked niekto tiez riesi ako s vynimkami nalozi, aby si mohol najst toto ucelene vlakno.

Patrik Votoček
Člen | 2221
+
0
-

Pozor na konstrukce:

try {
	$this->redirect('foo');
} catch (\Exception $e) { // TADY JE PROBLÉM!!!
	$this->flashMessage($e->getMessage());
}

Protože redirect jako takový je v Nette řízen vyjímnkou! Je tedy nutné chytat měně obecné vyjímky nebo znovu vyhodit onu vyjímku starající se o redirect:

try {
	$this->redirect('foo');
} catch (\Exception $e) {
	if ($e instanceof \Nette\Applitaion\AbortException) {
		throw $e;
	}
	$this->flashMessage($e->getMessage());
}