Skip to content

Joining a PageTable field results in an empty value when the field has more than one page #2066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
tuomassalo opened this issue Apr 22, 2025 · 0 comments

Comments

@tuomassalo
Copy link

NB: this is closely related to #1988

Short description of the issue

When a page has a PageTable field and it's joined with e.g. $pages->get($selector, ['loadOptions' => ['joinFields' => ['c_ref']]]) or $pages->find($selector, ['loadOptions' => ['joinFields' => ['c_ref']]]) (as opposed to id=123, field=c_ref), the resulting $p->c_ref is empty when the field contains more than one page.

Expected behavior

Adding joinFields should not affect the result, only performance.

Actual behavior

If there are more than one subpage, they are not fetched.

Screenshots/Links that demonstrate the issue

Possible cause: PageValues.php tries to explode the value, but only does it if the GROUP_CONCAT separator is seen in the results.

Issue #1988 was fixed by making sure that $value is an array.

I believe the correct way to fix this would be to avoid searching for separators in the string, and instead make sure that we always explode after GROUP_CONCAT. But it seems to me that instead we could just change the earlier FieldtypePageTable.php fix like this:

-if($value && !is_array($value)) $value = array($value);
+if($value && !is_array($value)) $value = explode(FieldtypeMulti::multiValueSeparator, $value);

Steps to reproduce the issue

The script below creates a parent and child template, p and c, and a field c_ref in the p template. Then it adds these pages:

Parent: parent-a
  Child: child-a1
  Child: child-a2
Parent: parent-b
  Child: child-b1

If run without GET params, it fetches all the pages and prints the above output. If run with ?join, only the lone child child-b1 is printed.

Setup/Environment

  • ProcessWire version: latest dev
  • (Optional) PHP version: 8.4

The script:

<?php

$processwirePath = '/var/www/html/';
include($processwirePath . 'index.php');
header('Content-Type: text/plain');

////// Install fixture templates, field and pages.
////// First, clean up previous run (if any).

// Remove pages with template 'p' or 'c'.
$pagesToRemove = $pages->find("template=p|c");
foreach ($pagesToRemove as $page) $pages->delete($page, true);

$pagesToRemove = $pages->find("template=p|c");
foreach ($pagesToRemove as $page) $pages->delete($page, true);

// Remove templates 'p' and 'c'.
$pTemplate = $templates->get('p');
if ($pTemplate) $templates->delete($pTemplate);

$cTemplate = $templates->get('c');
if ($cTemplate) $templates->delete($cTemplate);

// Remove field 'c_ref' if it exists.
$field = $fields->get('c_ref');
if ($field) $fields->delete($field);

// Create templates and field.

$pTemplate = $templates->add('p');
$pTemplate->save();

$cTemplate = $templates->add('c');
$cTemplate->save();

$field = $fields->makeItem();
$field->name = 'c_ref';
$field->type = 'PageTable';
$field->label = "c_ref";
$field->template_id = [$cTemplate->id];
$field->inputfield = "InputfieldPageTable";
$field->parent_id = 1;
$field->save();
$pTemplate->fields->add($field);
$pTemplate->save();

// Create pages.
$parent_a = $pages->add('p', '/', 'parent-a');

$child_a1 = $pages->add('c', '/', 'child-a1');
$parent_a->c_ref->add($child_a1);
$parent_a->save();

$child_a2 = $pages->add('c', '/', 'child-a2');
$parent_a->c_ref->add($child_a2);
$parent_a->save();

$parent_b = $pages->add('p', '/', 'parent-b');

$child_b1 = $pages->add('c', '/', 'child-b1');
$parent_b->c_ref->add($child_b1);
$parent_b->save();

//////// Now everything is set up.

$options = isset($_GET['join']) ? ['loadOptions' => ['joinFields' => ['c_ref']]] : [];

echo "--- get() ---\n";

foreach (['parent-a', 'parent-b'] as $parentName) {
    $parent = $wire->pages->get("name=$parentName", $options);
    echo "Parent: $parentName\n";

    foreach ($parent->c_ref as $child) {
        echo "  Child: " . $child->name . "\n";
    }
}

$wire->pages->unCacheAll();

echo "--- find() ---\n";

foreach ($wire->pages->find("template=p", $options) as $parent) {
    echo "Parent: $parent->name\n";

    foreach ($parent->c_ref as $child) {
        echo "  Child: " . $child->name . "\n";
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant