I'm creating a like feature for my application where users can like posts, events, products etc.
I have a LikeController and a Trait which handles the like functionality
public function store(Post $post)
{
$post->like();
return back();
}
The code above is to like a post
I don't want to duplicate code and create separate functions to perfrom the same exact thing on events or products and I was wondering how to perform route model binding and get the application to just execute the one function, passing model information depending on what is being liked post, event or product.
The following code works fine but does not implement the DRY principle
public function store(Post $post)
{
$post->like();
return back();
}
public function store_event(Event $event)
{
$event->like();
return back();
}
The followinf is the trait
trait LikeTrait
{
public function getLikesCountAtrribute()
{
return $this->likes->count();
}
public function like()
{
if (!$this->likes()->where(['user_id' => auth()->id()])->exists()) {
$this->likes()->create(['user_id' => auth()->id()]);
}
}
public function likes()
{
return $this->morphMany(Like::class, 'likeable');
}
public function isLiked()
{
return !!$this->likes->where('user_id', auth()->id())->count();
}
}
My web routes file is as follows
Route::post('post/{post}/likes', 'LikeController@store');
Route::post('event/{event}/likes', 'LikeController@store_event');
So the outcome I want is to call the same method and pass the relevant model.
Thanks in advance
You can have a specific route for such actions, may it be 'actions':
Then in the request you send the object you wish to perform the action on, i personal have it hashed, the hash contains the ID and the class_name (object type) in an stdClass.
That's how i personally do it: Every Model i have inherits
BaseModel, which containshashattribute, which containsThis will return a string value of what's there, and encrypted, you can have a password for that as well.
Then you let's say you have the like button inside a form or javascript you can do that:
Doing so, when liking an object you send the hashed string as the data, thus getting a request of
$request->get('item')containing the object (id and type). then process it in the controller however you like.then in
ActionsController@likeyou can have something like that:I personally prefer to combine and encrypt the id+type in a string, but you can send the id and type in plain text and have a route named like so:
Then build the model from the Type+ID followed by what you have in trait (
$Model->like());It's all up to you, but i'm trying to hint that if you want to reuse the
likeaction in many places, you may want to start building the logic starting from theactionitself(likes, comments) not from the target (posts, events).