NotionCommotion Posted June 12, 2021 Share Posted June 12, 2021 Haven't really used traits much and am confused whether to import other classes in the trait or the class that uses the trait (might also be an annotation question but not sure). Must import statements (i.e. use Foo\Bar;) be included in the class or can they be included in just the trait which is used by a class? Does it depend and if so on what? Does having one class use another class impact the decision? Is it okay for one trait to use another and another trait to just use the first trait or should it use both? What is odd is I apparently must (to not get an error) import ApiProperty to the trait but doing so is not required for the class, and must import Groups, SerializedName, and Mapping in the class but doing so is not required for the trait. Instead of just a yes/no answer, would appreciate an explanation why it is what it is. Thanks! <?php namespace App\Entity\Document; use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; use App\Entity\MultiTenenacy\PublicIdTenantTrait; // Must Groups, SerializedName, Owner be imported in this class or just PublicIdTenantTrait // use Symfony\Component\Serializer\Annotation\Groups; // use Symfony\Component\Serializer\Annotation\SerializedName;use // use App\Entity\Owner\Owner; /** * @ORM\Entity() * @ApiResource() */ class Document { use PublicIdTenantTrait; } <?php namespace App\Entity\MultiTenenacy; use ApiPlatform\Core\Annotation\ApiProperty; use Doctrine\ORM\Mapping as ORM; trait PublicIdTenantTrait { use PublicIdExtendedTenantTrait; /** * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") * @ApiProperty(identifier=false) * @ORM\Column(type="integer") */ private $id; public function getId(): ?int { return $this->id; } } <?php namespace App\Entity\MultiTenenacy; use ApiPlatform\Core\Annotation\ApiProperty; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; use Doctrine\ORM\Mapping as ORM; trait PublicIdExtendedTenantTrait { use TenantTrait; /** * @ORM\Column(type="integer") * @ApiProperty(identifier=true) * @Groups({"tenant_entity:read"}) * @SerializedName("id") */ private $publicId; public function getPublicId(): ?int { return $this->publicId; } public function setPublicId(int $publicId): PublicIdTenantInterface { $this->publicId = $publicId; return $this; } public function generatePublicId(): PublicIdTenantInterface { $this->getOwner()->setPublicId($this); return $this; } public function getPublicIdTag(): string { return lcfirst((new \ReflectionClass($this))->getShortName()).'Id'; } } <?php namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use App\Entity\Owner\Owner; trait TenantTrait { /** * inversedBy performed in child where required * @ORM\ManyToOne(targetEntity=Owner::class) * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ private $owner; public function getOwner(): ?Owner { return $this->owner; } public function setOwner(?Owner $owner): TenantInterface { $this->owner = $owner; return $this; } } Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/ Share on other sites More sharing options...
requinix Posted June 12, 2021 Share Posted June 12, 2021 This is a "try it and find out" situation. If you've tried it and discovered that the use statements in the trait's file can be picked up by the annotation parser then there's your answer. Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587183 Share on other sites More sharing options...
NotionCommotion Posted June 13, 2021 Author Share Posted June 13, 2021 18 hours ago, requinix said: This is a "try it and find out" situation. If you've tried it and discovered that the use statements in the trait's file can be picked up by the annotation parser then there's your answer. Thanks requinix, Appears that imports for non-annotation purposes (i.e. type declaration, creating a new object) should be located in the file where they are being used, right? For annotation purposes, sounds like it is based on how the given application's author elected to write the application, true? Is there any approach that is more typical than the other? Does it make sense to always import in both the trait and the class? Do you know whether PHP 8's attributes are independent of the application? Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587188 Share on other sites More sharing options...
requinix Posted June 13, 2021 Share Posted June 13, 2021 7 hours ago, NotionCommotion said: Appears that imports for non-annotation purposes (i.e. type declaration, creating a new object) should be located in the file where they are being used, right? As far as PHP is concerned, yeah. That's how they work. It's what they do. It wouldn't make sense to put them in other files. 7 hours ago, NotionCommotion said: For annotation purposes, sounds like it is based on how the given application's author elected to write the application, true? Is there any approach that is more typical than the other? Does it make sense to always import in both the trait and the class? If use statements are supported for annotations (they are) and if the parser is smart enough to grab those from the trait's definition rather than the class using the trait (apparently it is) then that means use statements for annotations work the same way as regular use statements. There is no question about "approaches". Use statements do what they do for code and also annotations. You can make use of them or not, and putting them in other files where they won't do anything is pointless. 7 hours ago, NotionCommotion said: Do you know whether PHP 8's attributes are independent of the application? What "application"? Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587194 Share on other sites More sharing options...
NotionCommotion Posted June 21, 2021 Author Share Posted June 21, 2021 On 6/13/2021 at 4:31 PM, requinix said: There is no question about "approaches". Use statements do what they do for code and also annotations. You can make use of them or not, and putting them in other files where they won't do anything is pointless. What "application"? The "application" I was referring to is Symfony and/or Doctrine. Take the following class which uses the traits posted in my original post: <?php namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; use App\Entity\Owner\Owner; /** * @ORM\Entity() */ class Test { use PublicIdTenantTrait; /** * @ORM\Column(type="string", length=255) */ private $name; } When checking the schema, all validates. But then I comment out the use input statements for Groups, SerializedName, and Owner, and get an error that I didn't use a "use" statement for Groups. I add back Groups, but then get it for SerializedName. I add back SerializedName and then get it for Owner. Nowhere in the Test class am I using any of these classes and only in the traits that I do, but still I get these errors. [michael@devserver api2]$ bin/console doctrine:schema:validate In AnnotationException.php line 39: [Semantical Error] The annotation "@Groups" in property App\Entity\MultiTenenacy\Test::$publicId was never imported. Did you maybe forget to add a "use" statement for this annotation? [michael@devserver api2]$ bin/console doctrine:schema:validate In AnnotationException.php line 39: [Semantical Error] The annotation "@SerializedName" in property App\Entity\MultiTenenacy\Test::$publicId was never imported. Did you maybe forget to add a "use" statement for this annotation? [michael@devserver api2]$ bin/console doctrine:schema:validate Mapping ------- In MappingException.php line 870: The target-entity App\Entity\MultiTenenacy\Owner cannot be found in 'App\Entity\MultiTenenacy\Test#owner'. doctrine:schema:validate [--em EM] [--skip-mapping] [--skip-sync] [michael@devserver api2]$ So, then I put them back in the Test class, and remove them from the traits, and have no errors. And then I remove the import for ApiProperty in the trait and get an error. [michael@devserver api2]$ bin/console doctrine:schema:validate In AnnotationException.php line 39: [Semantical Error] The annotation "@ApiProperty" in property App\Entity\MultiTenenacy\Test::$id was never imported. Did you maybe forget to add a "use" statement for this annotation? [michael@devserver api2]$ I then add ApiProperty to the Test class and then no errors. I see no pattern and am discovering these issues by just trial and error, but there has to be a reason, no? Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587421 Share on other sites More sharing options...
requinix Posted June 21, 2021 Share Posted June 21, 2021 Are you saying that in one situation, having the imports in the trait file and not the class file works, but in another situation the same arrangement does not work? Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587431 Share on other sites More sharing options...
NotionCommotion Posted June 21, 2021 Author Share Posted June 21, 2021 2 hours ago, requinix said: Are you saying that in one situation, having the imports in the trait file and not the class file works, but in another situation the same arrangement does not work? Yes! When you commented about the "parser", is this PHP's C code or PHP application code part of a given framework (i.e. Doctrine, Symfony)? If the later, I could see how one might get different results, but would not expect these two frameworks to implement it differently. Also, you will see that the traits provided in the original post use other traits. It is my understanding that doing so is acceptable but maybe I am not doing so correctly? On 6/12/2021 at 11:40 AM, NotionCommotion said: What is odd is I apparently must (to not get an error) import ApiProperty to the trait but doing so is not required for the class, and must import Groups, SerializedName, and Mapping in the class but doing so is not required for the trait. Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587440 Share on other sites More sharing options...
requinix Posted June 21, 2021 Share Posted June 21, 2021 PHP does not parse /** */ docblocks. That's Doctrine/Symfony (I forget which one technically does the annotation support). But code doesn't behave randomly so there must be some difference between the situation that works and the one that does not. Either way, the answer is the same: don't import stuff you don't need, do import stuff you do need. Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587442 Share on other sites More sharing options...
NotionCommotion Posted June 22, 2021 Author Share Posted June 22, 2021 Agree, code thankfully doesn't behave randomly, only me! Also, agree I shouldn't import stuff I don't need, but frustrating that there appears to be no way to determine whether stuff is needed other than trial and error. Back to earlier question, you think PHP8 attributes might be more consistent (assuming the framework supports them)? If you don't know, have what I need. Thanks Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587443 Share on other sites More sharing options...
requinix Posted June 22, 2021 Share Posted June 22, 2021 3 hours ago, NotionCommotion said: Also, agree I shouldn't import stuff I don't need, but frustrating that there appears to be no way to determine whether stuff is needed other than trial and error. There could also be a bug with annotation support. It really should not be that inconsistent - unless there's some kind of technical limitation. 3 hours ago, NotionCommotion said: Back to earlier question, you think PHP8 attributes might be more consistent (assuming the framework supports them)? Probably. Quote Link to comment https://forums.phpfreaks.com/topic/312898-how-should-importing-classes-be-used-when-using-traits/#findComment-1587446 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.