Laravel - Eager Loading - Trying to get property of non-object - laravel

Sorry for the noob question, but I am not able to make eager loading work, and instead getting: Trying to get property of non-object in my view (index.blade.php below).
Users table
id | first_name | other_columns
Credits table
id | recipient | other_columns
recipient is id from the Users table.
Credit.php
class Credit extends Model {
public function recipient() {
return $this->belongsTo('App\User', 'recipient');
}
}
User.php
class User extends Model {
public function credits() {
return $this->hasMany('App\Credit', 'recipient');
}
}
CreditController.php
class CreditController extends Controller {
public function index() {
$credits = Credit::with('recipient')->get();
return view('pages.credits.index')->withCredits($credits);
}
}
index.blade.php
#foreach($credits as $credit)
{{ $credit->recipient->first_name }}
#endforeach
What am I missing?

I solved this by changing in my Credit Model:
public function recipient() {}
into
public function user() {}

Related

creating query from other tables that has the ID of the primary table in laravel

Apology for the title. I'm really not sure how to name the title correctly base from my situation. I'm new in coding that's why I am not familiar with proper terminologies.
below are the tables I am working on right now.
I am displaying the details from loan_application table. I can able to include the loan_durations and users in my #foreach but I realized I need to include also the SUM of the AMOUNT from loan_interests table and the SUM of AMOUNT from LOAN PENALTIES which gives me an headache because I can't pull them out.
LOAN APPLICATION MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanApplication extends Model
{
public function user()
{
return $this->hasOne('App\User', 'id','user_id');
}
public function loanDuration()
{
return $this->hasOne('App\LoanDuration', 'id','loan_duration_id');
}
public function interest()
{
return $this->belongsTo('App\LoanInterest','loan_id', 'id');
}
public function penalty()
{
return $this->belongsTo('App\LoanPenalty','loan_id', 'id');
}
}
LOAN INTEREST MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanInterest extends Model
{
public function loanInterest()
{
return $this->belongsTo('App\LoanApplication','loan_id', 'id');
}
}
LOAN PENALTY MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanPenalty extends Model
{
public function loanPenalties()
{
return $this->belongsTo('App\LoanApplication','loan_id', 'id');
}
}
for my controller
public function collectorMembers($id)
{
$collectormember = CollectorMember::where('collector_id',$id)->get();
return view('dashboard.collector-members.collector-borrowers-list', compact('collectormember'));
}
This gives this result
the CollectorMember gets the info on this table
Can you help me please? thanks a lot in advance!
There is a way to accomplish what you're after, but first I think you need to revisit your schema and relationships.
Foreign key columns should be of the same type as the referenced column. For example loan_id on the loan_interests should be int(11) just like the id column on the loan_applications table
I think you may be confusing relationship types. For example a User hasMany LoanApplications and a LoanApplication belongsTo a User. A LoanApplication hasMany LoanPenaltys and hasMany LoanInterests. A LoanPenalty and a LoanInterest both belongsTo a LoanApplication
The user_id column on the loan_penalities table is redundant because a LoanPenalty belongsTo a LoanApplication and a LoanApplication belongsTo a User
I'd recommend storing currency amounts in cents and using unsigned integers as the column type (e.g. for interest_amount)
Consider the following schema (some columns not shown):
Then consider the following models with relationships:
class User extends Model {
public function loanApplications()
{
return $this->hasMany(LoanApplication::class);
}
public function collectors()
{
return $this->belongsToMany(Collector::class);
}
}
class Collector extends Model {
public function users()
{
return $this->belongsToMany(User::class);
}
}
class LoanApplication extends Model {
public function user()
{
return $this->belongsTo(User::class);
}
public function loanDuration()
{
return $this->belongsTo(LoanDuration::class);
}
public function loanInterests()
{
return $this->hasMany(LoanInterest::class, 'loan_id');
}
public function loanPenalties()
{
return $this->hasMany(LoanPenalty::class, 'loan_id');
}
}
class LoanDuration extends Model {
public function loanApplications()
{
return $this->hasMany(LoanApplication::class);
}
}
class LoanInterest extends Model {
public function loanApplication() {
return $this->belongsTo(LoanApplication::class, 'loan_id');
}
}
class LoanPenalty extends Model {
public function loanApplication()
{
return $this->belongsTo(LoanApplication::class, 'loan_id');
}
}
Then to list all loan applications in a Resource Controller:
class LoanApplicationController extends Controller {
public function index()
{
$loan_applications = LoanApplication
::with(['user', 'loanInterests', 'loanPenalties'])
->get();
$loan_applications = $loan_applications->map(function ($loan_application) {
$loan_application->loan_penalities_sum = $loan_application->loanPenalties->sum('penalty_amount_cents');
$loan_application->loan_interests_sum = $loan_application->loanInterests->sum('interest_amount_cents');
return $loan_application;
});
return view('dashboard.loan-applications.index', compact('loan_applications'));
}
}
And in your dashboard.loan-applications.index blade template:
<table>
<tr>
<th>Username</td>
<th>Total Interest</td>
<th>Total Penalty</td>
</tr>
#foreach ($loan_applications as $loan_application)
<tr>
<td>{{$loan_application->user->username}}</td>
<td>{{$loan_application->loan_interests_sum}}</td>
<td>{{$loan_application->loan_penalties_sum}}</td>
</tr>
#endforeach
</table>
Note the above example does not include pagination; all resources are loaded at once.
The above example also assumes there should be a many-to-many relationship between collectors and users, but I would imagine a Collector should be related to the loan_applications table, not to a User.

Laravel Elloquent Model Table Relations

I am learning Laravel and there is one thing I cannot solve.
What do I have:
Table of Users, Posts, Comments and corresponding Models
User.php:
public function comments() { return $this->hasMany(Comment::class); }
public function publishComment(Comment $comment)
{
$this->comments()->save($comment);
}
Post.php:
public function comments() { return $this->hasMany(Comment::class); }
Comment.php:
public function post() { return $this->belongsTo(Post::class); }
public function user() { return $this->belongsTo(User::class); }
What do I want?
Since I have Blog, one logged user can create many posts (this works).
But same logged user can create many comments to one post. (User has many comments, post has many comments).
Tables:
User: | id | name | email | password
Comment: | id | user_id | post_id | body
Post: | id | user_id | title | body
What have I tried?
I created controller
CommentsController:
class CommentsController extends Controller
{
public function store(Post $post)
{
$this->validate(request(), ['body' => 'required|min:2']);
auth()->user()->publishComment(
new Comment(request('body'));
);
return back();
}
And in my blade file I simply want $comment->user->name (get name of user who does the comment belongs to)
Error I get:
Trying to get property of non-object
<?php echo e($comment->user->name); ?>
Any help would be appreciated.
You need a Polymorphic Relations Relationship.
Table Structure
posts
id - integer
title - string
body - text
user_id - integer
users
id - integer
name - string
email - string
password - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string
Into commentable_id you save the User id or the Post id.
Into commentable_type you save the User Model or Post Model.
And also you can have another table using comments table.
Models
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get all of the owning commentable models.
*/
public function commentable()
{
return $this->morphTo();
}
}
class Post extends Model
{
/**
* Get all of the post's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
class User extends Model
{
/**
* Get all of the users's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
See the docs to get more details.
In this video you have a good explanation https://youtu.be/lePjXdMC6aM
You can simply do this in your view.blade.php:
// Here I am assuming you have a $post variable that contains your blog post.
<ul>
#foreach ($post->comments as $comment)
<li>{{ $comment->user->name }}</li>
#endforeach
</ul>
This will loop over all the comments that you have for your blog post and display the owner's name, hopefully this helps.
Try this if you need just the name of the person who created comment.
{{ $post->user->name }}
Or
user->name); ?>

Counting total posts by a user in the blade view

I have sent a collection of all posts in my blog to my index view and then used the following code to count the total posts made by each user.
<p class="joined-text">Posts: {{count(App\Posts::where('user_id', $post->user->id)->get())}}</p>
Is this bad practice to do this from within the blade view? If it is how would I achieve this?
Models
class Posts extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function comments()
{
return $this->hasMany(Comments::class, 'post_id');
}
}
class User extends Authenticatable
{
public function posts()
{
return $this->hasMany('\App\Posts::class');
}
public function comments()
{
return $this->hasMany(Comments::class);
}
}
Simple solution:
<p class="joined-text">Posts: {{ App\Posts::where('user_id', $post->user_id)->count() }}</p>
Updated
Complete and better solution:
Post.php:
public function user(){
return $this->belongsTo(App\User::class);
}
User.php:
public function posts(){
return $this->hasMany(App\Post::class);
}
public function getPostsCountAttribute(){
return $this->posts()->count();
}
blade:
<p class="joined-text">Posts: {{ $post->user->posts_count }}</p>
Yes it is bad.
You could use relationships if have the user_id field in posts table
class User extends Model
{
public function posts()
{
return $this->hasMany('App\Post');
}
}
In controller
return view('sth')->with(['posts'=>$user->posts]);
Then in view
$posts->count();
Or just getting counts if you don't need posts
$postCount = $user->posts()->count();

Laravel Nested Relationship Where 5.5 Return All Records

I'm having some trouble when trying to fetch records from database. Here's the table schema:
users
--------------
id
username
password
email
divisions
--------------
id
name
employee
--------------
name
birth_date
status
class
division_id
user_id
projects
--------------
id
title
body
user_id
So, for the relationship explanations:
relationship
Okay, i'm trying to fetch project based on division_id on table employee with the following code:
# query code
$division_id = 10;
$items = Project::with(['user.employee.division' => function($query) use ($division_id) {
$query->where('id', $division_id);
}])->get();
I've added the required belongsTo, hasMany or hasOne to the models.
# User.php
class User extends Authenticatable
{
public function employee()
{
return $this->hasOne('App\Employee', 'user_id');
}
public function projects()
{
return $this->hasMany('App\Project', 'user_id');
}
}
# Division.php
class Division extends Model
{
public function employee()
{
return $this->hasMany('App\Employee', 'division_id');
}
}
# Employee
class Employee extends Model
{
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
public function division()
{
return $this->belongsTo('App\Division', 'division_id');
}
}
# Project.php
class Project extends Model
{
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
}
So, what's the problem?
Here's the thing, when i run the query code i'm getting all the records and the division object on employe relationship returning null.
If anyone thinks my code is wrong, please enlighten me.
Thanks.
So after some digging, i found an answer. The query code should change to whereHas:
# query code
$division_id = 10;
$items = App\Project::whereHas('user.employee.division',
function($query) use ($division_id) {
$query->where('divisions.id', $division_id);
})
->with(['user.employee.division']) // N+1 problem
->get();
reference: Laravel 5.3 Constraining Eager Loads not working

Laravel eloquent hasmany->hasmany

it is possible to get all details (user, posts, postimages) within one collection / json?
user->hasmany(posts)
post->hasmany(postimage)
user:
id | name
post:
id | user_id | text
postimage:
id | post_id | imgpath
user model:
public function posts() {
return $this->hasMany('App\posts')->orderBy('id', 'ASC');
}
posts model:
public function images(){
return $this->hasMany('App\postsimages');
}
get all posts from user works fine:
$myposts = users::find(Auth::user()->id)->posts;
i'm able to get all images from a post within a loop
foreach($myposts as $mypost) {
$postimages = $mypost->images;
}
what i want is to get all posts, images without the loop e.g
$myposts = users::find(Auth::user()->id)->posts->images
thanks
Yes, use hasManyThrough relationship.
posts model:
public function images()
{
return $this->hasMany('App\postsimages');
}
user model
public function posts()
{
return $this->hasMany('App\posts')->orderBy('id', 'ASC');
}
public function images()
{
return $this->hasManyThrough('App\posts', 'App\postsimages');
}
then
$postimages = Auth::user()->images;

Resources