phpstan-symfony icon indicating copy to clipboard operation
phpstan-symfony copied to clipboard

Support `#[AutowireLocator]`

Open mvhirsch opened this issue 1 year ago • 4 comments

Symfony 6.4 introduced an attribute called #[AutowireLocator] which automatically creates and injects a ServiceLocator into a service. Looks like a similar feature was already implemented with #151.

Is it possible to add support for this feature, too?

final class TranscriptAdmin
{
   // ...

    #[Required]
    public function setContainer(
        #[AutowireLocator([ProfileRepository::class])] ContainerInterface $container
    ): void {
        $this->locator = $container;
    }
}
 ------ ---------------------------------------------------------------------- 
  Line   src/TranscriptBundle/Admin/TranscriptAdmin.php                        
 ------ ---------------------------------------------------------------------- 
  56     Service "App\ProfileBundle\Repository\ProfileRepository" is private.  
         ✏️  src/TranscriptBundle/Admin/TranscriptAdmin.php                    
 ------ ---------------------------------------------------------------------- 

mvhirsch avatar Oct 07 '24 06:10 mvhirsch

The current workaround is to use // @phpstan-ignore symfonyContainer.privateService above the line where we use $this->locator->get. Of course this is not a nice solution.

Looking at https://github.com/phpstan/phpstan-symfony/blob/1ef4dce2baabd464c2dd3109d051bad94efa1e79/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php and #151 it shouldn't be very hard to implement a fix, unfortunately I currently don't have time for that.

RafaelKr avatar Dec 30 '24 14:12 RafaelKr

I just implemented support for the basic syntax as described in the OP (#[AutowireLocator([ProfileRepository::class])]). See https://github.com/phpstan/phpstan-symfony/pull/420

RafaelKr avatar Dec 30 '24 17:12 RafaelKr

I actually took the time and implemented AutowireLocator attribute support in #420 Currently there are some failing checks I can't resolve, but besides from that everything should be ready!

RafaelKr avatar Jan 03 '25 20:01 RafaelKr

I have the same problem, but instead of defining specific services, I use a tag instead, so the container contains all services with this tag. This is also allowed by Symfony and the services don't have to be public to access them this way through this limited container. Could you consider this kind of usage too when fixing the issue? Thanks a lot!

#[AutoconfigureTag('app.some_tag')]
interface SomeInterface { }

class SomeServiceA implements SomeInterface { }
class SomeServiceB implements SomeInterface { public function doSomething(): void { } }
class SomeServiceC implements SomeInterface { }

class MainService {
    public function __construct(
        #[AutowireLocator('app.some_tag')]
        private ContainerInterface $myServices,
    ) { }

    public function someMethod(): void {
        $this->myServices->get(SomeServiceB::class)->doSomething();
    }
}

byWulf avatar Jan 16 '25 14:01 byWulf