Skip to content

[DI] Optional class for named services #21133

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

Merged
merged 2 commits into from
Jan 7, 2017

Conversation

nicolas-grekas
Copy link
Member

@nicolas-grekas nicolas-grekas commented Jan 2, 2017

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets -
License MIT
Doc PR -

Continues #20264:

From @hason:

I prefer class named services (in applications) because naming things are too hard:

services:
    Vendor\Namespace\Class:
        class: Vendor\Namespace\Class
        autowire: true

This PR solves redundant parameter for class:

services:
    Vendor\Namespace\Class:
        autowire: true

Inspirations: https://laravel.com/docs/5.3/container, #18268, http://php-di.org/,

@@ -29,6 +42,9 @@ public function process(ContainerBuilder $container)
if (!method_exists(\ReflectionMethod::class, 'getReturnType')) {
return;
}
if (null !== $this->resolveClassPass) {
$this->resolveClassPassChanges = $this->resolveClassPass->getChanges();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this property should be reset at the end of processing to release memory

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you forget to push the change or do I miss something? I don't see where it is reset.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saw it now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in fact, I removed the property completely for a local variable instead

@nicolas-grekas nicolas-grekas force-pushed the class-service branch 2 times, most recently from af7dfda to 5def4a7 Compare January 2, 2017 16:09
*
* @return string
*/
public function getCaseFullId($id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about getRawId() or getOriginalId()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bof :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But does case full id really exists in english ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, if anything it should be casefullId (or getCasefullId). But I like @theofidry's caseSensitiveId more 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to caseSensitive


if ($this->isFrozen() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
// setting a synthetic service on a frozen container is alright
throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a frozen container is not allowed.', $id));
}

unset($this->definitions[$id], $this->aliasDefinitions[$id]);
if ($id !== $caseFullId) {
$this->caseFullIds[$id] = $caseFullId;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

caseSensitiveIds?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 seems more obvious what is meant

@@ -101,6 +101,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
private $envCounters = array();

/**
* @var string[] A map of case less to case full ids
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string[] does not cover arrays where keys are no integers, does it?

@@ -837,6 +854,20 @@ public function findDefinition($id)
}

/**
* Returns the case full id used at registration time if any.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove the "if any" part because we always return the id that was used when defining the definition. This makes it look likenull might be returned in some cases too.

@nicolas-grekas nicolas-grekas force-pushed the class-service branch 4 times, most recently from f18bbe7 to 1d766ab Compare January 3, 2017 08:18
@nicolas-grekas nicolas-grekas changed the title [DI] Optional class for class named services [DI] Optional class for named services Jan 3, 2017
@nicolas-grekas nicolas-grekas force-pushed the class-service branch 3 times, most recently from 4b7cd67 to 01afe39 Compare January 3, 2017 08:44
@@ -301,7 +301,7 @@ private function processAnonymousServices(\DOMDocument $xml, $file)
if (false !== $nodes = $xpath->query('//container:argument[@type="service"][not(@id)]|//container:property[@type="service"][not(@id)]')) {
foreach ($nodes as $node) {
// give it a unique name
$id = sprintf('%s_%d', hash('sha256', $file), ++$count);
$id = sprintf('%d_%s', ++$count, hash('sha256', $file));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just made these changes so that anonymous classes won't have their class set to a random string (+ added corresponding regexp check in ResolveClassPass)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why hashing it? Wouldn't it be more explicit with the plain file name?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not related to this PR :)

if ($definition instanceof ChildDefinition || $definition->isSynthetic() || null !== $definition->getClass()) {
continue;
}
if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $id)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be covered by a test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

covered now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you 👍

@nicolas-grekas nicolas-grekas force-pushed the class-service branch 2 times, most recently from 68e9588 to 405b151 Compare January 3, 2017 17:39
@@ -638,6 +648,9 @@ public function setAlias($alias, $id)
}

unset($this->definitions[$alias]);
if ($alias !== $caseSensitiveAlias) {
$this->caseSensitiveIds[$alias] = $caseSensitiveAlias;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need the entry for aliases or could we just remove existing entries here?

Copy link
Member Author

@nicolas-grekas nicolas-grekas Jan 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For completeness yes: we track any id, wherever it comes from

@xabbuh
Copy link
Member

xabbuh commented Jan 3, 2017

👍

Status: Reviewed

@@ -364,14 +369,18 @@ public function getCompiler()
*/
public function set($id, $service)
{
$id = strtolower($id);
$caseSensitiveId = (string) $id;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you add a cast here?

Copy link
Member

@wouterj wouterj Jan 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably to be BC with the previous behaviour: It was possible to pass e.g. an object with __toString() as $id as strtolower() cast everything to a string.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that's the reason, I would revert this as $id is documented as being a string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted

@fabpot
Copy link
Member

fabpot commented Jan 7, 2017

Thank you @nicolas-grekas.

@fabpot fabpot merged commit a18c4b6 into symfony:master Jan 7, 2017
fabpot added a commit that referenced this pull request Jan 7, 2017
…-grekas)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DI] Optional class for named services

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

Continues #20264:
- makes the id-to-class mapping context-free (no `class_exist` check),
- deals with ChildDefinition (which should not have this rule applied on them),
- deprecates FactoryReturnTypePass as discussed on slack and reported in this comment: #19191 (comment)

From @hason:

> I prefer class named services (in applications) because naming things are too hard:

``` yaml
services:
    Vendor\Namespace\Class:
        class: Vendor\Namespace\Class
        autowire: true
```

> This PR solves redundant parameter for class:

``` yaml
services:
    Vendor\Namespace\Class:
        autowire: true
```

> Inspirations: https://laravel.com/docs/5.3/container, #18268, http://php-di.org/,

Commits
-------

a18c4b6 [DI] Add tests for class named services
71b17c7 [DI] Optional class for named services
@nicolas-grekas nicolas-grekas deleted the class-service branch January 7, 2017 16:32
@wouterj
Copy link
Member

wouterj commented Jan 7, 2017

Fyi, created a doc issue for this great feature: symfony/symfony-docs#7329

fabpot added a commit that referenced this pull request Jan 8, 2017
…tainer pass list (fabpot)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DependencyInjection] moved up ResolveClassPass in the container pass list

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | bug from #21133
| License       | MIT
| Doc PR        | n/a

Some compiler passes need access to the service class names. But when using an empty class name (the service id being the class name), the resolution happens too late (during the optimization step). This PR fixes this by moving up the ResolveClassPass earlier in the stack.

Commits
-------

2e5b69f [DependencyInjection] moved up ResolveClassPass in the container pass list
fabpot added a commit that referenced this pull request Jan 23, 2017
…izanagi)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DI] Add Yaml syntax for short services definition

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | N/A
| License       | MIT
| Doc PR        | todo

In my experience, most (at least, a lot) of the service definitions in an end-application only require the class and constructor arguments.

#21133 allows to get rid of the `class` attribute by using the service id.
Which means only arguments remain for most use-cases. Hence, we could support this syntax:

#### Before:

```yml
services:
    App\Foo\Bar:
        arguments: ['@baz', 'foo', '%qux%']
```

#### After:

```yml
services:
    App\Foo\Bar: ['@baz', 'foo', '%qux%']
```

It works especially well along with services `_defaults` introduced in #21071 :

```yml
services:
    _defaults:
        public: false
        autowire: ['set*']
        tags: ['serializer.normalizer']

    App\Serializer\FooNormalizer: ['@baz', 'foo', '%qux%']
```

Commits
-------

83b599c [DI] Add Yaml syntax for short services definition
@fabpot fabpot mentioned this pull request May 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.