Problem/Motivation

Follow-up from #2594425: Add the option in system menu block to "Expand all items in this tree" to make new constructor argument dependency optional

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

joelpittet created an issue. See original summary.

joelpittet’s picture

Status: Active » Needs review
FileSize
1.1 KB

Here's a patch to make the argument optional and still get the service dependency.

Berdir’s picture

You could also do it like this:

$this->menuActiveTrail = $menu_active_trail ?: \Drupal::service('menu.active_trail');

But then you can't do a @trigger_error(), which we might want to add as well.

joelpittet’s picture

Added a error for E_USER_DEPRECATED

The last submitted patch, 2: 3018863-2.patch, failed testing. View results

Berdir’s picture

Status: Needs review » Reviewed & tested by the community

Great.

Not sure if we need the change record referenced, since the necessary change is obvious and the change record does actually not explain it further anyway. We have a rule to always have it, but seems strange for those trivial constructor changes.

andypost’s picture

RTBC++ to get this change in, the list of contrib affected in related issue

Sam152’s picture

I didn't think constructors or plugins were part of the API, but perhaps this should be a special case if it's extended a lot in contrib.

For these kind of changes, do we require the code path be triggered at least once in a test?

joelpittet’s picture

https://www.drupal.org/core/d8-bc-policy

Constructors for service objects, plugins, and controllers

The constructor for a service object (one in the container), plugin, or controller is considered internal unless otherwise marked, and may change in a > minor release. These are objects where developers are not expected to call the constructor directly in the first place. Constructors for value objects where a developer will be calling the constructor directly are excluded from this statement.

Technically they are @internal implicitly by the BC policy.

I'm trying to fix in contrib, but just for the potential disruptive nature of them, it would be nice to the new things optional.
#2968049-19: Dependency Injection issue

alexpott’s picture

The thing is this work then needs to be undone sometime. Yes the @trigger_error() makes it easier to find but there's even less disruption if people extend plugins doing some thing like https://www.previousnext.com.au/blog/safely-extending-drupal-8-plugin-cl...

For me, contrib / custom doing something like:

class CorePlugin {
    protected $service;

    public function __construct($service) {
        $this->service = $service;
    }
    
    public static function create() {
        return new static('foo');
    }
}

class ContribPlugin extends CorePlugin {
    protected $anotherService;
    
    public function getAnotherService() {
        return $this->anotherService;
    }
    
    public static function create() {
        $instance = parent::create();
        $instance->anotherService = 'bar';
        return $instance;
    }
}

// Returns 'bar'
var_dump(B::create()->getAnotherService());
Berdir’s picture

@alexpott: Interesting, I think I like that approach. But nobody is using that yet, including core.

What about getting this in, because there are contrib modules out there that are now broken in 8.7 and then creating a documentation page on backwards and forwards compatible ways to subclass services as well as plugins/controllers/.. and start doing that in core?

For services, setter-based injection works well, which I've documented a while ago here: https://www.md-systems.ch/de/blog/techblog/2016/12/17/how-to-safely-inje....

alexpott’s picture

So I think to be friendly we should do this patch. In future I think we should seriously consider enforcing the non-extendability of plugin classes by using final so that people are force to use composition over inheritance to extend from core. This will solve lots of these type of issues and, whilst it will cost more upfront, will put the Drupal eco-system in a more maintainable and upgradable state.

On of the problems of doing this is that we're introducing logic that we need to add a test for. Here's one.

alexpott’s picture

Ughs meant to make the operator === instead of ==

alexpott’s picture

Just opened #3019332: Use final to define classes that are NOT extension points which was inspired by this and other issues.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 449e2e3 and pushed to 8.7.x. Thanks!

  • alexpott committed 449e2e3 on 8.7.x
    Issue #3018863 by joelpittet, Berdir, alexpott: Make SystemMenuBlock's...
jibran’s picture

Lee posted one as well https://www.previousnext.com.au/blog/safely-extending-drupal-8-plugin-cl... Don't mind me @alexpott shared it already in #10.

Status: Fixed » Closed (fixed)

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