1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-10 08:44:46 +02:00

Add new Selectors::selectorHasField() selector helper optimization method

This commit is contained in:
Ryan Cramer
2021-03-11 11:48:43 -05:00
parent 6b153794c8
commit 7cb11850e8

View File

@@ -31,7 +31,7 @@ require_once(PROCESSWIRE_CORE_PATH . "Selector.php");
* @link https://processwire.com/api/selectors/ Official Selectors Documentation
* @method Selector[] getIterator()
*
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer
* https://processwire.com
*
* @todo Move static helper methods to dedicated API var/class so this class can be more focused
@@ -1599,6 +1599,148 @@ class Selectors extends WireArray {
return $has;
}
/**
* Does given selector have given field (and optionally operator and/or value)?
*
* #pw-group-static-helpers
*
* @param string|array|Selectors $selectors Selector string, array or Selectors object to look in
* @param string|array $fieldName Field name string to match or array of them to match any one of them
* @param array $options
* - `verbose` (bool): Return associative array with verbose result? See return value. (default=false)
* - `operator` (string): Require this operator (default='' for any)
* - `value` (string|int): Require this value (default=null for any)
* - `remove` (bool): Remove matched Selector from Selectors returned in verbose result? (default=false)
* @return array|bool True of has field, false if not, or array with the following if 'verbose' option requested:
* - `result` (bool): Did it match (true or false)
* - `selector` (Selector|null): Selector object that matched (only if result is true)
* - `selectors` (Selectors|null): Selectors object that was analyzed or null if not needed
* - `field` (string): Field name that matched
* - `operator` (string): Operator that matched
* - `value` (string|null): Value that matched or null if not applicable
* @since 3.0.174
*
*/
static public function selectorHasField($selectors, $fieldName, array $options = array()) {
$defaults = array(
'operator' => '', // require this operator
'value' => null, // require this value
'verbose' => false, // return verbose information?
'remove' => false, // remove matched Selector from Selectors (when/if applicable)
);
$result = array(
'result' => false, // true if field found, false if not
'selectors' => null, // Selectors object when used
'selector' => null, // first Selector that matched
'field' => '', // field name that matched
'operator' => '', // operator that matched
'value' => null, // value that matched or null if not applicable
);
$options = count($options) ? array_merge($defaults, $options) : $defaults;
$fail = false;
if(is_array($selectors)) {
$selectors = new Selectors($selectors);
} else if(is_string($selectors)) {
if(is_array($fieldName)) {
foreach($fieldName as $key => $name) {
if(strpos($selectors, $name) === false) unset($fieldName[$key]);
}
$count = count($fieldName);
$fail = $count === 0;
if($count === 1) $fieldName = reset($fieldName); // simplify 1-item array to string
} else if(strpos($selectors, $fieldName) === false) {
$fail = true;
}
} else if(!$selectors instanceof Selectors) {
$fail = true;
}
if($fail) {
return ($options['verbose'] ? $result : $result['result']);
}
if(!$selectors instanceof Selectors) {
$selectors = new Selectors($selectors);
}
/** @var Selectors $selectors */
foreach($selectors as $selector) {
if($options['operator'] && $selector->operator() !== $options['operator']) continue;
$field = $selector->field;
// require specific field or one of array of fields to match
if(is_string($field)) {
// field is string
if(is_array($fieldName)) {
// find field in fieldName array
if(!in_array($field, $fieldName)) continue;
} else {
// both field and fieldName are strings
if($field !== $fieldName) continue;
}
} else if(is_array($field)) {
// field is array
if(is_array($fieldName)) {
// both field and fieldName are arrays
$has = false;
foreach($fieldName as $name) {
$has = in_array($name, $field) ? $name : false;
if($has) break;
}
if(!$has) continue;
$field = $has;
} else {
// find fieldName in field array
$key = array_search($fieldName, $field);
if($key === false) continue;
$field = $field[$key];
}
} else {
// field in unrecognized format (should not be reachable)
continue;
}
if($options['value'] !== null) {
// require specific value to match
$value = $selector->value;
if(is_array($value)) {
if(!in_array($options['value'], $value)) continue;
// match success
$result['value'] = $options['value'];
} else {
if("$value" !== "$options[value]") continue;
// match success
$result['value'] = $value;
}
} else {
// match success
$result['value'] = $selector->value;
}
if($options['remove']) $selectors->remove($selector);
$result = array_merge($result, array(
'result' => true,
'selectors' => $selectors,
'selector' => $selector,
'field' => $field,
'operator' => $selector->operator(),
));
break;
}
return ($options['verbose'] ? $result : $result['result']);
}
/**
* Simple "a=b, c=d" selector-style string conversion to associative array, for fast/simple needs
*
@@ -1614,7 +1756,7 @@ class Selectors extends WireArray {
* @return array
*
*/
public static function keyValueStringToArray($s) {
static public function keyValueStringToArray($s) {
if(strpos($s, '~~COMMA') !== false) $s = str_replace('~~COMMA', '', $s);
if(strpos($s, '~~EQUAL') !== false) $s = str_replace('~~EQUAL', '', $s);
@@ -1651,7 +1793,7 @@ class Selectors extends WireArray {
* @return string
*
*/
public static function arrayToKeyValueString($a) {
static public function arrayToKeyValueString($a) {
$s = '';
foreach($a as $key => $value) {
if(strpos($value, ',') !== false) $value = str_replace(array(',,', ','), ',,', $value);