processwire-issues
processwire-issues copied to clipboard
Nonexistent values are not cached with `field=myfield`, causing unneeded SQL queries
Short description of the issue
If I loop pages fetched with find("template=$template, field=mytext"), calling $page->mytext makes a database query for each page that do not have mytext value. This causes an "N+1 queries problem", potentially making a lot of unneeded queries.
Expected behavior
field=mytext should cache both the value and absence of a value, and no further database queries is needed when $page->mytext is accessed.
Actual behavior
For each page without mytext, $page->mytext triggers the query
SELECT field_mytext.data AS `mytext__data` FROM `field_mytext` WHERE field_mytext.pages_id=1015`
Optional: Suggestion for a possible fix
I suspect this to be a regression of https://github.com/processwire/processwire/commit/4344df336b0e8839e71c809b37d0a73bd1d7c2f5.
I believe the code should read:
if(strpos($key, '__')) {
if($value === null) {
$row[$key] = 'null'; // ensure detected by later isset in foreach($joinFields)
}
$page->setFieldValue($key, $value, false); // <--- always do this, as before the regression
} else {
$page->setForced($key, $value);
}
Steps to reproduce the issue
- Add a few pages
- Add a text field
mytexttobasic-page - Fill
mytextfor one page - Create and run this file:
<?php
$processwirePath = '/var/www/html/';
include($processwirePath . 'index.php');
$pages = $wire->pages->find("template=basic-page, field=mytext");
foreach($pages as $page) {
echo $page->mytext;
}
$queries = $wire->database->getQueryLog();
echo '<p>Number queries: ' . count($queries) . '</p>';
foreach($queries as $query){
echo '<p>' . htmlspecialchars($query) . '</p>';
}
- See that queries like the one above is executed for each page without
mytext.
Setup/Environment
- ProcessWire version: dev, vanilla installation with just one field added
- (Optional) PHP version: 8.2
- (Optional) MySQL version: MariaDB 10.5.26