Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

AbehoM's avatar

Trait method conflict

I'm creating a project where I have two packages installed: https://github.com/spatie/laravel-translatable and https://github.com/BenSampo/laravel-enum

The project has a few fields as tinyInteger and I need to cast them to enums, that is where the package comes in handy. The other package I'm using is the translatable that allows me to make the model translatable. For example, in my project the about field can be written in different languages and will be loaded depending on the application locale (it's done automatically)

The problem:

They both require for me to add a trait and they both have the same method getAttributeValue and setAttribute so PHP is yelling at me saying that it has a conflict.

What would be the best way to solve this?

0 likes
9 replies
JohnBraun's avatar

Taken from the PHP documentation about Traits:

Conflict Resolution

In this example, Talker uses the traits A and B. Since A and B have conflicting methods, it defines to use the variant of smallTalk from trait B, and the variant of bigTalk from trait A.

The Aliased_Talker makes use of the as operator to be able to use B's bigTalk implementation under an additional alias talk.

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}
?>
willvincent's avatar

I suspect what you'd ultimately want to do here is rename the trait's methods, then implement your own getAttributeValue() and setAttribute() methods and have your implementation call the renamed trait implementations..

Something like this:

class Foo extends Model {
  use CastsEnums , HasTranslations {
    CastsEnums::getAttributeValue as enumGetAttributeValue;
    CastsEnums::setAttribute as enumSetAttribute;
    HasTranslations::getAttributeValue as translationGetAttributeValue;
    HasTranslations::setAttribute as translationSetAttribute;
  }

  public function getAttributeValue($value) {
    $this->enumGetAttributeValue($value);
    $this->translationGetAttributeValue($value);
  }

  public function setAttribute($key, $value) {
    $this->enumSetAttribute($key, $value);
    $this->translationSetAttribute($key, $value);
  }
}

Not tested, but seems like it ought to be in the ballpark

AbehoM's avatar

@johnbraun @mabdullahsari I tried @willvincent answer but it doesn't work, I mean, it stops the error but when trying to access a model property it returns null, for example $user->name. I tried to call parent::getAttributeValue($value) in the getAttributeValue but it still doesn't work.

edit:

It stops the error, returns the value but the actual enum casting is not working:

    public function getAttributeValue($value)
    {
        $this->enumGetAttributeValue($value);
        $this->translationGetAttributeValue($value);

        return parent::getAttributeValue($value);
    }

    public function setAttribute($key, $value)
    {
        $this->enumSetAttribute($key, $value);
        $this->translationSetAttribute($key, $value);

        return $this;
    }

edit 2:

I used a $value variable, so if the translationGetAttributeValue translates it will return the value, the same with enumGetAttributeValue. I had to change the order tho, if I put the translationGetAttributeValue it will return 1 for some reason.

    public function getAttributeValue($key)
    {
        $value = $this->translationGetAttributeValue($key);
        $value = $this->enumGetAttributeValue($key);

        return $value;
    }

I'm not sure tho how one would affect the other, I think that its always returning the enumGetAttributeValue and not the translationGetAttributeValue. I'm confused.

willvincent's avatar
Level 54

@zefex Actually you'll probably also have to replicate the conditionals from both traits too:

    public function getAttributeValue($value)
    {
        if ($this->isTranslatableAttribute($value)) {
            return translationGetAttributeValue($value);
        }
        if ($this->hasEnumCast($value)) {
            return enumGetAttributeValue($value);
        }
        return parent::getAttributeValue($value);
    }
    public function setAttribute($key, $value)
    {
        if ($this->isTranslatableAttribute($key)) {
            return translationSetAttribute($key, $value);
        }
        if ($value !== null && $this->hasEnumCast($key)) {
            return enumSetAttribute($key, $value);
        }
        return parent::setAttribute($key, $value);
    }

Not sure off hand if $this-> is necessary before calling those aliased trait methods.

mohamed-3ly's avatar

I should put this code in my model where I use the two traits , Right ??

AbehoM's avatar

Now it's working, thank you and yes, $this-> is needed because it's an alias inside a class, meaning it behaves like a method.

willvincent's avatar

Yeah I kind of assumed so, but saw sample code both ways :) and am not currently in a place to putz around with actually writing/testing php code.

chenpion's avatar

@zefex Could you provide full sample code, I'm facing the same issue. I haven't been writing PHP much 😭

Please or to participate in this conversation.