How do I convert an API resource class in Laravel 5.5 to an array BEFORE returning from controller? - laravel

Ordinarily, in Laravel 5.5, when using an api resource class, you simply return the resource class instance from your controller method, like so:
public function show(Request $request, MyModel $model)
{
return new MyModelResource($model);
}
This converts the model to an array (and ultimately to json) in the response to the client.
However... I am trying to figure out how to convert everything to an array BEFORE returning it from the controller method. I tried this:
public function show(Request $request, MyModel $model)
{
$array = (new MyModelResource($model))->toArray($request);
// ...
}
The problem here is that any relationships loaded on the resource aren't also converted to an array. They show up inside $array as an instance of a resource class. Obviously calling toArray() manually does not result in a recursive call, and methods such as ->whenLoaded('relationship_name') aren't really respected either.
So how do I get Laravel to do everything it does to convert the resource to an array recursively WITHOUT having to return it from my controller method?

I believe what you are looking for is the resolve method on the resource class. See definition.
From the looks of it, it should handle converting the relationships into an array as well. Just be sure you are setting up your resource relationships properly.

Neither the toArray() or resolve() methods convert the related models to arrays which is really annoying because you'd expect them to.
You're better off using toResponse(null) which will return a JsonRepsonse object. Which you can then use the getContent() method for a json encoded string or the getData() method for an object.
So if you wanted an array not wrapped in a data variable it would be:
$array = json_decode(
json_encode(
(new MyModelResource($model))
->toResponse(null)
->getData()
->data
),
true);
Ugly but it works unlike the accepted answer.

Related

Laravel with() together Table or Variable Name

I was reading a blog related Repository Pattern. I saw use of withBlogs method.
public function index()
{
$blogs = $this->blogRepository->all();
return view('blog')->withBlogs($blogs);
}
I never see something like this before. What is the purpose of it or what it's doing?
it is laravel's magic methods
you can name the method anything you want with with() in laravel
let me explain you by example, the following code you write in your controller method
return view('index')->withName('Name')->withFullName('Full Name')->withaddress('Your address')->withcountryName('CountryName');
then you can access the values in view explained below
withName('Name') in view it becomes $name
withFullName('Full Name') in view it becomes $fullName
withaddress('Your address') in view it becomes $address
withcountryName('CountryName') in view it becomes $countryName
It is used for passing data into views. The with method returns an instance of the view object so that you can continue chaining methods before returning the view. All of the syntax below archives the same thing:
return view('blog')->withBlogs($blogs);
return view('blog')->with('blogs', $blogs);
return view('blog')->with(compact('blogs'));
return view('blog', compact('blogs'));

How to load a CodeIgniter view in $promise->then() in a controller?

In my CodeIgniter 2 controller I call a model method which returns a ReactPHP promise, and I want to load a CodeIgniter view in the function called by that promise's ->then() method. How can I do this? What happens instead is the controller method returns nothing, so I get a blank page in the browser.
Here is a simplified example illustrating what I'm trying to do:
class My_class extends My_Controller {
function my_method() {
$this->my_model->returns_a_promise()->then(function ($data) {
// How can I pass the promise's resolved value to the template here?
// It seems this never gets called, because my_method() returns
// before we get here. :(
$this->load->view('my_view', $data);
});
}
}
Is there any way to tell the controller method not to send output to the browser until after the promise has resolved?
I'm not sure what are you trying to do but if you want to stop view from outputting and return it as a string then output it with echo yourself you can do this:
$view = this->load->view('my_view', $data, TRUE);
Now you have the view as a var string you can use it to do what you are trying to do.
It turns out the code in my original question does work. So the question is the answer. But the reason it wasn't working for me was that returns_a_promise() was not returning a resolved promise, so ->then() was not called and the view was not rendered. In order to make it return a resolved promise, I had to call $deferred->resolve(); in the code that returned the promise.
The upshot of this is that this code example demonstrates it is possible to run asynchronous PHP (via ReactPHP in this case) in CodeIgniter controller methods. My particular use case is to run many database queries concurrently in the CodeIgniter model.
try this:
function my_method() {
$data = array();
$data['promise'] =$this->my_model->returns_a_promise();
$data['view'] = 'my_view';
$this->load->view('my_view', $data);
}

Sending request to a post controller function from another controller function

I have a controller like this.
public function barcode_approve(Request $request)
{
$barcodes = $request->input('barcode_values');
$upload_ids = $request->input('upload_id');
....
}
It is defined as post in route without any problem.
Route::post('my/url','BarcodeScanController#barcode_approve');
I would like to use barcode_approve by sending request from controller like
public function push_approve(){
$request = ['barcode_values' => '23ssdwe','upload_id'=>234234];
$this->barcode_approve($request);
.....
}
But $reqeust->input doesn't give the value when I send it through controller function (push_approve)
How can I send values from another controller function as input in $request?
Your barcode_approve expects a Request object, not an array. While you could instantiate a new Request object and potentially inject your fake inputs, I would consider that a bad practice.
Whenever you find yourself trying to call a controller method from another controller method, it usually means you have logic that can be extracted, either to a model, a trait, or in the case of the same controller, a separate protected function.
The purpose of a controller is to be the transport method, you shouldn't have much business logic in it, extract logic to the models when you can.
Required argument in barcode_approve() method must be instance of Request, not just array even if u call it $request.
So if you realy need your code to work, you must create Request instance at your push_approve method()
$request = new Request(['barcode_values' => '23ssdwe','upload_id'=>234234]);
But better way will be to route Request to push_approve() initially
extends your controller with the controller you want to used
then call the function this->barcode_approve($request)

Laravel Model Get Method Decoding JSON

Hi there below is what I'm storing in my db but when I use my get method in my model I have to use json_decode twice when formating my data why is this happening and can I have it just use it once somehow.
json exactly in db:
"[{\"id\":\"1\",\"country\":\"New Zealand\",\"shipping_rate\":\"1\"},{\"id\":\"2\",\"country\":\"Australia\",\"shipping_rate\":\"2\"}]"
Model Get Method:
public function getshippingAttribute()
{
return $this->attributes['shipping'] ? json_decode(json_decode($this->attributes['shipping'])) : [];
}
The problem is not clear enough from your question but the Laravel offers a builtin mechanism for attribute casting (Since v-5.1). In this case, in your model, just declare a $casts property for example:
protected $casts = [
'shipping' => 'array',
// more ...
];
Because of the $casts property given above, whenever you'll write (create/update) a model, you don't need to explicitly use json_encode to convert the array to json string, Laravel will do it for you and also, when you'll retrieve the model (single/collection), the shipping attribute will be automatically converted back to an array so you don't need to use json_decode for working with the attribute.
Regarding the response, that will be also handled by laravel if you don't convert it to json manually (when returning a model/collection). This will possibly solve your problem.
public function getshippingAttribute()
{
return $this->attributes['shipping'] ? json_decode($this->attributes['shipping']) : [];
}
Try return json response
public function getshippingAttribute()
{
return response()->json($this->attributes['shipping'])
}

Laravel Controller member variable

Is there any possibility in laravel to keep the state of the controller object?
In every example I found, the controller looks the following way:
class MyController extends Controller {
public function getView(){ //return the view }
public function postData() { //save the data }
}
What I would do is to call a service which loads specific data from my data base and return it to the view. In the example above this should be done within the getView() function. What if I need the same data in my postData() function.. Then I have to make another database call in the postData function. It is not possible to have a member variable in 'MyController' and to load the data only once for the class because of routing in laravel. When I call via routing the getView function I get another instance of MyController than I get if I call postData. Is there a possibility to call a specific function only once for the whole controller and to get access to this values from all the functions within the controller?
Is there a possibility to call a specific function only once for the
whole controller and to get access to this values from all the
functions within the controller?
As per my understanding it it not possible. Actually any function of controller is being called via routes. When your any route has been called every time the new object of controller is being created. But it has other way of round. You can use Cache. You can implement it as below:
Call to your specific function of controller.
Get the data from the database.
Store it in Cache for other functions.
In other functions check is data available in Cache? then get from Cache else call your database function to get the data.
Simply in coding as below:
Use Cache;
class MyController extends Controller {
public function getView(){
$data = call_to_database_and_returned_data();
Cache::put('data',$data,120);
return the view
}
public function postData() {
$data = null;
if(Cache::has('data')) {
$data = Cache::get('data');
} else {
$data = call_to_database_and_returned_data();
Cache::put('data',$data,120);
}
}
}
Syntax Description:
Cache::put('name_to_save_data',$your_variable_to_save,for_number_minutes);

Resources