Skip to content

Conversation

@dg
Copy link
Member

@dg dg commented Oct 3, 2018

Autowiring of array of Service this way: (BC break)

class Foo
{
	public $services;

	/**
	 * @param Service[] $services
	 */
	public function __construct(array $services)
	{
		$this->services = $services;
	}
}

@f3l1x
Copy link
Member

f3l1x commented Oct 3, 2018

So simple. 👍

@dg dg changed the title autowiring via Service[] (experimental) autowiring via Service[] (WIP) Oct 3, 2018
@dg dg force-pushed the autowire-collection branch 2 times, most recently from 4700fe0 to a2cec9c Compare October 3, 2018 12:05
@dg dg force-pushed the autowire-collection branch 3 times, most recently from 73cff52 to 9144555 Compare October 3, 2018 13:29
@milo
Copy link
Member

milo commented Oct 3, 2018

This is definetly time saver!

@milo
Copy link
Member

milo commented Oct 3, 2018

Without this (and previous tags() & types() commit), I'm solving it by extension. I have collections like:

class MyCollection
{
    public function add(MyInterface $service) {...}
}

and this DI extension which, in a short, finds all services of MyInterface type in container and creates MyCollection service with add() calls.

With proposed syntax, I don't need the extension anymore, because this collections have static factory createFromArray(array $items) too 👍

@enumag
Copy link
Contributor

enumag commented Oct 3, 2018

I'm solving it with this package which is much more powerful. This only solves the most simple use-case so it's not nearly enough for me.

@dg
Copy link
Member Author

dg commented Oct 3, 2018

@enumag Can you describe what it does?

@enumag
Copy link
Contributor

enumag commented Oct 3, 2018

@dg Sure. Basically when dealing with multiple services of the same type there are two use-cases:

  1. You need all of them because you need to "chain" them - run the same thing on all of them and collect the results. This is what you're solving here. My package does it too, but I'm using an Iterator instead of an array (that's a non-important detail). In my case the services need to be tagged and you can't simply autowire the iterator either so you definitely win here.

  2. Second use-case (and the reason why I wrote the package) is when you need some sort of a delegator to call specific implementation as needed. So the delegator only needs to call one or a few of the implementations, not all of them. Injecting an array is a no-go here because you want those services to be loaded lazily. So the package creates a callback (resolver) that can return a specific implementation based on some name. I've used this feature many times.

When integrating symfony/form to nette I also needed a third case which is in fact a combination of the first two - a resolver that returns an iterator of services. This was necessary for FormTypeExtensions - each FormType in symfony can have multiple FormTypeExtensions.


I realize it's not really too related to this PR, I just want to point out the fact that you rarely need all the services of the same type. The second use-case is much more common from my experience. You might want to consider addressing it too in the future.

@dg dg force-pushed the master branch 2 times, most recently from 1fc7645 to 485a875 Compare October 3, 2018 16:24
@dg
Copy link
Member Author

dg commented Oct 3, 2018

Point 2 looks useful, it is good idea to have multiple form of accessor.

interface DbAccessor
{
	function get(): Db; 
	// and allow this too:
	function get($name): Db
}

There should be enumeration of services in configuration, ie.:

services:
	- DbAccessor(
		name1: @a
		name2: @b
	)
	a: Db('***')
	b: Db('***')
	c: Db('***')

@enumag
Copy link
Contributor

enumag commented Oct 3, 2018

Personally I prefer configuration with tags (the name is a tag attribute) instead of inventing some new syntax but that's a detail.

Which service would the function get(): Db; return? I don't see a reason to allow calling it without argument...

@dg
Copy link
Member Author

dg commented Oct 3, 2018

Currently there si supported this syntax

services:
	- DbAccessor(@a)

so it is only enhancement. Tags seems like another good way.

@enumag
Copy link
Contributor

enumag commented Oct 3, 2018

Oh, right, forgot about that. Yeah this seems like a good improvement. 👍

@dg dg force-pushed the autowire-collection branch from 9144555 to a96c6b4 Compare October 3, 2018 17:48
@dg dg added this to the v3.0 milestone Oct 3, 2018
@dg dg force-pushed the autowire-collection branch from a96c6b4 to 36162f3 Compare October 4, 2018 11:21
@dg dg force-pushed the autowire-collection branch from 36162f3 to d1c0598 Compare October 4, 2018 11:46
@dg dg force-pushed the master branch 2 times, most recently from a27a10b to 594a33a Compare October 5, 2018 18:18
@TomasVotruba
Copy link
Contributor

TomasVotruba commented Oct 6, 2018

I tried to implement this feature in Symfony, where it's hard to get into config yaml parsing or hack into autowiring.

https://github.com/rectorphp/rector/pull/660/files#diff-6303621e84b7d6786a9fd24b8c2be71d

Let's see how it works in practice :) thanks for inspiration

@dg dg force-pushed the autowire-collection branch from ff55601 to 9a49252 Compare October 23, 2018 16:34
@dg dg merged commit 1342085 into nette:master Oct 23, 2018
@dg dg deleted the autowire-collection branch October 23, 2018 16:35
dg added a commit that referenced this pull request Oct 23, 2018
dg added a commit that referenced this pull request Oct 23, 2018
dg added a commit that referenced this pull request Oct 24, 2018
dg added a commit that referenced this pull request Oct 24, 2018
dg added a commit that referenced this pull request Oct 25, 2018
dg added a commit that referenced this pull request Oct 25, 2018
dg added a commit that referenced this pull request Oct 25, 2018
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.

5 participants