DEV Community

Bert Heyman
Bert Heyman

Posted on • Edited on

The power of PHP traits to create reusable components

Lastly, I wrote about using queryscopes as building blocks for your Eloquent queries. Let's further explore the book site and have a look at reusable functionality in our models.

Note: some functionality will be Laravel specific, but the core idea can be used in most PHP frameworks or as you seem fit.

Let's have a look where we left our Book model. This visible scope will enable us to easily hide all book suggestions, in case the diary of your 13 year old self ends up somewhere.

// App\Book.php (model)

protected static function boot()
{
    parent::boot();

    // This code makes sure every query will automatically be restricted to visible models
    static::addGlobalScope('visible', function (Builder $builder) {
        return $builder->where('visible', 1);
    });
}
Enter fullscreen mode Exit fullscreen mode

Now, imagine creating a book suggestion not yet visible: a preview link might come in handy to test the result.

// App\Book.php (model)

public $previewKey = 'preview';

protected static function boot()
{
    parent::boot();

    // It might be wise to move the code to a dedicated scope class at this point
    // I've left it here for the sake of simplicity
    static::addGlobalScope('visible', function (Builder $builder) {
        if (!empty($model->previewKey) && request()->has($model->previewKey)) {
            return $builder;
        }

        return $builder->where('visible', 1);
    });
}
Enter fullscreen mode Exit fullscreen mode

Visiting /books/childhood-diary?preview=true will bypass the visibility constraint and show a preview. We're satisfied with the result and carry on adding features:

  • A book can be linked to tags
  • The book overview can accept filters
  • ...

You'd now like to create the author model, with... tags, filters and hideability. Copy - paste - done? But, we'd like to pass our "good old lazy" developer, so what might be the most efficiënt long term option?

// App\Book.php (model)

Use Filterable, Hideable, Taggable;

public $previewKey = 'preview';

// App\Traits\Hideable.php

namespace App\Traits;

trait Hideable
{
    protected static function bootHideable()
    {
        // This is the boot function of the Trait, code here will have the same                 behaviour as in the boot function of the model
        static::addGlobalScope('visible', function (Builder $builder) {
        if (!empty($model->previewKey) && request()->has($model->previewKey)) {
            return $builder;
        }

        return $builder->where('visible', 1);
    }
}
Enter fullscreen mode Exit fullscreen mode

By working with Traits, it's very easy to reuse, update or delete behaviour in different models - you are now ready to become a lazy developer, congratulations!

Any feedback on this is very welcome! This includes:

  • How do you like to tackle shared functionality? Hit me up if you like to tell me about a different approach.
  • Anything that could be written in a better way regarding this article.

Top comments (0)