mirror of
https://github.com/processwire/processwire.git
synced 2025-08-12 01:34:31 +02:00
Additional updates for processwire/processwire-issues#751 plus some enhancements to PageFinder
This commit is contained in:
@@ -3149,9 +3149,10 @@ class Page extends WireData implements \Countable, WireMatchable {
|
||||
/**
|
||||
* Return the index/position of this page relative to siblings.
|
||||
*
|
||||
* If given a hidden or unpublished page, that page would not usually be part of the group of siblings,
|
||||
* unless specifically including hidden and/or unpublished pages. As a result, such pages will return -1
|
||||
* for this method (as of 3.0.121), indicating they are not part of the default index.
|
||||
* If given a hidden or unpublished page, that page would not usually be part of the group of siblings.
|
||||
* As a result, such pages will return what the value would be if they were visible (as of 3.0.121). This
|
||||
* may overlap with the index of other pages, since indexes are relative to visible pages, unless you
|
||||
* specify an include mode (see next paragraph).
|
||||
*
|
||||
* If you want this method to include hidden/unpublished pages as part of the index numbers, then
|
||||
* specify boolean true for the $selector argument (which implies "include=all") OR specify a
|
||||
|
@@ -43,7 +43,7 @@ class PageFinder extends Wire {
|
||||
*
|
||||
*/
|
||||
'findUnpublished' => false,
|
||||
|
||||
|
||||
/**
|
||||
* Specify that it's okay for hidden AND unpublished AND trashed pages to be included in the results
|
||||
*
|
||||
@@ -56,6 +56,12 @@ class PageFinder extends Wire {
|
||||
*/
|
||||
'findAll' => false,
|
||||
|
||||
/**
|
||||
* Always allow these page IDs to be included regardless of findHidden, findUnpublished, findTrash, findAll settings
|
||||
*
|
||||
*/
|
||||
'alwaysAllowIDs' => array(),
|
||||
|
||||
/**
|
||||
* This is an optimization used by the Pages::find method, but we observe it here as we may be able
|
||||
* to apply some additional optimizations in certain cases. For instance, if loadPages=false, then
|
||||
@@ -326,7 +332,7 @@ class PageFinder extends Wire {
|
||||
/**
|
||||
* Return all pages matching the given selector.
|
||||
*
|
||||
* @param Selectors|string|array $selectors Selectors object or selector string
|
||||
* @param Selectors|string|array $selectors Selectors object, selector string or selector array
|
||||
* @param array $options
|
||||
* - `findOne` (bool): Specify that you only want to find 1 page and don't need info for pagination (default=false).
|
||||
* - `findHidden` (bool): Specify that it's okay for hidden pages to be included in the results (default=false).
|
||||
@@ -345,7 +351,7 @@ class PageFinder extends Wire {
|
||||
* - `returnQuery` (bool): When true, only the DatabaseQuery object is returned by find(), for internal use. (default=false)
|
||||
* - `loadPages` (bool): This is an optimization used by the Pages::find() method, but we observe it here as we
|
||||
* may be able to apply some additional optimizations in certain cases. For instance, if loadPages=false, then
|
||||
* we can skip retrieval of IDs and omit sort fields. (default=true)
|
||||
* we can skip retrieval of IDs and omit sort fields. (default=true)
|
||||
* - `stopBeforeID` (int): Stop loading pages once a page matching this ID is found. Page having this ID will be
|
||||
* excluded as well (default=0).
|
||||
* - `startAfterID` (int): Start loading pages once a page matching this ID is found. Page having this ID will be
|
||||
@@ -365,7 +371,7 @@ class PageFinder extends Wire {
|
||||
if(is_string($selectors) || is_array($selectors)) {
|
||||
$selectors = new Selectors($selectors);
|
||||
} else if(!$selectors instanceof Selectors) {
|
||||
throw new PageFinderException("find() requires Selectors object or string");
|
||||
throw new PageFinderException("find() requires Selectors object, string or array");
|
||||
}
|
||||
|
||||
$this->fieldgroups = $this->wire('fieldgroups');
|
||||
@@ -487,16 +493,48 @@ class PageFinder extends Wire {
|
||||
/**
|
||||
* Same as find() but returns just a simple array of page IDs without any other info
|
||||
*
|
||||
* @param Selectors $selectors
|
||||
* @param Selectors|string|array $selectors Selectors object, selector string or selector array
|
||||
* @param array $options
|
||||
* @return array of page IDs
|
||||
*
|
||||
*/
|
||||
public function findIDs(Selectors $selectors, $options = array()) {
|
||||
public function findIDs($selectors, $options = array()) {
|
||||
$options['returnVerbose'] = false;
|
||||
return $this->find($selectors, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a count of pages that match
|
||||
*
|
||||
* @param Selectors|string|array $selectors Selectors object, selector string or selector array
|
||||
* @param array $options
|
||||
* @return int
|
||||
* @since 3.0.121
|
||||
*
|
||||
*/
|
||||
public function count($selectors, $options = array()) {
|
||||
|
||||
$defaults = array(
|
||||
'getTotal' => true,
|
||||
'getTotalType' => 'count',
|
||||
'loadPages' => false,
|
||||
'returnVerbose' => false
|
||||
);
|
||||
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
if(!empty($options['startBeforeID']) || !empty($options['stopAfterID'])) {
|
||||
$options['loadPages'] = true;
|
||||
$options['getTotalType'] = 'calc';
|
||||
$count = count($this->find($selectors, $options));
|
||||
} else {
|
||||
$this->find($selectors, $options);
|
||||
$count = $this->total;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-process given Selectors object
|
||||
*
|
||||
@@ -737,7 +775,7 @@ class PageFinder extends Wire {
|
||||
|
||||
if($findExtends) {
|
||||
if($foundTypes === null) {
|
||||
$foundTypes = isset($this->pageArrayData['extends']) ? $this->pageDataArray['extends'] : array();
|
||||
$foundTypes = isset($this->pageArrayData['extends']) ? $this->pageArrayData['extends'] : array();
|
||||
}
|
||||
$fType = $f->type->className();
|
||||
if(isset($foundTypes[$fType])) {
|
||||
@@ -1130,7 +1168,7 @@ class PageFinder extends Wire {
|
||||
continue;
|
||||
|
||||
} else if($this->wire('fields')->isNative($field) || strpos($fieldsStr, ':parent.') !== false) {
|
||||
$this->getQueryNativeField($query, $selector, $fields);
|
||||
$this->getQueryNativeField($query, $selector, $fields, $options);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1944,10 +1982,11 @@ class PageFinder extends Wire {
|
||||
* @param DatabaseQuerySelect $query
|
||||
* @param Selector $selector
|
||||
* @param array $fields
|
||||
* @param array $options
|
||||
* @throws PageFinderSyntaxException
|
||||
*
|
||||
*/
|
||||
protected function getQueryNativeField(DatabaseQuerySelect $query, $selector, $fields) {
|
||||
protected function getQueryNativeField(DatabaseQuerySelect $query, $selector, $fields, array $options) {
|
||||
|
||||
$values = $selector->values(true);
|
||||
$SQL = '';
|
||||
@@ -2077,6 +2116,14 @@ class PageFinder extends Wire {
|
||||
if($isName) $value = $this->wire('sanitizer')->pageName($value, Sanitizer::toAscii);
|
||||
$value = $database->escapeStr($value);
|
||||
$s = "$table." . $field . $operator . ((ctype_digit("$value") && $field != 'name') ? ((int) $value) : "'$value'");
|
||||
|
||||
if($field === 'status' && strpos($operator, '<') === 0 && $value >= Page::statusHidden && count($options['alwaysAllowIDs'])) {
|
||||
// support the 'alwaysAllowIDs' option for specific page IDs when requested but would
|
||||
// not otherwise appear in the results due to hidden or unpublished status
|
||||
$allowIDs = array();
|
||||
foreach($options['alwaysAllowIDs'] as $id) $allowIDs[] = (int) $id;
|
||||
$s = "($s OR $table.id IN(" . implode(',', $allowIDs) . '))';
|
||||
}
|
||||
}
|
||||
|
||||
if($selector->not) $s = "NOT ($s)";
|
||||
|
@@ -282,11 +282,26 @@ class PageTraversal {
|
||||
return $page->_pages('find', $selector, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get include mode specified in selector or blank if none
|
||||
*
|
||||
* @param string|array|Selectors $selector
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
protected function _getIncludeMode($selector) {
|
||||
if(is_string($selector) && strpos($selector, 'include=') === false) return '';
|
||||
if(is_array($selector)) return isset($selector['include']) ? $selector['include'] : '';
|
||||
$selector = $selector instanceof Selectors ? $selector : new Selectors($selector);
|
||||
$include = $selector->getSelectorByField('include');
|
||||
return $include ? $include->value() : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the PageFinder options for the _next() method
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string|array $selector
|
||||
* @param string|array|Selectors $selector
|
||||
* @param array $options
|
||||
* @return array
|
||||
*
|
||||
@@ -298,7 +313,16 @@ class PageTraversal {
|
||||
'startAfterID' => $options['prev'] ? 0 : $page->id,
|
||||
'stopBeforeID' => $options['prev'] ? $page->id : 0,
|
||||
'returnVerbose' => $options['all'] ? false : true,
|
||||
'alwaysAllowIDs' => array(),
|
||||
);
|
||||
|
||||
if($page->isUnpublished() || $page->isHidden()) {
|
||||
// allow next() to still move forward even though it is hidden or unpublished
|
||||
$includeMode = $this->_getIncludeMode($selector);
|
||||
if(!$includeMode || ($includeMode === 'hidden' && $page->isUnpublished())) {
|
||||
$fo['alwaysAllowIDs'][] = $page->id;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$options['until']) return $fo;
|
||||
|
||||
@@ -346,7 +370,7 @@ class PageTraversal {
|
||||
* Provides the core logic for next, prev, nextAll, prevAll, nextUntil, prevUntil
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string|array $selector Optional selector. When specified, will find nearest sibling(s) that match.
|
||||
* @param string|array|Selectors $selector Optional selector. When specified, will find nearest sibling(s) that match.
|
||||
* @param array $options Options to modify behavior
|
||||
* - `prev` (bool): When true, previous siblings will be returned rather than next siblings.
|
||||
* - `all` (bool): If true, returns all nextAll or prevAll rather than just single sibling (default=false).
|
||||
@@ -378,8 +402,12 @@ class PageTraversal {
|
||||
|
||||
if(is_array($selector)) {
|
||||
$selector['parent_id'] = $parent->id;
|
||||
} else {
|
||||
} else if(is_string($selector)) {
|
||||
$selector = trim("parent_id=$parent->id, $selector", ", ");
|
||||
} else if($selector instanceof Selectors) {
|
||||
$selector->add(new SelectorEqual('parent_id', $parent->id));
|
||||
} else {
|
||||
throw new WireException('Selector must be string, array or Selectors object');
|
||||
}
|
||||
|
||||
$pageFinder = $pages->getPageFinder();
|
||||
@@ -416,15 +444,16 @@ class PageTraversal {
|
||||
* Return the index/position of the given page relative to its siblings
|
||||
*
|
||||
* If given a hidden or unpublished page, that page would not usually be part of the group of siblings.
|
||||
* As a result, such pages will return -1 for this method (as of 3.0.121), indicating they are not part
|
||||
* of the default index.
|
||||
* As a result, such pages will return what the value would be if they were visible (as of 3.0.121). This
|
||||
* may overlap with the index of other pages, since indexes are relative to visible pages, unless you
|
||||
* specify an include mode (see next paragraph).
|
||||
*
|
||||
* If you want this method to include hidden/unpublished pages as part of the index numbers, then
|
||||
* specify boolean true for the $selector argument (which implies "include=all") OR specify a
|
||||
* selector of "include=hidden", "include=unpublished" or "include=all".
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string|array|bool $selector Selector to apply or boolean true for "include=all" (since 3.0.121).
|
||||
* @param string|array|bool|Selectors $selector Selector to apply or boolean true for "include=all" (since 3.0.121).
|
||||
* - Boolean true to include hidden and unpublished pages as part of the index numbers (same as "include=all").
|
||||
* - An "include=hidden", "include=unpublished" or "include=all" selector to include them in the index numbers.
|
||||
* - A string selector or selector array to filter the criteria for the returned index number.
|
||||
@@ -432,12 +461,8 @@ class PageTraversal {
|
||||
*
|
||||
*/
|
||||
public function index(Page $page, $selector = '') {
|
||||
if($selector === true) {
|
||||
$selector = "include=all";
|
||||
} else if(empty($selector) && ($page->isHidden() || $page->isUnpublished())) {
|
||||
return -1;
|
||||
}
|
||||
$index = $this->_next($page, $selector, array('prev' => true, 'all' => true, 'qty' => true));
|
||||
if($selector === true) $selector = "include=all";
|
||||
$index = $this->_next($page, $selector, array('prev' => true, 'all' => true, 'qty' => 'index'));
|
||||
return $index;
|
||||
}
|
||||
|
||||
@@ -445,7 +470,7 @@ class PageTraversal {
|
||||
* Return the next sibling page
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string $selector Optional selector. When specified, will find nearest next sibling that matches.
|
||||
* @param string|array|Selectors $selector Optional selector. When specified, will find nearest next sibling that matches.
|
||||
* @return Page|NullPage Returns the next sibling page, or a NullPage if none found.
|
||||
*
|
||||
*/
|
||||
@@ -457,7 +482,7 @@ class PageTraversal {
|
||||
* Return the previous sibling page
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string $selector Optional selector. When specified, will find nearest previous sibling that matches.
|
||||
* @param string|array|Selectors $selector Optional selector. When specified, will find nearest previous sibling that matches.
|
||||
* @return Page|NullPage Returns the previous sibling page, or a NullPage if none found.
|
||||
*
|
||||
*/
|
||||
@@ -470,7 +495,7 @@ class PageTraversal {
|
||||
* Return all sibling pages after this one, optionally matching a selector
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string $selector Optional selector. When specified, will filter the found siblings.
|
||||
* @param string|array|Selectors $selector Optional selector. When specified, will filter the found siblings.
|
||||
* @param array $options Options to pass to the _next() method
|
||||
* @return PageArray Returns all matching pages after this one.
|
||||
*
|
||||
@@ -485,7 +510,7 @@ class PageTraversal {
|
||||
* Return all sibling pages prior to this one, optionally matching a selector
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string $selector Optional selector. When specified, will filter the found siblings.
|
||||
* @param string|array|Selectors $selector Optional selector. When specified, will filter the found siblings.
|
||||
* @param array $options Options to pass to the _next() method
|
||||
* @return PageArray Returns all matching pages after this one.
|
||||
*
|
||||
@@ -503,7 +528,7 @@ class PageTraversal {
|
||||
* Return all sibling pages after this one until matching the one specified
|
||||
*
|
||||
* @param Page $page
|
||||
* @param string|Page|array $selector May either be a selector or Page to stop at. Results will not include this.
|
||||
* @param string|Page|array|Selectors $selector May either be a selector or Page to stop at. Results will not include this.
|
||||
* @param string|array $filter Optional selector to filter matched pages by
|
||||
* @param array $options Options to pass to the _next() method
|
||||
* @return PageArray
|
||||
|
Reference in New Issue
Block a user