I have 2 models:
class Order extends Model
{
protected $fillable = ['user_id','name','surname','fathers_name','phone_number','city','post_office','comment'];
public function user()
{
return $this->belongsTo('App\User');
}
public function products()
{
return $this->belongsToMany('App\Product', 'order_product');
}
}
class Product extends Model
{
public function order()
{
return $this->belongsToMany('App\Order', 'order_product');
}
public function category()
{
return $this->belongsTo('App\Category');
}
}
3 tables:
product:
id
name
...
order_product:
id
order_id
prod_id
qty
...
order
id
city
phone
...
and 2 arrays of data:
$data = $request->except('_token','submit'); - information about client
$order_content - array with info about products in cart
So, the question is how to insert all this data in DB? I tried to read about many to many insertion: sync, attach, etc.. but understood nothing :c
Imagine you have a product with id 1. And an order with id 1. The product is part of the order, so you have to attach them. You do
$product = Product::find(1);
$order = Order::find(1);
$order->products()->attach($order->id);
However, in your case, your pivot table has more data, like 'qty'. Then you do,
$order->product()->attach($order->id, ['qty' => 2]);
So far, we were only attaching a single product to an order. If you want to attach many products simultaneously, you do:
$order->products()->sync([
$product->id => ['qty' => 1],
$product2->id => ['qty' => 3]
]);
I hope this helps understand better. I recommend you read the doc again and again until it makes sense.
Related
I have 3 tables called games, products, game_product. And game_product is my pivot table
This is the structure.
id
game_id
product_id
1
1
1
1
1
2
30 Minutes ago I can attach the game_id and product_id correctly, then i changed nothing. And after I tried to create a new data, its give me this error message
Call to a member function games() on null
This is my model relationship
App\Models\Game.php :
public function products()
{
return $this->belongsToMany('App\Models\Product', 'game_product', 'product_id', 'game_id');
}
App\Models\Product.php :
public function games()
{
return $this->belongsToMany('App\Models\Game', 'game_product', 'game_id', 'product_id' );
And this is my create controller
public function productsNew(Request $request, $id)
{
$products = Product::find($id);
$new = Product::create([
'product_sku' => $request->product_sku,
'name' => $request->name,
'seller_price' => $request->seller_price,
'price' => $request->price,
'profit' => $request->price - $request->seller_price,
]);
$products->games()->attach($id);
$new->save();
notify("Product added successfully!", "", "success");
return redirect('admin/products/'.$id);
}
}
I try to post the id of game and product to pivot table game_id and product_id. What should I do to store the ID only without any other of value?
Just change the order of
$products->games()->attach($id);
$new->save();
to be
$new->save();
$products->games()->attach($id);
As a side note, you are creating a product. Just 1 product. So the variable name mustn't be pluralized as it is singular. $product
One final thing, if this function is just part of the CRUD, please follow the convention of naming functions to be: create/store/show/edit/update/destroy, makes your and everyone else's lives easier when asking questions.
I have 2 tables that are related to each other by 3rd table (where only stores the ids) now seems i can't get my data out of third table in API resource file
Logic
Product model (has many barcode)
Barcode model (belongs to product and belongs to outlet)
Outlet model (has many barcodes)
outlet_products table (stores barcode_id and outlet_id)
Code
Barcode model
class Barcode extends Model
{
public function product()
{
return $this->belongsTo(Product::class);
}
public function outlet()
{
return $this->belongsTo(Outlet::class, 'outlet_products', 'barcode_id', 'outlet_id');
}
}
Outlet model
class Outlet extends Model
{
public function barcodes()
{
return $this->hasMany(Barcode::class, 'outlet_products', 'outlet_id', 'barcode_id');
}
}
BarcodeResource
class BarcodeResource extends JsonResource
{
public function toArray($request)
{
$arrayData = [
'id' => $this->id,
'sku' => $this->sku,
'serial_number' => $this->serial_number ? (Int) $this->serial_number : null,
'price' => (Int) $this->price,
'discount' => $this->discount ? (Int) $this->discount : null,
'product' => new ProductsResource($this->whenLoaded('product')),
'outlet' => new OutletsResource($this->whenLoaded('outlet')),
];
return $arrayData;
}
}
Now I am trying to get my product barcodes and name of each barcode outlet.
Controller
$products = ProductsResource::collection(Product::orderBy('id', 'desc')->with(['barcodes', 'barcodes.outlet'])->get());
and the result is:
Any idea why i can't get my barcodes outlet?
Based on your question and comment above:
A Product has many Barcode and a Barcode belongs to a Product. They have a One To Many relationship.
An Outlet has many barcode and a Barcode has many Outlet. They have a Many To Many relationship.
Here's how to set the One To Many relationship.
In your Product class:
class Product extends Model
{
public function barcodes()
{
return $this->hasMany('App\Barcode');
}
}
In your Barcode class, set the inverse relationship:
class Barcode extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
}
Here's how to set the Many To Many relationship.
In your Outlet class:
class Outlet extends Model
{
public function barcodes()
{
return $this->belongsToMany('App\Barcode');
}
}
In your Barcode class:
class Barcode extends Model
{
public function outlets()
{
return $this->belongsToMany('App\Outlet');
}
}
With a Many to Many relationship, you also need to create an intermediate table.
In this case, your pivot table will be barcode_outlet.
Important: Per Laravel convention, the intermediate table name must be in singular form and alphabetical order of the related model names (barcode_outlet in your case).
The intermediate table must have barcode_id and outlet_id columns. I will let you modify your migrations accordingly.
After setting the relationships, you will be able to use Eloquent to retrieve your models.
Example:
$barcode->outlets;
// returns a Collection of outlets
$barecode->product;
// returns a Product
$product->barcodes;
// returns a Collection of barcodes
$outlet->barcodes;
// returns a Collection of barcodes
I am working with nested eager loading is there a way you can pick out certain columns from the middle relation in account.user.location ?
User Model
public function account(): HasMany
{
return $this->hasMany(Account::class);
}
public function location(): BelongsTo
{
return $this->belongsTo(Location::class);
}
Account model
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
Location model
public function user(): HasMany
{
return $this->hasMany(User::class);
}
Controller method that works
This method returns the nested relation but i want certain columns from the user relation instead of listing them all.
public function show(string $id)
{
$film = Film::with([
'account.user.location'
])->findOrFail($id);
}
Controller method that doesn't work
This is my sample code i've tried to pick out the name column from users then display the location relation.
public function show(string $id)
{
$film = Film::with([
'account.user:id,name',
'account.user.location:id',city
])->findOrFail($id);
}
Response
This is the response which is returned its returning the location as null from the not working method
+"account": {#2061
+"id": "191067a6-4c38-423d-a972-bb3a842ca89e"
+"user": {#2064
+"id": "d9f381c1-3899-367c-8d60-6d2bc3db6d23"
+"name": "Domenick"
+"location": null
Im unsure on how i pick out specific columns from the middle relation and then joining the location. Can i get some assistance on where i am going wrong?
Laravel is loading each level of relationships after another. In other words, if you use A::with('b.c')->get(), then Eloquent will first load all As, then all of their referenced Bs and finally all of the Cs referenced by the loaded Bs. The ORM uses navigation properties, i.e. foreign keys, to do so. If you omit these foreign keys on intermediate models, the framework is not able to load the referenced models anymore.
If you'd do it manually, you would use the following queries (used IDs and foreign keys are examples):
SELECT * FROM a; // returns As with ids 1, 2, 3
SELECT * FROM b WHERE a_id IN (1, 2, 3); // returns Bs with ids 4, 5, 6
SELECT * FROM c WHERE b_id IN (4, 5, 6);
In your case, it should be sufficient to use the following code:
public function show(string $id)
{
$film = Film::with([
'account.user:id,account_id,location_id,name',
'account.user.location:id,city'
])->findOrFail($id);
}
Update your User Model
public function account()
{
return $this->hasMany(Account::class, 'user_id');
}
public function location()
{
return $this->belongsTo(Location::class);
}
Update you Account class to
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
In your controller method try this
public function show($id)
{
$film = Film::where('id', $id)
->with([
'account.user:id,name',
'account.user.location:id',city
])->get();
}
I want to make a list of students to know how many products each student buys. I have two tables : Member and Orders. In Orders table have column member_id and product_id. I want to count how many products each student buys. I can get list of student but i can't count how many products each student buys.
public function index()
{
$students = Member::getStudents();
$order = Order::where('member_id', $students->id)->count();
return view('admin.student.index', compact('students'));
}
But it appears an error:
Property [id] does not exist on this collection instance.
function getStudents()
public static function getStudents()
{
$members = Member::where('member_type_id', BaseModel::$student)->get();
for ($idxMember = 0; $idxMember < count($members); $idxMember++) {
if ( $members[$idxMember]->user_id ) {
$members[$idxMember]->username = User::find($members[$idxMember]->user_id)->username;
}
}
return $members;
}
I think it is because you get a collection on id.
so you should foreach your collection and get specific ids.
public function index() {
$students = Member::getStudents();
foreach($students as $student ) {
$order = Order::where('member_id', $student->id)->count();
}
return view('admin.student.index', compact('students'));
}
I suggest to use relationships in Database. It would be more easy and simple.
In orders table, there is a column called member_id which reference to id column in members table. (Keep attention to singular plural usage)
Refer Laravel Documentation for foreign key design and implementation.
You need 2 models, Member and Order. You should define the relationship as below.
Since this is One To Many Relationship,
In Member Model,
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Member extends Model
{
/**
* Get the orders for the member.
*/
public function orders()
{
return $this->hasMany('App\Order');
}
}
?>
In Order Model,
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
/**
* Get the member that owns the order.
*/
public function member()
{
return $this->belongsTo('App\Member');
}
}
?>
Now you can get order count per user using this code.
Member::find(MEMBER_ID)->orders->count();
This will return order count of the selected member.
Please refer the Laravel Documentation here.
Relationships | One To Many | One To Many (Inverse)
You can achieve this by simply using laravel relationship
In order to do this please follow below steps
First, create two relation in members model
public function orders()
{
return $this->hasMany('App\Models\Order', 'member_id', 'id);
}
Then retrieve the students details with orders
public function getStudents()
{
return Member::where('member_type_id', BaseModel::$student)->withCount('orders)->get();
}
Hope this helps
Thank you.
Sharing solution with explanation.
Objects are
Member (Student is also a member. But the Type is different)
Order (One order can have multiple products)
Product (Product will allocate with Orders and Members can place Orders)
Now If you are using Laravel. So the best way is to use Eloquent Relationships.
Model Member :
1 Define Query Scope
public function scopeStudents($query)
{
return $query->where('member_type_id', 1);
}
2 Define One to Many relation between Order and Member (One Student can have multiple orders. And I hope that other members can also have orders. So i am going to relate direct Member to Order)
public function orders()
{
return $this->hasMany('App\Order');
}
and
public function products()
{
return $this->hasManyThrough('App\Product', 'App\Order');
}
Model Order :
1 Define relation with Member Model for One to Many
public function member()
{
return $this->belongsTo('App\Member');
}
2 Define one to many between Order and Product
public function products()
{
return $this->hasMany('App\Product');
}
Model Product :
1 Define Order Product Relation
public function order()
{
return $this->belongsTo('App\Order');
}
Now the Model work is done. Only data fetching is remaining. Tell me in comments if you think below code is less and useful and easy to understand.
Controller Member :
1 Index Function :
// this will fetch all students with their orders and products
$data = Member::students()->with('orders', 'products')->get();
// this will fetch all students with their orders and order's products
$data = Member::students()->with('orders.products')->get();
// this will fetch all students with their orders count and products count
$data = Member::students()->withCount('orders', 'products')->get();
I have two tables: users, orders. I try to get all orders for current user.
Users Orders
_____ ______
id | name id | user_id
User model:
public function orders(){
return $this->hasMany("App\Order");
}
Order model:
public function user(){
return $this->hasOne("App\User", 'user_id', 'id');
}
Query in controller:
public function index()
{
$orders = Order::where('user_id', Auth::guard('api')->id())->get();
return response()->json(
$orders->user
);
}
I get NULL result, I do something wrong, because there are related rows in both tables.
If you want to retrieve all the Orders belonging to the current user, try using the following function.
public function index()
{
$orders = Auth::user()->with('Orders')->get()->toArray();//To get the output in array
/* ^ ^
This will get the user | This will get all the Orders related to the user*/
return response()->json($orders);
}
As pointed out by #Martin Heralecký, you would also need to change the hasOne() to belongsTo() in Order Model. See following (copied from #Martin Heralecký answer)
public function user(){
return $this->belongsTo("App\User");// second and third arguments are unnecessary.
}
Why belongsTo():
has_one and belongs_to generally are the same in the sense that they point to the other related model. belongs_to make sure that this model has the foreign_key defined. has_one makes sure that the other model has_foreign key defined.
Your $orders array will look something like this:
User => [
id => 'user id',
name => 'user name'
orders => [
0 => [
//order data
]
1 => [
//order data
]
.
.
.
.
]
]
In Order model you need to use the belongsTo relationship:
public function user()
{
return $this->belongsTo("App\User"); // second and third arguments are unnecessary.
}
In User model you can use hasMany relationship, for example in:
App/User.php
Add
public function orders()
{
return $this->hasMany("App\Order", "user_id", "id");
}
Now you can use this:
return User::find(1)->orders;