API page: https://api.drupal.org/api/drupal/core%21modules%21views%21src%21Plugin%...

I would suggest to make StylePluginBase::renderFields(array $hresult) public instead of protected.

The module Views Merge Rows is a display extender plugin that modify Views output by implementing hook_views_pre_render(). As the module needs to access $view->style_plugin->rendered_fields during pre-rendering process, and because $view->style_plugin->rendered_fields is not rendered prior to the execution ofhook_views_pre_render, invoking $view->style_plugin->renderFields($view->result) is made necessary.

The access in the code is as follows:

$view->style_plugin->renderFields($view->result);
$rendered_fields = $view->style_plugin->getRenderedFields();

Prior to the proposed solution, creating a derived class of StylePluginBase was considered. However, the required property would not spread throughout all style plugins. The latter is pre-requisite because Views Merge Rows is a display extender intended to work with any style plugin.

Issue fork drupal-2824920

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

dgagne created an issue. See original summary.

cilefen’s picture

Title: StylePluginBase::renderFields(array $hresult) » Make StylePluginBase::renderFields public
Version: 8.2.x-dev » 8.3.x-dev
Component: documentation » views.module
Priority: Major » Normal
dgagne’s picture

Status: Active » Needs review
StatusFileSize
new426 bytes

Status: Needs review » Needs work

The last submitted patch, 3: StylePluginBase-public-renderFields-2824920-1.patch, failed testing.

dgagne’s picture

Status: Needs work » Needs review
StatusFileSize
new640 bytes
dawehner’s picture

Is there a reason you cannot use \Drupal\views\Plugin\views\style\StylePluginBase::getField ?

dgagne’s picture

The reason is that I need to access cached fields (in $rendered_fields) and before accessing them, I have to cache the fields because this is not done automatically before hook_pre_render is called. You may refer to https://www.drupal.org/node/2826755 to get more info.

dgagne’s picture

Issue tags: +Novice

Status: Needs review » Needs work

The last submitted patch, 5: StylePluginBase-public-renderFields-2824920-2.patch, failed testing.

dgagne’s picture

Status: Needs work » Needs review
josevitalsouto’s picture

Patch

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

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now 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.

pixelcab’s picture

I'll work on this as part of Drupal Global Sprint Weekend

pixelcab’s picture

Status: Needs review » Reviewed & tested by the community

I was able to successfully apply the patch to my local Drupal 8.4.0-dev instance. The renderFields method of the StylePluginBase class was successfully changed from protected to public. I was able to verify the patch is working by testing the change using the development version (8.x-1.0-dev) of the views_merge_rows.module which was already using the public version of the renderFields method. After applying the patch the module had the correct access to use the renderFields method.

dawehner’s picture

IMHO we need a clear issue summary why making this public is the only right way to solve it. Is there not maybe an underlying problem? Is there maybe a better way to solve this particular problem? Should there we a FieldAwareStylePluginInterface which exposes some of that kind of information?

Just making something public without a clear vision is IMHO not the right fix for a problem.

dawehner’s picture

I'm also curious whether we need this issue as well as #2829046: Create public $DisplayPluginBase::getExtender($id)

dgagne’s picture

dgagne’s picture

Issue summary: View changes
dgagne’s picture

dgagne’s picture

@dawehner:

I think implementing a FieldAwareStylePluginInterface would be similar to use a nuke to kill a fly. The method is defined directly in StylePluginBase and any style plugin extending it can access it. I don't see any reason why we should put this method in an interface. If it was defined in PluginBase (which is extended by StylePluginBase), my answer would have been different.

dgagne’s picture

Issue summary: View changes
xjm’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs subsystem maintainer review

Setting NR for @dawehner to review @dgagne's updated proposal in the summary. Thanks for your contributions on Views!

dgagne’s picture

Assigned: Unassigned » dgagne
andypost’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update

to access $view->style_plugin->rendered_fields during pre-rendering process

there's no render at pre render stage! indeed)

And the main question in why not inherit your style plugin from base one and alter discovery or views style plugins with own implementation?
Yep, that may cause incompatibilities like #2853002: Collision with ctools_views

xjm’s picture

Hi @dgagne,

I recommend discussing what you want to accomplish at a somewhat higher level in a single issue, so as not to fragment the discussion. Here are the related issues:

It should probably be possible to accomplish what you want to try without adding to the API surface like this. So I'd look more into @andypost's suggested directions in #24, and maybe explain the usecase in a bit more detail.

Thanks!

dgagne’s picture

Hi,

Before going forward, I just realized the proposed method $DisplayPluginBase::getExtender(id) is not needed. I was able to use another option.

Now, here is a quick wrap-up. I ported Views Merge Rows to Drupal 8 few months ago because the module maintainer doesn't work on the project anymore. Basically, VMR is run through hook_views_pre_render() and a display extender plugin is designed to define a merge option on a per-field basis. Currently, no style plugin is coded in the module.

Here is a sample of the relevant Drupal 7 code (hook_views_pre_render()):

function views_merge_rows_views_pre_render(&$view) {
  $options = $view->display_handler->extender['views_merge_rows']->get_options();
  if (!$options['merge_rows']) {
    return;
  }
  $rendered_fields = $view->style_plugin->render_fields($view->result);

  [Fields treatment here...]

  // Store the merged rows back to the view's style plugin.
  foreach ($merged_rows as $row_index => $merged_row) {
    foreach ($options['field_config'] as $field_name => $field_config) {
      switch ($field_config['merge_option']) {
        case 'merge':
        case 'merge_unique':
          $view->style_plugin->rendered_fields[$row_index][$field_name]
            = implode($field_config['separator'], $merged_row[$field_name]);
          break;

  [...]

}

My main concern was to keep the module behavior as is. So, here is a sample of the relevant Drupal 8 code (hook_views_pre_render()) as it is currently, assuming patches as they are currently proposed are applied:

function views_merge_rows_views_pre_render(ViewExecutable $view) {
  $items_per_page = get_items_per_page_for_current_display($view);

  $extender = $view->display_handler->getExtenders()['views_merge_rows'];
  //$extender = $view->display_handler->getExtender('views_merge_rows');
  if (isset($extender)) {
      $options = $extender->get_options();
  }
  else {
      $options = NULL;
  }

  if (!is_null($options) && $options['merge_rows'] && $items_per_page > 0) {
    $view->setItemsPerPage(0);
  }
  if (!is_null($options) && $options['merge_rows'] != FALSE) {
      $view->style_plugin->renderFields($view->result);
      $rendered_fields = $view->style_plugin->getRenderedFields();

  [Fields treatment here...]

        foreach ($options['field_config'] as $field_name => $field_config) {
          switch ($field_config['merge_option']) {
            case 'merge':
            case 'merge_unique':
              foreach ($merged_row[$field_name] as $field_index => $field_value) {
                if (empty($field_value)) {
                  unset($merged_row[$field_name][$field_index]);
                }
              }
                if ($field_config['exclude_first']) {
                array_shift($merged_row[$field_name]);
              }
              $value_count = count($merged_row[$field_name]);
              $i = 1;
              foreach ($merged_row[$field_name] as $field_index => $field_value) {
                  if ($i <> $value_count) {
                    $merged_row[$field_name][$field_index] = $field_config['prefix'] . $field_value . $field_config['separator'] . $field_config['suffix'];
                  }
                  else {
                    $merged_row[$field_name][$field_index] = $field_config['prefix'] . $field_value . $field_config['suffix'];
                  }
                  $i++;
              }
              unset($i);
              unset($value_count);
              $view->style_plugin->setRenderedField(implode($merged_row[$field_name]), $row_index, $field_name);
              break;

  [...]
}

Now, regarding @andypost suggestions:
"And the main question in why not inherit your style plugin from base one and alter discovery or views style plugins with own implementation?"

Duplicating current views style plugins would work (I tested the option), but as I pointed out in a prior comment, the module users would be constrained to remain within these and this is not the module's intent. It is intended to be used with whatever Views style the user decides to use. This also has the drawback to duplicate styles in the selection form.

Inheriting a style plugin from base was also looked at before proposing the patches. But as mentioned before, required properties/methods would not be available to default styles. I could alter discovery here (would need to know how to implement that), but once again it would go against the intents behind the module.

With regards to making renderFields() method public, I don't think there is an issue here. The only way I could get rid of that need would be to use another hook where $rendered_fields has been rendered, but I still need an access to that data to manipulate it.

I am really open to suggestions. I would really be happy to close the issues before version 8.4 is released. I am not comfortable to tell my users to patch the core to use the module with Drupal 8. Many thanks in advance.

dgagne’s picture

Status: Postponed (maintainer needs more info) » Needs review
dgagne’s picture

I forgot, here is a sample of renderFields():

  protected function renderFields(array $result) {
    if (!$this->usesFields()) {
      return;
    }

    if (!isset($this->rendered_fields)) {
      $this->rendered_fields = [];
      $this->view->row_index = 0;
      $field_ids = array_keys($this->view->field);

      [...]
  }

The function is called at rendering. It is explicitely checking whether $rendered_fields already exists. I examined the code and my understanding is that such case can only happen if renderFields() is run prior to rendering the view. So I also understand there is an implicit assumption here that renderFields() can be run during the pre-rendering process.

So, there is evidence that this method was intended to be public.

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

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now 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.

colan’s picture

@dgagne: Would you (or someone else that understands the problem) be able to update the issue title and summary with #26 and #28? It would make it much easier for core maintainers to review your original intent, rather than seeing this issue simply as a way to make something public.

Core reviewers/maintainers: Would you kindly take another look at this in the meantime given #26 and #28? This is currently causing #2868486: Call to protected method StylePluginBase::renderFields() in views_merge_rows_views_pre_render() and preventing Views Merge Rows from being usable without hacking core. Thanks!

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

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now 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.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now 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.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.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.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). 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.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now 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: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

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

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mlncn’s picture

Assigned: dgagne » Unassigned
Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

The patch still applies, still works, and is still needed. This 'non-public' API has stayed stable for five years across two major versions of Drupal.

But bottom line, a module needs it and no one has raised a specific objection. Drupal should not be trying to protect developers from themselves but making the tools available to build what it can. Please, let's not keep unnecessary barriers to extending Drupal!

ecj’s picture

Works like a charm! awaiting to become official patch for views.

alexpott’s picture

This method could be private for all of core usages... also I feel that it needs to be looked at alongside #2826755: Create a public read/write interface for $StylePluginBase::rendered_fields as views merge rows requires both patches to work. The work in 2826755 makes me feel uneasy because the idea of swapping out rendered things with setRenderedField() looks like a side-effect bug waiting to happen.

lendude’s picture

Status: Reviewed & tested by the community » Needs work

Just looking at the code of StylePluginBase::renderFields, it reads very much as internal code. Passing something that doesn't match the very vague description of "The result array from $view->result" will probably blow up your View, and there is zero validation of the input in this method (there doesn't need to be, it's protected after all).

At the very least, I think, making this public would require that we give this dedicated test coverage that shows that this is robust enough to be public API. Also we would need to have better documentation on the method to specify what we expect this method to do, and what we expect the result of calling this to be and why you might need to call it from outside the context of the current View rendering pipeline.

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

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.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.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now 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.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now 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: 10.1.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, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

brainiacque’s picture

Is this patch still required for Drupal 10? Composer will not apply this patch; however, I still get errors when building views with this module.

EDIT: Never mind. I was using 'drupal/view_merge_rows' as the project.

rajivgandhi chinnakrishnan’s picture

After applying the patch from (#11), we are getting the below error in 10.3.1. The below patch is the solution for the same.

mlncn’s picture

Issue tags: +Needs reroll
wolcen’s picture

Update of the protected->public patch piece only.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

ruslan piskarov’s picture