abdobargush's avatar

What is the best practice for using traits?

Hello everyone, I've several models that shares thumbnail functionality, so extracted it to a trait and used it like this, I think it's kinda clear and can easily be documented

namespace App\Traits;

/**
 * Add Thumnial functionality to models
 */
trait ThumbnailTrait
{
	private function setThumbnail(?string $value, string $directory, array $size) : void
	{
		// ...
	}
	
	private function getThumbnail(?string $value, string $default) : string
	{
		// ...
	}

}
namespace App\Models;

class Tool extends Model
{
	use \App\Traits\ThumbnailTrait;

	public function setThumbnailAttribute($value)
	{
		$this->setThumbnail($value, 'tools', [256, 256]);
	}

	public function getThumbnailAttribute($value)
	{
		return $this->getThumbnail($value, 'images/[email protected]');
	}
}

but I was thinking that it may be used with properties to alter traits like the following

class Tool extends Model
{
	use \App\Traits\ThumbnailTrait;

	protected $thumbnail = [
		'default' => 'images/[email protected]',
		'directory' => 'tools',
		'size' =>  [256, 256]
	];
}

then rename the trait functions to setThumbnailAttribute and getThumbnailAttribute and make then access the property directly with $this keyword without additional calls in the model

I'm just wondering what is the better way to do it, or if there is a best practice I'm not aware of?

0 likes
5 replies
fylzero's avatar

@abdobargush I would maybe do this as a polymorphic relationship rather than how you have it as a trait.

With Polymorph you could have a model called Thumbnail and a table for thumbnails that stores the thumbnail with the Model class it belongs to. Then just reference Tool::first()->thumbnail->size, etc.

https://laravel.com/docs/8.x/eloquent-relationships#polymorphic-relationships

Highly recommend this Laravel Daily course for explaining polymorphic relationships, if you've never used them. https://laraveldaily.teachable.com/p/laravel-eloquent-expert-level

2 likes
abdobargush's avatar

@fylzero Thank you for bringing up polymorphic relationship, I imagine it would be better approach if I needed more advanced thumbnail functionality as it adds complexity on the database level.

In my application every resource will have only one thumbnail and I don't need to store any additional data associated with it, size and directory are only used during the upload.

fylzero's avatar

@abdobargush This is actually the perfect case for a polymorphic relationship. It doesn't add much database complexity. In fact it should simplify things quite a bit as you'll only need a single table instead of a column on multiple tables to drive this. You should really look into / consider this approach.

2 likes
martinbean's avatar

@abdobargush Traits are a language construct. It’s like asking what the “best practice” is for classes. There aren’t “best practices”; you just use the language features for what they’re intended for.

Traits are used to overcome PHP’s lack of multiple inheritance, and to be able to re-share code between classes. Now, do you models need this code sharing? Or is it functionality that could be wrapped up in a class of its own?

1 like
abdobargush's avatar

Thank you @martinbean, I think I'm getting your point here. Yes, it can be wrapped in a class of its own. I thought of using trait as a code that can be reused by several classes.

Please or to participate in this conversation.