loading...

The power of PHP traits to create reusable components

bertheyman profile image Bert Heyman Updated on ・2 min read

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);
    });
}

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);
    });
}

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);
    }
}

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.

Posted on by:

bertheyman profile

Bert Heyman

@bertheyman

Laravel enthousiast, likes reading dev stories and the openness of communities like dev.to

Discussion

markdown guide