This is a follow up question of this question, which is not really important.
I have written the following front controller plugin:
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
$response = $this->getResponse();
$monitor = Zend_Registry::get('monitor');
if ($response->isException())
{
$monitor->log($response);
}
}
Where $monitor is an instance of a custom DB logging class (extending Zend_Log).
In the log method of the Monitor I loop over the Array of Zend_Exceptions returned by $response->getException().
For testing purposes I through an exception in an action:
throw new Zend_Exception('the big test', 555);
Most things work as expected, the Exception is written to the database.
Question
But, it's written twice. Why?
Because the dispatch loop is called twice. First for the current action and then for default:error:error :) Place the log into dispatchLoopShutdown() method
Related
I'm trying to do a redirect from my service class. I don't want to return the url to the caller because it's not being accessed directly from controller and it should return other data in some cases.
However I found that i can do the redirect this way:
Redirect::away('http://someexternalurl.com')->send();
This seems to work fine - the user gets redirected to the url I entered. The problem is that in this case the app "lives on" so following commands get executed. That's not what I need.
If I die(); immediately after that my session changes don't seem to be "saved".
Is there a way to make a redirect and stop the App immediately after that without simply "killing" it?
Basically is there a way to rewrite this code
Session::forget('myval');
Redirect::away('http://someexternalurl.com')->send();
mail('my#mail.com', 'Test', 'Still running');
So that myval would be gone from the session, the user would be redirected to the url and mail would not be sent (actually anything after the redirect shouldn't be executed)?
Thank you
The solution is to throw an Exception and adapt the render method of the Exception Handler.
In Your Controller:
// app/Controllers/DashboardController.php
public function index()
{
\App\Services\Test::test();
return view('dashboard');
}
My example service :
// app/Services/Test.php
<?php
namespace App\Services;
class Test {
public static function test() {
throw new \App\Exceptions\TestException('test');
}
}
In your Exception Handler :
// app/Exceptions/Handler.php
public function render($request, Exception $exception)
{
if ($exception instanceof TestException) {
return redirect(url('/?error=' . $exception->getMessage()));
}
return parent::render($request, $exception);
}
My example Exception (you can name it whatever you want), it just needs to extend the default Exception.
<?php
namespace App\Exceptions;
class TestException extends \Exception {
}
It looks like you just need to return on you Redirect?
return Redirect::away('http://someexternalurl.com')->send();
Here's the solution for Laravel 5.2. I reckon it would be work at all 5.*
abort(301, '', ['Location' => 'http://antondukhanin.ru']);
methodThatWouldntBeExecuted();
the function throws HttpException, so that will interrupt execution of any next commands
I am using Symfony 2.4 and am trying to create a more powerful exceptions handler that, on certain PDO / Doctrine exceptions, changes the status code of the response from 500 to 503 to display a different custom error message than our standard (in other words, it returns the error503.html.twig template rather than error500.html.twig). So far, I have created a custom Exceptions controller that extends the TwigBundle ExceptionController, I have changed the Twig exception parameter in config.yml, and I am able to catch any and all exceptions that are thrown once Symfony calls handle(...) in HttpKernel.php:185 (so it's really the second time that handle is called -- this time being on the HttpKernel rather than the AppKernel). I'll refrain from posting all that code, and instead direct the reader here to learn more about my method if they are unfamiliar. All of that code is working just fine -- I am able to modify any applications that are thrown within my application, so you can assume that I'm using the aforementioned approach properly.
The issue I am running into is that in addition to catching exceptions that are thrown within Symfony, I also want to also be able to catch exceptions that are thrown before the HttpKernel's handle method is called (an example being a PDO Access Denied exception that is thrown from improper database credentials). To give you a more specific rundown, in app_dev.php, you have:
$response = $kernel->handle($request);
which calls:
/**
* {#inheritdoc}
*
* #api
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot();
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
Now, if an exception gets thrown in $this->boot(), it doesn't look like it gets caught anywhere, and because of that, I can't see any way of gracefully handling said exception in Symfony. It's only if the exception gets thrown within the try / catch block contained in $this->getHttpKernel()->handle($request, $type, $catch) that it will be caught and gracefully handled using Symfony code. Am I wrong about that? Does anyone know of an approach to handling exceptions that are thrown in this context that utilizes Symfony? My apologies in advance if this has already been answered elsewhere.
I ran into a similar problem, I didn't see a neat way around this but was able to get nice error pages for my specific problem simply by generating a Response object and sending that. I placed the following in some code which was called by boot()
try {
someExceptionFunction();
} catch (Exception $e) {
$response = new Response('<html><body>'.$e->getMessage().'</body></html>');
$response->send();
exit;
}
You could easily add some more logic to the catch block, catching different exceptions. It's not as clean/abstract as it could be, but since the entire framework fails to boot I don't know of any option you could use it to parse an error page.
Hope this helps
I'm currently working on an open source personal project that provides a nice backend api for game developers. I'm in the early stages of development, but I plan to write tests as I go along, which is where I've hit a snag.
Through out the system when an error occurs such as incorrect api credentials or missing credentials, I throw a custom exception which stores a bit of extra data so that I can catch it and give a JSON encoded response.
The tests work fine for those thrown in my BaseController, but I also capture a few Laravel Exceptions so I can respond with my own, or at least, output JSON like below:
app/start/global.php
App::error(function(Exception $exception, $code) {
Log::error($exception);
});
App::missing(function(Exception $exception) {
return BaseController::error(
Config::get('response.method.code'),
Config::get('response.method.http'),
'Method not found'
);
});
App::error(function(Viper\Exception $exception) {
return BaseController::error(
$exception->getCode(),
$exception->getStatusCode(),
$exception->getMessage()
);
});
I'm using the try { } catch() { } approach as I need to check an extra value that isn't in the normal Exceptions.
public function testNoMethodGET() {
$config = Config::get('response.method');
try {
$this->call('GET', '/');
} catch(\Viper\Exception $e) {
$this->assertEquals($e->getCode(), $config['code']);
$this->assertEquals($e->getStatusCode(), $config['http']);
}
$this->fail('Exception not thrown');
}
This is all good and well, but I want to check a few things on the actual response, like for example, whether or not the json is valid, whether or not the response structure matches and whether or not the response values are correct.
If I set the return value of $this->call() to a variable, I'd be unable to access that variable within the catch block, so the question is this, how can I test the return value of $this->call() once the Exception has been caught?
According to Taylor Otwell:
"this can be solved by de-coupling your
test. You really want to test the handler and that the exception is
thrown totally separately anyways [sic] to isolate your tests. For
instance:
App::error(function(ErrorType $e)
{
App::make('ErrorTypeHandler')->handle($e);
});
Now you can write test cases for ErrorTypeHandler class separately
from the rest of your application. Then check that proper exceptions
are thrown by your app with #expectedException."
see How do you test your App::error implementations?
In your case, you already have isolated your error handler in BaseController::error(), so you can test the responses directly in separate unit tests, without the use of $this->call(). Instead, just call $response = BaseController::error() with the desired parameters and then inspect the response and apply relevant assertions.
Here is the exception I got:
No result was found for query although at least one row was expected.
I am basically getting that exception when a user id is not found in database.
Here is what my route looks like:
localhost/../user/18
and the code in my controller:
public function showAction(User $user){
// ..
}
I know I can use the kernel event exception to handle this, but is there an easier way to catch an exception generated by the ParamConverter?
In some cases it's useful to throw exception manually if object not found. You can tell action skip throw exception if entity not found by adding default value to param.
Example:
public function showUser(User $user = null) {
if (empty($user)) {
throw new CustomExceptionYouWant();
}
...
}
You can create your user ParamConverter by implementing ParamConverterInterface and inside it, create methods you can use as a custom exception or do other processing.
This a good exemple of what you want to create Custom ParamConverter
I'm using phpunit and the ecomdev module to unit test Magento. For a particular class the last code that needs to be tested is an exception on attempting to save a model in a try/catch. The only way I can see to get to the exception is alter the database temporarily. So I changed the table name which works, but then I have to name it back. If the test itself fails I'm in an inconsistent state.
I'd really like to get that code tested so the coverage is 100%. Otherwise I'll be wondering why it's 98% until I look at the code and remember the exception isn't tested.
I was trying to close the connection but I need it to log the exception. So I'm wondering if maybe there is something I can temporarily do to the model or resource model to cause the save to raise an exception. Something that would be reset on the next load.
One note - I can't see anyway that manipulating data will cause the exception. Again the only scenario I see causing an exception in production is if the database connection goes away.
Any ideas?
Edit:
Sample Code:
public function logStuff($stuff){
try{
Mage::getModel('my/stuff')
->setData('stuff', $stuff)
->save();
}catch(Exception $e){
Mage::helper('log/error')->logError(__METHOD__, "Could not save stuff: ". $e->getMessage());
}
}
To make test the exception catch, you need to replace your model instance with the mocked one.
It is very easy to achieve with EcomDev_PHPUnit extension:
$mockedStuff = $this->getModelMock('your/stuff', array('save'));
$mockedStuff->expects($this->once()) // How many times it is invoked
->method('save') // Wich method to mock
->will($this->returnCallback(function () {
throw new Exception('Some error text');
})); // Your exception
$this->replaceByMock('model', 'your/stuff', $mockedStuff);
Also you can evaluate your logging stuff by using mock as well.
$loggerMock = $this->getHelperMock('log/error', array('logError'));
$loggerMock->expects($this->once())
->method('logError')
->with('className::methodName', 'Could not save stuff: Some error text'); // Check that correct arguments passed
$this->replaceByMock('helper', 'log/error', $loggerMock);
Have fun with unit tests :)