Hi @cherifGsoul There's no pattern, at least none that I know of. I personnally split the directives in 4 files, based on the "type" of them.
return array_merge(
include 'sections/10-values.php',
include 'sections/20-preferences.php',
include 'sections/30-definitions.php',
include 'sections/40-virtual.php'
);
Where "preferences", "definitions" and "virtual" are derived from what you can find in Magento 2 (just because I'm used to it).
'app.base_url' => "some_value"
\App\BootstrapInterface::class => \DI\get(\App\Bootstrap::class)
\App\Bootstrap::class => \DI\autowire()->constructorParameter(...)
'App\ApiBootstrap::class => \DI\autowire(\App\Bootstrap::class)->constructorParameter(...)
I Also do not understand https://php-di.org/doc/definition-overriding.html#decorators chronology. Are the two snippets from different files?
I'd have thought having the same array key, that the definitions would overwrite. I think this might be why they are shown as they are, separate arrays, but something to confirm this would be nice.
For example, could I use this syntax with add if singular? or is addDefinitions the only way this works?
ContainerBuilder::enableCompilation()
it says for the parameter $containerClass
: "Name of the compiled class. Customize only if necessary". Is there any downside in deviating from the default class name, or why does it say to only do that if necessary? The reason is that I would like to have two different containers, which obviously will need to compile to two different filenames.
Hi, I'm having some issues and I'm not sure what I'm doing wrong.
I've got a class "DeclaredDependencyAggregator" which depends on an interface. That interface is registered in the definitions with an implementation. The implementation has dependencies. DI is failing to find the implementation dependencies through auto-wiring, which are also registered.
Here's a lean version of the container build:
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions(
[
Composer::class => $this->getComposer(true),
ComposerScopeDeterminer::class => create(ComposerScopeDeterminer::class)
->property('scope', $composerScope),
ScopeDeterminerInterface::class => create(ComposerScopeDeterminer::class),
]
);
$container = $containerBuilder->build();
Here's a lean version of the error message:
Entry "Navarr\Depends\Command\WhyBlockCommand" cannot be resolved: Entry "Navarr\Depends\DeclaredDependencyAggregator" cannot be resolved: Entry "Navarr\Depends\ScopeDeterminer\ScopeDeterminerInterface" cannot be resolved: Parameter $composer of __construct() has no value defined or guessable
Full definition:
Object (
class = Navarr\Depends\ScopeDeterminer\ComposerScopeDeterminer
lazy = false
)
Here's what ComposerScopeDeterminer's constructor looks like:
public function __construct(
Composer $composer,
PhpFileDeterminer $phpFileDeterminer,
#[ExpectedValues(valuesFromClass: ComposerScopeDeterminer::class)]
int $scope = self::SCOPE_PROJECT_ONLY
) {
EDIT: Wherever I was using create I should've been using autowire. I clicked an earlier link, seemingly unrelated, saw the syntax, and decided to try that.
Hi, I'm coming from a Java/Spring background. There was a super useful feature in Spring that would let you autowire/inject all implementing classes of an interface like this https://www.baeldung.com/spring-injecting-collections#reference
I was hoping to find some way in PHP-DI to do the same thing. Was planning on using this in an AMQP Message Router. Have some MessageHandler interface which has a canHandle(string)
method and the message router would basically loop through all of those and see if a certain message type could be handled. I was hoping to avoid having to autowire
each individual implementation. Any idea on how I could do something like this, or am I just trying to do something that really isn't in the wheelhouse of PHP-DI?
@autohausen You could use a LoggerFactory for this specific class.
This would require me to use the param-name instead of the interface-name.
Example:
MyClass::class => \DI\autowire()
->constructorParameter('log', MyLogger::class)
I don't like that solution because I have to use class internals within my di-config. Something like that would be much better:
MyClass::class => \DI\autowire()
->override(LoggerInterface::class, MyLogger::class)
I checked the docs but it seems php-di does not support that approach. Anyways. I will stick with the factory approach :-/
Since I try to solve my issue with the factory approach, there is another question: is there a way to get the "target class" within the factory? There is a \DI\Factory\RequestedEntry but this just provides the name of the requested interface (i.e. LoggerInterface). I'd like to somehow get the name of the class requesting that dependency (in my case this would be MyClass::class).
Is that possible somehow?
@odan Thanks for your reply. Injecting a LoggerFactory into my "business" classes moves the configuration and the complexity to the wrong place. My classes just depend on \Psr\Log\LoggerInterface. Anything else is bad design imho.
I decided to stick with this solution:
Convention: always call the ctor-param $log (yikes)
Set the custom logger by explicitly defining the ctor-param:
SomeService::class => \DI\autowire()
->constructorParameter('log', \DI\factory(function(LoggerFactory $loggerFactory){
return $loggerFactory->create('/var/log/my.log');
})),
I don't like it that much, but ey - it works.