So I am trying to use a resource collection to return datatable json information. Before I used my collection I first did a proof of concept that looked like this:
public function index()
{
$clients = QueryBuilder::for(Client::class)
->allowedIncludes('accounts')
->get();
if (request()->ajax()) {
return DataTables::of($clients)->make(true);
}
return view('client.index', compact('clients'));
}
This worked perfectly and the json response looked like so:
{data: [{id: "4428", number: "492501", name: "Test Client", email: "test#test.com",…},…]
draw:1
input:{view: "datatable", draw: "1",…}
recordsFiltered:2
recordsTotal:2}
Then I updated my index call to use my resource collection that looks like this:
public function toArray($request)
{
switch ($request->view) {
case 'datatable':
self::withoutWrapping();
return DataTables::of($this->collection)->make(true);
}
return parent::toArray($request);
}
The response is now plopped in an "original" attribute and a bunch of other items are added to the response. I don't understand why. It looks like this:
*callback: null
*charset: null
*content: <The above response is in here as a string>
*encodingOptions: 0
*statusCode: 200
*statusText: "OK"
*version: "1.0"
exception: null
headers: {}
original: <The above response is in here as an object>
I can set my dataSrc on datatables to original.data and it works fine but where did all this extra stuff come from? I have used a few other resource collections and never had all this stuff added in.
Update: because everything i am looking for is in "original" the pagination breaks as well as most of the other datatable functionality. If I move this return back into the controller it works fine.
So, the answer has to do with response type. The eloquent resource has an undocumented function called "toResponse" and if your return is going to be some kind of jsonResponse you need to modify it instead of your toArray method. What was happening was I was returning a JsonResponse and it was turning it into an array and just returning that json encoded.
To be clear as mud, here is my new Resource:
public function toResponse($request)
{
switch ($request->view) {
case 'datatable':
self::withoutWrapping();
return DataTables::of($this->collection)->toJson();
}
return parent::toResponse($request);
}
So, to reiterate, if you are returning an array or something that conforms to an array correctly (which datatables jsonresponse does not) you override "toArray". If you are returning a jsonResponse you need to override "toResponse".
Another option is to have your code start in toArray but when you know your going to return a jsonResponse you call $this->toResponse($request). Option is yours.
Related
I have a issue, after i eliminate cors policy on laravel i sending some json data to check respond. But nothing happens...
I sending request by axios using react.js, i sending json data collected from state.
and now i trying to collect that data by laravel, but that is hardest patch.
already try something like that:
$content='test';
return Response::$content;
or just echo 'test' but nothing comes...
My code is inside controller.
class testRequest extends Controller
{
public function show(Request $request)
{
//$data = $request->json()->all();
// $experience = $data->experience;
$content='test';
return Response::$content;
}
}
for now i expect to get respond like 'test' but after that i will need to send a link to file path for respond.
the Response::$content is just wrong... the :: operator is used to access static member functions or attributes of the Response class... you should do something like this:
return Response::json(['test' => $content]);
or
return response()->json(['test' => $content]);
in order to respond with a JSON document.
I have a method inside PostController
class PostController extends Controller {
public function index() {
$posts = Post::all();
return response($posts);
}
}
Two way:
class PostController extends Controller {
public function index() {
$posts = Post::all();
return $posts;
}
}
Both work fine but which way is better and more correctly?
I personnaly prefer this version:
return \Response::json($data);
Because it makes clear that the response is actual json data.
Just make sure your code is understandable by someone new on your project.
If you are writing an API project, where everything is always returned in json, simply return the model because you don't have to make the reader learn that it's JSON because everything is in JSON everywhere.
On the other hand, if it's some sort of mixed project (some routes return view, JSON, XML, whatever), try to make is as obvious as you can that this specific route return JSON data and nothing else.
Also as stated in comments, stay consistent. The shorter isn't the better. The better is the one that is simple to read and give enough info about what's going on.
It doesn't matter actually.. its depends on your desire and consistency..
return Response::json($model);
//or
return response()->json($model);
//or
return $model;
it give you same output..but if you using response, you can set the status code. most of the time, this reponse thing is used in API project.
I have method in my class that returns a JSON response.
public function response(){
return \Response::json(['data'=>'somedata']);
}
To be able to use more chain methods I want to use the __toString() method whenever I want to return an object as a response. Like this:
public function __toString(){
return $this->response();
}
But I get this error:
Method MyClass::__toString() must return a string value
Which makes sense but how can I do that. I looked in Laravel and Symfony JsonResponse classes and couldn't find a method to fix this. I tried the getContent() but that is just a string not a proper Json response.
After a lot of research I found a solution. I don't know if it is the best but here it is:
public function __toString(){
$this->response()->send();
return '';
}
Which is actually a call to Symfony\Component\HttpFoundation\Response::send() method instead of returning an string.
Thyis is a late response but I found a better solution, letting Laravel handle the response:
public function __toString(){
return Response::json($this)->content() ' Returns a string
}
I have a question about obtaining parameters from Request object.
What is the difference between
$name = $request->name;
OR
$name = $request->input("name");
They show the same behavior. I am asking that from the typing perspective, it is faster to utilize #1 method. But I don't know the difference. Is #1 prone to SQL injections?
Basically, the first case is just a syntactic sugar for the second. In Laravel, Request implements __get magic function to access its internal properties.
public function all()
{
return array_replace_recursive($this->input(), $this->allFiles());
}
public function __get($key)
{
$all = $this->all();
if (array_key_exists($key, $all)) {
return $all[$key];
} else {
return $this->route($key);
}
}
In the first case, if any files were uploaded, Laravel first looks for a property amongst them. And if there is no such param in files or in input, in your first snippet, Laravel also looks for a value amongst route parameters:
To protect your code against SQL injections, you have to use prepared statements/query builder/ORM. You should not escape/change input, so both these functions don't protect you against SQL injections.
As it's stated in docs, if AJAX validation fails you get json response:
If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.
But I'd prefer partial view with flashed error which is default for non AJAX.
So is it possible to emulate non AJAX or turn off AJAX without rebuilding source or some other awkwardness?
BTW, culprit function is buildFailedValidationResponse.
I got into a similar problem these days and ended up overwriting a method as well.
Under Laravel 5.1.20, i had to copy method response from class Illuminate\Foundation\Http\FormRequest into class App\Http\Requests\Request, and just like your answer, changed
if ($this->ajax() || $this->wantsJson()) {
with
if ($this->wantsJson())) {
This is the complete method in App\Http\Requests\Request class
public function response(array $errors)
{
if (!$this->pjax() && ($this->ajax() || $this->wantsJson())) {
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
Managed to solve the problem with brute force. Just overwritten the trait method in AuthController. Bad feel about that.
protected function buildFailedValidationResponse(Request $request, array $errors)
{
if (/*$request->ajax() ||*/ $request->wantsJson()) { return new JsonResponse($errors, 422);
}