Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
The way OrderTotalSummary
and OrderItemTable
formatters build their renderable array is not compatible with inserting them into views.
Here are the steps to reproduce:
- Make sure you have at least some orders already generated in your store
- Create a new view on commerce order
- Add "Total price" field to the view and specify "order total summary" as its formatter
- Add "Order items" field to the view and specify "order item table" as its formatter
- Observe nothing output in those 2 fields when the view is executed.
Both just do a simple (no-children) renderable array:
\Drupal\commerce_order\Plugin\Field\FieldFormatter\OrderTotalSummary::viewElements()
:
public function viewElements(FieldItemListInterface $items, $langcode) {
$order = $items->getEntity();
return [
'#theme' => 'commerce_order_total_summary',
'#totals' => $this->orderTotalSummary->buildTotals($order),
];
}
\Drupal\commerce_order\Plugin\Field\FieldFormatter\OrderItemTable::viewElements()
:
public function viewElements(FieldItemListInterface $items, $langcode) {
$order = $items->getEntity();
return [
'#type' => 'view',
// @todo Allow the view to be configurable.
'#name' => 'commerce_order_item_table',
'#arguments' => [$order->id()],
'#embed' => TRUE,
];
}
Then the view runs the following code (in \Drupal\views\Plugin\views\field\EntityField::getItems()
):
public function getItems(ResultRow $values) {
if (!$this->displayHandler->useGroupBy()) {
$build_list = $this->getEntityFieldRenderer()->render($values, $this);
}
else {
// For grouped results we need to retrieve a massaged entity having
// grouped field values to ensure that "grouped by" values, especially
// those with multiple cardinality work properly. See
// \Drupal\Tests\views\Kernel\QueryGroupByTest::testGroupByFieldWithCardinality.
$display = [
'type' => $this->options['type'],
'settings' => $this->options['settings'],
'label' => 'hidden',
];
// Optional relationships may not provide an entity at all. So we can't
// use createEntityForGroupBy() for those rows.
if ($entity = $this->getEntity($values)) {
$entity = $this->createEntityForGroupBy($entity, $values);
// Some bundles might not have a specific field, in which case the faked
// entity doesn't have it either.
$build_list = isset($entity->{$this->definition['field_name']}) ? $entity->{$this->definition['field_name']}->view($display) : NULL;
}
else {
$build_list = NULL;
}
}
// ---------------------
// --------------------- Here the $build_list is what the formatter has given us in its ::viewElements().
// ---------------------
if (!$build_list) {
return [];
}
if ($this->options['field_api_classes']) {
return [['rendered' => $this->renderer->render($build_list)]];
}
// ---------------------
// --------------------- The part below is the problem: here we expect the $build_list to be
// --------------------- indexed by deltas whereas the 2 formatters do not index them
// --------------------- that way.
// ---------------------
// Render using the formatted data itself.
$items = [];
// Each item is extracted and rendered separately, the top-level formatter
// render array itself is never rendered, so we extract its bubbleable
// metadata and add it to each child individually.
$bubbleable = BubbleableMetadata::createFromRenderArray($build_list);
foreach (Element::children($build_list) as $delta) {
BubbleableMetadata::createFromRenderArray($build_list[$delta])
->merge($bubbleable)
->applyTo($build_list[$delta]);
$items[$delta] = [
'rendered' => $build_list[$delta],
// Add the raw field items (for use in tokens).
'raw' => $build_list['#items'][$delta],
];
}
// ---------------------
// --------------------- Thus down here we wind up with empty $items.
// ---------------------
return $items;
}
Comment | File | Size | Author |
---|---|---|---|
#3 | phpunit-results.txt | 34.19 KB | bucefal91 |
#2 | 2871569-order-formatters-for-views-2.patch | 2.01 KB | bucefal91 |
Comments
Comment #2
bucefal91 CreditAttribution: bucefal91 at Websolutions Agency commentedLooking at the docs to the
::viewElements()
method (in\Drupal\Core\Field\FormatterInterface
) we see:So the interface obliges its implementations to index the returned renderable array by deltas. That means the 2 formatters are the offending side in this views vs. formatters confrontation :)
I attach a patch that simply wraps the existing 2 formatters into this delta notion that is expected from them.
Comment #3
bucefal91 CreditAttribution: bucefal91 at Websolutions Agency commentedI am not sure why it didn't want to queue my patch for testing, but I ran tests locally (including the JS ones) and have the following results (attached as a txt file).
Comment #4
sumanthkumarc CreditAttribution: sumanthkumarc at Azri Solutions commented@bucefal91 , the D.O issue queues are used for issue management and the github repo of commerce : https://github.com/drupalcommerce is used for PR. then the code is synced back. i guess there's some problme with drupal CI bot for commerce.
Comment #5
sumanthkumarc CreditAttribution: sumanthkumarc at Azri Solutions commentedfollow issue here: https://www.drupal.org/node/2855587 for CI bot, if you can help
Comment #6
bucefal91 CreditAttribution: bucefal91 at Websolutions Agency commentedI see. Didn't know about that. Thanks for letting me know.
Here's the pull request https://github.com/drupalcommerce/commerce/pull/723 (I hope I did everything properly, it's my 1st pull request on git hub :) )
Comment #7
bojanz CreditAttribution: bojanz at Centarro commentedLeft comments on the PR, don't see why we're introducing the if ($items->count() > 0) { check.
Comment #8
bojanz CreditAttribution: bojanz at Centarro commentedThis got forgotten for a long time. Wrapping up.
Comment #10
bojanz CreditAttribution: bojanz at Centarro commentedSorry for the delay!