I am creating a public API using Laravel 5.2. To keep the code in the controller short, I have created several helper functions, one of which is a function to return a response to the API call, as shown below:
if (! function_exists('buildResponse'))
{
function buildResponse($data)
{
return response()->json($data)->header('foo', 'bar');
}
}
This is how I would call it from the controller:
public function registration()
{
buildResponse(['a' => 'Success']);
}
However this does not work. It only works if I add a return in front of the function.
public function registration()
{
return buildResponse(['a' => 'Success']);
}
One might say, "Okay, then just include the return!". The thing is, this particular function will be called by another helper function, for example:
if (! function_exists('throwResponseCode'))
{
/**
* Throws a response code to the client.
* #param $code
* #return mixed
*/
function throwResponseCode($code)
{
switch ($code) {
case '101':
$data[$code] = 'Unable to establish a database connection';
return buildResponse($data);
// Other cases here
}
}
}
Is there any way that I can send a response to the client from the helper function?
Keep it simple bro!
Change
return response()->json($data)->header('foo', 'bar');
To
return response()->json($data)->header('foo', 'bar')->send();
Short answer, no. Not directly.
The purpose of return is to finish the function and give results. Laravel considers the return value of controller to be the response, so other functions can not do this using return.
There are someways around this. Consider this. Create a middleware, that works after the response has been generated by controller, i.e. calls $next($request) in the first line. Here you can change the response as you wish. To connect helpers to this middleware, you can use static methods or properties. The logic of middleware would be that if someone has put something in, say, $response static property of middleware, then send this one instead of controller response.
Related
In my API I used "with" method to get parent's model relation and everything works fine.
I want to add an attribute in my relation and return it in my API but I should use request in my model.
Something like this :
Book.php
protected $appends = ['userState'];
public function getUserStateAttribute () {
return User::find($request->id); //request not exists here currently
}
I have $request in my controller (api controller)
Controller.php
public function get(Request $request) {
Post::with('books')->all();
}
I believe using static content to append in array of model is so easy but how about using request's based content ?
I guess you can use request() helper :
public function getUserStateAttribute () {
return User::find(request()->get('id'));
}
Sure this is not really MVC pattern, but it can work
You want to take request as a parameter here:
public function getUserStateAttribute (Request $request) {
return User::find($request->id);
}
That way you can access it in the function. You will just need to always pass the Request object whenever you call that function.
e.g. $book->getUserStateAttribute($request);
Alternatively, you could just pass the ID, that way you need not always pass a request, like so:
public function getUserStateAttribute ($id) {
return User::find($id);
}
Which you would call like:
e.g. $book->getUserStateAttribute($request->id);
Let's say I'm building a small application, where a small part of it is responsible for sending an email when a contact form is submitted. I only want to do that if the contact form passes some simple validation.
In the following controller the ContactRequest $request parameter is unused inside the method, although Laravel used the type-hinting to automatically apply the ContactRequest logic to the request.
Is it possible to achieve the same thing without leaving an unused variable in the controller method?
// Route
Route::post( 'contact', 'PageController#submitContactForm' );
// PageController
public function submitContactForm( ContactRequest $request ) {
sendContactFormEmail();
return redirect()->back();
}
// ContactRequest
public function authorize() {
return hasNotSubmittedContactFormRecently();
}
public function rules() {
return [ 'message' => 'required' ];
}
Yes, you can write your controller method like so:
// PageController
public function submitContactForm()
{
app()->make(ContactRequest::class);
sendContactFormEmail();
return redirect()->back();
}
and it will have same effect. However for me it's better to use it as you used it before.
Also probably you somehow use data you receive, so it might be more reasonable to use it like this:
sendContactFormEmail($request);
instead of probably injecting request into sendContactFormEmail method.
So, I'm building an API architecture and I am struck on the way the programmer will be implementing the output of the API endpoints.
The thing is that there can be different ways to store the response that I'm going to output and I'dont know if it would be worth to make an interface and force the developer to use just one way.
First case, using a class property.
We have a controller that makes a number of actions all based on a resource 'user' and then in a response handler function returns the formed response:
class LogInController implements ResponseInterface{
private $user;
private function setUser(){...};
private function checkThatToTheUser();{...}
function LogInEndpoint(){
$this->setUser();
$this->checkThatToTheUser();
return $this->handledResponse();
}
/**implemented function that doesn't
take parameters as it has access
to the class property that has the response formed*/
function handledResponse(){
$response = [
'user_id' => $this->user->id
];
return $this->APIResponse($response);
};
}
Second case, directly calling to the response manager.
We have a controller that simply outputs some data from the database, which in this cases can be a collection or a collection of collections.
class UserController{
function get(){
$users = User::paginate(20);
return $this->APIReponse($users);
}
function getByID($id){
$user = User::find($id);
return $this->APIReponse($user);
}
}
Third case, we encapsulate all the response generation on a function but having no properties.
In this case we pass the instanciated user to the response handler.
class UserActionsController{
private function get(){
$user = User::find(1);
return $user
}
private function getComplexThings($user){
...
return $user;
}
function getComplextDataEndpoint(){
$user = $this->get();
$user = $this->getComplexThings($user);
return $this->handledResponse($user);
}
function handledResponse($user){
...
return $this->APIResponse($user);
}
}
Should I let this open and let the programmer choose in the moment of the implementation or force the way it gets implemented (properties, parameters, directly outputs, outputs under a response handler...).
i have this blogsController, the create function is as follows.
public function create() {
if($this->reqLogin()) return $this->reqLogin();
return View::make('blogs.create');
}
In BaseController, i have this function which checks if user is logged in.
public function reqLogin(){
if(!Auth::check()){
Session::flash('message', 'You need to login');
return Redirect::to("login");
}
}
This code is working fine , but it is not what is need i want my create function as follows.
public function create() {
$this->reqLogin();
return View::make('blogs.create');
}
Can i do so?
Apart from that, can i set authantication rules , like we do in Yii framework, at the top of controller.
Beside organizing your code to fit better Laravel's architecture, there's a little trick you can use when returning a response is not possible and a redirect is absolutely needed.
The trick is to call \App::abort() and pass the approriate code and headers. This will work in most of the circumstances (excluding, notably, blade views and __toString() methods.
Here's a simple function that will work everywhere, no matter what, while still keeping your shutdown logic intact.
/**
* Redirect the user no matter what. No need to use a return
* statement. Also avoids the trap put in place by the Blade Compiler.
*
* #param string $url
* #param int $code http code for the redirect (should be 302 or 301)
*/
function redirect_now($url, $code = 302)
{
try {
\App::abort($code, '', ['Location' => $url]);
} catch (\Exception $exception) {
// the blade compiler catches exceptions and rethrows them
// as ErrorExceptions :(
//
// also the __toString() magic method cannot throw exceptions
// in that case also we need to manually call the exception
// handler
$previousErrorHandler = set_exception_handler(function () {
});
restore_error_handler();
call_user_func($previousErrorHandler, $exception);
die;
}
}
Usage in PHP:
redirect_now('/');
Usage in Blade:
{{ redirect_now('/') }}
You should put the check into a filter, then only let the user get to the controller if they are logged in in the first place.
Filter
Route::filter('auth', function($route, $request, $response)
{
if(!Auth::check()) {
Session::flash('message', 'You need to login');
return Redirect::to("login");
}
});
Route
Route::get('blogs/create', array('before' => 'auth', 'uses' => 'BlogsController#create'));
Controller
public function create() {
return View::make('blogs.create');
}
We can do like this,
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect('/to/another/route/')->with('status', 'An error occurred.'));
It's not a best practice to use this method, but to solve your question, you can use this gist.
Create a helper function like:
if(!function_exists('abortTo')) {
function abortTo($to = '/') {
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect($to));
}
}
then use it in your code:
public function reqLogin(){
if(!Auth::check()){
abortTo(route('login'));
}
}
public function create() {
$this->reqLogin();
return View::make('blogs.create');
}
I'm building an API using Laravel. I'd like to pass data to a function in the base controller and have the JSON served out via Response::json() from there (the reason for this is so that the response method carries out benchmarking and logging, among other things)
This works:
<?php
public function show($id)
{
$data = Member::find($id);
return Response::json($data);
}
This doesn't:
<?php
public function show($id)
{
$data = Member::find($id);
$this->respond($data);
}
private function respond($data)
{
return Response::json($data);
}
Can anyone tell me why Response:json() doesn't like being popped into another function?
If I echo Response::json($data) instead of return it outputs the full response, including the headers.
All input appreciated. Thanks.
As cecilozaur commented, perhaps you need to:
return $this->respond($data);
So that the response actually gets returned to the parent function.