1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-13 18:24:57 +02:00

Add $pages->loader()->findCache() method - Find pages and cache the result for specified period of time. This is an experimental method that may find it's way to the public $pages API but is currently behind $pages->loader() while we experiment with it more and make sure it's worthwhile.

This commit is contained in:
Ryan Cramer
2023-05-19 14:54:04 -04:00
parent 481f6bbbdb
commit d455ab71cb

View File

@@ -818,6 +818,109 @@ class PagesLoader extends Wire {
return $page && $page->id ? $page : $this->pages->newNullPage();
}
/**
* Find pages and cache the result for specified period of time
*
* Use this when you want to cache a slow or complex page finding operation so that it doesnt
* have to be repated for every web request. Note that this only caches the find operation
* and not the loading of the found pages.
*
* ~~~~~
* $items = $pages->findCache("title%=foo"); // 60 seconds (default)
* $items = $pages->findCache("title%=foo", 3600); // 1 hour
* $items = $pages->findCache("title%=foo", "+1 HOUR"); // same as above
* ~~~~~
*
* @param string|array|Selectors $selector
* @param int|string|bool|null $expire When the cache should expire, one of the following:
* - Max age integer (in seconds).
* - Any string accepted by PHPs `strtotime()` that specifies when the cache should be expired.
* - Any `WireCache::expire…` constant or anything accepted by the `WireCache::get()` $expire argument.
* @param array $options Options to pass to `$pages->getByIDs()`, or:
* - `findIDs` (bool): Return just the page IDs rather then the actual pages? (default=false)
* @return PageArray|array
* @since 3.0.218
*
*/
public function findCache($selector, $expire = 60, $options = array()) {
$user = $this->wire()->user;
$cache = $this->wire()->cache;
$ns = 'pages.findCache';
$items = null;
if(is_string($selector)) {
$selectorStr = $selector;
$selectors = $selector;
} else {
$selectors = $this->wire(new Selectors($selector));
$selectorStr = (string) $selectors;
}
$rolesStr = (string) $user->roles;
if(strpos($rolesStr, '|')) {
$rolesArray = explode('|', $rolesStr);
sort($rolesArray);
$rolesStr = implode('|', $rolesArray);
}
$optionsStr = '';
foreach($options as $key => $value) {
if(!is_string($value)) {
if(is_array($value)) $value = print_r($value, true);
$value = (string) $value;
}
$optionsStr .= "$key==$value,";
}
$cacheName = "$rolesStr\r$selectorStr\r$optionsStr";
$pageNum = $this->wire()->input->pageNum();
if($pageNum > 1 && Selectors::selectorHasField($selectors, 'limit')) {
if(!Selectors::selectorHasField($selectors, 'start')) $cacheName .= "\r$pageNum";
}
$cacheName = md5($cacheName);
$data = $cache->getFor($ns, $cacheName, $expire);
if(!empty($data) && $data['selector'] === $selectorStr && $data['roles'] === $rolesStr) {
$ids = $data['pages'];
} else {
$ids = null;
if(strpos($selectorStr, 'template') !== false && empty($options['template'])) {
$info = Selectors::selectorHasField($selectors, array('template', 'templates_id'), array('verbose' => true));
if($info['result']) $options['template'] = $this->wire()->templates->get($info['value']);
echo "template=$options[template]\n";
}
}
if($ids === null) {
if(empty($options['findIDs'])) {
$items = $this->find($selectors, $options);
$ids = $items->explode('id');
} else {
$ids = $this->pages->findIDs($selectors, $options);
}
$data = array(
'selector' => $selectorStr,
'roles' => $rolesStr,
'pages' => $ids
);
$cache->saveFor($ns, $cacheName, $data, $expire);
} else if(empty($options['findIDs'])) {
$items = $this->pages->getByIDs($ids, $options);
}
if(!empty($options['findIDs'])) return $ids;
foreach($items as $item) {
if($item instanceof NullPage || $item->status & Page::statusTrash) {
$items->remove($item);
}
}
return $items;
}
/**
* Returns the first page matching the given selector with no exclusions
*