Photo by Larry Li

Many of the applications I write often contain very similar functionality, so it’s important that I try to regularly review my workflow and how I architect my code so that future feature additions can be made quickly and new projects can easily expand on previous ideas.

When it comes to relationships between your models in Laravel, it couldn’t be simpler:

public function user(){

return $this->belongsTo(User::class,'user_id');

}

What about reusing that code in another method? Simple enough, just copy and paste it over into the new model and it works. If you’re anything like me though, doing that enough times will certainly start to cause a code smell, especially when we expect to add a bit more functionality.

Consider an example where we have a basic company membership portal. Employees can login and view other employees in the system. Similarly, clients of the company have a profile of their own with some basic contact information. Perhaps our migrations would look something like this:

Schema::create('users', function (Blueprint $table) {

$table->increments('id');

$table->string('name');

$table->string('email')->unique();

$table->string('password');

$table->rememberToken();

$table->timestamps();

}); Schema::create('employees', function (Blueprint $table) {

$table->increments('id');

$table->integer('user_id');

$table->string('employee_code');

$table->string('phone');

$table->timestamps();

}); Schema::create('clients', function (Blueprint $table) {

$table->increments('id');

$table->integer('user_id');

$table->string('company_name');

$table->string('phone');

$table->timestamps();

});

So with very basic information we have 3 primary models in our application (User, Employee, and Client). Like we saw before, simply adding our relationship method to both classes would get us some nifty $modelInstance->user functionality, but adding this into a trait can give us a simple way to keep our code duplication in check:

<?php



namespace App\Support\Traits;



trait BelongsToUser{



public function user(){

return $this->belongsTo(\App\User::class,'user_id');

}



}

As our application grows, we can simply define the new model’s relation to the users table by dropping in our trait in.

<?php



namespace App;



use App\Support\Traits\BelongsToUser;

use Illuminate\Database\Eloquent\Model;



class Client extends Model

{



use BelongsToUser;



} <?php



namespace App;



use App\Support\Traits\BelongsToUser;

use Illuminate\Database\Eloquent\Model;



class Employee extends Model

{



use BelongsToUser;



}

Now $employee->user and $client->user work great! Even better, if you find another common method in your models that relates to how the user should be interacted with, the trait might not be a bad place to keep it.

<?php



namespace App\Support\Traits;



trait BelongsToUser{



public function user(){

return $this->belongsTo(\App\User::class,'user_id');

} public function getUserNameAttribute(){

return $this->user->name;

} }

Letting you now simply write $model->user_name for each model using this trait.

This works well when we only have a few things, however if you see yourself filling up this trait with a large amount of methods then it might be time to start looking for more appropriate places to put this code (repository class, decorator…)

In a new example below, I have a few models that have a simple “slug” field used to generate their uri. While it’s not a relationship, I might create a HasSlug trait to keep any logic relating to the field since I know each model is going to interact with the field in exactly the same way:

<?php



namespace App\Support\Traits;



trait HasSlug{



public static function findBySlug($slug){

return static::where('slug', $slug)->first();

} }

So I know I’m going to want each of these classes to have a simple static method to find an instance by it’s slug value (Post::findBySlug(‘slug’)).

Now what if I wanted to add in the ability to generate a new slug based on the model’s title.

<?php



namespace App\Support\Traits;



trait HasSlug{



public static function findBySlug($slug){

return static::where('slug', $slug)->first();

}



public function updateSlug(){

$this->slug = Formatter::slugify($this->title);

$this->save();

} }

So models can simply run $model->updateSlug(); to generate a new slug from it’s title, but what about models where “title” isn’t the field we want to use to generate the slug? We could leave a parameter in the updateSlug method and pass it through each time:

$user->updateSlug('username');

//or

$user->updateSlug($user->username);

But it doesn’t seem right that we would pass instructions to the model about what the model should already know how to do on it’s own.

Instead, in cases like this I might just make a simple property on the model itself to indicate a detail about how this model would interact with the relationship or field:

<?php



namespace App;



use App\Support\Traits\HasSlug;

use Illuminate\Database\Eloquent\Model;



class User extends Model

{



use HasSlug;



protected $fieldNameForSlugGeneration = 'username';



}

Then our trait:

<?php



namespace App\Support\Traits;



trait HasSlug{



public static function findBySlug($slug){

return static::where('slug', $slug)->first();

}



public function updateSlug(){

$generationFieldName = $this->fieldNameForSlugGeneration ?? 'title';

$this->slug = Formatter::slugify($this->$generationFieldName);

$this->save();

} }

Disclaimer: All of this is probably bad practice. I’m just a developer trying to get by and looking for ways to have my code make sense. 🙃