Updated: Comment 0

Problem/Motivation

Currently we do have a couple of container aware services which provided $container as well as setContainer().

Proposed resolution

If you value uniformity in core then when should either extend a class with ContainerAware or use its corresponding trait ( ContainerAwareTrait )

/**
 * Attaches access check services to routes and runs them on request.
 *
 * @see \Drupal\Tests\Core\Access\AccessManagerTest
 */
class AccessManager extends ContainerAware {

  /**

ControllerResolver.php is an example which proves the point that ContainerAwareTrait should be used in preference to extending ContainerAware.

class ControllerResolver extends BaseControllerResolver implements ControllerResolverInterface {

  /**
   * The injection container that should be injected into all controllers.
   *
   * @var \Symfony\Component\DependencyInjection\ContainerInterface
   */
  protected $container;

and need to become

class ControllerResolver extends BaseControllerResolver implements ControllerResolverInterface {
   use ContainerAwareTrait;

tim.plunkett and msonnabaum have raised valid concerns in #19 and #20

So the use of ContainerAwareTrait should be limited in scope to where dynamically changing the container might be a useful thing.

If the object can't function at all without the container, it should use constructor injection.

Remaining tasks

User interface changes

API changes

CommentFileSizeAuthor
#55 2229183-apache-crash-ff.png20.87 KBplach
#55 2229183-apache-crash-chrome.png12.4 KBplach
#49 interdiff-46.49.txt773 bytesmartin107
#49 container_aware_trait-2229183-49.patch24.26 KBmartin107
#46 container_aware_trait-2229183-46.patch24.37 KBmartin107
#40 container_aware_trait-2229183-40.patch24.36 KBmartin107
#40 interdiff-38-40.txt5.94 KBmartin107
#38 container_aware_trait-2229183-38.patch24.38 KBmartin107
#38 interdiff-37-38.txt544 bytesmartin107
#37 interdiff.txt1.93 KBdawehner
#37 container_aware_trait-2229183-37.patch24.38 KBdawehner
#35 interdiff-31-34.txt10.57 KBmartin107
#35 ContainerAwareTraits-2229183-34.patch24.15 KBmartin107
#31 interdiff-29-31.txt632 bytesmartin107
#31 ContainerAwareTraits-2229183-31.patch22.79 KBmartin107
#29 interdiff-26-29.txt1.13 KBmartin107
#29 ContainerAwareTraits-2229183-29.patch22.44 KBmartin107
#26 interdiff-22-26.txt1.48 KBmartin107
#26 ContainerAwareTraits-2229183-26.patch22.41 KBmartin107
#24 ContainerAwareTraits-2229183-22.patch23.23 KBmartin107
#22 interdiff-15-22.txt9.44 KBmartin107
#22 ContainerAwareTraits-2229183-22.patch0 bytesmartin107
#15 interdiff-13-15.txt2.47 KBmartin107
#15 ContainerAwareTraits-2229183-15.patch30.04 KBmartin107
#13 interdiff-11-13.txt3.11 KBmartin107
#13 ContainerAwareTraits-2229183-13.patch28.06 KBmartin107
#11 interdiff-9-11.txt1.98 KBmartin107
#11 ContainerAwareTraits-2229183-11.patch25.66 KBmartin107
#9 ContainerAwareTraits-2229183-9.patch25.64 KBmartin107
#9 interdiff-6-9.txt1.94 KBmartin107
#6 interdiff-3-6.txt14.34 KBmartin107
#6 ContainerAwareTraits-2229183-6.patch24.53 KBmartin107
#3 ContainerAwareTraits-2229183-3.patch15.18 KBmartin107
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

martin107’s picture

@dawehner - Just before I jump on this and get ahead of myself.

Are you saying the template to follow should be :-

From core_servies.yml

  access_manager:
    class: Drupal\Core\Access\AccessManager
    arguments: ['@router.route_provider', '@url_generator', '@paramconverter_manager']
    calls:
      - [setContainer, ['@service_container']]
      - [setRequest, ['@?request']]

and this is an example of what needs to change ?

  keyvalue:
    class: Drupal\Core\KeyValueStore\KeyValueFactory
    arguments: ['@service_container', '@settings']
dawehner’s picture

The @setContainer would stay and the second example would use setter injection.

martin107’s picture

Assigned: Unassigned » martin107
Status: Active » Needs review
FileSize
15.18 KB

First Pass .. I hope I have them all...

With this patch drupal installs .. which shows a lot of functionality .. lets see what testbot has to say.

Status: Needs review » Needs work

The last submitted patch, 3: ContainerAwareTraits-2229183-3.patch, failed testing.

dawehner’s picture

+++ b/core/lib/Drupal/Core/Cache/CacheContexts.php
@@ -16,14 +16,7 @@
+class CacheContexts extends ContainerAware {

can't we use the trait all over the place?

martin107’s picture

1) Removed all instances of "extends ContainerAware" in favour of "use ContainerAwareTrait"

2) For style and layout perspective using BrokenHandlerTrait as found in core as the template.. so removed fully qualified use of
"use \Symfony\Component\DependencyInjection\ContainerAwareTrait;"

3) most of the failing tests seem to come from DrupalUnitTest.php and is construction of KeyValueFactory, its constructor now need only a
single parameter and a set to inject the service_container.

      $container
        ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory')
        ->addArgument(new Reference('settings'));
      $container->set('service_container', newReference('service_container'));
martin107’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 6: ContainerAwareTraits-2229183-6.patch, failed testing.

martin107’s picture

Status: Needs work » Needs review
FileSize
1.94 KB
25.64 KB
     $this->container
       ->register('keyvalue.expirable', 'Drupal\Core\KeyValueStore\KeyValueExpirableFactory')
-      ->addArgument(new Reference('service_container'))
+      ->addMethodCall('setContainer', new Reference('service_container'))
       ->addArgument(new Reference('settings'));
     // Define two data collections,

Now using AddMethodCall to inject the service_continaer correctly. Fixed in two other places.

Status: Needs review » Needs work

The last submitted patch, 9: ContainerAwareTraits-2229183-9.patch, failed testing.

martin107’s picture

Status: Needs work » Needs review
FileSize
25.66 KB
1.98 KB

Fixed malformed AddMethodCall

-      ->addMethodCall('setContainer', new Reference('service_container'))
+     ->addMethodCall('setContainer', array(new Reference('service_container')))

Status: Needs review » Needs work

The last submitted patch, 11: ContainerAwareTraits-2229183-11.patch, failed testing.

martin107’s picture

Status: Needs work » Needs review
FileSize
28.06 KB
3.11 KB

Fixed more tests.

Status: Needs review » Needs work

The last submitted patch, 13: ContainerAwareTraits-2229183-13.patch, failed testing.

martin107’s picture

Fixed a few more tests

CacheContextsTest and HttpKernelTest

martin107’s picture

Status: Needs work » Needs review
dawehner’s picture

Oh I would not have expected that this issue is so much effort.
Thank you!

Status: Needs review » Needs work

The last submitted patch, 15: ContainerAwareTraits-2229183-15.patch, failed testing.

msonnabaum’s picture

class: Drupal\Core\KeyValueStore\KeyValueFactory
-    arguments: ['@service_container', '@settings']
+    arguments: ['@settings']
+    calls:
+      - [setContainer, ['@service_container']]

I don't think we should be making these classes use ContainerAware if they aren't already. Really, i don't understand why we're doing it at all. Why not just inject it in the constructor like KeyValueFactory does? If the object can't function at all without the container, it should use constructor injection.

From what I can tell, there isn't a scenario where setContainer is called again, so all this seems to be gaining us is a more cumbersome service definition.

tim.plunkett’s picture

Yeah I think replacing "extends ContainerAware" is about all we should do here. Any services using proper injection can be left alone.

martin107’s picture

Title: Use ContainerAwareTrait » use ContainerAwareTrait, over extending ContainerAware
Issue summary: View changes

Forgive me if I am 'Tilting at windmills"

I accept this is a minor, subtle point, but forcing me to make the case for using ContainerAwareTrait vs "extends ContainerAware" is no bad thing!

So I have updated the issue summary

In the next patch I will back out the changes unless in fits with only changing existing extended ContainerAware classes.

martin107’s picture

Category: Bug report » Task
Issue summary: View changes
FileSize
0 bytes
9.44 KB

1) I have backed out CacheContext, KeyValueFactory and KeyValueFactoryExpirable. Lets see what the tesbot reports now.

2) I have also addressed a couple of cascaded bug each hiding each other in ThemeTestSubscriber - which incorrectly extended ContainerAware

ThemeTestSubscriber does not need a service_container it needs an IntrospectableContainer.

In any event theme_test.services.yml does not as expected inject a container of any form

The place where the uninitialised container is used is "unreached code" by the testbot hence no bug is picked up!

Since there is no need to dynamically inject a container into this class I have just added a todo in the constructor and removed the extends ContainerAware

If the testbot does not report a fail in this department I will file a separate bug report.

martin107’s picture

Status: Needs work » Needs review
martin107’s picture

Resubmitting

Status: Needs review » Needs work

The last submitted patch, 24: ContainerAwareTraits-2229183-22.patch, failed testing.

martin107’s picture

Ok that blew up badly because of a failure to backout changes to KeyValueFactory that affected every unit test ( DrupalUnitTestBase)

Fixed

martin107’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 26: ContainerAwareTraits-2229183-26.patch, failed testing.

martin107’s picture

Status: Needs work » Needs review
FileSize
22.44 KB
1.13 KB

this should get back to the 70 fails of #15

Status: Needs review » Needs work

The last submitted patch, 29: ContainerAwareTraits-2229183-29.patch, failed testing.

martin107’s picture

This next patch is a test to prove a point ( it is not core quality code )

There is a another difference between "use ContainerAwareTrait" and "extends ContainerAware"

Only when using extends does it inherit "implements ContainerAwareInterface".

The bug I think I can see is that the controllerResolver picks up on this and at the appropriate time calls setContainer

This is the temporary change I have made to see if it resolves all the remaining issues.

-    if ($controller instanceof ContainerAwareInterface) {
+    if (method_exists($controller,'setContainer')) {
       $controller->setContainer($this->container);

Once again this change is just to highlight the issue not to solve it...

So I expect a division into two camps

To the "This issue is just needless fiddling" camp -- I think it strengthens your point.

To the "I like everything to be explicit when constructing my class" the fact that every class that may pass through ControllerResolver needs to be altered to explicitly add "implements ContainerAwareInterface" then this is a good thing...

Meh - I myself have no opinion...

martin107’s picture

Status: Needs work » Needs review
tstoeckler’s picture

Yes, we should definitely add "implements ContainerAwareInterface" to all of the classes using the trait.

martin107’s picture

Reverted #31, implemented #33 If this stays green, I will add what I expect to be the template for class definition, service build instructions and factory construction of containerAware classes to the issue summary.

and then leave it for review.

martin107’s picture

tstoeckler’s picture

Patch looks great now, thanks!

I have a couple of points, that are very minor, but since isn't blocking anything we should fix them before commit I think.

Also you re-introduced the change of moving a lot of classes from constructor injection to setter injection for the container. I personally think it makes a lot of sense to consistently use setter injection in case, but there were some people that had reservations against that above. So maybe just leave that part out, so this doesn't get held up any longer?

  1. +++ b/core/lib/Drupal/Core/Access/AccessManager.php
    @@ -26,7 +27,8 @@
    +class AccessManager implements ContainerAwareInterface {
    +  use ContainerAwareTrait;
    

    And elsewhere: There should be an empty line between these two.

  2. +++ b/core/lib/Drupal/Core/HttpKernel.php
    @@ -29,31 +27,12 @@
    +class HttpKernel extends BaseHttpKernel implements ContainerAwareInterface
     {
    

    While we're at it, can we move the curly brace "{" on the same line as the "class" declaration, please?

dawehner’s picture

@martin107
Great battle against the bot!

Also you re-introduced the change of moving a lot of classes from constructor injection to setter injection for the container. I personally think it makes a lot of sense to consistently use setter injection in case, but there were some people that had reservations against that above. So maybe just leave that part out, so this doesn't get held up any longer?

This is instance is certainly special for various reasons:

  • A service depending on the container has to real dependency, but just potentially all
  • Using base-classes/traits can be really simplified if you use setter injection, let me demonstrate that in the patch.
martin107’s picture

Thank you gentleman for your comments...

So my task from 36 was to revert every case where I mangled the constructor and converted from constructor dependency injection to setter injection....
The changes in 37 affect every instance of that... so if I have analysed the situation correctly there is nothing more for me to do.

So onto the cosmetic changes...

regarding

class AccessManager implements ContainerAwareInterface {
   use ContainerAwareTrait;

versus

class AccessManager implements ContainerAwareInterface {
(new line)
   use ContainerAwareTrait;

I went looking for the definitive way forward here https://drupal.org/coding-standards
but could not find anything helpful.

I have copied the implicit standard, which is that in the very limited example of traits in core, currently,
the traits hugs the class definition...(see BrokenHandlerTait )

Can I humbly suggest that the uniform styling of traits is best done in a separate issue. Where more eyes will see it.

So that leaves #36.2 - ok no problem.

Minor Housekeeping

1) I have just been reading around the issue and just seen some of the policy discussions, and feels like I may have just blindly stepped on a landmine...I am linking here to prevent any new visitors from doing something similar

2) Linking to the bug that this issue discovered.

dawehner’s picture

@martin107
The way to move forward is to use something sane in several issues and you have implemented a "standard" by that.

martin107’s picture

less hugging, more sanity

dawehner’s picture

Yeah, let's do work to undo work to add more work later.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

But yeah I don't care at all tbh.

tstoeckler’s picture

The class whitespace stuff is documented here: https://drupal.org/node/608152#indenting

...that means BrokenHandlerTrait is doing it wrong, not a biggie though.

Thanks for updating the patch nevertheless @martin107!

Since @dawehner agrees, being bold and marking RTBC. (Nice trick in the services.yml btw!)

Edit: crosspost

tim.plunkett’s picture

Title: use ContainerAwareTrait, over extending ContainerAware » use ContainerAwareTrait instead of extending ContainerAware

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 40: container_aware_trait-2229183-40.patch, failed testing.

martin107’s picture

Status: Needs work » Needs review
FileSize
24.37 KB

Reroll.

martin107’s picture

Status: Needs review » Reviewed & tested by the community

Reroll was trivial, nothing has changed -- so back to RTBC

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/system/tests/modules/theme_test/lib/Drupal/theme_test/EventSubscriber/ThemeTestSubscriber.php
@@ -24,6 +23,11 @@ class ThemeTestSubscriber extends ContainerAware implements EventSubscriberInter
+  public function __construct() {
+     // @todo - Must initialize $container.
+     // see onView()
+  }

This code looks unnecessary.

martin107’s picture

Status: Needs work » Needs review
FileSize
24.26 KB
773 bytes

Removed __construct

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 12b53d0 and pushed to 8.x. Thanks!

alexpott’s picture

Looks like https://drupal.org/node/1937056 could do with an update.

  • Commit 12b53d0 on 8.x by alexpott:
    Issue #2229183 by martin107, dawehner: Use ContainerAwareTrait instead...
martin107’s picture

Assigned: martin107 » Unassigned

#52 change record updated

plach’s picture

After this commit I am no longer able to access any Drupal-generated page without Apache crashing in a Windows 8 64-bit + Acquia Dev Desktop (Apache 2.2.22, PHP 5.4.8, MySQL 5.166-community) dev environment. The page is rendered and immediately after Apache dies (you can see the results attached).

I am pretty sure this is the issue causing this behavior: I identified it through git bisect and if I apply -R the committed patch to the latest HEAD everything works fine.

I've no idea of what might be going on, it seems we are triggering some weird PHP bug. Any suggestion?
(Possibly related issue: #2041375: Drupal 8 crashes apache 2.4.4 on 64bit).

dawehner’s picture

Does windows provide some logging of apache, ... is this an actual segfault?

plach’s picture

No error in the error.log (obviously :), Windows syslog says:
(translating from italian)

Name of the application that generated the error: httpd.exe, version: 2.2.22.0, timestamp: 0x4f242d7a
Name of the module that generated the error: php5ts.dll, version: 5.4.8.0, timestamp: 0x507dd793
Exception code: 0xc0000005
Error offset: 0x00058e5f
ID of the process that generated the error: 0x13a8
Start time of the application that generated the error: 0x01cf5c30a8bdc760
Path of the application that generated the error: F:\bin\acquia-dd\apache\bin\httpd.exe
Path of the module that generated the error: F:\bin\acquia-dd\php5_4\php5ts.dll
Notice ID: ed1b1f2c-c823-11e3-bee7-f9dc4f72b177
Full name of the package that generated the error:
Application ID for the package that generated the error:

So, yes, I think this is the Windows equivalent of a segfault.

alexpott’s picture

YesCT’s picture

@plach please open an issue with your error and info with the tag
d8 dev environment
(http://drupal.org/project/issues/search?projects=&issue_tags=d8+dev+envi...)

the issue you open might be closed if this is reverted, or if another follow-up issue fixes it, but it is just the kind of d8 dev env thing that me and other people will run into when helping other people get setup with d8 locally. so having an issue will help.

alexpott’s picture

There is also https://bugs.php.net/bug.php?id=60369 and https://bugs.php.net/bug.php?id=63002 - plach can you disable wncache or upgrade your php?

plach’s picture

WinCache is not enabled but upgrading to PHP 5.4.27 does fix the issue :)

@YesCT:

Since it seems we have a fix here, what about just tagging this with "d8 dev environment"?

xjm’s picture

FWIW, this commit also broke installation for me on OSX 10.8, using PHP 5.4.10 with MAMP (2.1.2). I'm going to try upgrading MAMP and see if it resolves the issue.

martin107’s picture

Works for me

OSX 10.9.2
MAMP 2.2
PHP 5.5.3

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

YesCT’s picture

Issue tags: +Traits