mirror of
https://github.com/processwire/processwire.git
synced 2025-08-15 03:05:26 +02:00
Upgrade Page matching in-memory selectors by adding support for OR-groups, sub-selectors, and same (1) item group matches.
This commit is contained in:
@@ -214,7 +214,7 @@ class PageComparison {
|
|||||||
// exit early for simple path comparison
|
// exit early for simple path comparison
|
||||||
return true;
|
return true;
|
||||||
} else if($page->name === $s) {
|
} else if($page->name === $s) {
|
||||||
// early exit for simple name atch
|
// early exit for simple name match
|
||||||
return true;
|
return true;
|
||||||
} else if(Selectors::stringHasOperator($s)) {
|
} else if(Selectors::stringHasOperator($s)) {
|
||||||
// selectors string
|
// selectors string
|
||||||
@@ -243,39 +243,138 @@ class PageComparison {
|
|||||||
if(!empty($options['useDatabase'])) {
|
if(!empty($options['useDatabase'])) {
|
||||||
$selectors->add(new SelectorEqual('id', $page->id))->add(new SelectorEqual('include', 'all'));
|
$selectors->add(new SelectorEqual('id', $page->id))->add(new SelectorEqual('include', 'all'));
|
||||||
return $page->wire()->pages->count($selectors) > 0;
|
return $page->wire()->pages->count($selectors) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$matches = false;
|
$matchFail = false;
|
||||||
|
$groupSelectors = array(); // same (1) item match group selectors
|
||||||
|
$orGroupSelectors = array(); // OR-group selectors
|
||||||
|
|
||||||
foreach($selectors as $selector) {
|
foreach($selectors as $selector) {
|
||||||
|
|
||||||
$property = $selector->field;
|
if($selector->quote === '(') {
|
||||||
$subproperty = '';
|
// OR-groups are handled below this loop
|
||||||
|
$orGroup = $selector->field() . '.';
|
||||||
if(is_array($property)) $property = reset($property);
|
if(!isset($orGroupSelectors[$orGroup])) $orGroupSelectors[$orGroup] = array();
|
||||||
if(strpos($property, '.')) list($property, $subproperty) = explode('.', $property, 2);
|
$orGroupSelectors[$orGroup][] = $selector;
|
||||||
if(in_array($property, $this->matchesIgnores)) continue;
|
continue;
|
||||||
|
|
||||||
$matches = true;
|
|
||||||
$value = $page->getUnformatted($property);
|
|
||||||
|
|
||||||
if(is_object($value)) {
|
|
||||||
// convert object to array value(s)
|
|
||||||
$value = $this->getObjectValueArray($value, $subproperty);
|
|
||||||
} else if(is_array($value)) {
|
|
||||||
// ok: selector matches will accept an array
|
|
||||||
} else {
|
|
||||||
// convert to a string value, whatever it may be
|
|
||||||
$value = "$value";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$selector->matches($value)) {
|
if(!$this->selectorMatches($page, $selector)) {
|
||||||
$matches = false;
|
$matchFail = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($selector->group !== null) {
|
||||||
|
// validate that same (1) item matches from these later
|
||||||
|
$groupName = $selector->group;
|
||||||
|
if(!isset($groupSelectors[$groupName])) $groupSelectors[$groupName] = array();
|
||||||
|
$groupSelectors[$groupName][] = $selector;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OR-groups
|
||||||
|
if(!$matchFail && count($orGroupSelectors)) {
|
||||||
|
foreach($orGroupSelectors as /* $orGroupName => */ $selectors) {
|
||||||
|
$orGroupMatches = false;
|
||||||
|
foreach($selectors as $selector) {
|
||||||
|
if($this->matches($page, $selector->value)) {
|
||||||
|
// OR-group selector matches
|
||||||
|
$orGroupMatches = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!$orGroupMatches) {
|
||||||
|
$matchFail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// same (1) item match groups
|
||||||
|
if(!$matchFail && count($groupSelectors)) {
|
||||||
|
foreach($groupSelectors as /* $groupName => */ $selectors) {
|
||||||
|
$matchGroupKeys = null;
|
||||||
|
foreach($selectors as $selector) {
|
||||||
|
$keys = $selector->get('_matchGroupKeys'); // populated by selectorMatchesProperty
|
||||||
|
if($matchGroupKeys === null) {
|
||||||
|
$matchGroupKeys = $keys;
|
||||||
|
} else {
|
||||||
|
$matchGroupKeys = array_intersect($matchGroupKeys, $keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(empty($matchGroupKeys)) {
|
||||||
|
$matchFail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !$matchFail;
|
||||||
|
}
|
||||||
|
|
||||||
return $matches;
|
/**
|
||||||
|
* Return whether individual Selector object matches Page
|
||||||
|
*
|
||||||
|
* @param Page $page
|
||||||
|
* @param Selector $selector
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function selectorMatches(Page $page, Selector $selector) {
|
||||||
|
$match = false;
|
||||||
|
$properties = $selector->fields();
|
||||||
|
foreach($properties as $property) {
|
||||||
|
$match = $this->selectorMatchesProperty($page, $selector, $property);
|
||||||
|
if($match) break;
|
||||||
|
}
|
||||||
|
return $match;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether single property from individual Selector matches Page
|
||||||
|
*
|
||||||
|
* @param Page $page
|
||||||
|
* @param Selector $selector
|
||||||
|
* @param string $property
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function selectorMatchesProperty(Page $page, Selector $selector, $property) {
|
||||||
|
|
||||||
|
$subproperty = '';
|
||||||
|
if(strpos($property, '.')) list($property, $subproperty) = explode('.', $property, 2);
|
||||||
|
if(in_array($property, $this->matchesIgnores)) return true;
|
||||||
|
|
||||||
|
if($selector->quote === '[' && Selectors::stringHasOperator($selector->value())) {
|
||||||
|
$selector->value = $page->wire()->pages->findIDs($selector->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $page->getUnformatted($property);
|
||||||
|
|
||||||
|
if(is_object($value)) {
|
||||||
|
// convert object to array value(s)
|
||||||
|
$value = $this->getObjectValueArray($value, $subproperty);
|
||||||
|
|
||||||
|
} else if(is_array($value)) {
|
||||||
|
// ok: selector matches will accept an array
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// convert to a string value, whatever it may be
|
||||||
|
$value = "$value";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$selector->matches($value)) return false;
|
||||||
|
|
||||||
|
if($selector->group !== null && is_array($value)) {
|
||||||
|
// see which individual values match and record their keys for later comparison
|
||||||
|
$matchGroupKeys = array();
|
||||||
|
foreach($value as $key => $val) {
|
||||||
|
if($selector->matches($val)) $matchGroupKeys[] = $key;
|
||||||
|
}
|
||||||
|
$selector->setQuietly('_matchGroupKeys', $matchGroupKeys); // used by matches() method
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user