Updated: Comment 0

Problem/Motivation

At the moment a lot of services call the $view_entity->getExecutable() which is just a wrapper function around the static function Views::executableFactory()->get($this);.
The proper way to use the factory would be to inject it instead.

Proposed resolution

Inject the view executable factory where possible.

Remaining tasks

User interface changes

API changes

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task since we are refactoring the code to follow best practices.
Issue priority Normal because we are replacing code that works with code that is the current best practice.
Prioritized changes The main goal of this issue is refactor code to follow best practices.
Disruption None
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

Issue summary: View changes
Issue tags: +Novice

.

bnjmnm’s picture

I experimented with this replacement in a few places -
In views_ui\Form\Ajax\AddItem the replacement was fine but in views_ui/admin.inc functionality was disrupted to the point that the 'add' button in a view would not function.

My thought was to add the following code to each occurrence of $view->getExecutable(), to see if executable factory can safely be used instead.

$ex2 = Views::executableFactory()->get($view);
$executable = $view->getExecutable();
if($executable == $ex2){
  drupal_set_message('view object match');
}else{
  drupal_set_message('view object does not match');
}

I'd like to get verification from a more experienced contributor that determining an object match is sufficient evidence that ->getExecutable can be replaced by executable factory.
If this looks like it will work, I'll apply this test to each occurrence, change to executable factory when the objects match, and create a patch.

a.hover’s picture

Assigned: Unassigned » a.hover
YesCT’s picture

@a.hover Did you have any questions?

a.hover’s picture

Assigned: a.hover » Unassigned
saltednut’s picture

It looks like the ::getExecutable method still exists in core/modules/views/lib/Drupal/views/Entity/view.php but it is not being called anywhere in the system.

Is this issue still relevant?

If we are not using the global, perhaps it should be removed altogether, lest someone accidentally start using it again?

zaporylie’s picture

Assigned: Unassigned » zaporylie
Issue tags: +SprintWeekend2015

I found some usages of getExecutable() with phpStorm "Find Usages" function. Will try to replace it with Views::executableFactory()->get($view); and publish a patch.

zaporylie’s picture

Assigned: zaporylie » Unassigned
Status: Active » Needs review
FileSize
3.39 KB

Please, check this patch and say if it is going in the right direction.

Status: Needs review » Needs work

The last submitted patch, 8: 2102293-8.patch, failed testing.

alexandre.todorov’s picture

Status: Needs work » Needs review
FileSize
3.43 KB

HI,
I just rerolled #8 patch witch didn't apply on latest 8.0.x. Without doing any changes, I ran tests witch have previously failed (Drupal\views\Tests\Handler\HandlerTest, Drupal\views_ui\Tests\DisplayCRUDTest) and finally those tests pass.

Drupal Dev Days Mentor Sprint - Montpellier (France) 2015

zaporylie’s picture

Status: Needs review » Needs work
Issue tags: +drupaldevdays

Thanks for moving this issue forward. It wasn't finished though so I'm moving it back to "Needs work" but that's great it's green now. Do you want to finish my work or should I take care of it?

Also, I've added drupaldevdays tag since you are working on it here.

zaporylie’s picture

Status: Needs work » Needs review
FileSize
50.37 KB
53.23 KB

Ok, I think I went through all occurrences of getExecutable(). Let's try patch it against testbot.

Status: Needs review » Needs work

The last submitted patch, 12: inject_the_view-2102293-12.patch, failed testing.

tim.plunkett’s picture

This just switches to using a static method call, which is a wrapper around \Drupal::service('views.executable')

As the issue title says, we should be injecting the factory instead.

geertvd’s picture

Let's see what the testbot says

geertvd’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 15: inject_the_view-2102293-15.patch, failed testing.

geertvd’s picture

Status: Needs work » Needs review
FileSize
5.19 KB
53.31 KB

Status: Needs review » Needs work

The last submitted patch, 18: inject_the_view-2102293-18.patch, failed testing.

geertvd’s picture

Status: Needs work » Needs review
FileSize
58.13 KB
7.8 KB
geertvd’s picture

Status: Needs review » Needs work

The last submitted patch, 20: inject_the_view-2102293-20.patch, failed testing.

geertvd’s picture

Status: Needs work » Needs review
FileSize
1.56 KB
58.64 KB
Anonymous’s picture

Status: Needs review » Needs work
Issue tags: +Needs beta evaluation

Overall this looks very good. All injections seem to be done properly, so most remarks below are minor really.

This needs a beta evaluation, so tagging accordingly.

  1. +++ b/core/modules/views/src/EventSubscriber/RouteSubscriber.php
    @@ -121,8 +132,7 @@ public function routes() {
    +      if (($view = $this->executableFactory->get($view)) && $view instanceof ViewExecutable) {
    
    +++ b/core/modules/views/src/Plugin/views/HandlerBase.php
    @@ -335,6 +343,29 @@ public function setModuleHandler(ModuleHandlerInterface $module_handler) {
    +   * @return \Drupal\views\ViewExecutableFactory
    

    The factory always returns an instance of ViewExecutable, so the second check is unneeded.

  2. +++ b/core/modules/views/src/EventSubscriber/RouteSubscriber.php
    @@ -143,8 +153,7 @@ protected function alterRoutes(RouteCollection $collection) {
    +      if (($view = $this->executableFactory->get($view)) && $view instanceof ViewExecutable) {
    

    Same.

  3. +++ b/core/modules/views/src/Plugin/views/HandlerBase.php
    @@ -335,6 +343,29 @@ public function setModuleHandler(ModuleHandlerInterface $module_handler) {
    +   * @return \Drupal\views\ViewExecutableFactory
    

    Can we add an explanatory paragraph under the @return here?

  4. +++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
    @@ -83,6 +83,8 @@
    +
    +
    

    These newline are redundant.

  5. +++ b/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
    @@ -64,6 +66,42 @@
       /**
    +   * The factory to load a view executable with.
    +   *
    +   * @var \Drupal\views\ViewExecutableFactory
    +   */
    +  protected $executableFactory;
    

    Is this the right place to define the factory? Shouldn't that be moved to a superclass? Not sure though, we might want to check with a maintainer.

  6. +++ b/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
    @@ -64,6 +66,42 @@
    +   * Constructs an GroupwiseMax object.
    

    "a"

  7. +++ b/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
    @@ -64,6 +66,42 @@
    +   *   The plugin_id for the plugin instance.
    

    "plugin id"

  8. +++ b/core/modules/views/src/Plugin/views/row/RowPluginBase.php
    @@ -56,6 +58,42 @@
    +   *   The plugin_id for the plugin instance.
    

    "plugin id"

  9. +++ b/core/modules/views/src/Plugin/views/row/RowPluginBase.php
    @@ -82,7 +120,8 @@ protected function defineOptions() {
    +      $executable->initDisplay();
    

    Why is this needed, since it wasn't there before? (I found this 8 times, so it will have some use, but I don't get it)

  10. +++ b/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php
    @@ -115,12 +117,29 @@
    +   *   The plugin_id for the plugin instance.
    

    "plugin id"

  11. +++ b/core/modules/views/tests/src/Unit/EventSubscriber/RouteSubscriberTest.php
    @@ -41,6 +41,13 @@ class RouteSubscriberTest extends UnitTestCase {
    +   * The mocked view executable.
    

    It's a mocked view executable "factory".

  12. +++ b/core/modules/views/tests/src/Unit/Plugin/area/ViewTest.php
    @@ -31,12 +31,22 @@ class ViewTest extends UnitTestCase {
    +   * The mocked view executable.
    

    Same.

  13. +++ b/core/modules/views/tests/src/Unit/ViewsHandlerManagerTest.php
    @@ -44,6 +44,13 @@ class ViewsHandlerManagerTest extends UnitTestCase {
    +   * The mocked view executable.
    

    And again.

  14. +++ b/core/modules/views_ui/src/ViewEditForm.php
    @@ -611,8 +628,10 @@ public function submitDisplayUndoDelete($form, FormStateInterface $form_state) {
         // setOption doesn't work because this would might affect upper displays
    

    All lines around this comment change, so I'd fix the comment as well.

dawehner’s picture

Its great that people work on those issues. Thank you!!!

geertvd’s picture

Status: Needs work » Needs review
FileSize
7.2 KB
58.5 KB
  1. Agreed, fixed
  2. ok
  3. done
  4. ok
  5. I didn't add it there since it's not needed in any other relationship handlers.
  6. fixed
  7. fixed
  8. fixed
  9. This is needed to initialise the display handler.
    I'm thinking this was not necessary before since this was already being called in View::calculateDependencies() when a new view object was constructed.
  10. fixed
  11. fixed
  12. fixed
  13. fixed
  14. Removed the comment since it's inaccurate as we are actually using setOption() there

Perhaps dawehner should verify 5 and 9 since I'm not sure about those.

dawehner’s picture

I didn't add it there since it's not needed in any other relationship handlers.

+1

+++ b/core/modules/views_ui/src/ViewEditForm.php
@@ -96,6 +108,8 @@ public static function create(ContainerInterface $container) {
+    $executable = $this->executableFactory->get($view);
+    $executable->initDisplay();

@@ -107,7 +121,7 @@ public function form(array $form, FormStateInterface $form_state) {
-      if (!$view->getExecutable()->setDisplay($display_id)) {
+      if (!$this->executableFactory->get($view)->setDisplay($display_id)) {

If we have both bits, I really think we don't need it. Have you tried to remove the additional calls, does something break?

geertvd’s picture

When I remove the $executable->initDisplay() there I get a white screen with the following error:

Call to a member function has() on a non-object in /var/www/html/d8.local/drupal/core/modules/views_ui/src/ViewEditForm.php on line 209

Same kind of error is thrown whenever I try to call something on $executable->displayHandlers without adding the $executable->initDisplay() line first.

geertvd’s picture

FileSize
58.48 KB
641 bytes

Well at least I should be using the $executable variable there.

geertvd’s picture

FileSize
58.44 KB
662 bytes

Ok then I can actually remove that line since the display is initialised in setDisplay()

geertvd’s picture

I just checked every addition of the the $executable->initDisplay() line.
Looks like the above was the only one that could be removed though, in the other occasions we call a method on $executable->displayHandlers or $executable->display_handler without calling $executable->setDisplay() before that.

dawehner’s picture

Thank you! Note: We should still add a beta evaluation as well as maybe improve the issue summary in general a bit.

geertvd’s picture

Issue summary: View changes

Thanks for reviewing, added the beta evaluation.

geertvd’s picture

Issue summary: View changes

Improved the IS a bit.

geertvd’s picture

Issue summary: View changes
Anonymous’s picture

Issue summary: View changes
Status: Needs review » Needs work
Issue tags: -Needs beta evaluation

@geertvd: Thanks for your work on this and investigating the uncertainties!
@dawehner: Thanks for your input!

This issue is both normal priority and a task because we refactor to follow best practices. See priorities and categories. I tweaked the beta evaluation to reflect that.

The issue summary itself looks good now.

I looked over the patch again, and I missed some things the first time reviewing. These are minor, but will need to be addressed before the patch goes in.

  1. +++ b/core/modules/views/src/Plugin/Derivative/ViewsExposedFilterBlock.php
    @@ -58,7 +69,9 @@ public function __construct($base_plugin_id, EntityStorageInterface $view_storag
    +
    

    This newline should be removed.

  2. +++ b/core/modules/views/src/Plugin/views/row/RowPluginBase.php
    @@ -56,6 +58,42 @@
    +   * Constructs a PluginBase object.
    

    RowPluginBase

  3. +++ b/core/modules/views/src/Plugin/views/row/RssPluginBase.php
    @@ -35,8 +36,8 @@
    +  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ViewExecutableFactory $executable_factory) {
    

    The $executable_factory that was added, needs an @param definition in the docblock.

geertvd’s picture

Status: Needs work » Needs review
FileSize
1.92 KB
58.61 KB

Thanks for the feedback

Anonymous’s picture

Status: Needs review » Reviewed & tested by the community

Ok, thanks for addressing that!

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

This is a lot of disruption for:

Normal because we are replacing code that works with code that is the current best practice.

How likely is it that this will break existing Drupal 8 sites?

aspilicious’s picture

Well in order to keep DS working in D8 I had to update the views integration 12 times since january. (last time this week) This change will brake it *again*.
So I don't think it's ok, while being in beta, to randomly change constructor arguments if they don't fix any real problem.

dawehner’s picture

Well in order to keep DS working in D8 I had to update the views integration 12 times since january. (last time this week) This change will brake it *again*.

So you basically want to treat constructor arguments like an API now? I try to understand your particular point here ...

aspilicious’s picture

Well, it's a grey line.

For example, let's compare these two cases:

(1) For some reason we add new constructor argument to 'DefaultPluginManager' and by doing that we would break every contrib module that deals with custom plugin managers.
(2) We commit this patch and we would potentially break contrib modules that extends one of the affected classes.

From a technical perspective (1) and (2) are the same.

(1) will never be allowed at this stage unless it fixes a critical/major bug
(2) possibly will be allowed because the affected code out of core will be very limited at the moment.

To be honest, I personally don't care because I don't have any working D8 sites at the moment. But *if* people are using it (and apparently according to the statistics, they do), they have no clue which version of the module they need to use to make everything work for them.

dawehner’s picture

My personal opinion is that subclassing and especially the constructor side of things is not directly part of an public API.
No question, we should try to avoid changes, especially after the release, but at least for me, it should not be a reason to do things in a wrong way.

For core I would like to see some kind of @api tag for some base classes, so we promise to not change things there, see http://symfony.com/doc/current/contributing/code/bc.html
for a similar promise.

jp.stacey’s picture

Issue tags: -Novice

This issue was reverted to Needs Review in comment #39, based on needing to discuss how much disruption it's likely to cause (really a Needs Work?)

At any rate, I'm going to remove the novice tag, because I don't think it's reviewable by a novice in its current state.

jp.stacey’s picture

Issue tags: +SprintWeekend2016

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

joachim’s picture

+++ b/core/modules/views/src/EventSubscriber/RouteSubscriber.php
@@ -121,8 +132,7 @@ public function routes() {
-      if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) {
+      if ($view = $this->executableFactory->get($view)) {

I think that replacing the $view variable with the executable is bad code style because it makes it really hard to read or debug the code, or inherit methods.

It's a problem with the existing code, so I'd be ok with this being done in a follow-up.

Mile23’s picture

Status: Needs review » Needs work
Parent issue: » #2729597: [meta] Replace \Drupal with injected services where appropriate in core

Adding parent #2729597: [meta] Replace \Drupal with injected services where appropriate in core because views executable is a service. All of those code paths eventually reach Views::executableFactory() which is just a wrapper for \Drupal::service('views.executable').

One reason to do IoC and inject the service is that we're calling a bunch of functions that all wrap wrappers. Except for the very last one, of course. So let's just call the last one, once.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

dimitriskr’s picture

Issue tags: +GreeceSpringSprint2024