annotated-container icon indicating copy to clipboard operation
annotated-container copied to clipboard

Allow profiles to be assigned a priority

Open cspray opened this issue 2 years ago • 1 comments

Problem

There's currently a drawback when using profiles to resolve multiple aliases. You're required to specify a profile for all concrete services that would be used as an alias for an abstract service. There are scenarios where it would be preferable not to have to declare profiles on every concrete implementation. Take the following example:

<?php

use Cspray\AnnotatedContainer\Attribute\Service;

#[Service]
interface Widget {}

#[Service]
class StandardWidget implements Widget {}

#[Service(profiles: ['test'])
class TestWidget implements Widget {}

In this example the intent of the annotations is that if the list of active profiles includes test we should use TestWidget otherwise we should use the StandardWidget. Right now our implementation doesn't allow this and would require you to specify on the StandardWidget a profile that would be used in all non-test situations, depending on how your profiles are setup this could cause you to list every single profile other than test. This is not a good experience.

Conceptually this problem also exists when needing to disambiguate multiple #[Inject] definitions.

Solution

Whenever we are required to disambiguate multiple aliases or inject definitions we would gather the set of ambiguous definitions. An implicit, per-set priority is assigned to all annotations that make use of profiles. An annotation that does not explicitly set a profile would have a priority of 0. Each explicitly set, active profile would increase the priority for that annotation by 1. If there is a single annotation with the highest priority it would be chosen. If there are multiple annotations with the highest priority we would continue to handle this however the app is currently handling it.

For example, given the code example above, if the active profiles were default, test then the StandardWidget would be given a priority of 0, because it does not explicitly set a profile, and the TestWidget would be given a priority of 1, because it has 1 profile explicitly set. The TestWidget would be used. If the active profiles were default, prod then the StandardWidget would continue to receive a 0 priority but the TestWidget would no longer be a candidate, because the active profiles would preclude it.

cspray avatar May 15 '22 02:05 cspray