1
0
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:
Ryan Cramer
2018-12-07 09:57:07 -05:00
parent 0dc8766491
commit af0afe9f95
3 changed files with 102 additions and 29 deletions

View File

@@ -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

View File

@@ -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)";

View File

@@ -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