laravel api return null - mysql

i have api that returns my data. i have a conditions that if visible==1 then return data otherwise don't return any thing.
but what i have receive is this
{
"data": [null, {
"order": 2,
"path": "http:\/\/controlpanel.test\/uploads\/7bb61115dd77823d8e8e3f2b6afa401b.png",
"visible": 1
}]
}
i want this to be return
{
"data": [{
"order": 2,
"path": "http:\/\/controlpanel.test\/uploads\/7bb61115dd77823d8e8e3f2b6afa401b.png",
"visible": 1
}]
}
without null.
this is my code
if($this->visible==1){
return [
'order' =>$this->order,
'path' => asset('uploads').'/' . $this->path,
'visible'=> $this->visible,
];
}

You need to define FK for post() relation in your comments model like
public function post(){
return $this->belongsTo('App\Posts' , 'post_id');
}
Using App\Posts name convention laravel is looking for posts_id not post_id
update your post model also as
public function comments(){
return $this->hasMany('App\Comment', 'post_id');
}

You have Posts model so while in relation, it search for posts_id in the table attribute.
you can solve the problem using either of the following
update the comment module
public function post(){
return $this->belongsTo(Posts::class , 'post_id');
}
Update the model name
from Posts to Post

Related

Angular how to handle a nested http response

My angular service returns the following type of response:
{
"name": "abc",
"id": 1,
"list": [
{
"name": "listName1",
"id": 1
},
{
"name": "listName2",
"id": 2
}
]
}
This is what the call in the service looks like:
fetchX(): Observable<X> {
return this.http.get<X>(some_url)
}
Now, in my component I can access the 'name' and 'id' attribute of the returned object, but for the 'list', which is a list itself, I only get 'undefined'. I'm displaying the list elements in my application (by their name), and they don't actually show up there either (the HTML part for this is definitely correct, this isn't the issue).
myX: CustomX
myList: CustomList[]
ngOnInit() {
this.service.fetchX().subscribe((response) => {
this.myX = response,
this.myList = response.list,
console.log(response.name), //returns 'abc'
console.log(response.id), //returns '1'
console.log(response.list) //returns 'undefined'})}
The entities look like this:
export class CustomX {
name: string
id: number
list: CustomList[]
}
class CustomList {
name: string
id: number
}
What am I missing? I think I may be handling the response in the service incorrectly.

Laravel using avg() function with foreign key

I want to get the average rates for each product.
I have a rates table which has a foreign key to product table,
the rates table is similar to this
when I try to get products with this code:
$stocks = Stocks::with('images:url,color', 'tags:tag', 'sizes', 'rates')
->get()
->pluckDistant('tags', 'tag')
->pluckDistant('sizes', 'size');
it returns this
[
{
"id": 10,
"name": "name",
"image": "1564964985mI7jTuQEZxD49SGTce6Qntl7U8QDnc8uhVxedyYN.jpeg",
"images": [
{
"url": "1564964985mI7jTuQEZxD49SGTce6Qntl7U8QDnc8uhVxedyYN.jpeg",
"color": ""
},
{
"url": "1564964985EV20c1jGvCVCzpCv2Gy9r5TnWM0hMpCBsiRbe8pI.png",
"color": ""
},
{
"url": "1564964985iFcMox6rjsUaM8CHil5oQ9HkrsDqTrqLNY1cXCRX.png",
"color": ""
}
],
"tags": [
"عطور"
],
"sizes": [],
"rates": [
{
"id": 1,
"stocks_id": 10,
"rate": 2
},
{
"id": 2,
"stocks_id": 10,
"rate": 4
}
],
}
]
How can I get the average of rates as "rates":3 using the eloquent relations to get them all by sql without php proccessing?
You could leverage something like Appending. Say you have a Product model which has a OneToMany relationship with Rate model.
Your Product model would look something like this:
class Product extends Model
{
protected $with = ['rates'];
protected $appends = ['average_rate'];
public function getAverageRateAttribute()
{
return $this->attributes['average_rate'] = $this->rates->avg('rate');
}
public function rates() {
return $this->hasMany(Rate::class);
}
}
Now anytime you query your products from the database, you'll have the rate appended with the result.
array:7 [▼
"id" => 1
"created_at" => "2019-08-12 14:08:09"
"updated_at" => "2019-08-12 14:08:09"
"average_rate" => 4.5
"rates" => array:2 [▶]
]
However, be aware of causing n+1 problem. If you're using this approach make sure to always eager load your rates.
You could just use join and use aggregate function on rates table.
Stocks::with('images:url,color', 'tags:tag', 'sizes')
->join('rates', 'rates.stocks_id', '=', 'stocks.id')
->selectRaw('stocks.*')
->selectRaw('AVG(rates.rate) as average_rating')
->selectRaw('tags.*')
->selectRaw('sizes.*')
->selectRaw('images.*')
->groupBy('stocks.id')
->get()

How to add custom properties to Laravel paginate json response

I have the following simple index method:
public function index()
{
// dd(Poll::paginate(2));
return response()->json(Poll::paginate(2),200);
}
The output of that method is looks like the following json object:
{
"current_page": 1,
"data": [
{
"id": 1,
"title": "I suppose?' said Alice. 'Why, you don't know.",
"created_at": "2018-09-14 16:42:11",
"updated_at": "2018-09-14 16:42:11"
},
{
"id": 2,
"title": "Alice; but she knew that it seemed quite.",
"created_at": "2018-09-14 16:42:11",
"updated_at": "2018-09-14 16:42:11"
}
],
"first_page_url": "http://127.0.0.1:8000/polls?page=1",
"from": 1,
"last_page": 6,
"last_page_url": "http://127.0.0.1:8000/polls?page=6",
"next_page_url": "http://127.0.0.1:8000/polls?page=2",
"path": "http://127.0.0.1:8000/polls",
"per_page": 2,
"prev_page_url": null,
"to": 2,
"total": 11
}
I want to add another array property after "total: 11" attribute such as:
,
"anotherData" : [
"userId": 1,
"userName": "john10",
"message": "This is a message"
]
I have tried to understand how response()->json() works, so it can extract some data from LengthAwarePaginator object which it is the output of Poll::paginate(2) from this resource, but I could not able to understand how does it able to get an array from LengthAwarePaginator that holds the resultant keys in the json object?!
From the regarded resource above, the json() method takes an array and, I guess that, if the parameter is not an array, it tries to convert it to array, specially if it is an object like LengthAwarePaginator, so it may use toArray() method.
I have tried replacing return response()->json(Poll::paginate(2),200) with return response()->json(Poll::paginate(2)->toArray,200), then I have got the same output. Hence, I have decided to replace the code of my index method to be like the following:
public function index()
{
//dd(Poll::paginate(2)->toArray());
$output = Poll::paginate(2)->toArray();
$output['userData'] = ['userId' => \Auth::user()->id, 'userEmail' => \Auth::user()->email];
return response()->json($output,200);
}
The resultant output is:
...
"path": "http://127.0.0.1:8000/polls",
"per_page": 2,
"prev_page_url": null,
"to": 2,
"total": 11,
"userData": {
"userId": 1,
"userEmail": "lion#example.com"
}
}
If you're directly responding with the paginated data, a better option would be to wrap it in a Resource Collection and adding meta data to it.
This is how I implemented it.
CategoryController.php
public function index()
{
return new CategoryCollection(Category::paginate(10));
}
CategoryCollection.php
public function toArray($request)
{
return [
'status' => 1,
'message' => 'Success',
'data' => $this->collection,
];
}
Since Collection extends JsonResource, your response would automatically be converted to JSON when returned from the Controller.

How to remove Task json properties in Nancy.Response.AsJson

I've made one of my API endpoints and inner logic asynchronous and when previously I've used Response.AsJson(Foo.bar()) , it would return the json representation normally, but now I see this appended to it:
{
"result": [
{
"id": "59d680cc734d1d08b4e6c89c",
"properties": {
"name": "value"
}
}
],
"id": 3,
"exception": null,
"status": 5,
"isCanceled": false,
"isCompleted": true,
"isCompletedSuccessfully": true,
"creationOptions": 0,
"asyncState": null,
"isFaulted": false
}
But I want it to be like this:
"id": "59d680cc734d1d08b4e6c89c",
"properties": {
"name": "value"
}
As I understand, it's because I've wrapped my object in a Task , but I can't figure out, how with Nancy framework, which I use the Response.AsJson, to make it so the properties are excluded. I can obviously omit the Response.AsJson of the returned object, but then response is no longer Json if requesting through web-browser for example.
For further example
NancyModule for routing API:
public ItemCatalogModule(IItemCatalog itemCatalog) : base("/itemCatalog")
{
Get("/fetch/{id}", async parameters =>
{
var id = (string) parameters.id;
var response = await Response.AsJson(itemCatalog.GetItem(id));
return response;
});
}
How the interface looks like of ItemCatalog:
public interface IItemCatalog
{
Task<Item> GetItem(string id);
}
You shoud do this :
public ItemCatalogModule(IItemCatalog itemCatalog) : base("/itemCatalog")
{
Get("/fetch/{id}", async parameters =>
{
var id = (string) parameters.id;
return Response.AsJson(await itemCatalog.GetItem(id));
});
}

Yii2 Nested relations in Rest results

I have a customer table and a user table, they have a M:M relationship set in user_has_customer.
The entire application is a Rest API, and i use extraFields() and GET customers?expand=users to get the connected users when looking at customers.
user_has_customer stores some additional information on when the user was assigned to the customer and a few other fields, and several fields can have the same combination of user and customer. To be able to update or delete a relation, I need the relation id (user_has_customer.id) to be visible when looking at customers.
This function will return the customer, and its related users:
public function getUsers() {
return $this->hasMany(User::className(), ['id' => 'user_id'])
->viaTable('user_has_customer', ['customer_id' => 'id'])
->select(['id', 'username']);
}
This function will return the user-customer relationship:
public function getUserRelations() {
return $this->hasMany(UserHasCustomer::className(), ['customer_id' => 'id'])
->select(["id",
"customer_id",
"user_id",
"created_by",
"created_at"]);
}
But i would like to know how i can nest these relations, so the result looks like this:
{
"id": 11148,
....
"users": {
"id": 1,
"user_id": 1,
"added": "2017-08-01 22:23:24"
"user": {
"id": 1,
"username": "admin"
}
}
}
or even like this (like a MySQL join):
{
"id": 11148,
....
"users": {
"id": 1,
"user_id": 1,
"added": "2017-08-01 22:23:24"
"username": "admin"
}
}
For some reason this will not work (the created SQL is correct, but the AR refuse to show the fields from user in the result):
public function getUserRelations() {
return $this->hasMany(UserHasCustomer::className(), ['customer_id' => 'id'])
->joinWith('user', true)
- ->select('*');
}