I thought I was going quite well in developing my Laravel skills, but it seems I am stuck and can't find the solution online yet.
My project is set up in Laravel and Vue and I am trying to store a product with ingredients. The products are in the products table. The ingredients in the ingredients table. I succeeded in storing the product with a brand_id and later retrieve the brand (one-to-many), but I don't know how to do this for many-to-many: Ingredients to products.
Since I am working with Vue I have add JSON output that posts my data.
public function store()
{
$product = new Product();
$product->ean = request('ean');
$product->name = request('productName');
$product->brand_id = request('brandId');
$ingredients = request('ingredients');
$product->save();
}
As I explained above saving the product is going well.
But now I need to do something with the $ingredients array, I've found lines like these:
$user->roles()->save($role);
So I think I have to do a foreach loop for all ingredients and within do this:
$product->ingredients()->save($ingredient);
What I fail to understand. This array will contain existing ingredients that are already stored, but also new ingredients that have to be added to the ingredients table. How to make this work?
So store new ingredients in it's table and also store the relation in the eloquent table. I might be close, I might be far off, anyone?
While looping the ingredients, look into the firstOrNew() method:
foreach($request->input("ingredients") AS $ingredient){
$ingredient = Ingredient::firstOrNew(["name" => $ingredient]);
// Note: assumed name for column that matches `$ingredient` from array, adjust as needed.
}
While in that loop, attach() your $ingredient to your new $product. Your code should look like this when fully implemented:
$product = new Product();
...
$product->save();
foreach($request->input("ingredients") AS $ingredient){
$ingredient = Ingredient::firstOrNew(["name" => $ingredient]);
$product->ingredients()->attach($ingredient->id);
}
attach() will associate this new or existing $ingredient with the new $product by adding a record to the pivot between Product and Ingredient. The reason you can't use $product->ingredients()->save($ingredient); is that this is a many-to-many, which requires attach(). $model->relationship()->save(); is used for a one-to-many.
Full documentation on the creation methods can be found here: https://laravel.com/docs/5.8/eloquent#other-creation-methods
Related
strange question:
I have 3 Models
Order
with id as PK
Orderline
with id as PK and order_id as FK. brand and partnumber are two separatet colums
Article
with combined PK brand and partnumber
**which is on another database **
One Order hasMany Orderlines. Every Orderline hasOneArticle.
i had make a function within order:
public function articles()
{
$foreignKeys = [
'brand_id',
'article_number',
];
$localKeys = [
'brand',
'partnumber',
];
return $this->hasManyThrough('App\Models\Masterdata\Articles','App\Models\Oms\OrderLine',$foreignKeys,$localKeys,'id','id');
}
How can i retrieve all Attributes from articles through Order?
I tried something like this:
$order = Order::find($orderid)->articles();
dd($order);
//did not work
$order = Order::with('orderlines.articles')->where('id','=',$orderid)->get();
Do you have an idea for me?
You can configure more than one database in the database.php config, and specify the $connection name in the Model class.
For the most part, Eloquent doesn't do JOINs, it just does IN statements on the key values from the preceding query, and programmatically marries the results together after the fact. Partly to avoid the mess of keeping table aliases unique, and partly to offer this kind of support- that your relations don't need to live in the same database.
In other words, what you have there should work just fine. If there's a specific error getting thrown back though, please add it to your post.
I have three tables: restaurant_location, cuisine_restaurant_location and cuisines.
There is a list of all cuisines in my cuisines table. I have all the details of the restaurant in my restaurant_location table. A restaurant can have many cuisines so I made a table cuisine_restaurant_location in which there are two columns cuisine_id and restaurant_id. I have created a belongs to many relation in my restaurant_location model.
restaurant_location model
public function cuisines()
{
return $this->belongsToMany(Cuisine::class, 'cuisine_restaurant_location', 'restaurant_id', 'cuisine_id');
}
I have a form in which all the details of the restaurant along with cuisines is supposed to be added. Right now I am adding all the details of the restaurant. Now the question is how can I insert the cuisines in "cuisine_restaurant_location".
Controller
$rest = new restaurant_location;
$rest->name = $request->input('name');
$rest->description = $request->input('desc');
$rest->save();
$cuisine = new cuisine_restaurant_location
$cuisine_lists = $request->input('cuisines');
foreach ($cuisine_lists as $cuisine_list) {
$cuisine->name = $cuisine_list;
}
You can use the sync and attach methods, described in the Many to many section of the eloquent documentation, for that:
$rest->cuisines()->attach([$cuisineIds])
Where cuisineIds is the list of ids of the cuisines you want to relate.
The difference between sync and attach is that sync will remove all id's not present on the array of ids you are passing.
Try sync() method:
$h = [];
if (isset($input["cuisine_id"])) {
$h = $input["cuisine_id"];
}
$restaurant_location->cuisines()->sync($h);
I have two models, Payments_Distribution and Donation.
In my Donation model:
public function payments() {
return $this->morphToMany(Payments_Distribution::class, 'payable');
}
And I can save a payment distribution to the donation model using the following:
$distribution = new Payments_Distribution;
$distribution->payment_id = $payment->id;
$amount = $request->payment_details['amount'][$i];
$donation->payments()->save($distribution);
But I'm stuck on how to retrieve the sum of all the associated records' amount fields in the Payment_Distribution model table.
Would it be something like:
$donation->payments()->______ ->sum('amount');
Or something else? I'm still a bit new to polymorphic relationships.
In your code, you are not saving amount to the Payments_Distribution instance before using the ->save() method. Replace:
$amount = $request->payment_details['amount'][$i];
With:
$donation->amount = $request->payment_details['amount'][$i];
I have a flight class and this flight has a custom view field like so:
This represents a belongs to many relationship which stores website_id / flight_id and pricing as pivot data in a pivot table.
The custom view uses JS to send this data back to the controller in this format:
{"1":{"price_adult":"434","price_child":"545"},"2":{"price_adult":"323","price_child":"324"},"3":{"price_adult":"434","price_child":"43"}}
Trying to send this data with the request doesn't create the relations fields, and because I do not have a flight ID at the point of creating this within the controller I can not loop this JSON to make the relations manually.
Can anyone point out what the best course of action is or if there is support for this? I took a look at the docs but they are woefully short and patchy in terms of being much help.
EDIT:
I should have said I can probably make this work using a custom name attribute on the model for the relation, then add a set mutator to loop this data and update the prices relation but I don't want to go down this route if there is support for this I am missing out of the box in backpack.
EDIT2:
Someone asked about the relation:
$this->belongsToMany(Website::class, 'website_pricing')->withPivot('price_adult', 'price_child');
This is working fine its not a problem with the relation working its how can I get backpack to store the data as a relation when the flight has no ID yet, or how can I pass the data I posted above in such a way that the backpack crud controller can handle it?
You may need to create a flight first, if no flight id is being provided. Can you explain the database relational structure more?
Basically thought I should post what I did because no one could provide an answer to this.
So basically you have to copy the store / update functions from the parent, changing a few lines.
$this->crud->hasAccessOrFail('create');
// fallback to global request instance
if (is_null($request)) {
$request = \Request::instance();
}
// replace empty values with NULL, so that it will work with MySQL strict mode on
foreach ($request->input() as $key => $value) {
if (empty($value) && $value !== '0') {
$request->request->set($key, null);
}
}
// insert item in the db
$item = $this->crud->create($request->except(['save_action', '_token', '_method']));
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
\Alert::success(trans('backpack::crud.insert_success'))->flash();
// save the redirect choice for next time
parent::setSaveAction();
return parent::performSaveAction($item->getKey());
Basically any line which references a function in the parent class using $this->method needs to be changed to parent::
This line is what I used to submit the relations JSON string passed to the controller as relations $item->prices()->sync(json_decode($request->input('prices'), true));
This is done after the line containing $item = $this->crud->create as the item id that just got stored will be available at that point.
I'm using CodeIgniter and have three tables and a model for each:
User - table of users
Product - table of products
UserProduct - table showing which users have which products (two foreign key columns, and some other columns such as date)
In my code I want to display a list for a particular user showing which products they have. So I have a method in the UserProduct class that does a select on the UserProduct table matching for the userId, and a join bringing in all the data I need about each product.
This works fine, but I am concerned now that I am moving down a path of tight coupling. For example, say I want to find out the URL of a product image. I have a method in the product model to return this, I don't want a duplicate method in the UserProduct model, and I don't want to create a coupling by having the UserProduct model trying to access methods in other models (which I don't think CodeIgniter likes you to do).
This problem seems likely to occur in any model that accesses a DB table that has foreign keys where that model may need data from the parent table and want to manipulate it.
Is there an elegant solution, or do I need to accept that foreign keys necessarily create couplings in models or the need for similar methods across models?
TIA,
Phil.
My personal standard is to create 1 controller + 1 model always.
for example site.com/users will use model_users.php
or
site.com/products will use model_products.php
to slim your code and re-use methods use methods params for example a model method to be re-used could be:
function getUsers($data){
foreach($data as $key=>$value){
$this->db->where($key,$value);
}
$query = $this->db->get('users');
return $query->result();
}
the more you extend this method the more you can re-use, just another example of extending:
function getUsers($data,$order_by = false){
foreach($data as $key=>$value){
$this->db->where($key,$value);
}
if($order_by){
foreach($order_by as $key=>$value){
$this->db->order_by($key,$value);
}
}
$query = $this->db->get('users');
return $query->result();
}
//then you call results with this in your controller
$results = $this->model->getUsers(
$data = array('id'=>'12','country'=>'USA'),
$order_by = array('username'=>'DESC')
);
so now you got also order_by , and so on, you can add joins, limit,offset,like etc.. all in the same or quite the same way , the more accurated you are the more you can re-use the same methods