We saw earlier how to set up a Trait for easy code reuse. Now it’s time to add the ability to record favorites as part of any user’s activity feed. The good news is that since we have already did all the work to set up activity recording, it is going to be easy to add this new feature. In addition, since the existing code uses Polymorphic relations, add new and different types of models to the activity will “just work” so to speak. Let’s see how we can include creating a favorite as part of the user activity stream now.
Activityify The Favorite Model
Adding the ability to record activity to favorites is pretty easy now. Open up the Favorite Model, and simply add the use RecordsActivity
line like so.
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Favorite extends Model
{
use RecordsActivity;
protected $guarded = [];
}
Test Favorite Recording Into Database
With the RecordsActivity trait in place on our Favorite Model, adding a favorite to a reply should now be recorded in the database. Let’s see. We can log in as user Nikola Tesla, and add a favorite to a reply created by user Tom.
Checking the database manually shows us that the recording of a favorite in the activities table is in fact working!
Adding A New Partial
If you recall, we had set up partial view files for each different activity we are recording. In the activities view directory we have a file of created_reply.blade.php and created_thread.blade.php which are used by the main show.blade.php file to display an activity from the feed based on what type of activity it is. So we can see that we already account for a reply activity as well as a new thread activity. Now, we are going to need a created_favorite.blade.php.
Adding a new morphTo relationship to the Favorite Model
Now, we are going to need a new relationship to work with in this new view file. So before we start adding the markup to the newly created created_favorite.blade.php file, let’s take care of adding the morphTo() relationship on the Favorite Model like so.
<?php
namespace App;
use IlluminateDatabaseEloquentModel;
class Favorite extends Model
{
use RecordsActivity;
protected $guarded = [];
public function favorited()
{
return $this->morphTo();
}
}
With that morphTo() relationship defined, we should now be able to see the association between a favorite, and which reply was favorited. We can try it our real quick in Tinker. First, we’ll just fetch the most recent favorite, and of course this will be the favorite that we just added above.
vagrant@homestead:~/Code/forumio$ php artisan tinker Psy Shell v0.8.16 (PHP 7.1.2-3+deb.sury.org~xenial+1 â cli) by Justin Hileman >>> $fav = AppFavorite::latest()->first(); => AppFavorite {#792 id: 2, user_id: 53, favorited_id: 2, favorited_type: "AppReply", created_at: "2018-02-06 16:06:37", updated_at: "2018-02-06 16:06:37", }
Now that we have saved an instance of Favorite into the $fav variable, we should be able to use the new relationship we defined to load the associated data.
>>> $fav->favorited; => AppReply {#795 id: 2, thread_id: 53, user_id: 52, body: "I would agree with this sentiment.", created_at: "2018-01-16 15:32:21", updated_at: "2018-01-16 15:32:21", owner: AppUser {#801 id: 52, name: "Tom", email: "qwer@qwer.com", created_at: "2018-01-16 15:32:01", updated_at: "2018-01-16 15:32:01", }, favorites: IlluminateDatabaseEloquentCollection {#804 all: [ AppFavorite {#793 id: 2, user_id: 53, favorited_id: 2, favorited_type: "AppReply", created_at: "2018-02-06 16:06:37", updated_at: "2018-02-06 16:06:37", }, ], }, }
Adding a path() method to the Reply class
Another thing we are going to want to do is to be able to link directly to a reply. Not only should clicking a link to a reply bring you to the correct thread page it is associated with, it should also scroll to the exact spot on the page the favorite references. So we can just add this method to the Reply model.
public function path()
{
return $this->thread->path() . '#reply-' . $this->id;
}
So what is happening here is that in addition to the path to the thread page, we are appending a hash concatenated with the id of the particular reply we would like to link to. So a generated href might have this format http://forum.io/threads/quo/53#reply-2. Now, in the reply.blade.php file, we can add the hash to link to dynamically using this markup.
<div id="reply-{{ $reply->id }}" class="panel panel-default">
<div class="panel-body">
<div class="level">
<h5 class="flex">
<a href="{{ route('profile', $reply->owner) }}">
{{$reply->owner->name}}
</a> said {{ $reply->created_at->diffForHumans() }}
</h5>
<div>
<form method="POST" action="/replies/{{$reply->id}}/favorites">
{{csrf_field()}}
<button type="submit" class="btn btn-primary {{ $reply->isFavorited() ? 'disabled' : '' }}">
{{ $reply->favorites_count }} {{ str_plural('Favorite', $reply->favorites_count) }}
</button>
</form>
</div>
</div>
</div>
<div class="panel-body">
{{ $reply->body }}
</div>
</div>
Adding Markup To created_favorite.blade.php
Ok, we now have everything in place, all we need to do is add the right markup to the created_favorite.blade.php partial view file.
@component('profiles.activities.activity')
@slot('heading')
<a href="{{ $activity->subject->favorited->path() }}">
{{ $profileUser->name }} favorited a reply
</a>
@endslot
@slot('body')
{{ $activity->subject->favorited->body }}
@endslot
@endcomponent
Visiting the activity feed of a user now also displays any favorites the user has made. In addition, you can see we click the link for the favorite of a reply, and we are taken right to the exact reply on the page. Very slick!
Making Favorites Part Of The Activity Feed Summary
In this tutorial, we learned how to add the action of creating a favorite on a reply to a users activity feed. Thanks to the fact that we had created that convenient trait we had used earlier, by simply making use of this trait in the Favorite Model, we were able to quickly add this feature. Then, all we had to do was update some things on the browser side to display favorites as part of a user’s activity profile.