Writing a Blog in Laravel: Model Events and Observers

Naren Chitrakar
Sep 2, 2018 · 2 min read

One of the issue with creating a blog post was

We do not check slug for uniqueness meaning that if you post the same title, it will give you a database error.

Let’s try and fix that. Laravel provides an easy way to listen to model events. Whenever something happens with a model like when it is being saved, or after being saved, there are events that trigger. The list of events that happen with a model are:

  1. retrieved
  2. creating
  3. created
  4. updating
  5. updated
  6. saving
  7. saved
  8. deleting
  9. deleted
  10. restoring
  11. restored
  12. forceDeleted

We can listen to creating event and make sure that the slug that we created for the post. Let’s do this.

Creating an Observer

Observer is a class that can house all in one class, so that we can centralize the logic on model events. Just like with everything else, laravel has a command to create an observer.

php artisan make:observer PostObserver --model=Post

This command will create a file app/Observers/PostObserver.php file with content

There are few default events here but we do not need any of these here. We can just listen to the creating event. Lets remove all the methods here and add the creating method.

We need to check if the slug exists in the database and add a number behind the slug it it exists.

The PostObserver with the changes look like this

Let me break down what is happening here

$posts = Post::slugLike($slug)->pluck('slug');

We check if database has post with slug like we are creating. You may be wondering what this slugLike method does and is that a model method. Laravel provides a way to hook our custom query into the query builder. These are called scopes. The way it works is that we can add a function in model with a method with prefix scope and the function we like to call. So for the slugLike method to work. We need to add function scopeSlugLike to model. This method will accept query as first parameter. Our model function now looks like this.

The query returns all the post that has a slug like the one we just created. pluck method of the query builder return just that column of the table. $posts is a collection class .

$i=0;
while($posts->contains($slug)){
$slug = $originalSlug .'-'. ++$i;
}

$post->slug = $slug;

We can check if the slug contains in the collection and if it does, we just increase the number.

After all the changes, we need to register this Observer in the AppServiceProvider.

public function boot()
{
Post::observe(PostObserver::class);
}

In the PostController, we had a method that added the slug in the post while we created with this line

$formData['slug'] = str_slug($request->get('title'));

We can now remove this line because we handle this in the Observer.

Now if we save the post with same title, it will just generate a new slug with a number as the suffix like

title, title-1, title-2 and so on.

The changes made in this post are here.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade