Have a question on Slim Framework php.
In my application, I would like to stop the application execution if a condition is mismatched.
There is a halt function, per Slim documentation. But that does not appear to be working.
the application continuous to execute even after calling Halt.
pseudo code:
if ( $valid ) {
// Do something
} else {
$app->halt(500, "not valid");
}
// Other code here.
$app->run();
I was expecting that, we we call Halt function, the "Other code" should not execute.
But it does not appear to be the case.
Any ideas?
Halt should work. As Josh mentioned, it does need to be called from within a route callback. For example, I use the following as a custom 404 (inside of index.php) in the event that a specified route is not found.
// not found (custom 404)
$app->notFound(function () use ($app) {
// build response
$response = array(
'type' => 'not_found',
'message' => 'The requested resource does not exist.'
);
// output response
$app->halt(404, json_encode($response));
});
Note the reference to use ($app) -- more on this can be found here: http://www.slimframework.com/documentation/stable#scope-resolution
Halt should only be invoked within the context of a route callback. I recommend you ask any further questions on the official Slim Framework support forum:
http://help.slimframework.com
Best regards,
Josh
You can always call exit manually to stop the script execution.
$app->halt(500, "not valid");
exit;
You can use return if you are in a callback function
return $app->halt(500,"message");
or
$app->stop();
after halt function.
Related
I'm using CakePHP 3.5 and two of the methods I want to use are deprecated and I can't find an alternative.
The methods are:
$this->response->send();
$this->response->stop();
I want to redirect to a different page and stop the execution of the current method. I've tried calling die() after my redirect and it doesn't work.
According to the migration guide the methods have been made obsolete.
Any thoughts?
Edit:
I'm trying to redirect users without access to certain pages. This is in the initialize() method in the controllers.
if ($allowedAccess) {
$this->Flash->error("Insufficient rights to access that location");
$this->redirect($this->referer());
// FIXME - find alternative to deprecated methods
return $this->response;
$this->response->send();
$this->response->stop();
}
Are you trying this in a controller? Simply return the response object from your controllers method:
public function index() {
// Some code
return $this->response;
}
send() was just a wrapper around phps exit(). Use exit() if you need to somewhere.
What happens when you return the response is that the ActionDispatcher processes the return value and if it's a Response object. See the __invoke() method.
The response will go through the middleware layer and will be finally send by the ResponseEmitter which is used by the Server. Check your webroot/index.php to see it:
// Bind your application to the server.
$server = new Server(new Application(dirname(__DIR__) . '/config'));
// Run the request/response through the application
// and emit the response.
$server->emit($server->run());
I have two route groups in my Laravel application, one for an API and one for the website itself. I've added the following code in global.php for error handling of my API.
App::error(function(ModelNotFoundException $e)
{
return Response::json('', 404);
});
But not this obviously also has effect on my normal website, where I want to return a normal view when the ModelNotFoundException occurs. Like so:
App::error(function(ModelNotFoundException $e)
{
return Response::view('404.html', [], 404);
});
How can I setup different error handlers for different route groups?
I think you shouldn't care what part of the site that threw the error, but instead respond with whatever format the client requested. In general this is set in the Accepts header of the request and can be accessed in Laravel by:
if (Request::format() == 'json')
{
//
}
(above is taken from the documentation)
In your case, this would turn your error handling function to this:
App::error(function(ModelNotFoundException $e)
{
if (Request::format() == 'json') {
return Response::json('', 404);
} else {
return Response::view('404.html', [], 404);
}
});
This automatically covers you if, for instance, you add an non-API AJAX request to the main portion of your website (for whatever reason) that could potentially trigger a ModelNotFoundException. As long as your client sends the appropriate request headers, you're good.
You could try with changing environment. For selected group you could change environment using:
$app->setEnvironment('enviromentname');
and create new environmentname.php file in start directory
But I don't know if it will work.
You could also create a session variable and in App:error add code depending on this session variable:
$value = Session::get('type');
if ($value == 'onetype') {
// something
}
else {
// something else
}
I think this is more of a general question (so not php restricted) with regards to ddd and the command pattern.
Let's say I execute a CreatePostCommand from within the create action of my controller, the command will be handled and eventually executed successfully. What's the appropriate way to notify the controller which response to return in case the command did fail or succeed? Given the command handler will fire a domain specific event, I could hook up the controller to the event, but that seems a quite awkward, also not appropriate for every situation (e.g. a post could be created somewhere else and the controller really doesn't know about this :) ).
public function createAction($title, $content)
{
$this->commandBus->execute(new CreatePostCommand($title, $content);
$this->render('…'); // what if the command execution failed?
}
Any thoughts on this?
I think if you are really trying to follow the DDD command pattern then you need to treat the command bus as a fire and forget asynchronous process that may take a long time to complete.
Consider immediately redirecting to a command verifier controller. It's up to the command verifier to actively check the status of the command and see if it worked.
In most cases, the command will have finished successfully and your verifier can then redirect once again to continue normal flow.
If the command fails then the verifier puts up an appropriate error message.
If the command is in progress then you can entire a redirect loop while informing the user that the command is in progress.
Something like:
// Execute the command
$command = new CreatePostCommand($title, $content);
$this->commandBus->execute($command);
return redirect '/command-verifier/' . $command->getId();
// The verification action
public function verifyCommandAction($commandId)
$commandStatus = $this->commandBus->getStatus($commandId);
if ($commandStatus == SUCCESS) redirect to all is well;
if ($commandStatus == FAILED) then oops;
if ($commandStatus == IN_PROGRESS) then maybe pause a bit and redirect again while keeping the user informed.
Clearly there is quite a bit of hand waving going on but I think this is the most general approach especially with php where every request starts from ground zero.
The way I'm currently doing it is as follows (excuse long post).
public function createAction($title, $content) {
try {
$post = $this->commandBus->execute(new CreatePostCommand($title, $content);
}
catch (Exception $e) {
return $this->render('some error template file', $e);
}
return $this->render('successful creation template file', $post);
}
This way, you're creating a post and if everything goes as planned, return the $post object and send that to your view. On the other hand, when an exception is thrown during execution, you catch that error and send it to a view.
My preferred way is to have the controller call a method on a service that manages that behaviour, and have the controller injected as a listener that manages the responses, ie:
public function createAction($title, $content) {
$service = new CreateActionService($title, $content);
return $service->create($this);
}
public function onError(Exception $e) {
return $this->render('some error template file', $e);
}
public function onSuccess($post) {
return $this->render('success', $post);
}
Then in your service...
public function create($listener)
{
try {
$this->commandBus->execute(new CreatePostCommand($title, $content);
}
catch (Exception $e) {
return $this->listener->onError($e);
}
return $this->listener->onSuccess($post);
}
This way your service is managing the various results that the command handler may return, and your controller is left simply to manage the responses that you may wish returned to your presentation layer.
As stated, when I use in a shell :
$this->requestAction('/sites/zaz/option1');
The action doesn't get triggered. To test this, I tried :
public function zaz($option1 = null) {
CakeLog::write('acces', 'action triggered');
return 'got it !';
}
And the action isn't done and there is no log written whatsoever. All my other logs do work.
So I tried :
$this->requestAction('/sites/actionwhichdoesntexist/option1');
And I got an error stating that the action doesn't exist.
I really need to use requestAction, because I have a model/controller and this action is typically testing that a ressource is still alive. I want to use requestAction in order to smoothly handle the "requested" aspect, so that I will build something more robust :
if(empty($this->request->params['requested']))
$this->redirect(array('controller'=>'proxies', 'action'=>'index', 'admin'=>true));
else
return true;
I tried with 2.4.1 and 2.5, nothing just happens, no output is given, even if I put a 'die()' in the action.
As stated in the first comment, I should have checked the beforeFilter function.
I have just built a restful API with Slim Framework. For error conditions I simply respond with appropriate error codes for each error case and called with $app->halt, for example:
$app->halt(403, "Unauthorized");
But when I curled my API with -v and when I viewed headers in Firefox with HTTPFox I am always seeing error code 500. Anyone else notice this? Is there something I'm missing?
I ran into this same issue myself recently because I had forgotten to instantiate the $app variable within my function.
If you are not explicitly stating for your function to use($app), try adding the following line before $app-halt(403, 'Unauthorized') in order to see the desired error code:
$app = Slim::getInstance();
It is not allowed to call halt() method outside of the route callback.
You should use like this;
$app->get('/method/', function () {
//logical controls
//do something
//or
$app->halt();
});
There is a difference between halt() and setStatus().
With halt(), you will stop the current script execution and render a response according to the HTTP status code and message you choose to send. You can do it anywhere in your app with this code :
$app = \Slim\Slim::getInstance(); //if you don't have access to $app
$statusCode = 403;
$body = 'Unauthorized';
$app->halt($statusCode, $body);
//App will stop immediately
With setStatus() or $this->response->status(); you will only change the HTTP status code you are sending but your app will continue to execute like normally and won't stop. Its only changing the header that Slim will send to your client at then end of the route execution.
$app = \Slim\Slim::getInstance(); //if you don't have access to $app
$statusCode = 403;
$app->response->setStatus(400);
//App will continue normally