Problem/Motivation

Discovered while working on #2735997: Decimal separator and precision settings unavailable when aggregating decimal fields, but independent of decimal formatting. This issue concerns how the Views aggregation-settings form selects its handler during submission.

When aggregation is enabled, Views may replace an entity field handler with an aggregation-specific handler. ConfigHandlerGroup::buildForm() uses that overridden handler and stores it in form state. However, ConfigHandlerGroup::submitForm() recreates the underlying entity field handler instead of reusing the handler that built the form.

If the numeric handler built the form, the entity field handler subsequently attempts to submit group_column and group_columns elements that were not present. This causes a TypeError when EntityField::submitGroupByForm() passes the missing group_columns value to array_filter().

An AJAX HTTP error occurred. \HTTP Result Code: 500
Debugging information follows. 
Path: /admin/structure/views/ajax/handler-group/awards/default/field/field_decimal_test
StatusText: error 
ResponseText: The website encountered an unexpected error. Try again later. 
TypeError: array_filter(): Argument #1 ($array) must be of type array, null given in array_filter() (Line 727 of core/modules/views/ src/Plugin/views/field/EntityField.php). Drupal\views\Plugin\views\field\EntityField-> submitGroupByForm() (Line: 106
Drupal\views_ui\Form\Ajax\|ConfigHandlerGroup->submitForm(/
call_user_func_array@) (Line: 268)
Drupal\views_ui\ViewUI->standardSubmit()
call_user_func_array() (Line: 129) 
Drupal\Core\Form\FormSubmitter-> executeSubmitHandlers() (Line: 67) 
Drupal\Core\Form\FormSubmitter-> doSubmitForm() (Line: 597)
Drupal\Core\Form\FormBuilder->processForm() (Line: 326) 
Drupal\Core\Form\FormBuilder->buildForm() (Line: 215)
Drupal\views_ui\Form\Ajax\ViewsFormBase->Drupal\ Iviews_ui\Form\Ajax\{closure}() (Line: 638)
Drupal\Core\Render\Renderer->executeInRenderContext()(Line: 217)
Drupal\views_ui\Form\Ajax\ViewsFormBase->ajaxFormwrapper() (Line: 127)
Drupal|\views_ui\
\Form\ \Ajax\ViewsFormBase->getForm() (Line: 38) 
Drupal\views_ui\Form\Ajax\ConfigHandlerGroup->getForm() 
call_user_func_array() (Line: 123) 
Drupal\Core\EventSubscriber\
\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber|/closureF() (Line: 638) 
Drupal\Core\Render\Renderer-> executeInRenderContext() (Line: 121 
Drupal\ \Corel \EventSubscriber1
\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97) 
Drupal||Core|\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal||Core\EventSubscriber||(closure]
() (Line: 181) 
Symfony\Component\HttpKernel|\HttpKernel->handleRaw() (Line: 76) 
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 53) 
Drupal\Core\StackMiddleware|\Session->handle() (Line:
48 
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28) 
Drupal1\Core\StackMiddleware\ContentLength->handle() (Line: 116 
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line:
90) 
Drupal\page_cache\|StackMiddleware\PageCache->handle() (Line: 48)
Drupal\Core\StackMiddleware|\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware|
egotiationMiddleware-
> handle() (Line: 36) 
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51) 
Drupal\Core\StackMiddleware|\StackedHttpKernel->handle() (Line: 741) 
Drupal\Core\DrupalKernel->handle() (Line.
19) 
", name: "AjaxError", stack: "...


Before aggregation enabled, field aggregation settings saved options:


Before aggregation, aggregation options


Missing options after save aggregation settings and exception tested for:


Missing options after save aggregation settings and exception tested for

Missing field settings after aggregation function saved:

Decimal Field settings missing after saved aggregation settings

Steps to reproduce

  1. Create a content View and enable aggregation.
  2. Add an entity field such as Content: ID.
  3. Open its aggregation settings.
  4. Select Count and apply the change.
  5. Reopen the aggregation settings.
  6. Apply Count again, or switch back to “Group results together.”
  7. Observe that the AJAX request fails with an unexpected-error response.

Expected:
The handler that built the aggregation form submits it, and the setting can be saved or changed without an error.

Actual:
The original entity field handler submits a form built by the numeric handler and expects handler-specific elements that are absent.

Proposed resolution

Reuse the initialized handler stored in form state by ConfigHandlerGroup::buildForm() when submitting the form. Store that handler’s updated options back on the View.

Issue fork drupal-3613882

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

joelpittet created an issue. See original summary.

joelpittet’s picture

Issue summary: View changes

joelpittet’s picture

Issue summary: View changes
joelpittet’s picture

Priority: Normal » Major
Issue summary: View changes

Rewriting the issue summary and changing this to major due to the exception.

joelpittet’s picture

Status: Active » Needs review
joelpittet’s picture

Title: Aggregation settings form builds and submits with different handlers, causing an exception » TypeError: array_filter() Aggregation settings form builds and submits with different handlers
Component: views.module » views_ui.module
Issue summary: View changes

Tweaking the title and adding the callstack from the screenshot to help people discover this issue better. Moving to views_ui.module component

acbramley’s picture

Status: Needs review » Reviewed & tested by the community

This is looking good to go, nice catch @joelpittet!

joelpittet’s picture

Thanks again @acbramley!

I went dupe hunting and this one is super close: #3344910: Ajax error on views with aggregation

The diff:

The current #3344910: Ajax error on views with aggregation MR changes build so it uses the original handler:

$handler = \Drupal::service('views.plugin_managers')
  ->get($type)
  ->getHandler($item);

instead of the aggregation-overridden handler.

This MR "accepts" that Views intentionally built the form using the aggregation handler and makes submit reuse that exact handler:
$handler = $form_state->get('handler');

That directly enforces:

the handler that built the form submits it.

turneight’s picture

I'm glad someone looked into this issue thoroughly and that the test I developed was helpful.

I tried the patch, and the AJAX error no longer occurs.

However, the secondary settings are no longer visible after subsequent changes.

Tested on Umami 11.4.6

Unless you also want to keep the changes from #3344910 or change the way Views provides aggregation settings.

joelpittet’s picture

Status: Reviewed & tested by the community » Needs work

I am going to set this to NW to try and reproduce #10, thanks for testing @turneight. I haven't run into this yet.

turneight’s picture

The main problem is that the views default aggregations are all numeric, but NumericField doesn't handle the aggregation fields.
So, when the NumericField handler is called, it doesn't find the settings.
I think the problem needs to be fixed in the views.

turneight’s picture

Status: Needs work » Reviewed & tested by the community

I've taken a closer look at how aggregations work.
The hidden display of grouping options when selecting an aggregation method appears to be expected behavior, not a bug.

I apologize for the false alarm.

I've noticed AJAX errors when running aggregations with minimum and maximum values ​​on text fields. You'd expect the minimum or maximum value to be displayed in the text field, rather than an error. But this is another issue that was already present.

I'm restoring the status of this MR.

quietone’s picture

Title: TypeError: array_filter() Aggregation settings form builds and submits with different handlers » Aggregation settings form builds and submits with different handlers