Laravel class isn't in polymorphic relationship with other class - laravel

I am working on a polymorphic relationship between these classes in my small project: Submissions (same as posts), Comments and Users.
The problem is, I am able to gather all comments by relying on Submission model, for example:
$submissions = Submission::with('comments')->get()->find( $submission );
But, if I try something like this in tinker:
$users = User::with( 'comments' )->get();
I get all the users data, but no comments show up:
comments: Illuminate\Database\Eloquent\Collection {#3003
all: [],
},
Here's all the code of relations between models:
class Comment extends Model
{
protected $fillable = [ 'commentable_id', 'commentable_type', 'text' ];
public function commentable() {
return morphTo();
}
}
Now this is being added inside Submission and User model:
public function comments() {
return $this->morphMany( Comment::class, 'commentable' );
}
In Submission model I am using protected $guarded = []; to deal with Mass Assignment and I don't call it inside user model.
I hope you can tell me what am I doing wrong since somehow I can't access user model by comment model and vice versa.
Thanks in advance!
edit: Here's a code of creation of a comment:
public function store( Submission $submission ) {
$data = request()->validate([
'text' => [ 'required', 'string', 'max:255' ]
]);
$id = $submission->comments()->create([ 'text' => request()->text ]);
dd( $submission, $data );
}

Relation morphMany is one-to-many relation, like hasMany. So one comment can belong to a submission or a user, not both. One option is to create separate comments for submission and user (for the user do the same as for submission $user->comments()->->create([...])). Second option is to use many-to-many polymorphic relation, where one comment can belong to multiple submissions and users.

Related

Laravel 9 Cannot UPDATE Data

CONTROLLER
public function update(Request $request)
{
DB::table('bahanbaku')->where('id', $request->id)->update([
'id_bb' => $request->id_bb,
'nama_bb' => $request->nama_bb,
'stok' => $request->stok
]);
dd($request);
return redirect('/bahanbaku');
}
Sorry for my bad english, but in my case,
After Submit, Data still same, not change
Can you help me? T.T
Id does not exist, this is quite basic, but i feel like there is some misunderstandings with Laravel. Just to get the basics down, in Laravel i would expect you to do the following.
Use models for database operations
Instead of passing the id on the request, pass it on URL parameters
Use model binding for getting your model.
Create your model, since it has a non standard table name define that. Add the properties you want to be filled when updating it as fillables.
use Illuminate\Database\Eloquent\Model;
class Bahanbaku extends Model {
protected $table = 'bahanbaku';
protected $fillables = [
'id_bb',
'nama_bb',
'stok',
];
}
In your route, define the model as a parameter.
Route::put('bahanbaku/{bahanbaku}', [BahanbakuController::class, 'update']);
Now the logic can be simplified to this, which will automatically handle if the model is not found and give you a 404 error.
public function update(Request $request, Bahanbaku $bahanbaku)
{
$bahanbaku->fill(
[
'id_bb' => $request->id_bb,
'nama_bb' => $request->nama_bb,
'stok' => $request->stok
],
);
$bahanbaku->save();
return redirect('/bahanbaku');
}
To improve even more, i would look into utilizing form requests.

How to create a data associatively? laravel eloquent

I have a Post model:
class Post extends Model
{
protected $fillable = [
'title',
'user_id',
'token',
'body'
];
public function favorites()
{
return $this->hasMany(Favorite::class);
}
public function addFavorite($state = 1)
{
$this->favorites()->create(compact('state'));
}
}
Favorite model:
class Favorite extends Model
{
protected $fillable = ['user_id', 'post_id', 'state'];
}
When I test in tinker:
$post = Post::first();
$post->addFavorite();
It returns me an error below:
Illuminate/Database/QueryException with message 'SQLSTATE[HYOOO]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into favorites...
Why it ask user_id when it is given in the post? Question is do I necessarily need to input the user_id to achieve this?
The question of whether user_id is necessary is up to you. Will it come in handy later on? Does having it on the posts table suffice?
It is asking for user_id because you do not have a default value field on that field in the favorites table. You can either set a default value, remove it from the table (if you decide you don't need it), OR provide it when creating via the relationship:
class Post extends Model
{
protected $fillable = [
'title',
'user_id',
'token',
'body'
];
public function addFavorite($state = 1)
{
$this->favorites()->create([
'state' => $state,
'user_id' => $this->user_id,
]);
}
public function removeFavorite()
{
$this->addFavorite(0);
}
}
Don't forget to include the relationship definition of favorites on the Post model.
Based on the plural name, it seems that a post has many favorites, but then your removeFavorite() method calls the addFavorite method?? This would not actually remove anything - it would create a new record.
Since Favorite model is related to Post model and you create it via relation()->create(), you can skip specifying post_id as Laravel can deduce it. But you do have to specify user_id, because there's no way for your code to know that favourite.user_id and post.user_id is the same. So in short: yes, you have to specify user_id.

Eloquent Injected Multiple Model Relationships

So I learned in JeffreyWay's screencasts that I can use Eloquent to get the associated id from a model injected to another model.
I'm following his series about Laravel 5.4.
Here, I have a one-to-many relationships of user to posts.
App/Post
public function user()
{
return $this->belongsTo(User::class);
}
In my User Model, I have a publish method where the Post Model is injected. The publish method is used to create a post entry into the database.
App/User
public function posts()
{
return $this->hasMany(Post::class);
}
public function publish(Post $post)
{
$this->posts()->save($post);
}
I then have a store method in my PostsController that calls the publish method inside my User Model.
PostsController
class PostsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
}
public function store()
{
auth()->user()->publish(
new Post(request(['title', 'body']))
);
}
}
When the publish method is called, the injected Post class automatically sets the user_id to the save method.
My question is, how do I make a relationship like this in a situation where for every posts, there are comments. These comments are associated to the Post and the User that created the comment.
In short, I should have both user_id and post_id when I call the addComment method.
User Model:
public function posts(){
return $this->hasMany(Post::class);
}
public function comments(){
return $this->hasMany(Comments::class);
}
Posts Model
public function user(){
return $this->belongsTo(User::class);
}
public function comments(){
return $this->hasMany(Comments::class);
}
Comments Model
public function post(){
return $this->belongsTo(Post::class);
}
public function user(){
return $this->belongsTo(User::class);
}
Example Problems:
1) Get user comments:
Solution: auth()->user()->comments()->get(); <- collection of user
comments .
2) Get user from the given comment:
Solution: Comment::find($someCommentId)->user()->first()->name; <-
User name from a specific comment.
3) Get all comments for a specific post .
Solution: Post::first()->comments()->get(); or eager load
Post::with('comments')->first(); <- A collection that contains post
information within it u can find a collection of comments for that
post.
4) Load user when loading a comment:
Solution: Comment::with('user')->first(); <- single collection
containing a collection with user info and comment info.
5) Load a specific user post and comments for that post at the same time:
Solution: User::with('posts.comments')->first(); <- Contains a
collection with user info and collection of all user posts with each
post containing comments.
In your question you wrote:
In short, I should have both user_id and post_id when I call the addComment method.
Which is absolutely correct and no problem. You don't have to set these properties through a method like $user->posts()->save($post) - this is just a convenience method that does the job for you (see save($model) and related setForeignAttributesForCreate($model) in the framework code; these methods just set the foreign key property for you).
In fact, the following three ways to create a new post are interchangeable:
// what you did
$user->posts->save(
new Post([
'title' => 'Hello',
'body' => 'World!',
])
);
// equivalent
Post::create([
'user_id' => \Auth::user()->id, // or \Auth::id()
'title' => 'Hello',
'body' => 'World!',
]);
// also equivalent
$post = new Post([
'user_id' => \Auth::user()->id, // or \Auth::id()
'title' => 'Hello',
'body' => 'World!',
]);
$post->save();
When storing a new comment, you will most likely have a controller like this, because a comment always belongs to a post and you therefore will need a reference of the post:
class CommentsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
}
public function store(Post $post)
{
$comment = new Comment(request(['body']));
$comment->user_id = \Auth::user()->id;
$comment->post_id = $post->id;
$comment->save();
}
}
You could also abbreviate it and write:
Comment::create(
array_merge(request(['body']), ['user_id' => \Auth::id(), 'post_id' => $post->id])
);

Laravel getting users from multiple messages

I've got offers table with id's
Messages table with columns offer_id and from
and Users table with id's
I want to get users starting with offer $this in OfferResource
My goal is to get users that have replied to the offer with at least one message.
I started to configure Offer model with function messages to get messages
public function messages(){
return $this -> hasMany('App\Message');
}
so I'm able to get all messages (starting from offer resource):
'users' => $this->messages
How should I now configure messages model to get all users instead of messages?
I tried to write in Message model :
public function fromContact()
{
return $this->hasOne(User::class, 'id', 'from');
}
and then:
'users' => $this->messages->fromContact
but i've got error: "message": "Property [fromContact] does not exist on this collection instance.",
How should I correct my code to make this work?
I am assuming the from field on the Messages table is populated using user ID. Then you could establish belongsToMany relationship between the Offer and User models. Since this is actually a many-to-many relation with a pivot table messages.
In the Offer model define
public function users()
{
return $this->belongsToMany('App\User', 'messages', 'offer_id', 'from');
}
Then from the OfferResource you could load the offers data like this—
$offers = App\Offer::with('users')->get();
Then loop over the $offers like this:
foreach ($offers as $offer) {
dd($offer->users); // one offer will have multiple users as a Collection
}
Similarly for an $offer of ID 1 you could do this
$offer = App\Offer::with('users')->find(1)
Then to get the users that commented on this offer just use $offer->users
See the official documentation for defining many-to-many relationship.
In the Message model you have to spesify the column that refer to the user :
public function fromContact()
{
return $this->hasOne(User::class, 'from');
}
And then after geting the messages loop over them to get the user like this :
foreach ($this->messages as $message) {
$user = $message->fromContact;
// do somthing with the user :)
}
Your messages table has from field that is referencing User model and offer_id field which referencing Offer model that means you have ManyToMany relations between Offer and User.
Offer Model
public function users(){
return $this->belongsToMany(User::class, 'messages', 'offer_id', 'from')->using('App\Message');
}
Message Pivot
class Message extends Pivot {
protected $table = 'messages';
}
User model
public function offers(){
return $this->belongsToMany(Offer::class, 'messages', 'from', 'offer_id')->using('App\Message');
}
OfferResource
public function toArray($request)
{
$users = $this->users;
return [
'id' => $this->id,
... //add your offer fields here
'users' => $users->toArray(), // here $users is a laravel Collection
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
Access from Controller or Route
Route::get('/offer', function () {
return new OfferResource(Offer::with('users')->find(1)); //eager load users
});

Laravel 5.4 Eager loading belongsToMany Relationship null Binding

I have an existing model that is lazy loading a belongsToMany relationship just fine.
My problem is, when i try to eager load the relationship, i get an empty result.
When I inspect the query, it shows that the binding for the relationship query is null.
Here is my (simplified) code:
// Controller
public function filter(Request $request, App\Programs $program)
{
$program = $program->newQuery();
$program->select(
'slug',
'title',
'season'
);
$program->with([
'sports'
]);
return $program->get();
}
// Model
class Programs extends Model
{
public function sports(){
return $this->belongsToMany('App\Sport', 'program_sport', 'program_id', 'sport_id');
}
}
The problem is that you don't take id from database so Eloquent cannot get related models. Instead of:
$program->select(
'slug',
'title',
'season'
);
you should use:
$program->select(
'id',
'slug',
'title',
'season'
);
Be aware however you could use simpler syntax (and don't inject model in controller like this):
return Program::select('id','slug', 'title', 'season')->with('sports')->get();
Also I have no idea why you use route model binding in that case

Resources