laravel access related model using mutator during $user->posts()->create([...]) - laravel

I have User and Post models.
Would like to access the User when the mutator for the post's title is being called at the time of the post creation. Similar to a question from a few years ago.
But I am unable to access the User inside the Posts title mutator.
Tried $this->user->id (preferred). Also tried: $this->user_id, $this->user()->get()->id.
>>> User::first()->posts()->create(['title'=>'test '.now()])
PHP Warning: Attempt to read property "id" on null <<<=== when trying $this->user->id
=> App\Models\Post {#4155
title: "test 2021-05-08 11:41:55", <<<=== title is shown before user_id
user_id: 1, <<<=== but in migration user_id is defined *before* title
updated_at: "2021-05-08 11:41:55",
created_at: "2021-05-08 11:41:55",
id: 1,
user: null, <<<=== note "user" attribute is added as result of the $this->user->id
}
Would think the user is definitely known at that time, as we're using that user to add a post to.
If I make the user_id fillable, then this one works as expected (for that one: the array order matters):
Post::create(['user_id'=>User::first()->id, 'title'=>'test '.now()])
But, that's less... eloquent.
My config + test details:
// Post.model
protected $fillable = [
// 'user_id', // also tried with making user_id fillable
'title',
];
public function setTitleAttribute($value) {
// dump($this->user_id); // null
// dump($this->user); // null (& adds empty user property to this)
// dump($this->user->id); // PHP Warning: Attempt to read property "id" on null (& adds property)
// dump($this->user()->get()); // empty collection Illuminate\Database\Eloquent\Collection
// dump($this->user()->toSql()); // select * from "users" where "users"."id" is null
$this->attributes['title'] = $value;
}
public function user() {
return $this->belongsTo(User::class);
}
// User.model
public function posts() {
return $this->hasMany(Post::class);
}
// posts migration
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained();
$table->string('title');
$table->timestamps();
});
Using mysql as DB.

This seems to be the safest + cleanest: use boot event closure 'creating', which is triggered after the mutators and right before data is saved to the database.
public static function boot() {
parent::boot();
static::creating(function (Post $post) {
// now we have both $post->user and $post->title
dump($post->user->name);
dump($post->title);
});
}

can you provide more detail?
try this
auth()->user()->id
if user is logged in
if u want select user from db
User::where("filed name","value")->first()->id

Related

View is not returning attributes stored in database

I am attempting to return which user posted a comment, along with the time they posted the comment.
I have a model for comments
use Illuminate\Database\Eloquent\Model;
class comments extends Model
{
protected $guarded = [];
public function adjustments()
{
return $this->belongsToMany(User::class, 'adjustments')
->withTimestamps();
}
}
A pivot table which tracks which users posted which comments
public function up()
{
Schema::create('adjustments', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id')->index();
$table->unsignedInteger('comments_id')->index();
$table->timestamps();
});
}
An empty adjustments model
use Illuminate\Database\Eloquent\Model;
class adjustment extends Model
{
//
}
In php artisan tinker when $comment = App\comment::first(); and $user = App\user::first(); I'm able to successfully attach a user_id to a comment_id using $comment->adjustments()->attach($user->id) and calling App\adjustments::all(); will correctly return
=> Illuminate\Database\Eloquent\Collection {#2935
all: [
App\adjustment {#2941
id: 1,
user_id: 1,
comments_id: 1,
created_at: "2019-11-16 17:05:10",
updated_at: "2019-11-16 17:05:10",
},
],
}
When I'm trying to show the adjustments in my view, I get an empty list.
#foreach ($comment->adjustments as $user)
<li>{{$user->name}} on {{$user->pivot->updated_at}}</li>
#endforeach
In my products controller (a user makes comments on products) I have the following code in my show function
public function show(products $product, comments $comment, User $user)
{
return view ('products.show', compact('product'), compact('comment'));
}
Here you don't need a pivot table. Becasue here you has one to many relation. User can create many comment. & one comment is belongs one user.In user model add this
public function comments()
{
return $this->hasMany(Comment::class);
}
& comments table u have a foreign key user_id.
in comment model
public function user()
{
return $this->belongsTo(User::class,'user_id','id')
}
public function show(products $product, comments $comment, User $user)
{
$comments=Comment::with('user')->all();
return view ('products.show', compact(['product','comments']));
}
#foreach ($comments as $comment)
<li>{{$comment->user->name}} on {{$comment->updated_at}}</li>
#endforeach
Then you can acces all comments table data with a user

Laravel 5.6 eager load nested childrelations

I'm having an issue with getting child relations from a Card object to a User object. The relations are as following:
'User' -> hasOne 'Company'
'Company' -> hasMany 'Card'
So the other way around is:
'Card' -> belongsTo 'Company'
'Company' -> belongsTo 'User'
My Card model has got this:
public function company()
{
return $this->belongsTo('App\Company');
}
My Company model has got this:
public function user()
{
return $this->belongsTo('App\User');
}
public function cards()
{
return $this->hasMany('App\Card');
}
My User model has got this:
public function company()
{
return $this->hasOne('App\Company');
}
What I want to do is: in the User model I want to eager load all cards from that user. So my code looks like this:
$cards = Card::with('company.user')->get();
But it's constantly returning me all the card records in the database, not the ones that are from the logged in user itself. There definitely
is a userID, cause when I dump $this->id in the User model, I'm getting the ID '1'. In the database I've configured all foreign keys so that won't be the problem I assume.
Table 'cards' has a foreign key to 'company_id', and table 'companies' has a foreign key to 'user_id', they are all set by the migration script, which looks like this:
Schema::create('cards', function (Blueprint $table) {
$table->increments('id');
$table->integer('amount');
$table->string('status');
$table->unsignedInteger('company_id');
$table->timestamp('expires_at')->nullable();
$table->boolean('is_debit_allowed')->default(1);
$table->string('cancelled_by')->nullable();
$table->timestamp('cancelled_at')->nullable();
$table->timestamps();
$table->foreign('company_id')->references('id')->on('companies');
});
What am I doing wrong guys?
In the User model, you can add it to the $with array:
// this will eager load the company and cards for every user query, so beware!
protected $with = ['company.cards'];
Or create a new function cards:
public function cards()
{
return $this->company->cards;
}
$cards = $user->cards();
// use the auth helper to get logged in user's cards
$cards = auth()->user()->cards();
This should work for accessing via Card:
$cards = Card::whereHas('company.user', function ($query) {
$query->whereKey(auth()->id());
})->get();

laravel relationship one to many

before anything ,Highly appreciated in advance for help . i have two model
user:
public function posts(){
return $this->hasMany('App\Post');}
post:
public function user(){
return $this->belongsTo('App\user');}
my post have column "user_id" so every post have owner "user_id".
here is my question: i want to delete user but nothing happen to related post. right now i can do this ,but my problem is post_id column have id belongs to deleted user. i want to change that to "null" or "0".
You can do this with model events. Something like this on your User model.
public static function boot() {
parent::boot();
static::deleting(function($user) {
$user->posts()->update(['user_id' => null]);
});
}
Also make sure the user_id field is nullable on the migration.
Just make sure that your post_id field is set to nullable in your migration AND in your database.
You can do this with SQL power - add a migration to your table "posts"
...
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('set null');
It will create a foreign key which sets null to related field on deleting user row
You can change the function boot() from User model:
protected static function boot() {
parent::boot();
static::deleting(function($user) {
$user->posts()->delete();
});
}

Laravel eloquent attach auto generate random ID

I have an eloquent many to many relationship and I want to use attach() to easily create role_permissions data but the problem is I'm using an UUID for my ID and it throws an error Field 'id' doesn't have a default value. Any way of hijacking the attach() method? so I can set my UUID?
My migration
Schema::create('role_permissions', function (Blueprint $table) {
$table->increments('count')->unique();
$table->string('id')->unique();
$table->string('role_id');
$table->string('permission_id');
$table->timestamps();
});
My model
class Role extends Model
{
//
public $incrementing = false;
public function users()
{
return $this->belongsToMany('App\User', 'user_roles', 'role_id', 'user_id');
}
public function permissions()
{
return $this->belongsToMany('App\Permission', 'role_permissions', 'role_id', 'permission_id');
}
}
My attach code
$role->permissions()->attach($permission_ids);
I know the problem here is that my id is not an incrementing number it's an unique string. My question is how do I "Inject" that unique string to the attach() method? Thank you guys.
The error
Field 'id' doesn't have a default value
refers to the fact that your database does not know how to fill the id field when it's not specified.
Either you edit the schema adding a nullable:
Schema::create('role_permissions', function (Blueprint $table) {
$table->increments('count')->unique();
$table->string('id')->unique()->nullable(); // Bad idea
$table->string('role_id');
$table->string('permission_id');
$table->timestamps();
});
or injecting it via attach:
$role->permissions()->attach($permission_ids, ["id" => null]);
More info on Laravel official doc
Update
For the future developers who encounter this problem you can also set anything inside the attach array, for example:
$role->permissions()->attach($permission_ids, ["id" => Uuid::generate()]);
Update 2
There's also a more clean way to handle this to be honest. I will try to explain it.
You can handle the Pivot events inside the event service provider by simply hooking into the bootmethod:
Here's a snippet
/App/Providers/EventServiceProvider.php
public function boot()
{
Pivot::creating(function($pivot) {
if ($pivot->getTable() == 'role_permissions') {
$pivot->id = Uuid::generate();
}
});
}
Be aware I do not know if this is actually possible on your laravel version. Mine (5.4.*) works as intended
Okay managed to fixed it, what I did with the help of #Claudio Ludovico Panneta's tip.
foreach($permission_ids as $permission_id)
{
$role->permissions()->attach($permission_id, ["id" => Uuid::generate()]);
}

Laravel 5.2 User/Following System: hasMany Relation

I'm stuck on a problem: I've created a simple user following system so users can follow each other. I'm using a table named follows to store the relation. I've created a hasMany relationship in my User class, and, when retrieving the results I'm getting exactly what I expect, however, I'd like to get some additional information from the users table, such as the username, avatar, etc. How do I go about this?
The follows table
// following_id is the person being followed
public function up()
{
Schema::create('follows', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('following_id')->unsigned();
$table->timestamps();
$table->unique(['user_id', 'following_id']);
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
The User class
class User extends Authenticatable
{
// a user can have many followers
public function followers()
{
return $this->hasMany(Follow::class, 'following_id');
}
// a user may be following many people
public function following()
{
return $this->hasMany(Follow::class);
}
}
The method I'm calling in UsersController to see the results
// route is /{username}/followers
public function followers($username)
{
$user = User::where('username', $username)->first();
// get the user's followers
$followers = $user->following;
return $followers;
}
The current results are
[
{
id: 24,
user_id: 3,
following_id: 1,
created_at: "2016-02-13 11:42:59",
updated_at: "2016-02-13 11:43:02"
}
]
However, I'd like them to be the following: where fredflintstone is the user with ID of 1; e.g.; the user who is following user 3
[
{
id: 24,
user_id: 3,
following_id: 1,
following_username: 'fredflintstone',
created_at: "2016-02-13 11:42:59",
updated_at: "2016-02-13 11:43:02"
}
]
I've also created a Follow model, which is currently empty. I tried adding an inverse belongsTo relationship in it, but it didn't work. Mayhaps I did it wrong?
I have been using laravel for a long time,and i suggest you use join instead if laravel built in model for 'with'
Here is the code of using join, modify it according to your use
public function followers($username)
{
$user = User::where('username', $username)->first();
//Follower your model name for the follows table
//if you dont have a model use DB::table('follows') instead
$followers=Follower::where('user_id',$user->id)
->join('users as follower','follower.id','=','follows.following_id')
->select('follows.id','follows.following_id','follows. user_id','follower.name as following_username')->get();
return $followers;
}
Figured it out. I needed to join the users table to the query.
public function following()
{
return $this->hasMany(Follow::class, 'user_id')
->join('users', 'users.id', '=', 'follows.following_id')
->select('user_id','username');
}

Resources