Skip to content

Templated ServiceLocator to be used for tagged services #248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

zmitic
Copy link
Contributor

@zmitic zmitic commented Apr 7, 2022

With service locator anti-pattern being deprecated long ago, we can now use ServiceLocator class for tagged services. If you check compiler passes, it is only used for that anyway.

Use case:


Tagged services must have interface. So fictional exporter:

#[AutoconfigureTag(name: self::class)]
interface ExporterInterface
{
    public static function getName(): string;

    public function export(User $user): string;
}

Simple implementation:

class JsonExporter implements ExporterInterface
{
    public static function getName(): string
    {
		return 'json';	
    }

    public function export(User $user): string
	{
		// convert $user to json string
	}
}

Real usage with autowiring (other cases also work in 100% same way):

class Exporter
{
    /**
     * @param ServiceLocator<ExporterInterface> $strategies
     */
    public function __construct(
        #[TaggedLocator(tag: ExporterInterface::class, defaultIndexMethod: 'getName')]
        private ServiceLocator $strategies,
    )
    {
    }

    public function export(User $user, string $name): string
    {
        $exporter = $this->strategies->get($name); // psalm now knows it is instance of ExporterInterface
        
        return $exporter->export($user);
    }
}

So in the above case, site visitors would pick name via some dropdown or button, and that value sent to Exporter class.

Potential problem:

None found for last 6+ months. The only issue I can think of is if someone uses ServiceLocator class in undocumented ways.

I.e. Symfony still allows public services but they are discouraged, and all documentation is using ContainerInterface; something that ServiceLocator extends.

But after testing it for long time, I think it is safe to stub it.

Updated:

This is the feature I mentioned, if someone is not familiar with it: symfony/symfony#39924

@zmitic
Copy link
Contributor Author

zmitic commented May 14, 2022

@seferov @VincentLanglet

Can you guys take a look at idea? Do you think it is worth it?

@VincentLanglet
Copy link
Contributor

Can you guys take a look at idea? Do you think it is worth it?

Symfony project started to add some template in their code. For instance: symfony/symfony#45696.
I think you should try to make the PR on this repo first.
The more generic are added to symfony the less work it five for plugins maintainer.

Moreover, every new generic added to psalm repository, need to be added to phpstan repository too (for developers which are using both tools). So it simpler if it's on symfony repo.

@zmitic
Copy link
Contributor Author

zmitic commented May 14, 2022

@VincentLanglet Agreed, but how do you test it? Are those even needed?

@VincentLanglet
Copy link
Contributor

@VincentLanglet Agreed, but how do you test it? Are those even needed?

Your example

class Exporter
{
    /**
     * @param ServiceLocator<ExporterInterface> $strategies
     */
    public function __construct(
        #[TaggedLocator(tag: ExporterInterface::class, defaultIndexMethod: 'getName')]
        private ServiceLocator $strategies,
    )
    {
    }

    public function export(User $user, string $name): string
    {
        $exporter = $this->strategies->get($name); // psalm now knows it is instance of ExporterInterface
        
        return $exporter->export($user);
    }
}

seems to be a good one.

So a template T of object might be ok.

@weirdan weirdan mentioned this pull request Oct 28, 2022
@zmitic zmitic closed this Jan 4, 2024
@zmitic zmitic deleted the service-locator branch January 4, 2024 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants