mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 00:06:55 +02:00
Update the Page::matches() method to make it smarter and more flexible. This also accommodates issue #21.
This commit is contained in:
@@ -49,13 +49,27 @@ class PageComparison {
|
|||||||
*/
|
*/
|
||||||
public function matches(Page $page, $s) {
|
public function matches(Page $page, $s) {
|
||||||
|
|
||||||
|
$selectors = array();
|
||||||
|
|
||||||
if(is_string($s) || is_int($s)) {
|
if(is_string($s) || is_int($s)) {
|
||||||
if(ctype_digit("$s")) $s = (int) $s;
|
if(ctype_digit("$s")) $s = (int) $s;
|
||||||
if(is_string($s)) {
|
if(is_string($s)) {
|
||||||
|
if(!strlen($s)) {
|
||||||
|
// blank string matches nothing
|
||||||
|
return false;
|
||||||
|
} else if(substr($s, 0, 1) == '/' && $page->path() == (rtrim($s, '/') . '/')) {
|
||||||
// exit early for simple path comparison
|
// exit early for simple path comparison
|
||||||
if(substr($s, 0, 1) == '/' && $page->path() == (rtrim($s, '/') . '/')) return true;
|
return true;
|
||||||
if(!Selectors::stringHasOperator($s)) return false;
|
} else if($page->name === $s) {
|
||||||
|
// early exit for simple name atch
|
||||||
|
return true;
|
||||||
|
} else if(Selectors::stringHasOperator($s)) {
|
||||||
|
// selectors string
|
||||||
$selectors = $page->wire(new Selectors($s));
|
$selectors = $page->wire(new Selectors($s));
|
||||||
|
} else {
|
||||||
|
// some other type of string
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else if(is_int($s)) {
|
} else if(is_int($s)) {
|
||||||
// exit early for simple ID comparison
|
// exit early for simple ID comparison
|
||||||
@@ -66,39 +80,27 @@ class PageComparison {
|
|||||||
$selectors = $s;
|
$selectors = $s;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// unknown data type to match
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$matches = false;
|
$matches = false;
|
||||||
|
$ignores = array('limit', 'start', 'sort', 'include');
|
||||||
|
|
||||||
foreach($selectors as $selector) {
|
foreach($selectors as $selector) {
|
||||||
|
|
||||||
$name = $selector->field;
|
$property = $selector->field;
|
||||||
if(in_array($name, array('limit', 'start', 'sort', 'include'))) continue;
|
$subproperty = '';
|
||||||
|
|
||||||
|
if(strpos($property, '.')) list($property, $subproperty) = explode('.', $property, 2);
|
||||||
|
if(in_array($property, $ignores)) continue;
|
||||||
|
|
||||||
$matches = true;
|
$matches = true;
|
||||||
$value = $page->getUnformatted($name);
|
$value = $page->getUnformatted($property);
|
||||||
|
|
||||||
if(is_object($value)) {
|
if(is_object($value)) {
|
||||||
// if the current page value resolves to an object
|
// convert object to array value(s)
|
||||||
if($value instanceof Page) {
|
$value = $this->getObjectValueArray($value, $subproperty);
|
||||||
// if it's a Page, get both the ID and path as allowed comparison values
|
|
||||||
$value = array($value->id, $value->path);
|
|
||||||
} else if($value instanceof PageArray) {
|
|
||||||
// if it's a PageArray, then get the ID and path of all of them
|
|
||||||
// @todo add support for @ selectors
|
|
||||||
$_value = array();
|
|
||||||
foreach($value as $v) {
|
|
||||||
$_value[] = $v->id;
|
|
||||||
$_value[] = $v->path;
|
|
||||||
}
|
|
||||||
$value = $_value;
|
|
||||||
} else if($value instanceof Template) {
|
|
||||||
$value = array($value->id, $value->name);
|
|
||||||
} else {
|
|
||||||
// otherwise just get the string value of the object
|
|
||||||
$value = "$value";
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if(is_array($value)) {
|
} else if(is_array($value)) {
|
||||||
// ok: selector matches will accept an array
|
// ok: selector matches will accept an array
|
||||||
} else {
|
} else {
|
||||||
@@ -115,5 +117,112 @@ class PageComparison {
|
|||||||
return $matches;
|
return $matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an object, return the value(s) it represents (optionally from a property in the object)
|
||||||
|
*
|
||||||
|
* This method is setup for the matches() method above this. It will go recursive when given a property
|
||||||
|
* that resolves to another object.
|
||||||
|
*
|
||||||
|
* @param Wire|object $object
|
||||||
|
* @param string $property Optional property to pull from object (may also be property.subproperty, and so on)
|
||||||
|
* @return array Always returns an array, which may be empty or populated
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function getObjectValueArray($object, $property = '') {
|
||||||
|
|
||||||
|
$value = array();
|
||||||
|
$_property = $property; // original
|
||||||
|
$subproperty = '';
|
||||||
|
if(strpos($property, '.')) list($property, $subproperty) = explode('.', $property, 2);
|
||||||
|
|
||||||
|
// if the current page value resolves to an object
|
||||||
|
if($object instanceof Page) {
|
||||||
|
// object is a Page
|
||||||
|
if($property) {
|
||||||
|
// pull specific property from page
|
||||||
|
$v = $object->getUnformatted($property);
|
||||||
|
if(is_object($v)) {
|
||||||
|
$value = $this->getObjectValueArray($v, $subproperty);
|
||||||
|
} else if(!is_null($v)) {
|
||||||
|
$value = array($v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if no property, get id, name and path as allowed comparison values
|
||||||
|
$value[] = $object->id;
|
||||||
|
$value[] = $object->path;
|
||||||
|
$value[] = $object->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if($object instanceof WireArray) {
|
||||||
|
// it's a WireArray|PageArray
|
||||||
|
|
||||||
|
if($property === 'count') {
|
||||||
|
// quick exit for count property
|
||||||
|
return array(count($object));
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate and get value of each item present
|
||||||
|
foreach($object as $v) {
|
||||||
|
if(is_object($v)) {
|
||||||
|
$v = $this->getObjectValueArray($v, $_property); // use original property.subproperty
|
||||||
|
if(count($v)) $value = array_merge($value, $v);
|
||||||
|
} else {
|
||||||
|
$value[] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if($object instanceof Template) {
|
||||||
|
// Template object, compare to id and name
|
||||||
|
if($property) {
|
||||||
|
$v = $object->get($property);
|
||||||
|
if(!is_null($v)) $value[] = $v;
|
||||||
|
} else {
|
||||||
|
$value[] = $object->id;
|
||||||
|
$value[] = $object->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if($object instanceof WireData) {
|
||||||
|
// some other type of WireData object
|
||||||
|
if($property) {
|
||||||
|
$v = $object->get($property);
|
||||||
|
if(is_object($v)) {
|
||||||
|
$value = $this->getObjectValueArray($v, $subproperty);
|
||||||
|
} else if(!is_null($v)) {
|
||||||
|
$value = array($v);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// no property present, so we'll find some other way to identify the object
|
||||||
|
// get string value of object as a potential comparison
|
||||||
|
$v = (string) $object;
|
||||||
|
// string value that doesn't match class name identifies the object in some way
|
||||||
|
if($v !== wireClassName($object)) $value[] = $v;
|
||||||
|
// if the object uses the common 'id' or 'name' properties, consider those as well
|
||||||
|
foreach(array('id', 'name') as $key) {
|
||||||
|
$v = $object->get($key);
|
||||||
|
if(!is_null($v)) $value[] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if($property && method_exists($object, '__get')) {
|
||||||
|
// some other object, property is present, object has a __get method that we can pull it from
|
||||||
|
$v = $object->__get($property);
|
||||||
|
if(is_object($v)) {
|
||||||
|
$value = $this->getObjectValueArray($v, $subproperty);
|
||||||
|
} else if(!is_null($v)) {
|
||||||
|
$value = array($v);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(!$property && method_exists($object, '__toString')) {
|
||||||
|
// items in WireArray are some type of Wire, use string value if not className
|
||||||
|
if(wireClassName($object) != (string) $object) $value[] = (string) $object;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// property present with some kind of value that we don't know how to pull from
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -225,10 +225,17 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
|
|||||||
$selector = $findPagesSelector;
|
$selector = $findPagesSelector;
|
||||||
if($editPage) $selector = self::getFindPagesSelector($editPage, $selector);
|
if($editPage) $selector = self::getFindPagesSelector($editPage, $selector);
|
||||||
if(!$page->matches($selector)) {
|
if(!$page->matches($selector)) {
|
||||||
|
// failed in-memory check, attempt $page->count() check...
|
||||||
|
$selector .= ", id=$page->id";
|
||||||
|
if($page->wire('pages')->count($selector)) {
|
||||||
|
// looks like its okay
|
||||||
|
} else {
|
||||||
|
// also fails $pages->cont() check, so definitely not valid
|
||||||
if($editPage) $editPage->set('_isValidPage', "Page $page does not match findPagesSelector: $selector");
|
if($editPage) $editPage->set('_isValidPage', "Page $page does not match findPagesSelector: $selector");
|
||||||
$valid = false;
|
$valid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if($field->findPagesCode) { } // we don't currently validate these
|
// if($field->findPagesCode) { } // we don't currently validate these
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user