Using Multiple Traits with __get/__set
While powerful, using multiple traits that all override magic methods like __get
or __set
can lead to conflicts. PHP provides a clear way to solve this.
The Problem: Fatal Error
If you use HasTranslations
and another trait that also defines __get
or __set
, PHP will throw a fatal error because it doesn't know which method to use.
The Solution: Composition in the Model
The best solution is not to choose one trait over the other, but to compose the behavior of both. This is done by renaming the methods from both traits using the as
keyword and then creating your own __get
or __set
method in the model to act as a controller, calling the aliased trait methods as needed.
Example Implementation
Here is an example of a Product
model that uses both HasTranslations
and a hypothetical OtherPackage\HasSku
trait, both of which define __get
and __set
.
<?php
namespace App\Models;
use Aaix\EloquentTranslatable\Traits\HasTranslations;
use Illuminate\Database\Eloquent\Model;
use OtherPackage\HasSku;
class Product extends Model
{
use HasTranslations {
__get as getFromTranslations;
__set as setInTranslations;
}
use HasSku {
__get as getFromSkuGenerator;
__set as setInSkuGenerator;
}
public array $translatable = ['name', 'description'];
/**
* Custom __get method to orchestrate trait methods.
*/
public function __get($key)
{
// 1. Check if the key is a translatable attribute.
if ($this->isTranslatableColumn($key)) {
return $this->getFromTranslations($key);
}
// 2. Check if the key is the special 'sku' attribute.
if ($key === 'sku') {
return $this->getFromSkuGenerator($key);
}
// 3. Fallback to the default Eloquent behavior.
return parent::__get($key);
}
/**
* Custom __set method to orchestrate trait methods.
*/
public function __set($key, $value)
{
// 1. Check if the key is a translatable attribute.
if ($this->isTranslatableColumn($key)) {
$this->setInTranslations($key, $value);
return;
}
// 2. Check if the key is the special 'sku' attribute.
if ($key === 'sku') {
$this->setInSkuGenerator($key, $value);
return;
}
// 3. Fallback to the default Eloquent behavior.
parent::__set($key, $value);
}
}