Olen aloittelemassa Zend Frameworkin käyttöä ja muuten olen kaiken saanut toimimaan haluamallani tavalla, mutta virheidenhallinta ei toimi (toimi hetken, mutta vaikka nyt teen kaiken esimerkin mukaan nollasta uusiksi, ei virheidenhallinta toimi).
Ongelmana on, että framework ei ohjaa löytymättömiä controllereita ja actioneja ErrorControllerille, vaan näyttää aina vain php-errorin, vaikka oletuksenahan virheelliset urlit pitäisi ohjautua ko. controllerille ja tuloksen tapahtua sen mukaisesti.
Esim: http://localhost/zend -> tulostaa ihan oikein IndexControllerin mukaisesti
Esim: http://localhost/controller -> valittaa: 'Invalid controller specified (controller)', vaikka pitäisi valittaa: 'Invalid controller specified (error)' (jos controlleria ei ole luotu) tai renderöidä ErrorControllerin mukaisesti (jos controller löytyy).
Riippumatta siitä, miten koodia muutan, en saa koskaan tätä:
Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with message 'Invalid controller specified (error)'...
...vaan aina valituksen, että haettua controlleria tai actionia ei löytynyt.
Rakenne:
/application /controllers IndexController.php ErrorController.php /models /views /scripts /index index.phtml /error error.phtml /public .htaccess index.php
IndexController.php
<?php class IndexController extends Zend_Controller_Action { function indexAction() { } } ?>
ErrorController.php
<?php class ErrorController extends Zend_Controller_Action { public function errorAction() { } } ?>
.htaccess
RewriteEngine on RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
index.php
<?php error_reporting(E_ALL|E_STRICT); ini_set('display_errors', 'on'); ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . '../../__library'); require_once 'Zend/Loader.php'; Zend_Loader::loadClass('Zend_Controller_Front'); $front = Zend_Controller_Front::getInstance(); $front->setControllerDirectory('../application/controllers'); /** * Tälläkään ei ole mitään vaikutusta (eikä pitäisikään olla, koska asetuksen pitäisi olla oletuksena 'false') */ $front->throwExceptions(false); $front->dispatch(); ?>
Ensinnäkin tuo ErrorController pitää rekisteröidä plugariksi:
<?php $front->registerPlugin(new OmaErrorController()); ?>
Tuo, että jos ei löydy controlleria, niin se on huolestuttavaa. Silloin kannattaisi ehkää ajaa ZF:ää modulerakenteella ja ohjata virhetilanteessa etusivulle kaikki liikenne. Controllerin tai modulin löytymättömyys on aina aika iso virhe, actionin puuttuminen voidaan helposti vielä korjata.
Controllerin tai modulin puuttumattomuus pystytään kuitenkin tunnistamaan, mutta sinun pitää tunnistaa kyseinen ongelma ENNEN kuin dispatcher ajetaan. Siihen on olemassa ZF:ssä oma järjestelmä johon löydät vastauksen linkistä http://framework.zend.com/manual/en/zend.controller.html
Controllereiden sisällä voit tehdä magic metodin:
<?php public function __call($method, $args) { // Forward to indexAction $this->_forward('index'); } ?>
ErrorController käyttää syntaksia jotakuinkin hieman transaktio tyyliin alla olevan mallin mukaan.
Tässä ihan manuaalin mukaan mitä tarvitset (tämä EI OLE suora ratkaisu koodiisi, sinun pitää rakentaa se tämän mallin mukaisesti ITSE):
<?php /** * Define a custom exception class */ class MyException extends Exception { // Redefine the exception so message isn't optional public function __construct($message, $code = 0) { // some code // make sure everything is assigned properly parent::__construct($message, $code); } // custom string representation of object public function __toString() { return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; } public function customFunction() { echo "A Custom function for this type of exception\n"; } } /** * Create a class to test the exception */ class TestException { public $var; const THROW_NONE = 0; const THROW_CUSTOM = 1; const THROW_DEFAULT = 2; function __construct($avalue = self::THROW_NONE) { switch ($avalue) { case self::THROW_CUSTOM: // throw custom exception throw new MyException('1 is an invalid parameter', 5); break; case self::THROW_DEFAULT: // throw default one. throw new Exception('2 isnt allowed as a parameter', 6); break; default: // No exception, object will be created. $this->var = $avalue; break; } } } // Example 1 try { $o = new TestException(TestException::THROW_CUSTOM); } catch (MyException $e) { // Will be caught echo "Caught my exception\n", $e; $e->customFunction(); } catch (Exception $e) { // Skipped echo "Caught Default Exception\n", $e; } // Continue execution var_dump($o); echo "\n\n"; // Example 2 try { $o = new TestException(TestException::THROW_DEFAULT); } catch (MyException $e) { // Doesn't match this type echo "Caught my exception\n", $e; $e->customFunction(); } catch (Exception $e) { // Will be caught echo "Caught Default Exception\n", $e; } // Continue execution var_dump($o); echo "\n\n"; // Example 3 try { $o = new TestException(TestException::THROW_CUSTOM); } catch (Exception $e) { // Will be caught echo "Default Exception caught\n", $e; } // Continue execution var_dump($o); echo "\n\n"; // Example 4 try { $o = new TestException(); } catch (Exception $e) { // Skipped, no exception echo "Default Exception caught\n", $e; } // Continue execution var_dump($o); echo "\n\n"; ?>
Tässä on linkki siihen mitä sinun pitää opetella käyttämään: https://www.php.net/exceptions TAI sitten ZF:n oma malli http://framework.zend.com/manual/en/zend.exception.html
Vastaus kysymykseesi on kuitenkin:
<?php try { // Ensin siis yritetään jotain } catch (Exception $e) { // Heitetään ErrorControllerille jos ei TRY onnistu ja jos ErrorController tunnistaa ongelman } ?>
EDIT: koska olen hyvällä tuulella, niin tässä on sinulle malliratkaisu:
<?php $errors = $this->_getParam('error_handler'); switch ($errors->type) { case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER: case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION: // 404 error -- controller or action not found $this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found'); // ... get some output to display... break; default: // application error; display error page, but don't change // status code // ... // Log the exception: $exception = $errors->exception; $log = new Zend_Log(new Zend_Log_Writer_Stream('/tmp/applicationException.log')); $log->debug($exception->getMessage() . "\n" . $exception->getTraceAsString()); break; } ?>
Lisää tuo omaan ErrorControlleriisi ja tee antamieni ohjeiden mukaan. Toimii ainakin minulla todella hyvin.
Hieman tarkennusta:
Yritän siis käyttää ihan tuota Zend Frameworkin omaa virheidenhallintaa, jonka pitäisi Zendin mukaan olla oletuksena päällä ilman kikkailuja:
"By default, the error handler plugin is registered. This plugin expects that a controller exists to handle errors. By default, it assumes an ErrorController in the default module with an errorAction method."
...ja oma kokeiluni on tehty täysin tämän sivun videoiden mukaisesti: http://framework.zend.com/manual/videos#bootstrappin
...ja kuten videoista huomaa, on oma esimerkkini sen mukainen ja pitäisi toimia oikein, mutta kuitenkaan virheelliset urlit eivät ohjaudu oikein error-controllerille...
Frameworkkina: Zend Framework 1.5.1 (kokeiltu asentaa uusiksi)
Muistaakseni tuossa oletus controllerissa EI ole käsittelyä puuttuville controllereille ja moduleille. Actionit ovat hieman sellaisia, että niihin voi käyttää controllerin sisällä joko magic metodia __call tai sitten ne voidaan ajaa suoraan tuonne globaalille error controlerille.
ZF 1.5.x sarja on muuttanut (taas kerran) noita käsittelyitä hieman, mutta ainakin omissa järjestelmissä tuo virheidenkäsittely toimii tuolla viimeisellä edellisen viestin mallilla tosi hyvin. Muuta vain tuota outputtia '404 not found' kohtaa omaksesi. Tuo malli pitää olla sinun OMASSA error controllerissa sitten. ja kuten itsekin lainasit: "This plugin expects that a controller exists to handle errors".
Nähtävästi sinulla on sitten ongelmia itse ZF:n alustuksessa. En noita malleja nyt ole jaksanut plarata läpi kun ZF:n manuaalit ja mallit ovat aina ajastaan jäljessä nykyiseen uusimpaan versioon nähden. Esim. manuaaleissa on malleja jotka on tarkoitettu < 1.0.x versioihin ja ne eivät toimi nykyisissä versioissa millään.
-W-
Aihe on jo aika vanha, joten et voi enää vastata siihen.