1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-08 07:47:00 +02:00

Update PagesLoader.preloadPage() method to support a loadPageRefs option which loads page references separately and as a group. Not yet certain this will remain though, as it seems like the FieldtypePage loader is already fast enough

This commit is contained in:
Ryan Cramer
2024-11-15 14:31:03 -05:00
parent ca74514288
commit 53b7aa39eb

View File

@@ -2052,9 +2052,10 @@ class PagesLoader extends Wire {
* @param Page $page Page to preload fields for
* @param array $fieldNames Names of fields to preload
* @param array $options
* - `debug` (bool): Specify true to return array of debug info (default=false).
* - `debug` (bool): Specify true to include additional debug info in return value (default=false).
* - `useFieldtypeMulti` (bool): Enable FieldtypeMulti for testing purposes (default=false).
* @return int|array Number of fields preloaded, or array of details (if debug)
* - `loadPageRefs` (bool): Optimization to early load pages in page reference fields? (default=true)
* @return array Array containing what was loaded and skipped
* @since 3.0.243
*
*/
@@ -2063,13 +2064,14 @@ class PagesLoader extends Wire {
$defaults = [
'debug' => is_bool($options) ? $options : false,
'useFieldtypeMulti' => false,
'loadPageRefs' => true,
];
static $level = 0;
$options = is_array($options) ? array_merge($defaults, $options) : $defaults;
$debug = $options['debug'];
$database = $page->wire()->database;
$database = $this->wire()->database;
$fieldNames = array_unique($fieldNames);
$fields = $page->wire()->fields;
$loadFields = [];
@@ -2084,10 +2086,9 @@ class PagesLoader extends Wire {
'skipped' => [],
'blank' => [],
'queries' => 1,
'timer' => 0.0,
];
if(!$page->id || !$page->template) return $debug ? $log : 0;
if(!$page->id || !$page->template) return $log;
foreach($fieldNames as $fieldKey => $fieldName) {
@@ -2099,7 +2100,7 @@ class PagesLoader extends Wire {
if($error) {
unset($fieldNames[$fieldKey]);
if($debug) $log['skipped'][$fieldName] = $error;
if($fieldName) $log['skipped'][] = "$fieldName ($error)";
continue;
}
@@ -2127,7 +2128,7 @@ class PagesLoader extends Wire {
unset($fieldNames[$fieldKey]);
}
if(!count($selects)) return $debug ? $log : 0;
if(!count($selects)) return $log;
$level++;
$timer = $debug ? Debug::timer() : false;
@@ -2158,58 +2159,90 @@ class PagesLoader extends Wire {
}
// wake up loaded values and populate to $page
$pageIds = [];
foreach($data as $fieldName => $sleepValue) {
if(!isset($loadFields[$fieldName])) continue;
if(!isset($loadFields[$fieldName])) {
unset($data[$fieldName]);
continue;
}
$field = $loadFields[$fieldName];
$fieldtype = $field->type;
$cols = array_keys($sleepValue);
if(count($cols) === 1 && array_key_exists('data', $sleepValue)) {
$sleepValue = $sleepValue['data'];
}
if($sleepValue === null) continue; // force to getBlankValue in loop below this
if($sleepValue === null) {
unset($data[$fieldName]);
continue; // force to getBlankValue in loop below this
}
if($options['useFieldtypeMulti'] && $fieldtype instanceof FieldtypeMulti) {
if(strrpos($sleepValue, FieldtypeMulti::multiValueSeparator)) {
$sleepValue = explode(FieldtypeMulti::multiValueSeparator, $sleepValue);
}
}
if($fieldtype instanceof FieldtypePage && $sleepValue && $options['loadPageRefs']) {
if(!is_array($sleepValue)) $sleepValue = [ $sleepValue ];
foreach($sleepValue as $pageId) {
$pageId = (int) $pageId;
if(!$pageId) continue;
if($this->pages->cacher()->hasCache($pageId)) continue;
$parentId = $field->get('parent_id');
$templateId = FieldtypePage::getTemplateIDs($field, true);
if(!ctype_digit("$parentId")) $parentId = 0;
if(!ctype_digit("$templateId")) $templateId = 0;
$groupKey = "$parentId,$templateId";
if(!isset($pageIds[$groupKey])) $pageIds[$groupKey] = [];
$pageIds[$groupKey][$pageId] = $pageId;
}
}
$data[$fieldName] = $sleepValue;
}
// preload all pages in template or parent groups
if(count($pageIds)) {
foreach($pageIds as $groupKey => $ids) {
list($parentId, $templateId) = explode(',', $groupKey);
$this->pages->getByID($ids, [ 'template' => $templateId, 'parent_id' => $parentId ]);
}
}
foreach($data as $fieldName => $sleepValue) {
$field = $loadFields[$fieldName];
$fieldtype = $field->type;
$value = $fieldtype->wakeupValue($page, $field, $sleepValue);
$page->_parentSet($field->name, $value);
$loadedFields[$field->name] = $fieldName;
unset($loadFields[$field->name]);
if($debug) {
$log['loaded'][$fieldName] = "$fieldtype->shortName: " . implode(',', $cols);
}
unset($loadFields[$field->name]);
$log['loaded'][] = $fieldName;
}
// any remaining loadFields not present in DB should get blank value
foreach($loadFields as $field) {
$value = $field->type->getBlankValue($page, $field);
$page->_parentSet($field->name, $value);
if($debug) $log['blank'][$field->name] = $field->type->shortName;
$fieldName = $field->name;
$page->_parentSet($fieldName, $value);
$log['blank'][] = $fieldName;
}
$numLoaded = count($loadedFields);
// go recursive for any remaining fields
if(count($fieldNames)) {
$result = $this->preloadFields($page, $fieldNames, $debug);
if($debug) {
foreach($log as $key => $value) {
if(is_array($value)) {
$log[$key] = array_merge($value, $result[$key]);
} else if(is_int($value)) {
$log[$key] += $result[$key];
}
$result = $this->preloadFields($page, $fieldNames, $options);
foreach($log as $key => $value) {
if(is_array($value)) {
$log[$key] = array_merge($value, $result[$key]);
} else if(is_int($value)) {
$log[$key] += $result[$key];
}
} else {
$numLoaded += $result;
}
}
$level--;
if($debug && $timer && !$level) $log['timer'] = Debug::timer($timer);
return $debug ? $log : $numLoaded;
return $log;
}
/**
@@ -2285,7 +2318,7 @@ class PagesLoader extends Wire {
} else if($fieldtype instanceof FieldtypePage && $field->get('derefAsPage') > 0) {
// allow single-page matches
} else {
$error = "$shortName: Unsupported";
$error = "$shortName: Unsupported without useFieldtypeMulti=true";
}
} else if($fieldtype instanceof FieldtypeFieldsetOpen) {
$error = 'Fieldset: Unsupported';