NotionCommotion Posted February 8, 2022 Share Posted February 8, 2022 The previous code that is working shown below along with a pre-persist event listener is used to create an auto-incrementing identifier (called publicId) for each type of entity on a per account/tenant basis. I later had a need to get this publicId before the entity was persisted. This made me consider that I am way overcomplicating matters and should just set this publicId when setting the entities tenant property, and I added the following method: trait HasPublicIdTrait { // other methods // Override parent to set entities publicid. public function setTenant(?Tenant $tenant): self { $this->tenant = $tenant; $tenant->generatePublicId($this); return $this; } } When trying it out, however, I got the following error: Compile Error: Trait method App\Entity\MultiTenenacy\HasPublicIdTrait::setTenant has not been applied as App\Entity\Organization\Vendor::setTenant, because of collision with App\Entity\MultiTenenacy\BelongsToTenantTrait::set Is it possible to make trait methods override other trait methods? Any other suggestions other than just not having AbstractPublicIdTenantEntity extend AbstractPublicIdTenantEntity? PREVIOUS CODE THAT IS WORKING <?php declare(strict_types=1); namespace App\Entity\Organization; use Doctrine\ORM\Mapping as ORM; use App\Repository\Organization\TenantRepository; use App\Entity\MultiTenenacy\HasPublicIdInterface; #[ORM\Entity(repositoryClass: TenantRepository::class)] class Tenant extends AbstractOrganization { #[ORM\Column(type: 'json')] private array $publicIdStack = []; public function publicIdSetter(HasPublicIdInterface $hasPublicId): self { $publicIdIndex = $hasPublicId->getPublicIdIndex(); $this->publicIdStack[$publicIdIndex] = ($this->publicIdStack[$publicIdIndex]??0) + 1; $hasPublicId->setPublicId($this->publicIdStack[$publicIdIndex]); return $this; } } <?php namespace App\Entity\MyEntity; use App\Entity\MultiTenenacy\AbstractPublicIdTenantEntity; class MyEntity extends AbstractPublicIdTenantEntity { public function getPublicIdIndex(): ?string { return 'my-entity'; } } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use App\Entity\Trait\NonIdentifyingIdTrait; abstract class AbstractPublicIdTenantEntity extends AbstractTenantEntity implements HasPublicIdInterface { use NonIdentifyingIdTrait; use HasPublicIdTrait; } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use App\Entity\AbstractEntity; abstract class AbstractTenantEntity extends AbstractEntity implements BelongsToTenantInterface { use BelongsToTenantTrait; } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use App\Entity\Organization\Tenant; use Symfony\Component\Serializer\Annotation\Ignore; trait BelongsToTenantTrait { #[ORM\ManyToOne(targetEntity: Tenant::class)] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] #[Ignore] protected ?Tenant $tenant = null; public function getTenant(): Tenant { return $this->tenant; } public function setTenant(?Tenant $tenant): self { $this->tenant = $tenant; return $this; } } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Serializer\Annotation\Ignore; use App\Entity\Organization\Tenant; #[ORM\UniqueConstraint(columns: ['public_id', 'tenant_id'])] trait HasPublicIdTrait { #[SerializedName('id')] #[Groups(['public_id:read'])] #[ORM\Column(type: 'integer')] protected ?int $publicId = null; public function getPublicId(): ?int { return $this->publicId; } public function setPublicId(int $publicId): HasPublicIdInterface { $this->publicId = $publicId; return $this; } public function generatePublicId(): HasPublicIdInterface { $this->getTenant()->publicIdSetter($this); return $this; } abstract public function getPublicIdIndex(): ?string; } Quote Link to comment https://forums.phpfreaks.com/topic/314530-how-to-override-trait-methods-from-another-trait/ Share on other sites More sharing options...
Solution gizmola Posted February 8, 2022 Solution Share Posted February 8, 2022 In the PHP manual section Traits section. You have 2 options: Alias the conflicting method so it doesn't conflict Specify an "insteadof" method statement in the use section of the class 1 Quote Link to comment https://forums.phpfreaks.com/topic/314530-how-to-override-trait-methods-from-another-trait/#findComment-1593989 Share on other sites More sharing options...
NotionCommotion Posted February 8, 2022 Author Share Posted February 8, 2022 Thanks gizmola, Looks like insteadof is exactly what I want and think/hope the following will do the trick. Not positive, but wouldn't using an alias break an interface? abstract class AbstractPublicIdTenantEntity extends AbstractTenantEntity implements HasPublicIdInterface { use NonIdentifyingIdTrait, HasPublicIdTrait { HasPublicIdTrait::setTenant insteadof NonIdentifyingIdTrait; } // bla bla bla } Quote Link to comment https://forums.phpfreaks.com/topic/314530-how-to-override-trait-methods-from-another-trait/#findComment-1593991 Share on other sites More sharing options...
gizmola Posted February 9, 2022 Share Posted February 9, 2022 I was just laying out the options. In your use case it seems like you would need to use the insteadof. Quote Link to comment https://forums.phpfreaks.com/topic/314530-how-to-override-trait-methods-from-another-trait/#findComment-1593993 Share on other sites More sharing options...
NotionCommotion Posted February 9, 2022 Author Share Posted February 9, 2022 Actually, my earlier code was incorrect. NonIdentifyingIdTrait doesn't have method setTenant() but BelongsToTenantTrait does. When I changed it to the following, I received error: "Compile Error: Required Trait App\Entity\MultiTenenacy\BelongsToTenantTrait wasn't added to App\Entity\MultiTenenacy\AbstractPublicIdTenantEntity abstract class AbstractPublicIdTenantEntity extends AbstractTenantEntity implements HasPublicIdInterface { use NonIdentifyingIdTrait, HasPublicIdTrait { HasPublicIdTrait::setTenant insteadof BelongsToTenantTrait; } } I have since changed it to the following and no longer get the error. Is there any concern about having both AbstractTenantEntity and AbstractPublicIdTenantEntity which extends AbstractTenantEntity use the same trait? abstract class AbstractPublicIdTenantEntity extends AbstractTenantEntity implements HasPublicIdInterface { use NonIdentifyingIdTrait, HasPublicIdTrait, BelongsToTenantTrait { HasPublicIdTrait::setTenant insteadof BelongsToTenantTrait; } } Also, I am rethinking whether aliases might be applicable but am still uncertain of the implications of the following from the docs. It does not rename the method? What does this mean? Quote Since this only allows one to exclude methods, the as operator can be used to add an alias to one of the methods. Note the as operator does not rename the method and it does not affect any other method either. Quote Link to comment https://forums.phpfreaks.com/topic/314530-how-to-override-trait-methods-from-another-trait/#findComment-1594014 Share on other sites More sharing options...
gizmola Posted February 9, 2022 Share Posted February 9, 2022 An Alias only affects the class it is defined in. If I alias a method with "MyTrait::foo as bar" then within that class you would need to use self::bar. Assuming this is in the definition of class A, then the original A::foo would be called. It's worth also noting that if the methods are public, trying to use a trait that has an overlap simply results in the non-inclusion of the trait. <?php trait Basic { public function whichFoo() { return 'basicFoo'; } } class Foo { use Basic; public function whichFoo() { return 'FooFoo'; } } $f = new Foo(); echo $f->whichFoo(); # outputs FooFoo I can see that you are trying to use these to handle relationships between doctrine entities, although I don't really know what these specific id methods are for, but I have to question your approach vs. a more traditional setup, given all the troubles you are having. Quote Link to comment https://forums.phpfreaks.com/topic/314530-how-to-override-trait-methods-from-another-trait/#findComment-1594026 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.