I working on an API for my app.
I'm trying to pull items from the database and return them in JSON object,
my items table looks like this:
Items
-id
-name
-description
-price
-currency_id
-company_id
this is how I'm getting the items:
$rows = Company::where('guid',$guid)
->first()
->items()
->orderBy('name', $sort_order);
I want to replace the currency_id with a currency object that contains all the columns of currency table
so my result will be like this:
[
{
'id':'1',
'name':'name',
'description': 'example',
'price':'100',
'currency':{
'id':'1',
'name':'usd',
'symbol': '$'
}
}
]
update:
This is my currencies table:
id
name
symbol
code
Edit 2: The user's problem was more complex than this since there was pagination and search integration with the query. Helped with https://pastebin.com/ppRH3eyx
Edit : I've tested the code. So here.
In Company model
public function items()
{
return $this->hasMany(Item::class);
}
In Item model
public function currency()
{
return $this->belongsTo(Currency::class);
}
Controller logic
$items = Company::with(['items' => function($query) use ($sort_order) {
$query->with('currency')->orderBy('name', $sort_order);
}])
->where('guid', $guid)
->first()
->items;
Result with test data
[
{
"id": 2,
"name": "Toy",
"description": "Random text 2",
"price": 150,
"company_id": 1,
"currency_id": 1,
"currency": {
"id": 1,
"name": "usd",
"symbol": "$",
"code": "USD"
}
},
{
"id": 1,
"name": "Phone",
"description": "Random text",
"price": 100,
"company_id": 1,
"currency_id": 1,
"currency": {
"id": 1,
"name": "usd",
"symbol": "$",
"code": "USD"
}
}
]
Try this.
$rows = Company::with('items.currency')
->where('guid', $guid)
->first()
->items()
->orderBy('name', $sort_order);
Try below
Make one relationship in Item Model
public function currencies() {
return $this->hasMany('App\Currency');
}
then do below in your controller
$row=Items::All()->with('currencies');
Related
This is a long post, sorry in advance.
I have a couple of questions regarding the diagram below.
How do I create a relationship for these tables? (tried "belongsToMany" and "hasMany")
Should I use Eloquent or Query Builder to get desired result? (image is attached below for desired result)
Is "client_order_items" a pivot table?
How can you distinguish a pivot table? Is it because the table has multiple
foreign keys?
How can I access "images" table from "Manufacturer" model? Can "hasOneThrough / hasManyThrough" achieve this?
Is the desired result achievable purely using Eloquent or DB Query?
//sample:
Manufacturers::find(2)->client_order_items->cars->images->car_image
I tried considering "client_order_items" as a pivot table then making relationships using "belongsToMany" in "Manufacturer", "Car" and "ClientOrder" models.
// App\Model\Manufacturer.php
public function client_orders() {
return $this->belongsToMany(ClientOrder::class,
"client_order_items", "manufacturer_id", "client_order_id")
->withPivot('id', 'quantity', 'car_id');;
}
public function cars() {
return $this->belongsToMany(Car::class,
"client_order_items", "manufacturer_id", "car_id");
}
// App\Model\Car.php
public function client_orders() {
return $this->belongsToMany(ClientOrder::class,
"client_order_items", "car_id", "client_order_id");
}
public function manufacturers() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "car_id", "manufacturer_id");
}
// App\Model\ClientOrder.php
public function cars() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "client_order_id", "car_id");
}
public function manufacturers() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "client_order_id", "manufacturer_id");
}
I also tried "hasMany" relationship:
// App\Model\Manufacturer.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\Cars.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\ClientOrder.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\ClientOrderItems.php
public function car() {
return $this->belongsTo(Car::class);
}
public function manufacturer() {
return $this->belongsTo(Manufacturer::class);
}
public function client_order() {
return $this->belongsTo(ClientOrder::class);
}
My goal is to get the result if i did something like this:
// Manufacturer::find(2)->client_orders
// Desired Result:
[
{
"client_order_id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"order_items": [
{
"client_order_item_id": 37394,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
}
]
},
{
"client_order_id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"order_items": [
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
}
]
But the result I'm currently getting (with "belongsToMany") is:
// Manufacturer::find(2)->client_orders
// Current Result:
[
{
"id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 88062,
"id": 37394,
"quantity": 1,
"car_id": 68
}
},
{
"id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 60978,
"id": 79913,
"quantity": 1,
"car_id": 68
}
},
{
"id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 60978,
"id": 84743,
"quantity": 1,
"car_id": 95
}
}
]
Sorry again for the long post.
Thank you in advance.
After experimenting and reading for couple of hours, I was able to get the result I want.
Making the relationships:
Manufacturer model has "belongsToMany" relationship with "ClientOrder"
// App\Model\Manufacturer
public function client_orders() {
return $this->belongsToMany(ClientOrder::class, 'client_order_items', 'manufacturer_id', 'client_order_id');
}
"Car" and "Image" model has "hasMany" relationship. This will give us access to "Image" model from "ClientOrderItems" model.
// App\Models\Car
public function image() {
return $this->belongsTo(Image::class);
}
// App\Models\Image
public function cars() {
return $this->hasMany(Car::class);
}
Creating Accessors to Models
In "ClientOrder" model, create an accessor for the "order_items" key. This will fetch rows from "OrderLineItems" that are related to the "manufacturer_id" and "client_order_id".
// App\Models\ClientOrder
protected $appends = ["order_items"];
public function getOrderItemsAttribute() {
$items = ClientOrderItems::where("manufacturer_id", '=', $this->pivot->manufacturer_id)
->where("client_order_id","=",$this->pivot->client_order_id)
->select(["id as client_order_item_id","car_id","quantity"])
->get();
return $items;
}
In "ClientOrderItems" pivot model, create an accessor for the "image".
// App\Models\ClientOrderItems
protected $appends = ["image"];
public function getImageAttribute() {
return Car::find($this->car_id)->image->car_image;
}
The result of the 2 codes above looks something like this:
[
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
More on Accessors & Mutators:
https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators
Retrieving Records
To get the "client orders" that are related to manufacturer_id, use:
/// App\Http\Controllers\ManufacturerController;
public function index() {
$client_order = Manufacturer::find($manufacturer_id)->client_orders->unique("id")->values();
}
Above code will only fetch unique rows from "client_orders" table. Appending the related "order_items" for each row with the help of accessors.
[
{
"client_order_id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"order_items": [
{
"client_order_item_id": 37394,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
}
]
},
{
"client_order_id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"order_items": [
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
}
]
Here i am using method chaining on Laravel Eloquent model (User) with pagination,but after calling method each pagination stop working.
Is this behaviour expected or i am missing something. there noting mentioned about this on official docs.
Works fine
User::paginate(10)
->appends(request()->all());
Output
{
"data": [
{
"id": 1,
"email": "user#email.com",
},
{
"id": 2,
"email": "two#email.com",
},
],
"current_page": 1,
"first_page_url": "//localhost/users?page=1",
"last_page": 5,
"last_page_url": "//localhost/users?page=5",
"next_page_url": "//localhost/users?page=2",
"path": "//localhost/users",
"per_page": 10,
"prev_page_url": null,
"total": 50
}
But problem arrives when i call each() method on it
Not working
User::paginate(10)
->appends(request()->all())
->each(function ($user) {
$user['someAttribute'] = 'value';
return $user;
})
Output (pagination not working)
plain simple result only query records. (Omitted pagination info)
[
{
"id": 1,
"email": "user#email.com",
},
{
"id": 2,
"email": "two#email.com",
},
]
I don't think you can retrieve the pagination properties after altering the $items. You'd have to convert the altered data into the LengthAwarePaginator object manually.
$users = User::paginate(15);
$alteredUsers = $users->getCollection()
->each(function($user) {
$user['someAttribute'] = 'value';
return $user;
});
$newPaginatedUsers = new \Illuminate\Pagination\LengthAwarePaginator(
$alteredUsers,
$users->total(),
$users->perPage(),
$users->currentPage(),
[
'path' => \Request::URL(), // optional
]
)->appends(request()->all());
You can look at the source here and have a better idea of how to build the object.
Create an accessor:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function getSomeAttributeAttribute()
{
return 'value';
}
}
$users = User::paginate(10)->appends(request()->all());
https://laravel.com/docs/8.x/eloquent-mutators#defining-an-accessor
https://laravel.com/docs/8.x/eloquent-serialization#appending-values-to-json
now i have this method inside my Product model
public static function product_lines($request)
{
$keyword = Helper::clean_keyword($request['keyword']);
$data = Product::where
('number','like','%'.$keyword.'%')->
orWhere('name','like','%'.$keyword.'%')->
with('get_unit_relations')-> // this is one to many
limit(30)->
get();
return $data;
}
and this is the get_unit_relations
public function get_unit_relations()
{
return $this->hasMany('App\Models\Product_unit','product_id','id');
}
like this its working and its return data without any problem ..
{
"id": 1,
"number": "1",
"name": "test",
"foreign_name": null,
"get_unit_relations": [
{
"id": 3,
"unit_id": 2,
"product_id": 1,
"barcode": "455",
"smallest_unit_relation": 12,
"price": 12,
"cost": null,
"created_by": null,
"deleted_by": null,
"created_at": "2020-05-17T21:46:26.000000Z",
"updated_at": "2020-05-17T21:46:26.000000Z",
"deleted_at": null
}
]
}
but if i change the code like this ..
public static function product_lines($request)
{
$keyword = Helper::clean_keyword($request['keyword']);
$data = Product::where
('number','like','%'.$keyword.'%')->
orWhere('name','like','%'.$keyword.'%')->
with('get_smallest_unit_id')-> // this is one to one
limit(30)->
get();
return $data;
}
and this is the get_smallest_unit_id
public function get_smallest_unit_id()
{
return $this->hasOne('App\Models\Unit','id','smallest_unit_id');
}
im getting null in return like this ..
{
"id": 1,
"number": "1",
"name": "test",
"foreign_name": null,
"get_smallest_unit_id": null // it always return null in any one to one relaiton ..
}
how can i use ->with() method with one to one relation
thanks
In controller get data from db like this, I want to pass whole of $request to another function in this controller to get price it calculating price based of many things from $request:
$user = Auth::user();
$query = Post::query();
$query
->where('province', '=', $user->province)
->where('city', '=', $user->city);
$customers = $query->get();
$customers['calculator'] = $this->calculator($request); // call function
my problem is it return like this:
{
"0": {
"id": 1,
"hash": "RqH29tkfm1dwGrXp4ZCV",
},
"1": {
"id": 3,
"hash": "RqH29tkfm1dwGsXp4ZCV",
},
"calculator": {
"price": 1
}
}
But I need to use that function for each data, and result should be like this:
{
"0": {
"id": 1,
"hash": "RqH29tkfm1dwGrXp4ZCV",
"calculator": {
"price": 1
}
},
"1": {
"id": 3,
"hash": "RqH29tkfm1dwGsXp4ZCV",
"calculator": {
"price": 1
}
}
}
What you want is to set a calculator key for each item in the $customers collection. So you need to loop over it:
foreach ($customers as $customer) {
$customer->calculator = $this->calculator($request);
}
Notice that since the $customer is a Model you should set the calculator as a property. Internally it will be set to the attributes array.
Description:
Hello, in my scenario I'm trying to perform joins on 3 tables regarding a connections system I've built up. I'm able to use eloquent to connect these 3 tables together correctly and return the results no problem however, I'm trying to be more efficient in how it's done. I don't enjoy the fact that every query eloquent fires off defaults to a select * so I'd like to select specific columns instead. Here's where I'm currently at:
Connection Controller Code
Groups::with([
'list.userAccount.profile'
])->where('user_id_fk', $my->user_id)
->orderBy('group_num', 'ASC')
->take(3)
->get(['group_num','group_title','group_id']);
Group Settings Model
public function list() {
return $this->hasMany('App\UserConnections','group_id_fk');
}
User Connections Model
public function userAccount() {
return $this->hasOne('App\User','user_id_fk');
}
User Account Model
public function profile() {
return $this->hasOne('App\Profile','user_id_fk');
}
Now, If I make a call to it's assigned route to get users an example result is the following:
{
"conn_id_fk": 2,
"user_id_fk": 10,
"type": 0,
"group_id_fk": 4,
"status": 1,
"created_at": "2017-02-09 13:58:34",
"updated_at": "2017-02-09 13:58:34",
"user_account": {
"user_id": 10,
"email": "someemail#email.com",
"verified": 0,
"locked": 0,
"code": 0,
"request": "",
"created_at": "2017-02-09 13:20:51",
"updated_at": "2017-02-09 13:20:51",
"profile": {
"user_id_fk": 3,
"first_name": "Jillian",
"last_name": "Jacobs",
"avatar": "",
"age": 0,
"about_me": "",
"one_liner": "",
"inspire": "",
"created_at": "2017-02-09 13:18:32",
"updated_at": "2017-02-09 13:18:32"
}
}
Again My dilemma is that I don't want it to do select * to get all that data, it's unnecessary and will eventually slow down my server and cost me more money on I/O alone.
I've tried doing something like the following for example:
public function profileEnd() {
return $this->hasOne('App\Profile','user_id_fk');
}
public function profile() {
return $this->profileEnd->select('first_name','last_name','avatar');
}
///////////////////// AND I have tried///////////////////////////
public function profileEnd() {
return $this->hasOne('App\Profile','user_id_fk');
}
public function profile() {
return $this->profileEnd->select(['first_name','last_name','avatar'])->get(); <---Returns 500
}
which results in the following:
{
"conn_id_fk": 2,
"user_id_fk": 10,
"type": 0,
"group_id_fk": 4,
"status": 1,
"created_at": "2017-02-09 13:58:34",
"updated_at": "2017-02-09 13:58:34",
"user_account": {
"user_id": 10,
"email": "someemail#email.com",
"verified": 0,
"locked": 0,
"code": 0,
"request": "",
"created_at": "2017-02-09 13:20:51",
"updated_at": "2017-02-09 13:20:51",
"profile": null <------------------------------- Kills off the profile section
}
So What am I doing wrong here and how can I fix this? Any assistance is greatly appreciated.
Thanks in advance
Cheers!
Laravel needs the keys in order to match up the related collections of models. In your example, you did not select the key, so after the records are retrieved, Laravel has no idea which profiles are related to which user accounts. Add the key to the select and you should be good to go.
public function profileEnd() {
return $this->hasOne('App\Profile', 'user_id_fk');
}
public function profile() {
return $this->profileEnd->select('user_id_fk', 'first_name', 'last_name', 'avatar');
}