Laravel attach manytomany with extra field - php

There are 3 tables. Products, Users and product_user. There are 3 fields in product_user table. product_id, user_id and price.
product_id and user_id will be attached and filled automatically. But I want a textfield named price which user fill it to be inserted in price field in database.
I mean I want to insert a textfield when attaching.

To insert an extra field in your pivot table first of all, you need to specify this extra field in your models.
For Example this:
In Product model
public function users()
{
return $this->belongsToMany('App\User', 'product_user')
->withPivot('price');
}
In User model
public function products()
{
return $this->belongsToMany('App\Product', 'product_user')
->withPivot('price');
}
Furthermore, in you Controller you can attach this extra field like this:
$product->users()->attach($user_id, ['price'=> $price ]);
I hope this will help you !!!

A best practice example to pass one array to attach is this example:
$extra = array(
'expense_type_id' => $request->expenseType,
'quantity' => $request->quantity,
'price' => $request->price
);
//dd($extra);
$logisticCost->expenses()->attach($logisticCost->id,$extra);
Cheers!

Related

How to add pivot table when inserting data to database in Laravel 8

maybe someone know how to insert pivot table in Laravel 8 automatically every i insert counselings table?
I have Model Counseling n to n Problem,
Input form
counselings table
problems table
Counselings Model
Problem Model
Controller
public function create()
{
return view('admin.counseling.create', [
'title' => 'Tambah Bimbingan dan Konseling',
'students' => Student::all(),
'problems' => Problem::all()
]);
}
public function find_nis(Request $request)
{
$student = Student::with('student_class', 'counselings')->findOrFail($request->id);
return response()->json($student);
}
public function store(Request $request)
{ dd($request->all());
$counseling = new Counseling();
$counseling->student_id = $request->student_id;
$counseling->user_id = Auth::user()->id;
$counseling->save();
if ($counseling->save()) {
$problem = new Problem();
$problem->id = $request->has('problem_id');
$problem->save();
}
}
You can insert into a pivot table in a few different ways. I would refer you to the documentation here.
Attaching
You may use the attach method to attach a role to a user by inserting
a record in the relationship's intermediate table:
Example:
$problem->counselings()->attach($counseling->id);
Sync
You may also use the sync method to construct many-to-many
associations. The sync method accepts an array of IDs to place on the
intermediate table. Any IDs that are not in the given array will be
removed from the intermediate table.
Example:
$problem->counselings()->sync($counselingsToSync);
Toggle
The many-to-many relationship also provides a toggle method which
"toggles" the attachment status of the given related model IDs. If the
given ID is currently attached, it will be detached. Likewise, if it
is currently detached, it will be attached:
Example:
$problem->counselings()->toggle($counselingsToToggle);
I would change your store() method to something like this :
public function store(Request $request)
{
$counseling = Counseling::create([
'student_id' => $request->student_id,
'user_id' => Auth::user()->id
]);
if($request->has('problem_id'){
$counseling->problems()->attach($request->problem_id);
//return something if problem id is in request
}
//return something if problem id is not there
}

Problem with Polymorphic Relationships in Laravel

I'm trying to implement a way to get the details of a person depending on the group it belongs to.
My database looks like this:
persons:
id
group
type
1
person
9
2
company
30
3
person
9
and so on.
Each "group" has a model which contains detail information for this record specific to the group.
For example:
persondetails looks like this
id
person_id
firstname
lastname
birthname
1
1
Harry
Example
Bornas
2
3
Henrietta
Example
Bornas
I created models for each table and I'm no trying to implement a relationship which allows me to query a person->with('details') via the person model (for example: for a complete list of all persons no matter which type it is).
For single records I got it working via a simple "if $this->group === person {$this->hasOne()}" relation, which doesn't work for listings.
I tried to wrap my head around a way to use a polymorphic relationship, so I put the following into the person model:
public function details(){
Relation::morphMap([
'person' => 'App\Models\Persondetail',
'company' => 'App\Models\Companydetail',
]);
return $this->morphTo();
}
and a subsequent
public function person(){
return $this->morphMany(Person::class, 'details');
}
which doesn't work sadly. Where is my thinking error?
As you're not using laravel convention for the keys, you need to define the keys on your relation
public function details()
{
Relation::morphMap([
'person' => 'App\Models\Persondetail',
'company' => 'App\Models\Companydetail',
]);
return $this->morphTo(__FUNCTION__, 'group', 'type');
}
Docs Link:
https://laravel.com/docs/9.x/eloquent-relationships#morph-one-to-one-key-conventions
Based on the reply by https://stackoverflow.com/users/8158202/akhzar-javed I figure it out, but I had to change the code a bit:
Instead of the code in the answer, I had to use the following:
public function details()
{
Relation::morphMap([
'person' => 'App\Models\Persondetails',
'company' => 'App\Models\Companydetail',
]);
return $this->morphTo(__FUNCTION__, 'group', 'id', 'person_id');
}

Laravel relationship storing to pivot null

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.

OctoberCMS filter Relation Widget based from currently selected record

The title says it all, but to give an example. I have a Member record and a Group. A member can have memberships in many groups and a group can have many members. (So that's many to many and I would have a pivot table for it.)
Now, each group has membership grades. E.g., (Free, Freemium, Premium, Super Premium). So the membership_grade shall belong to the pivot table, right? But here's the problem, not all groups share the same grades. Some might have Free and Freemium only, some might have all.
In the fields.yaml of the Membership pivot model, I defined the membership_grades as a Relation Widget, like this:
pivot[grade]:
label: Membership Grade
span: full
type: relation
nameFrom: name
And in its relationship in Membership.php like this:
public $belongsTo = [
'grade' => [
'Acme\Models\Grade',
]
];
Obviously, this will expose ALL grades, since I'm pulling data from the Grade model. What I want is to expose the grades that is just available on that group, not all.
What I've thought to do (but I didn't, because it seemed impossible) is to try to pull data from the grades relationship of the Group, but how am I suppose to do that? (Since Relation widget manages the relation of the Model, I cannot simply pull data from other sources just like that).
Also I've tried to do scopes but how am I suppose to pass the current Group I'm in? Since it is needed as the filter, like this:
// Membership.php
public $belongsTo = [
'grade' => [
'Acme\Models\Grade',
'scope' => 'filteredIt'
],
// added this relationship to try the scopes approach
'group' => [
'Acme\Models\Group'
]
];
// Grade.php
public function scopeFilteredIt($query, Membership $m)
// yes, the second parameter in the scope will be the
// current Membership model. I've tried it.
{
// this won't work, since we want the overall relation filter;
// an instance of Membership won't help.
// this would work if I can find a way to pass the
// current Group (record) selected, and get its grades, then use it here.
return $query->whereIn('id', $m->group->grades->pluck('id')->all());
}
Any thoughts?
I have noticed some post values during pivot model ajax call.
When you add new record and when your pivot model opens post values are like this
Array (
[_relation_field] => groups
[_relation_extra_config] => W10=
[foreign_id] => 1
[_session_key] => VrSCoKQrSkIsZNGIju5QIqpdbS3AADoGQRHAsv1e
)
So good thing is that we can now get foreign_id as it will be your selected group id
and we can use it at creation time and for update time you know we have relation so we use that.
public function scopefilteredIt($query, Membership $m)
{
// we are checking relation is there or not
if($m->group) {
// yes group is there we use it
return $query->whereIn('id', $m->group->grades->pluck('id')->all());
}
else {
// seems new record then use foreign_id
$foreign_id = post('foreign_id'); //<-this will be your selected group id
if($foreign_id) { // <- double check if its there
$group = Group::find($foreign_id);
return $query->whereIn('id', $group->grades->pluck('id')->all());
}
}
return $query;
}
please comment if you get any issue.
to check post
public function scopefilteredIt($query, Membership $m)
{
// will show flash message with post data array
$post = print_r(post(), true);
\Flash::success($post);
// we are checking relation is there or not
if($m->group) {
// yes group is there we use it
return $query->whereIn('id', $m->group->grades->pluck('id')->all());
}
else {
// seems new record then use foreign_id
$foreign_id = post('foreign_id'); //<-this will be your selected group id
if($foreign_id) { // <- double check if its there
$group = Group::find($foreign_id);
return $query->whereIn('id', $group->grades->pluck('id')->all());
}
}
return $query;
}

Display attribute using via() or viaTable() when there is multiple relations- YII2

I have for models say, supplier-machine, supplier, supplier-to-part and parts.
This is how these tables are related to each other.
In Supplier model the relation is defined as below to retrieve part_name of Part table keeping supplier-to-part as junction table.
public function getSupplierToParts()
{
return $this->hasMany(SupplierToPart::className(), ['supplier_id' => 'id']);
}
public function getParts()
{
return $this->hasMany(Part::className(), ['id' => 'part_id'])->viaTable('supplier_to_part', ['supplier_id' => 'id']);
}
In Detail view I use implode to display part_name
[
'attribute'=>'Nature of business',
'value' => implode(\yii\helpers\ArrayHelper::map($model->parts, 'id', 'part_name')),
],
My question is how do I display part_name in supplier-machine model instead of supplier model?? In this case I think supplier and supplier-to-part becomes like a two junction tables. How do I solve this?
You can access the parts through the supplier relation via $model->supplier->parts, assuming your relation to Supplier in your SupplierMachine model is supplier. You still have to account for the multiple parts though:
'value' => implode(",",
\yii\helpers\ArrayHelper::map($model->supplier->parts, 'id', 'part_name')
),

Categories