1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-24 15:23:11 +02:00

Add new $page->if(condition, yes, no) convenience method

This commit is contained in:
Ryan Cramer
2019-02-13 14:53:59 -05:00
parent b499aad60e
commit 3f5773e674
2 changed files with 203 additions and 5 deletions

View File

@@ -77,9 +77,12 @@
* @property string $editURL Alias of $editUrl. #pw-internal
* @property PageRender $render May be used for field markup rendering like $page->render->title. #pw-advanced
* @property bool $loaderCache Whether or not pages loaded as a result of this one may be cached by PagesLoaderCache. #pw-internal
* @property PageArray $references Return pages that are referencing the given one by way of Page references. #pw-group-traversal
* @property int $numReferences Total number of pages referencing this page with Page reference fields. #pw-group-traversal
* @property int $hasReferences Number of visible pages (to current user) referencing this page with page reference fields. #pw-group-traversal
* @property PageArray $referencing Return pages that this page is referencing by way of Page reference fields. #pw-group-traversal
* @property int $numReferencing Total number of other pages this page is pointing to (referencing) with Page fields. #pw-group-traversal
* @property PageArray $links Return pages that link to this one contextually in Textarea/HTML fields. #pw-group-traversal
* @property int $numLinks Total number of pages manually linking to this page in Textarea/HTML fields. #pw-group-traversal
* @property int $hasLinks Number of visible pages (to current user) linking to this page in Textarea/HTML fields. #pw-group-traversal
*
@@ -149,6 +152,7 @@
* @method string|mixed renderValue($value, $file) Returns rendered markup for $value using $file relative to templates/fields/. #pw-internal
* @method PageArray references($selector = '', $field = '') Return pages that are pointing to this one by way of Page reference fields. #pw-group-traversal
* @method PageArray links($selector = '', $field = '') Return pages that link to this one contextually in Textarea/HTML fields. #pw-group-traversal
* @method string|mixed if($key, $yes, $no = '') If value is available for $key return or call $yes condition (with optional $no condition)
*
* Alias/alternate methods
* -----------------------
@@ -1220,18 +1224,34 @@ class Page extends WireData implements \Countable, WireMatchable {
}
/**
* Returns whether or not $field is valid for this Page
* Returns whether or not given $field name, ID or object is valid for this Page
*
* Note that this only indicates validity, not whether the field is populated.
*
* #pw-advanced
*
* @param int|string|Field $field Field name, object or ID to chck
* @return bool True if valid, false if not.
* @param int|string|Field|array $field Field name, object or ID to check.
* - In 3.0.126+ this may also be an array or pipe "|" separated string of field names to check.
* @return bool|string True if valid, false if not.
* - In 3.0.126+ returns first matching field name if given an array of field names or pipe separated string of field names.
*
*/
public function hasField($field) {
return $this->template ? $this->template->fieldgroup->hasField($field) : false;
if(!$this->template) return false;
if(is_string($field) && strpos($field, '|') !== false) {
$field = explode('|', $field);
}
if(is_array($field)) {
$result = false;
foreach($field as $f) {
$f = trim($f);
if(!empty($f) && $this->hasField($f)) $result = $f;
if($result) break;
}
} else {
$result = $this->template->fieldgroup->hasField($field);
}
return $result;
}
/**
@@ -1479,6 +1499,94 @@ class Page extends WireData implements \Countable, WireMatchable {
return $value;
}
/**
* If value is available for $key return or call $yes condition (with optional $no condition)
*
* This merges the capabilities of an if() statement, get() and getMarkup() methods in one,
* plus some useful PW type-specific logic, providing a useful output shortcut. It many situations
* it enables you to accomplish on one-line of code what might have otherwise taken multiple lines
* of code. Use this when looking for a useful shortcut and this one fits your need, otherwise
* use a regular PHP if() statement.
*
* This function is primarily intended for conditionally outputting some formatted string value or
* markup, however its use is not limited to that, as you can specify whatever youd like for the
* $yes and $no conditions. The examples section best describes potential usages of this method,
* so I recommend looking at those before reading all the details of this method.
*
* Note that the logic is a little bit smarter for PW than a regular PHP if() statement in these ways:
*
* - If value resolves to any kind of *empty* `WireArray` (like a `PageArray`) the NO condition is used.
* If the WireArray is populated with at least one item then the YES condition is used. So this if()
* method (unlike PHP if) requires that not only is the value present, but it is also populated.
*
* - If value resolves to a `NullPage` the NO condition is used.
*
* The `$key` argument may be any of the following:
*
* - A field name, in which case we will use the value of that field on this page. If the value is
* empty the NO condition will be used, otherwise the YES condition will be used. You can use any
* format for the field name that the `Page::get()` method accepts, so subfields and OR field
* statements are also okay, i.e. `categories.count`, `field1|field2|field3', etc.
*
* - A selector string that must match this page in order to return the YES condition. If it does not
* match then the NO condition will be used.
*
* - A boolean, integer, digit string or PHP array. If considered empty by PHP it will return the NO
* condition, otherwise it will return the YES condition.
*
* The `$yes` and `$no` arguments (the conditional actions) may be any of the following:
*
* - Any string value that youd like (HTML markup is fine too).
*
* - A field name that is present on this page, or optionally the word “value” to refer to the field
* specified in the `$key` argument. Either way, makes this method return the actual field value as it
* exists on the page, rather than a string/markup version of it. Note that if this word (“value”) is
* used for the argument then of course the `$key` argument must be a field name (not a selector string).
*
* - Any callable inline function that returns the value you want this function to return.
*
* - A string containing one or more `{field}` placeholders, where you replace “field” with a field name.
* These are in turn populated by the `Page::getMarkup()` method. You can also use `{field.subfield}`
* and `{field1|field2|field3}` type placeholder strings.
*
* - A string containing `{val}` or `{value}` where they will be replaced with the markup value of the
* field name given in the $key argument.
*
* - If you omit the `$no` argument an empty string is assumed.
*
* - If you omit both the `$yes` and `$no` arguments, then boolean is assumed (true for yes, false for no),
* which makes this method likewise return a boolean. The only real reason to do this would be to take
* advantage of the methods slightly different behavior than regular PHP if() statements (i.e. treating
* empty WireArray or NullPage objects as false conditions).
*
* ~~~~~
* // if summary is populated, output it in an paragraph
* echo $page->if("summary", "<p class='summary'>{summary}</p>");
*
* // same as above, but shows you can specify {value} to assume field in $key arg
* echo $page->if("summary", "<p class='summary'>{value}</p>");
*
* // if price is populated, format for output, otherwise ask them to call for price
* echo $page->if("price", function($val) { return '$' . number_format($val); }, "Please call");
*
* // you can also use selector strings
* echo $page->if("inventory>10", "In stock", "Limited availability");
*
* // output an <img> tag for the first image on the page, or blank if none
* echo $page->if("images", function($val) { return "<img src='{$val->first->url}'>"; });
* ~~~~~
*
* @param string|bool|int $key Name of field to check, selector string to evaluate, or boolean/int to evalute
* @param string|callable|mixed $yes If value for $key is present, return or call this
* @param string|callable|mixed $no If value for $key is empty, return or call this
* @return mixed|string|bool
* @since 3.0.126
*
*/
public function ___if($key, $yes = '', $no = '') {
return $this->comparison()->_if($this, $key, $yes, $no);
}
/**
* Return the markup value for a given field name or {tag} string
@@ -1555,7 +1663,7 @@ class Page extends WireData implements \Countable, WireMatchable {
return $value;
}
/**
* Same as getMarkup() except returned value is plain text
*

View File

@@ -39,6 +39,96 @@ class PageComparison {
return false;
}
/**
* If value is available for $key return or call $yes condition (with optional $no condition)
*
* This merges the capabilities of an if() statement, get() and getMarkup() methods in one,
* plus some useful PW type-specific logic, providing a useful output shortcut.
*
* See phpdoc in `Page::if()` for full details.
*
* @param Page $page
* @param string|bool|int $key Name of field to check, selector string to evaluate, or boolean/int to evalute
* @param string|callable|mixed $yes If value for $key is present, return or call this
* @param string|callable|mixed $no If value for $key is empty, return or call this
* @return mixed|string|bool
* @since 3.0.126
*
*/
public function _if(Page $page, $key, $yes = '', $no = '') {
/** @var Sanitizer $sanitizer */
$sanitizer = $page->wire('sanitizer');
// if only given a key argument, we will be returning a boolean
if($yes === '' && $no === '') list($yes, $no) = array(true, false);
if(is_bool($key) || is_int($key)) {
// boolean or int
$val = $key;
$action = empty($val) ? $no : $yes;
} else if(ctype_digit("$key")) {
// integer or string value of Wire object
$val = (int) $key;
$action = empty($val) ? $no : $yes;
} else if(!ctype_alnum("$key") && Selectors::stringHasOperator($key)) {
// selector string
$val = $page->matches($key) ? 1 : 0;
$action = $val ? $yes : $no;
} else {
// field name or other format string accepted by $page->get()
$val = $page->get($key);
$action = empty($val) || ($val instanceof WireArray && !$val->count()) || $val instanceof NullPage ? $no : $yes;
}
if(is_string($action)) {
// action is a string
$getValue = false;
$tools = $sanitizer->getTextTools();
if(($action === 'value' || $action === 'val') && !$page->template->fieldgroup->hasField($action)) {
// implicit 'value' or 'val' maps back to name specified in $key argument
$getValue = $key;
}
if(empty($action)) {
$result = $action;
} else if($getValue) {
$result = $page->get($getValue);
} else if($tools->hasPlaceholders($action)) {
// action is a getMarkup() string
$keyIsFieldName = $sanitizer->fieldName($key) === $key;
$act = $action;
// if value placeholders present, replace them with field name placeholders
foreach(array('{value}', '{val}') as $tag) {
// string with {val} or {value} has that tag replaced with the {field_name}
if(strpos($action, $tag) === false) continue;
// if val or value is actually the name of a field in the system, then do not override it
if($page->hasField(trim($tag, '{}'))) continue;
$action = str_replace($tag, ($keyIsFieldName ? '{' . $key . '}' : $val), $action);
}
$result = $act === $action || $tools->hasPlaceholders($action) ? $page->getMarkup($action) : $action;
} else if($sanitizer->fieldSubfield($action, -1) === $action && $page->hasField($sanitizer->fieldSubfield($action, 0))) {
// action is another field name that we want to get the value for
$result = $page->get($action);
} else {
// action is just a string to return
$result = $action;
}
} else if(is_callable($action)) {
// action is callable
$result = call_user_func_array($action, array($val, $key, $page));
} else {
// action is a number, array or object
$result = $action;
}
return $result;
}
/**
* Given a Selectors object or a selector string, return whether this Page matches it
*