how to fix relationship error between models? - php

I have set up two models and made the relationship between them. I want to pass the attributes of the user as well as the user_detail.
I have used a similar code somewhere and it worked perfectly. But it is not working here.
//This is the function in "User.php" model.
public function user_detail(){
return $this->hasOne('App\Profile');
}
//This is the function in "Profile.php" model.
public function user(){
return $this->belongsTo('App\User');
}
//edit function in ProfileController
public function edit($id)
{
$user=User::find($id);
return view('profile.edit')->with('data',$user->user_detail);
}
When I click the edit button in the view, I expect the extract all the details from user table as well as from user_detail table.

I think you should edit your this code a little bit
public function edit($id)
{
$user=User::findOrFail($id);
return view('profile.edit')->with('data',$user);
}
And in your blade file (profile.edit), You can get all details from User and Profile Model.
{{ $data->id }}
{{ $data->user_detail->YOURPARAMETERS }}

The problem is with the relationship naming. Make it camelCase like,
//This is the function in "User.php" model.
public function userDetail(){
return $this->hasOne('App\Profile');
}
//edit function in ProfileController
public function edit($id)
{
$user=User::find($id);
return view('profile.edit')->with('data',$user->userDetail);
}
Reference: https://github.com/laravel/framework/issues/4307#issuecomment-42037712

try using where instead of find and then use with:
$user = User::where('id', $id)->with('user_detail')->first();
return view('profile.edit')->with('data', $user);
In your model:
public function user_detail(){
return $this->hasOne('App\Profile', 'student_no');
}

Related

Call to a member function update() on null

I'm building my first Laravel app. That's my first problem that I can't overcome.
I tried to google something about it, but I couldn't find something that could help me.
class ProfilesController extends Controller
{
public function index(User $user)
{
return view('profiles.index', compact('user'));
}
public function edit(User $user){
return view('profiles.edit', compact('user'));
}
public function update(User $user){
$data = request()->validate([
'description' => 'required',
]);
$user->profile->update($data);
return redirect("{$user->id}/edit");
}
}
I want to get through that and update $data.
Edit
public function profile() {
return $this->hasOne(Profile::class);
}
public function posts(){
return $this->hasMany(Post::class)->orderBy('created_at', 'DESC');
}
Try this:
optional($user->profile)->update($data);
You can see the official documentation of optional() helper here.
I think you cannot update directly on an instance, you'd have to do : User::where('user_id', $user->id);
If you want to "update" an instance, you would have to do : $user->description = $data['description']; $user->save();
Do this:
if($user->profile) {
$user->profile()->update($data);
}
Hope this will help you.
I would imagine this is because the user doesn't have a profile by default.
One way you can get around this is by using withDefault() on your profile relationship in your User model e.g.
public function profile()
{
return $this->hasOne(Profile::class)->withDefault();
}
You would then need to change your controller code slightly since the profile might not exist:
Change:
$user->profile->update($data);
To:
$user->profile->fill($data)->save();
I had the same issue. As it turned out I forgot to create a new empty profile while creating a new user. So i was calling an update on the user's profile in this case null.
Try adding this to the User model and later migrate:fresh your data.
protected static function boot()
{
parent::boot();
static::created(function ($user) {
$user->profile()->create();
});
}
This will create a new profile for user automatically.

How to filter entries via hasMany relationship in Laravel

I'm trying write an website with Laravel (current version is 5.7) and I have 3 models as: Post, User and Fav. I'm using a simple form to add posts to "favs" table which has 3 columns as; id, user_id and post_id. And I want to list posts that user added favorites bu I can't use "hasMany" method properly.
I can use variables like; $post->user->name but I can't figure it out how to use relationship with "favs" table.
Post Model
public function user() {
return $this->belongsTo('App\User');
}
public function favs() {
return $this->hasMany('App\Fav');
}
Fav Model
public function users() {
return $this->hasMany('App\User');
}
public function posts() {
return $this->hasMany('App\Post', 'post_id', 'id');
}
User Model
public function posts() {
return $this->hasMany('App\Post');
}
public function favs() {
return $this->hasMany('App\Fav');
}
Controller
public function user($id){
$favs = Fav::orderBy('post_id', 'desc')->get();
$user = User::find($id);
$posts = Post::orderBy('id', 'desc')->where('user_id', $id)->where('status', '4')->paginate(10);
return view('front.user')->with('user', $user)->with('posts', $posts)->with('favs', $favs);
}
The Fav model only has one User and Post each, so you need to use belongsTo() instead of hasMany and change the method names to singular. You can also remove the additional parameters in post() since they're the default values.
public function user() {
return $this->belongsTo('App\User');
}
public function post() {
return $this->belongsTo('App\Post');
}
Loading all Posts that a user has favorited:
$user->favs()->with('post')->get();
The with() method is used to eager load the relationship.
Now you can loop through the Favs:
#foreach($favs as $fav)
{{ $fav->post->name }}
#endforeach
I think you can change these two lines of your code to
$posts = Post::orderBy('id', 'desc')->where('user_id', $id)->where('status', '4')->paginate(10);
return view('front.user')->with('user', $user)->with('posts', $posts)->with('favs', $favs);
to
$posts = Post::where('user_id', $id)->where('status', '4')->latest()->paginate(10);
return view('front.user', compact('user', 'posts', 'favs'));
And for retrieving favorite posts of an user,
if you will change the fav table to make it a pivot table only to handle a many to many relationships between Post and User, you can get it as $user->posts, for a separate model, I think you can consider something like $user->favs and in view
In Fav model
public function user() {
return $this->belongsTo('App\User');
}
public function post() {
return $this->belongsTo('App\Post');
}
and in view
#foreach ( $user->favs as $fav )
{{ $fav->post->id }}
#endforeach
If an User, per example, have many Favs you need to use a Iteration Block, like foreach.
Example:
foreach($user->favs as $fav) {
dd($fav) // do something
}
Ps.: Be careful not to confuse hasMany and belongsToMany.

Query with two laravel models and return result

I have two models, User and Post
User Model:
public function posts()
{
return $this->hasMany('App\Post');
}
Post Model:
public function user()
{
return $this->belongsTo('App\User');
}
In my controller I have a public function which has:
$users = User::orderBy('is_ban', 'desc')->paginate(10);
$posts = Post::orderBy('created_at', 'desc')->paginate(10);
Which is working as expected.
I also have one column in users table `is_ban' It's of boolean type.
I am looking for a query which will return the following:
Only get post which has been made by the user which has is_ban=false
perhaps i haven't understood you, but i hope it will help. You can add it to your Post model
public function getBannedUsersPosts()
{
return self::whereIn('user_id', User::where('is_ban', 0)->pluck('id'))->get();
}

Laravel models to return null relation?

I am writing a website for photo posts and I have these functions relating likes (they determine if the user is liking the specific post or not)
Post Model:
public function likes()
{
return $this->hasMany('Like');
}
public function isLiked()
{
return $this->likes()->where('user_id', Auth::user()->id);
}
Post Controller function for example:
public function postsByType($type)
{
if($this->user){
$posts = Post::with('isLiked')->where('type', '=', $type)->paginate(12);
} else {
$posts = Post::where('type', '=', $type)->paginate(12);
}
return $posts;
}
Is there any way to return null in MODEL function when user is not logged in, without running a query?
I want to avoid writing that if in post controller
I thought about the following solution but it's not working...
public function isFollowing()
{
return $this->setRelation('isFollowing', null);
}
getting this error:
Call to undefined method Illuminate\Database\Query \Builder::addEagerConstraints()
Since you probably always want to fetch the relation (except if there's no user logged in) I suggest you do something like this in your model:
(I also renamed the relationship to liked, you'll see later why)
public function newQuery(){
$query = parent::newQuery();
if(Auth::check()){
$query->with('liked');
}
return $query;
}
Now every time a query is run with the model with('isLiked') will be added if the user is logged in.
One problem remains though. If you access isLiked the query will be run anyways. And even for every post because it's not eager loaded. You can fix that by adding an attribute accessor:
public function getIsLikedAttribute(){
if(Auth::guest) return false;
return ! $this->liked->isEmpty();
}
So in your view you can just do this:
#if($post->isLiked)
Note: It would be nicer to move the things inside newQuery() to a global scope. Make sure to check out how to do that in the documentation if you're interested.
Here's an example with a scope. Create a class, let's call it LikedScope:
class LikedScope implements Illuminate\Database\Eloquent\ScopeInterface {
public function apply(Builder $builder, Model $model){
if(Auth::check()){
$builder->with('liked');
}
}
public function remove(Builder $builder, Model $model){
}
}
And then add it to your model:
public static function boot(){
parent::boot();
static::addGlobalScope(new LikedScope);
}

Laravel 4:: Returning models and its relationship

I would like to return the model and part of its relationship
EX::
User model
public function comments()
{
return $this->hasMany('comments');
}
Comments model
public function user()
{
return $this->belongsTo('user');
}
Can I return all comments and the user's name associated with the comment?
The desired effect is
$comment = Comments::find($id);
$comment->user;
return $comment;
This will return the one comment and the associated user full model. I just need the name of the user. And this does not works if I call Comments::all()
Thank you in advance.
You're looking for Eloquent's Eager Loading
Assuming your Comments model has a method user():
public function user()
{
return $this->belongsTo('User');
}
You should be able to do this in your controller:
$comments = Comments::with('user')->where('post_id', $post_id);
// Return JSON, as is Laravel's convention when returning
// Eloquent model directly
return $comments;
You can do the opposite as well:
Assuming your User model has a method 'comments()', like so:
public function comments()
{
return $this->hasMany('Comment');
}
Inside of your controller, you should be able to do the following, assuming your have the $id of the user available:
$user = User::with('comments')->find($id);
// Return JSON, as is Laravel's convention when returning
// Eloquent model directly
return $user;

Categories