Laravel5.8 belongsTo relation not working for foreach loop - php

I'm working on Laravel relation using hasMany and belongsTo. It work fine for hasMany relation but I have problem on belongsTo for collection foreach loop. This is my categories table.
id name
--------------
1 food
And products table.
id name category_id
----------------------------------
1 pizza 1
2 hamburger 1
Below is hasMany product model.
# Product.php
public function products()
{
return $this->hasMany(Product::class);
}
Below is belongsTo category model.
# Category.php
public function category()
{
return $this->belongsTo(Category::class, 'id');
}
I got an error in blade:
Trying to get property of non-object
<tbody>
#foreach ($products as $product)
<tr>
<td> {{ $product->category->name }} </td>
</tr>
#endforeach
</tbody>
Any advice or guidance on this would be greatly appreciated, Thanks

The problem is the method defintion. The second parameter of the belongsTo method is the foreign key column name. Try this:
# Product.php
public function category()
{
return $this->belongsTo(Category::class, 'category_id');
}
But, given that your foreign key is the model name followed by _id (category_id), Laravel will look up for this key by default.. so you could simplify it like this:
# Product.php
public function category()
{
return $this->belongsTo(Category::class);
}
From the documentation:
... In the example above, Eloquent will try to match the post_id
from the Comment model to an id on the Post model. Eloquent
determines the default foreign key name by examining the name of the
relationship method and suffixing the method name with a _ followed
by the name of the primary key column. However, if the foreign key on
the Comment model is not post_id, you may pass a custom key name
as the second argument to the belongsTo method:
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post', 'foreign_key');
}

Category.php
public function category()
{
return $this->belongsTo(Category::class, 'category_id');
}
Instead of 'id' in category() use 'category_id'..... as you have given category_id as foreign key ....so laravel will search for it...

Related

Laravel 6 eager loading using with() on a belongsTo relationship is only *sometimes* returning null

I am working on a project where we have a model for a service provider, the type of care provided, and the status:
Provider:
class Provider extends Model
{
protected $table = 'providers';
public function status() {
return $this->belongsTo('App\Status');
}
public function caretype() {
return $this->belongsTo('App\CareType', 'id');
}
}
CareType:
class CareType extends Model
{
protected $table = 'type_of_care';
public function providers() {
return $this->hasMany('App\Providers', 'type_of_care_id');
}
public function category() {
return $this->belongsTo('App\CareCategory');
}
}
Status:
class Status extends Model
{
protected $table = 'status';
public function providers() {
return $this->hasMany('App\Providers');
}
}
On the my SearchController (the controller that processes search requests for providers), the show() function using eager loading retrieves the caretype perfectly. But on the search() function that lists the collection of search results, the caretype is always listed as null.
I don't understand why it would be working in one function but not the other, especially when the code to eager load is exactly the same in both functions:
public function search(Request $request)
{
$validated = $request->validate([
//I removed the validation code for this post
]);
$providers = Provider::with(['status', 'caretype'])->get();
return view('search.results', ['providers' => $providers]);
}
public function show($id)
{
$single_provider = Provider::with(['status', 'caretype'])->where('id', $id)->first();
return view('search.details', ['provider' => $single_provider]);
}
Any help in this would be appreciated. I know that the model and relationship foreign keys are properly defined because the show() function is able to get the caretype just fine.
nope. your relationship and foreign keys are not correct. as from the doc
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a _ followed by the name of the primary key column. However, if the foreign key on the Child model is not like that, you may pass a custom key name as the second argument to the belongsTo method.
you are passing the id column as the foreign key in Provider model's caretype ralation but your foreign key is type_of_care_id. so you are getting some results when the id matches but if not, you are getting null. change your relationship code to
public function caretype()
{
return $this->belongsTo('App\CareType', 'type_of_care_id');
}
now again from the doc
If your parent model does not use id as its primary key, or you wish to join the child model to a different column, you may pass a third argument to the belongsTo method specifying your parent table's custom key.
in your case id is the primary key. so you don't have to pass the third parameter. just update the primary key reference and everything will work perfectly.

how to get desired column from other table

there are two tables products and categories, that I created by PHPMyAdmin.
In the products table, it has a column name prd_category that has the foreign key of table categories named cat_id(primary key of categories table).
i am quite new in laravel
i want return all data from product table with category name(cat_name) from another table
//here is my controller
use App\Models\product;
class items extends Controller
{
public function sample(){
return product::all();
}
}
//route
Route::get('/',[items::class,'sample']);
//model for products table
class product extends Model
{
use HasFactory;
function category(){
return $this->hasOne('App\Models\category','cat_id','prd_id');
}
}
//model for category
class category extends Model
{
protected $table='categories';
use HasFactory;
}
pls help and thanks in advance..
you can use this code:
$products = product::whereHas('category',function($q)use($cat_name){
$q->where('name',$cat_name)
})->get();
or :
$categories = Category::where('name',$cat_name)->get()->pluck('id')->toArray()
$products = product::whereIn('category_id',$categories)->get();
Are you sure that one-to-many relation is correct? If a product can belong to many categories, you need to use many-to-many relations. Furthermore, if something else belongs to categories you should use many-to-many polymorphic relations. But let's go with one-to-many.
First, the relation function in Product.php looks incorrect. I think products should belong to a category.
function category(){
return $this->belongsTo('App\Models\Category','cust_name','name');
}
Then you need to define reverse relation in Category.php
function products(){
return $this->hasMany('App\Models\Product','cust_name','name');
}
When you define the relations properly, all you need yo do is to fetch data in controller:
use App\Models\Category
...
Category::with('products')->get();
you can use relationship with forign key like pro_id
function category(){
return $this->belongsTo('App\Models\Category','pro_id');
}
function products(){
return $this->hasMany('App\Models\Product','id');
}
$cat = Category::with('products')->all();
in Blade :
{{ $cat->products->cat_name; }}

Set up many to many relationship in laravel eloquent

What is the best practice to setup many to many relationship with post and categories in laravel eloquent? Do I create a separate model for pivot table?
This is how I defined it in post model.
public function category()
{
return $this->belongsToMany('App\Category');
}
you need to change the relationship method name to categories()
/**
* The categories that belong to the product.
*/
public function categories()
{
return $this->belongsToMany('App\Category', 'category_product');
}
category_product - is your pivot table, you can define if you change the naming convention or its optional.
In Category model, you can define it like blow
/**
* The users that belong to the role.
*/
public function products()
{
return $this->belongsToMany('App\Product', 'category_product');
}
If you require you can create a model for pivot table, in my case this is how i store data to pivot table (using attach method)
$product->categories()->attach($category); //list of category id's
And you can update it again using detach method or synch method.
$product->categories()->sync($synch); // new category id's
The best way to do this is:
public function categories(){
return $this->belongsToMany('App\Models\Categories', 'categories_posts', 'post_id', 'category_id');
}
And then in your Categories model:
public function posts(){
return $this->belongsToMany('App\Models\Posts', 'categories_posts', 'category_id', 'post_id');
}
belongsToMany() method can receive up to 4 parameters, the first one is the location of your model to link, the second is the name of the pivot table, the third one is the current model foreign key and the fourth one is the other's model foreign key.
You can also specify extra data on pivot table using the withPivot() method like this for example:
public function categories(){
return $this->belongsToMany('App\Models\Categories', 'categories_posts', 'post_id', 'category_id')->withPivot('quantity');
}
And then for attaching you can do as follows:
$post = Posts:find(1);
$post->categories()->attach($category_id, ['quantity' => 2]);
But please, refer to Laravel's official documentation:
https://laravel.com/docs/5.6/eloquent-relationships
To define this relationship, three database tables are needed: post, category, and category_post. The category_post table is derived from the alphabetical order of the related model names, and contains the category_id and post_id columns.

Laravel - Query builder get relation

In my project I have a Polymorphic relation. This relation is as followes:
Plugins
id - integer
composer_package - string
Themes
id - integer
composer_package - string
Products
id - integer
name - text
...
commentable_id - integer
commentable_type - string
When I need to display all the products that are a Theme I do the following:
$themes = DB::table('products')->orderBy('id', 'asc')->where('productable_type', Theme::class)->get();
The code above provides me with a list of all the products where the productable_type field is filled with App/Theme, I display them with a foreach loop like this #foreach($themes as $theme). Now my problem is.
I need to get the composer_package from the themes table that belongs to that product. So say for instance. I get a product from the products table where the productable_id is 3. I want the value of the composer_package field in the themes table where the ID is 3. When I do {{ $theme->products->composer_package }} or {{ $theme->composer_package }} It gives me the error Undefined property What is causing this?
This is my product model
public function product()
{
return $this->morphTo();
}
public function order_items()
{
return $this->hasMany(Orderitems::class);
}
And this is my theme model
public function webshops()
{
return $this->hasMany(Webshop::class);
}
public function products()
{
return $this->morphMany(Product::class, 'productable');
}
Thanks in advance!
Is there any reason you are using the DB facade to pull data instead of the actual models?
One issue your are having is that your polymorphic relationship is stored in the commentable_id / commentable_type field, while your function name is product. Laravel does some of its magic just by naming alone, so let's make sure the column names and polymorphic function names match up in the product model:
public function commentable()
{
return $this->morphTo();
}
After that, try something like this in the controller:
$themeProducts = Product::where('commentable_type', Theme::class)->get();
And this in the view
#foreach ($themeProducts as $themeProduct)
{{ $themeProduct->commentable->composer_package }}
#endforeach
Your table has "commentable", but your model is looking for "productable". You're also missing a method.
in your product model add:
public function commentable(){
return $this->morphTo();
}
in your theme model modify the products() method to:
public function products(){
return $this->morphMany(Product::class, 'commentable');
}
You could also update your commentable_type and commentable_id columns in your table to productable_type and productable_id, in which case you need to rename commentable() in the code for the product model above to productable(), and 'commentable' to 'productable' in the code for the theme model above.
(Source: https://laravel.com/docs/5.6/eloquent-relationships#polymorphic-relations)
Create relations with the model as mentioned in above answers, then you can retrieve relations using with helper.
E.g.:
Product::where('commentable_type', Theme::class)->with('commentable')->get();
and then can directly use as mentioned above.
e.g.: $themeProduct->commentable

Retrieving collection from linked eloquent models laravel

I am using laravel 5.3 and need a bit of help with Eloquent model queries. I have three models (UserDetails, Categories, Articles). I have a relationship between UserDetails->Categories (belongstoMany), and a relationship between Categories->Articles (belongstoMany) which work well. However how would I go about getting the relationship data between Userdetails->Categories->Articles.
Each individual relationship is working fine i.e. Userdetails::find(1)->categories and Categories::find(1)->Articles.
I have a feeling that scopes may be the answer but they don't seem to work when I've attempted it.
Relationships in models
UserDetails.php
public function Categories(){
return $this->belongstoMany('App\Categories', 'users_cats', 'user_id','cat_id');
}
Categories.php
public function articles(){
return $this->belongsToMany('App\Article', 'article_categories', 'categoryID', 'articleID');
}
Ive looked into HasManyThrough function but again, I'm having issues implementing it, as far as I can see it should be
return $this->hasManyThrough('App\Article', 'App\Categories', TertiaryForeignKey, FinalForeignKey, LocalForeignKey);
My tables are set up as
articles_categories pivot table
articleID – primary key of the article
categoryID – primary key of the category
users_cats pivot table
user_id – primary key of the userdetails
cat_id – primary key of the categories
Based on this it the hasManyThrough should look like this?
public function articles(){
return $this->hasManyThrough('App\Article', 'App\Categories', 'user_id', 'articleID', 'id');
}
however this returns the error
Column not found: 1054 Unknown column 'categories.user_id' in 'field list'
update
So if you want to have this kind of relationship
userdetails->categories->articles
then you need to make this:
Userdetail model:
public function categories()
{
return $this->hasMany(Category::class);
}
public function articles()
{
return $this->hasManyThrough(Article::class, Categories::class);
}
Category model:
public function userdetails()
{
return $this->belongsTo(Userdetails::class);
}
public function categories()
{
return $this->hasMany(Category::class);
}
Article model:
public function categories()
{
return $this->belongsToMany(Category::class);
}
Then you can call UserDetails::find(1)->articles->get(); directly
You just need to declare the relationship like this in the
UserDetails.php model:
public function categories()
{
return $this->hasMany(Categories::class);
}
in Categories.php model:
public function articles()
{
return $this->hasMany(Articles::class);
}
Then you can retrieve the collection of categories in your controller:
$userdetails = UserDetails::get();
pass that $categories variable into your View and display each record with an foreach loop (where the articles is the function in your model)
#foreach($userdetails->categories as $usercategories )
<div> {{$usercategories->name}} </div>
#foreach($usercategories->articles as $categoryarticles )
<div> {{$categoryarticles->name}} </div>
#endforeach
#endforeach
with the second foreach you will access the articles of the categories that belongs to the user.

Categories