On #2148255: [meta] Make better D8 api.d.o landing page, linked to high-level overview topics, and put it in Core api.php files, we made a patch that included a stub Topic page for api.drupal.org (i.e., a @defgroup) titled:
Services and Dependency Injection Container
This can be found in file core/modules/system/core.api.php where it says
@defgroup container
The documentation to go on this page needs to be written. The idea is:
a) Write a few paragraphs about the topic.
b) Link to more detailed documentation on
https://drupal.org/developing/api/8
c) If the more detailed documentation does not yet exist, create stub page(s), link to the stub pages, and add a note to this issue stating that the stub pages need to be filled out.
d) If the topic has related classes, interfaces, and functions -- appropriate for an overview -- add
@ingroup container
to their documentation headers. That will make these classes etc. show up on the Topic page on api.drupal.org. Only include classes/functions that are appropriate for an overview page please!
For more info -- documentation standards for @defgroup/@ingroup:
https://drupal.org/coding-standards/docs#defgroup
Comment | File | Size | Author |
---|---|---|---|
#15 | 2216551-container-docs-15.patch | 12.88 KB | jhodgdon |
#13 | interdiff.txt | 2.28 KB | jhodgdon |
#13 | 2216551-container-docs-13.patch | 12.88 KB | jhodgdon |
#11 | 2216551-container-docs-11.patch | 12.8 KB | jhodgdon |
Comments
Comment #1
jhodgdonI'm taking this on...
Comment #2
jhodgdonHere's a first draft patch.
One note: the section on "discovering" says that api.drupal.org generates a list of services. This is not quite true yet -- the API module has this feature in the -dev version and it has not been deployed to api.drupal.org yet. I expect it to be deployed sometime in the next week or two, so I think it's OK to go ahead and refer to it in the documentation now. Hopefully. :)
Comment #3
joachim CreditAttribution: joachim commentedA few comments based on a read-through as a developer who's fairly new to the topic -- hence can't vouch for accuracy. (Though seems to match up with the little I know!)
I don't think a topic needs to say it's 'information about...'? That's implicit, surely?
This seems to imply that providing a class is optional. Is it?
If not, I would syggest:
'A service [...] is provided by Drupal core of a module by defining the service [in a .yml file?] and a default class [...]'
I don't think we need the quotes here.
Maybe call it *.services.yml?
Machine name: prefixed with module name? and by convention?
Machine name is presumably what you use when you want to access the service. Could do with a mention here?
Some explanation of the syntax for the arguments is needed. What does the @ mean?
Should be made clear that service.name is the machine name mentioned earlier. Or is the 'service' part a special prefix?
I don't think we need quotes here.
Comment #4
jhodgdonThanks for the review in comment #3! I think I've addressed most of your comments.
Comment #5
BerdirShouldn't this be added to ServiceProviderInterface then too?
And CoreServiceProvider might be an interesting example to look at, so add that too?
There are common exceptions to the prefix by module rule, certain similar things share a common prefix, for example, all cache bins are registered as cache.name_of_the_bin, and most plugin managers are named plugin.manager.something.
Should probably at least mention that instead of defining a class, it's also possible to define a factory class or service, the cache bins are a good example for that, and then refer to some documentation?
There are multiple different create() methods and they only work when that class implements the corresponding interface. Different interfaces are needed because they have different arguments:
ContainerInjectionInterface: just the container, for forms and controllers
ContainerDerivativeInterface: for plugin derivatives, container + base plugin id
ContainerFactoryPluginInterface: for plugins, receives container, $configuration, $plugin_id and $definition
EntityControllerInterface: $container and $entity_type, named createInstance() due to a name clash with the create() method on entity storage classes.
Mentioning them all here might be too long, but it should be mentioned that the right interface needs to be implemented, maybe they can be added to a documentation page?
Might be worth mentioning here why we bother with the create() stuff and constructor injection if this is so easy: This makes your code dependent on the container itself which makes it harder to write unit tests for your code. The service() is also less useful for IDE autocomplete and self-documentation, constructor injection allows to enforce the right thing with interface type hints.
It's technically also a service locator pattern when used like that and not dependency injection (nothing is injected, it's fetched). The difference to the create method is that calling that method is optional, in a unit test for example, you can directly call the constructor.
Should this also mention that services can be defined dynamically in a service provider? See CoreServiceProvider.
There are a few things that are only possible there, for example compiler passes.
Speaking of those, a concept that is unclear to many is what tags do. I think a chapter that quicky explains what they are and commonly used tags would be very useful here.
short version:
Tagged services can be discovered/queried in a so called compiler pass while the container is built. See CoreServiceProvider::register(). They don't do anything on their own, it completely depends on the compiler pass that is doing something with them. Most of the time, tags come with a corresponding interface that such a service must implement.
common:
- event_subscriber: Needed by event subscribers, not sure if that should be a completely separate topic to explain in depth, as it's fairly important.
- access_check: Used for route access checks, additionally contains the name that is then used in the route requirements definition.
- cache.bin: Must be added to cache bin services, so that cache clear all and cache bin removal on module uninstallation works.
- needs_destruction: Can be used if a service wants to be called at the end of a request if he was initialized. For example writing a cache that was collected during a request.
Do we really need to document this here? There's nothing special about that, you also need a use for ServiceModifierInterface and ContainerBuilder is in the alter() method, so not having it will fail with an error, just like every other missing use.
Comment #6
jhodgdonThanks for the great review (and corresponding clarifications in IRC from berdir and timplunkett)!
I think I've addressed all the above points. One note: in point 7, I was just trying to document what the $container argument was to the alter() method; I did it in a different way in the new patch.
Comment #7
Berdirevent_subscriber is a more generic topic than just routing, that's just one using, like something else uses hooks to allow other modules to do something. Already mentioned above, this is big enough to deserve it's own @defgroup, maybe set that up as a @todo to be able to reference it?
All other changes look great, RTBC imho when that above is resolved.
Comment #8
jhodgdonThat is a good point. How about if instead of writing our own defgroup, we just link to existing Symfony docs on the subject?
Comment #9
BerdirWorks for me. Maybe we will have useful information of our own at one point (there's discussion to move that to separate file) but then this will need to be updated anyway.
Comment #10
Crell CreditAttribution: Crell commentedMinor nit: The core file is core.services.yml. (If someone searches for services.yml as a file name they'll find nothing.)
Otherwise this looks solid. Well done!
Comment #11
jhodgdonThere are many services files in core, *.services.yml. New patch attached. I suspect/hope it is still as solid. :)
Comment #12
BerdirReferencing core.services.yml explicitly would have been a valid option too, as that contains more examples than you'll ever need.
I'm happy, Crell is happy, everyone's happy!
Comment #13
jhodgdonchx was not entirely happy with the latest patch and suggested a few improvements in IRC. Here's a new patch.
Note: the first hunk of the interdiff is big because things had to be rewrapped. Only the first two lines of that section actually changed their text.
Comment #14
joachim CreditAttribution: joachim commented> + * interface text) is defined (given an name and an interface or at least a
'an name'
Comment #15
jhodgdonDoh. Fixed that typo. Didn't make an interdiff; that is the only change. Thanks!
Comment #16
chx CreditAttribution: chx commentedLet's do this, we can "iterate" more later (i want the bike shed red).
Comment #17
webchickThis is great!!
Committed and pushed to 8.x. Thanks!
Comment #19
jhodgdonThis patch actually isn't in core. Hopefully it will still apply.
Comment #21
jhodgdonOh good, the patch still applies. Amazing, after a month... I figured some of the classes marked with @ingroup might have moved.
Comment #22
alexpottCommitted 13f3582 and pushed to 8.x. Thanks!