mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 00:06:55 +02:00
Various updates including optimizations to WireHooks, support for a hookable renderReadyHook method in Inputfield, cache prevention measures for Pages::findMany() per @apeisa, and some work in progress on InputfieldSelector support for improved "custom (field=value)" searches.
This commit is contained in:
@@ -44,16 +44,22 @@ class HookEvent extends WireData {
|
|||||||
/**
|
/**
|
||||||
* Construct the HookEvent and establish default values
|
* Construct the HookEvent and establish default values
|
||||||
*
|
*
|
||||||
|
* @param array $eventData Optional event data to start with
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function __construct(array $eventData = array()) {
|
||||||
$this->set('object', null);
|
$data = array(
|
||||||
$this->set('method', '');
|
'object' => null,
|
||||||
$this->set('arguments', array());
|
'method' => '',
|
||||||
$this->set('return', null);
|
'arguments' => array(),
|
||||||
$this->set('replace', false);
|
'return' => null,
|
||||||
$this->set('options', array());
|
'replace' => false,
|
||||||
$this->set('id', '');
|
'options' => array(),
|
||||||
$this->set('cancelHooks', false);
|
'id' => '',
|
||||||
|
'cancelHooks' => false
|
||||||
|
);
|
||||||
|
if(!empty($eventData)) $data = array_merge($data, $eventData);
|
||||||
|
$this->data = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -202,7 +208,7 @@ class HookEvent extends WireData {
|
|||||||
* ~~~~~
|
* ~~~~~
|
||||||
*
|
*
|
||||||
* @param string|null $hookId
|
* @param string|null $hookId
|
||||||
* @return $this
|
* @return HookEvent|WireData $this
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function removeHook($hookId) {
|
public function removeHook($hookId) {
|
||||||
@@ -227,6 +233,5 @@ class HookEvent extends WireData {
|
|||||||
return $s;
|
return $s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -69,7 +69,7 @@
|
|||||||
* @property InputfieldWrapper|null $parent The parent InputfieldWrapper for this Inputfield or null if not set. #pw-internal
|
* @property InputfieldWrapper|null $parent The parent InputfieldWrapper for this Inputfield or null if not set. #pw-internal
|
||||||
* @property null|bool|Fieldtype $hasFieldtype The Fieldtype using this Inputfield, or boolean false when known not to have a Fieldtype, or null when not known. #pw-group-other
|
* @property null|bool|Fieldtype $hasFieldtype The Fieldtype using this Inputfield, or boolean false when known not to have a Fieldtype, or null when not known. #pw-group-other
|
||||||
* @property bool|null $useLanguages When multi-language support active, can be set to true to make it provide inputs for each language, where supported (default=false). #pw-group-behavior
|
* @property bool|null $useLanguages When multi-language support active, can be set to true to make it provide inputs for each language, where supported (default=false). #pw-group-behavior
|
||||||
* @property null|bool|int $entityEncodeLabel Set to boolean false to specifically disable entity encoding of field header/label, or set to a Inputfield::textFormat constant. (default=true). #pw-group-output
|
* @property null|bool|int $entityEncodeLabel Set to boolean false to specifically disable entity encoding of field header/label (default=true). #pw-group-output
|
||||||
* @property null|bool $entityEncodeText Set to boolean false to specifically disable entity encoding for other text: description, notes, etc. (default=true). #pw-group-output
|
* @property null|bool $entityEncodeText Set to boolean false to specifically disable entity encoding for other text: description, notes, etc. (default=true). #pw-group-output
|
||||||
* @property int $renderValueFlags Options that can be applied to renderValue mode, see "renderValue" constants (default=0). #pw-group-output
|
* @property int $renderValueFlags Options that can be applied to renderValue mode, see "renderValue" constants (default=0). #pw-group-output
|
||||||
* @property string $wrapClass Optional class name (CSS) to apply to the HTML element wrapping the Inputfield. #pw-group-other
|
* @property string $wrapClass Optional class name (CSS) to apply to the HTML element wrapping the Inputfield. #pw-group-other
|
||||||
@@ -80,6 +80,7 @@
|
|||||||
* ================
|
* ================
|
||||||
* @method string render()
|
* @method string render()
|
||||||
* @method string renderValue()
|
* @method string renderValue()
|
||||||
|
* @method void renderReadyHook(Inputfield $parent, $renderValueMode)
|
||||||
* @method Inputfield processInput(WireInputData $input)
|
* @method Inputfield processInput(WireInputData $input)
|
||||||
* @method InputfieldWrapper getConfigInputfields()
|
* @method InputfieldWrapper getConfigInputfields()
|
||||||
* @method array getConfigArray()
|
* @method array getConfigArray()
|
||||||
@@ -385,7 +386,7 @@ abstract class Inputfield extends WireData implements Module {
|
|||||||
*
|
*
|
||||||
* @param string $key Name of property to set
|
* @param string $key Name of property to set
|
||||||
* @param mixed $value Value of property
|
* @param mixed $value Value of property
|
||||||
* @return $this
|
* @return Inputfield|WireData
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function set($key, $value) {
|
public function set($key, $value) {
|
||||||
@@ -642,7 +643,7 @@ abstract class Inputfield extends WireData implements Module {
|
|||||||
* - String with attributes split by "+" or "|" to set them all to have the same value.
|
* - String with attributes split by "+" or "|" to set them all to have the same value.
|
||||||
* - Specify boolean true to get all attributes in an associative array.
|
* - Specify boolean true to get all attributes in an associative array.
|
||||||
* @param string|int|null $value Value to set (if setting), omit otherwise.
|
* @param string|int|null $value Value to set (if setting), omit otherwise.
|
||||||
* @return mixed|$this If setting an attribute, it returns this instance. If getting an attribute, the attribute is returned.
|
* @return Inputfield|array|string|int|object|float If setting an attribute, it returns this instance. If getting an attribute, the attribute is returned.
|
||||||
* @see Inputfield::removeAttr(), Inputfield::addClass(), Inputfield::removeClass()
|
* @see Inputfield::removeAttr(), Inputfield::addClass(), Inputfield::removeClass()
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -702,7 +703,7 @@ abstract class Inputfield extends WireData implements Module {
|
|||||||
* - Omit if getting an attribute.
|
* - Omit if getting an attribute.
|
||||||
* - Value to set for $key of setting.
|
* - Value to set for $key of setting.
|
||||||
* - Boolean false to remove the attribute specified for $key.
|
* - Boolean false to remove the attribute specified for $key.
|
||||||
* @return string|array|$this Returns one of the following:
|
* @return Inputfield|string|array|null Returns one of the following:
|
||||||
* - If getting, returns attribute value of NULL if not present.
|
* - If getting, returns attribute value of NULL if not present.
|
||||||
* - If setting, returns $this.
|
* - If setting, returns $this.
|
||||||
* @see Inputfield::attr(), Inputfield::addClass()
|
* @see Inputfield::attr(), Inputfield::addClass()
|
||||||
@@ -1030,8 +1031,23 @@ abstract class Inputfield extends WireData implements Module {
|
|||||||
public function renderReady(Inputfield $parent = null, $renderValueMode = false) {
|
public function renderReady(Inputfield $parent = null, $renderValueMode = false) {
|
||||||
if($parent) {}
|
if($parent) {}
|
||||||
if($renderValueMode) {}
|
if($renderValueMode) {}
|
||||||
return $this->wire('modules')->loadModuleFileAssets($this) > 0;
|
$result = $this->wire('modules')->loadModuleFileAssets($this) > 0;
|
||||||
|
if($this->wire('hooks')->isMethodHooked($this, 'renderReadyHook')) {
|
||||||
|
$this->renderReadyHook($parent, $renderValueMode);
|
||||||
}
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hookable version of renderReady(), not called unless 'renderReadyHook' is hooked
|
||||||
|
*
|
||||||
|
* Hook this method instead if you want to hook renderReady().
|
||||||
|
*
|
||||||
|
* @param Inputfield $parent
|
||||||
|
* @param bool $renderValueMode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function ___renderReadyHook(Inputfield $parent = null, $renderValueMode) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This hook was replaced by renderReady
|
* This hook was replaced by renderReady
|
||||||
@@ -1502,7 +1518,7 @@ abstract class Inputfield extends WireData implements Module {
|
|||||||
* @param string $what Name of property that changed
|
* @param string $what Name of property that changed
|
||||||
* @param mixed $old Previous value before change
|
* @param mixed $old Previous value before change
|
||||||
* @param mixed $new New value
|
* @param mixed $new New value
|
||||||
* @return $this
|
* @return Inputfield|WireData $this
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function trackChange($what, $old = null, $new = null) {
|
public function trackChange($what, $old = null, $new = null) {
|
||||||
|
@@ -124,6 +124,12 @@ class PageFinder extends Wire {
|
|||||||
*/
|
*/
|
||||||
'reverseSort' => false,
|
'reverseSort' => false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow use of _custom="another selector" in Selectors?
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
'allowCustom' => false,
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $fieldgroups;
|
protected $fieldgroups;
|
||||||
@@ -293,7 +299,6 @@ class PageFinder extends Wire {
|
|||||||
$sort = $parent->template->sortfield;
|
$sort = $parent->template->sortfield;
|
||||||
if(!$sort) $sort = $parent->sortfield;
|
if(!$sort) $sort = $parent->sortfield;
|
||||||
if($sort) $selectors->add(new SelectorEqual('sort', $sort));
|
if($sort) $selectors->add(new SelectorEqual('sort', $sort));
|
||||||
$hasSort = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,23 +317,31 @@ class PageFinder extends Wire {
|
|||||||
* @param array $options
|
* @param array $options
|
||||||
* - `findOne` (bool): Specify that you only want to find 1 page and don't need info for pagination (default=false).
|
* - `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).
|
* - `findHidden` (bool): Specify that it's okay for hidden pages to be included in the results (default=false).
|
||||||
* - `findUnpublished` (bool): Specify that it's okay for hidden AND unpublished pages to be included in the results (default=false).
|
* - `findUnpublished` (bool): Specify that it's okay for hidden AND unpublished pages to be included in the
|
||||||
* - `findTrash` (bool): Specify that it's okay for hidden AND unpublished AND trashed pages to be included in the results (default=false).
|
* results (default=false).
|
||||||
* - `findAll` (bool): Specify that no page should be excluded - results can include unpublished, trash, system, no-access pages, etc. (default=false)
|
* - `findTrash` (bool): Specify that it's okay for hidden AND unpublished AND trashed pages to be included in the
|
||||||
* - `getTotal` (bool|null): Whether the total quantity of matches should be determined and accessible from getTotal() method call.
|
* results (default=false).
|
||||||
|
* - `findAll` (bool): Specify that no page should be excluded - results can include unpublished, trash, system,
|
||||||
|
* no-access pages, etc. (default=false)
|
||||||
|
* - `getTotal` (bool|null): Whether the total quantity of matches should be determined and accessible from
|
||||||
|
* getTotal() method call.
|
||||||
* - null: determine automatically (default is disabled when limit=1, enabled in all other cases).
|
* - null: determine automatically (default is disabled when limit=1, enabled in all other cases).
|
||||||
* - true: always calculate total.
|
* - true: always calculate total.
|
||||||
* - false: never calculate total.
|
* - false: never calculate total.
|
||||||
* - `getTotalType` (string): Method to use to get total, specify 'count' or 'calc' (default='calc').
|
* - `getTotalType` (string): Method to use to get total, specify 'count' or 'calc' (default='calc').
|
||||||
* - `returnQuery` (bool): When true, only the DatabaseQuery object is returned by find(), for internal use. (default=false)
|
* - `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
|
* - `loadPages` (bool): This is an optimization used by the Pages::find() method, but we observe it here as we
|
||||||
* some additional optimizations in certain cases. For instance, if loadPages=false, then we can skip retrieval of IDs and omit
|
* may be able to apply some additional optimizations in certain cases. For instance, if loadPages=false, then
|
||||||
* 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).
|
* - `stopBeforeID` (int): Stop loading pages once a page matching this ID is found. Page having this ID will be
|
||||||
* - `startAfterID` (int): Start loading pages once a page matching this ID is found. Page having this ID will be excluded as well (default=0).
|
* excluded as well (default=0).
|
||||||
|
* - `startAfterID` (int): Start loading pages once a page matching this ID is found. Page having this ID will be
|
||||||
|
* excluded as well (default=0).
|
||||||
* - `reverseSort` (bool): Reverse whatever sort is specified.
|
* - `reverseSort` (bool): Reverse whatever sort is specified.
|
||||||
* - `returnVerbose` (bool): When true, this function returns array of arrays containing page ID, parent ID, template ID and score.
|
* - `returnVerbose` (bool): When true, this function returns array of arrays containing page ID, parent ID,
|
||||||
* When false, returns only an array of page IDs. True is required by most usage from Pages class. False is only for specific cases.
|
* template ID and score. When false, returns only an array of page IDs. True is required by most usage from
|
||||||
|
* Pages class. False is only for specific cases.
|
||||||
|
* - `allowCustom` (bool): Whether or not to allow _custom='selector string' type values (default=false).
|
||||||
* @return array|DatabaseQuerySelect
|
* @return array|DatabaseQuerySelect
|
||||||
* @throws PageFinderException
|
* @throws PageFinderException
|
||||||
*
|
*
|
||||||
@@ -469,6 +482,27 @@ class PageFinder extends Wire {
|
|||||||
return $this->find($selectors, $options);
|
return $this->find($selectors, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-process given Selectors object
|
||||||
|
*
|
||||||
|
* @param Selectors $selectors
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function preProcessSelectors(Selectors $selectors, $options = array()) {
|
||||||
|
if(!empty($options['allowCustom'])) {
|
||||||
|
foreach($selectors as $selector) {
|
||||||
|
$field = $selector->field;
|
||||||
|
if(!is_string($field) || $field !== '_custom') continue;
|
||||||
|
$selectors->remove($selector);
|
||||||
|
$_selectors = $this->wire(new Selectors($selector->value()));
|
||||||
|
/** @var Selectors $_selectors */
|
||||||
|
foreach($_selectors as $s) $selectors->add($s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre-process the given selector to perform any necessary replacements
|
* Pre-process the given selector to perform any necessary replacements
|
||||||
*
|
*
|
||||||
@@ -742,6 +776,7 @@ class PageFinder extends Wire {
|
|||||||
// $this->extraJoins = array();
|
// $this->extraJoins = array();
|
||||||
$startLimit = false; // true when the start/limit part of the query generation is done
|
$startLimit = false; // true when the start/limit part of the query generation is done
|
||||||
$database = $this->wire('database');
|
$database = $this->wire('database');
|
||||||
|
$this->preProcessSelectors($selectors, $options);
|
||||||
|
|
||||||
/** @var DatabaseQuerySelect $query */
|
/** @var DatabaseQuerySelect $query */
|
||||||
$query = $this->wire(new DatabaseQuerySelect());
|
$query = $this->wire(new DatabaseQuerySelect());
|
||||||
@@ -1070,7 +1105,7 @@ class PageFinder extends Wire {
|
|||||||
static $tableCnt = 0;
|
static $tableCnt = 0;
|
||||||
$table = $database->escapeTable($field->table);
|
$table = $database->escapeTable($field->table);
|
||||||
$tableAlias = $table . "__blank" . (++$tableCnt);
|
$tableAlias = $table . "__blank" . (++$tableCnt);
|
||||||
$blankValue = $field->type->getBlankValue(new NullPage(), $field, $value);
|
$blankValue = $field->type->getBlankValue(new NullPage(), $field);
|
||||||
$blankIsObject = is_object($blankValue);
|
$blankIsObject = is_object($blankValue);
|
||||||
if($blankIsObject) $blankValue = '';
|
if($blankIsObject) $blankValue = '';
|
||||||
$blankValue = $database->escapeStr($blankValue);
|
$blankValue = $database->escapeStr($blankValue);
|
||||||
|
@@ -199,20 +199,22 @@ class Pages extends Wire {
|
|||||||
*
|
*
|
||||||
* @param string|int|array|Selectors $selector Specify selector (standard usage), but can also accept page ID or array of page IDs.
|
* @param string|int|array|Selectors $selector Specify selector (standard usage), but can also accept page ID or array of page IDs.
|
||||||
* @param array|string $options One or more options that can modify certain behaviors. May be associative array or "key=value" selector string.
|
* @param array|string $options One or more options that can modify certain behaviors. May be associative array or "key=value" selector string.
|
||||||
* - `findOne` (boolean): Apply optimizations for finding a single page.
|
* - `findOne` (boolean): Apply optimizations for finding a single page (default=false).
|
||||||
* - `findAll` (boolean): Find all pages with no exculsions (same as include=all option).
|
* - `findAll` (boolean): Find all pages with no exclusions, same as "include=all" option (default=false).
|
||||||
* - `getTotal` (boolean): Whether to set returning PageArray's "total" property (default: true except when findOne=true).
|
* - `getTotal` (boolean): Whether to set returning PageArray's "total" property (default=true, except when findOne=true).
|
||||||
* - `loadPages` (boolean): Whether to populate the returned PageArray with found pages (default: true).
|
* - `loadPages` (boolean): Whether to populate the returned PageArray with found pages (default=true).
|
||||||
* The only reason why you'd want to change this to false would be if you only needed the count details from
|
* The only reason why you'd want to change this to false would be if you only needed the count details from
|
||||||
* the PageArray: getTotal(), getStart(), getLimit, etc. This is intended as an optimization for $pages->count().
|
* the PageArray: getTotal(), getStart(), getLimit, etc. This is intended as an optimization for $pages->count().
|
||||||
* Does not apply if $selector argument is an array.
|
* Does not apply if $selector argument is an array.
|
||||||
* - `caller` (string): Optional name of calling function, for debugging purposes, i.e. pages.count
|
* - `cache` (boolean): Allow caching of selectors and loaded pages? (default=true). Also sets loadOptions[cache].
|
||||||
* - `include` (string): Optional inclusion mode of 'hidden', 'unpublished' or 'all'. Default=none. Typically you would specify this
|
* - `allowCustom` (boolean): Allow use of _custom="another selector" in given $selector? For specific uses. (default=false)
|
||||||
|
* - `caller` (string): Optional name of calling function, for debugging purposes, i.e. "pages.count" (default=blank).
|
||||||
|
* - `include` (string): Optional inclusion mode of 'hidden', 'unpublished' or 'all'. (default=none). Typically you would specify this
|
||||||
* directly in the selector string, so the option is mainly useful if your first argument is not a string.
|
* directly in the selector string, so the option is mainly useful if your first argument is not a string.
|
||||||
* - `stopBeforeID` (int): Stop loading pages once page matching this ID is found (default=0).
|
* - `stopBeforeID` (int): Stop loading pages once page matching this ID is found (default=0).
|
||||||
* - `startAfterID` (int): Start loading pages once page matching this ID is found (default=0).
|
* - `startAfterID` (int): Start loading pages once page matching this ID is found (default=0).
|
||||||
* - `lazy` (bool): Specify true to force lazy loading. This is the same as using the Pages::findMany() method (default=false).
|
* - `lazy` (bool): Specify true to force lazy loading. This is the same as using the Pages::findMany() method (default=false).
|
||||||
* - `loadOptions` (array): Optional assoc array of options to pass to getById() load options.
|
* - `loadOptions` (array): Optional associative array of options to pass to getById() load options.
|
||||||
* @return PageArray Pages that matched the given selector.
|
* @return PageArray Pages that matched the given selector.
|
||||||
*
|
*
|
||||||
* Non-visible pages are excluded unless an "include=x" mode is specified in the selector
|
* Non-visible pages are excluded unless an "include=x" mode is specified in the selector
|
||||||
@@ -289,6 +291,7 @@ class Pages extends Wire {
|
|||||||
$debug = $this->debug;
|
$debug = $this->debug;
|
||||||
if($debug) $this->debug(false);
|
if($debug) $this->debug(false);
|
||||||
$options['lazy'] = true;
|
$options['lazy'] = true;
|
||||||
|
if(!isset($options['cache'])) $options['cache'] = false;
|
||||||
$matches = $this->loader->find($selector, $options);
|
$matches = $this->loader->find($selector, $options);
|
||||||
if($debug) $this->debug($debug);
|
if($debug) $this->debug($debug);
|
||||||
return $matches;
|
return $matches;
|
||||||
|
@@ -154,6 +154,8 @@ class PagesLoader extends Wire {
|
|||||||
* - findOne: boolean - apply optimizations for finding a single page
|
* - findOne: boolean - apply optimizations for finding a single page
|
||||||
* - findAll: boolean - find all pages with no exculsions (same as include=all option)
|
* - findAll: boolean - find all pages with no exculsions (same as include=all option)
|
||||||
* - getTotal: boolean - whether to set returning PageArray's "total" property (default: true except when findOne=true)
|
* - getTotal: boolean - whether to set returning PageArray's "total" property (default: true except when findOne=true)
|
||||||
|
* - cache: boolean - Allow caching of selectors and pages loaded (default=true). Also sets loadOptions[cache].
|
||||||
|
* - allowCustom: boolean - Whether to allow use of "_custom=new selector" in selectors (default=false).
|
||||||
* - lazy: boolean - makes find() return Page objects that don't have any data populated to them (other than id and template).
|
* - lazy: boolean - makes find() return Page objects that don't have any data populated to them (other than id and template).
|
||||||
* - loadPages: boolean - whether to populate the returned PageArray with found pages (default: true).
|
* - loadPages: boolean - whether to populate the returned PageArray with found pages (default: true).
|
||||||
* The only reason why you'd want to change this to false would be if you only needed the count details from
|
* The only reason why you'd want to change this to false would be if you only needed the count details from
|
||||||
@@ -177,6 +179,8 @@ class PagesLoader extends Wire {
|
|||||||
$caller = isset($options['caller']) ? $options['caller'] : 'pages.find';
|
$caller = isset($options['caller']) ? $options['caller'] : 'pages.find';
|
||||||
$lazy = empty($options['lazy']) ? false : true;
|
$lazy = empty($options['lazy']) ? false : true;
|
||||||
$debug = $this->debug && !$lazy;
|
$debug = $this->debug && !$lazy;
|
||||||
|
$cachePages = isset($options['cache']) ? (bool) $options['cache'] : true;
|
||||||
|
if(!$cachePages && !isset($loadOptions['cache'])) $loadOptions['cache'] = false;
|
||||||
$pages = $this->findShortcut($selector, $options, $loadOptions);
|
$pages = $this->findShortcut($selector, $options, $loadOptions);
|
||||||
|
|
||||||
if($pages) return $pages;
|
if($pages) return $pages;
|
||||||
@@ -293,7 +297,9 @@ class PagesLoader extends Wire {
|
|||||||
$pages->setSelectors($selectors);
|
$pages->setSelectors($selectors);
|
||||||
$pages->setTrackChanges(true);
|
$pages->setTrackChanges(true);
|
||||||
|
|
||||||
if($loadPages) $this->pages->cacher()->selectorCache($selectorString, $options, $pages);
|
if($loadPages && $cachePages) {
|
||||||
|
$this->pages->cacher()->selectorCache($selectorString, $options, $pages);
|
||||||
|
}
|
||||||
|
|
||||||
if($debug) {
|
if($debug) {
|
||||||
$this->pages->debugLog('find', $selectorString, $pages);
|
$this->pages->debugLog('find', $selectorString, $pages);
|
||||||
|
@@ -29,6 +29,7 @@ require_once(PROCESSWIRE_CORE_PATH . "Selector.php");
|
|||||||
* #pw-body
|
* #pw-body
|
||||||
*
|
*
|
||||||
* @link https://processwire.com/api/selectors/ Official Selectors Documentation
|
* @link https://processwire.com/api/selectors/ Official Selectors Documentation
|
||||||
|
* @method Selector[] getIterator()
|
||||||
*
|
*
|
||||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||||
* https://processwire.com
|
* https://processwire.com
|
||||||
@@ -365,10 +366,9 @@ class Selectors extends WireArray {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a selector string, return an array of (field, value, operator) for each selector in the strong.
|
* Given a selector string, populate to Selector objects in this Selectors instance
|
||||||
*
|
*
|
||||||
* @param string $str The string containing a selector (or multiple selectors, separated by commas)
|
* @param string $str The string containing a selector (or multiple selectors, separated by commas)
|
||||||
* @return array
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function extractString($str) {
|
protected function extractString($str) {
|
||||||
@@ -741,6 +741,47 @@ class Selectors extends WireArray {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return array of all field names referenced in all of the Selector objects here
|
||||||
|
*
|
||||||
|
* @param bool $subfields Default is to allow "field.subfield" fields, or specify false to convert them to just "field".
|
||||||
|
* @return array Returned array has both keys and values as field names (same)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getAllFields($subfields = true) {
|
||||||
|
$fields = array();
|
||||||
|
foreach($this as $selector) {
|
||||||
|
$field = $selector->field;
|
||||||
|
if(!is_array($field)) $field = array($field);
|
||||||
|
foreach($field as $f) {
|
||||||
|
if(!$subfields && strpos($f, '.')) {
|
||||||
|
list($f, $subfield) = explode('.', $f, 2);
|
||||||
|
if($subfield) {} // ignore
|
||||||
|
}
|
||||||
|
$fields[$f] = $f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return array of all values referenced in all Selector objects here
|
||||||
|
*
|
||||||
|
* @return array Returned array has both keys and values as field values (same)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getAllValues() {
|
||||||
|
$values = array();
|
||||||
|
foreach($this as $selector) {
|
||||||
|
$value = $selector->value;
|
||||||
|
if(!is_array($value)) $value = array($value);
|
||||||
|
foreach($value as $v) {
|
||||||
|
$values[$v] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the given Wire match these Selectors?
|
* Does the given Wire match these Selectors?
|
||||||
*
|
*
|
||||||
|
@@ -50,7 +50,7 @@
|
|||||||
* @property WireMailTools $mail #pw-internal
|
* @property WireMailTools $mail #pw-internal
|
||||||
* @property WireFileTools $files #pw-internal
|
* @property WireFileTools $files #pw-internal
|
||||||
*
|
*
|
||||||
* @method changed(string $what) See Wire::___changed()
|
* @method changed(string $what, $old = null, $new = null) See Wire::___changed()
|
||||||
* @method log($str = '', array $options = array()) See Wire::___log()
|
* @method log($str = '', array $options = array()) See Wire::___log()
|
||||||
* @method callUnknown($method, $arguments) See Wire::___callUnknown()
|
* @method callUnknown($method, $arguments) See Wire::___callUnknown()
|
||||||
* @method Wire trackException(\Exception $e, $severe = true, $text = null)
|
* @method Wire trackException(\Exception $e, $severe = true, $text = null)
|
||||||
@@ -367,12 +367,15 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
|
|||||||
* @param $method
|
* @param $method
|
||||||
* @param $arguments
|
* @param $arguments
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @internal
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function _callMethod($method, $arguments) {
|
public function _callMethod($method, $arguments) {
|
||||||
|
if(empty($arguments)) {
|
||||||
|
return $this->$method();
|
||||||
|
} else {
|
||||||
return call_user_func_array(array($this, $method), $arguments);
|
return call_user_func_array(array($this, $method), $arguments);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the gateway for calling hooks in ProcessWire
|
* Provides the gateway for calling hooks in ProcessWire
|
||||||
@@ -953,7 +956,13 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(is_null($old) || is_null($new) || $lastValue !== $new) {
|
if(is_null($old) || is_null($new) || $lastValue !== $new) {
|
||||||
|
/** @var WireHooks $hooks */
|
||||||
|
$hooks = $this->wire('hooks');
|
||||||
|
if(($hooks && $hooks->isHooked('changed')) || !$hooks) {
|
||||||
$this->changed($what, $old, $new); // triggers ___changed hook
|
$this->changed($what, $old, $new); // triggers ___changed hook
|
||||||
|
} else {
|
||||||
|
$this->___changed($what, $old, $new);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->trackChanges & self::trackChangesValues) {
|
if($this->trackChanges & self::trackChangesValues) {
|
||||||
@@ -1490,8 +1499,6 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
|
|||||||
/**
|
/**
|
||||||
* ProcessWire instance
|
* ProcessWire instance
|
||||||
*
|
*
|
||||||
* This will replace static fuel in PW 3.0
|
|
||||||
*
|
|
||||||
* @var ProcessWire|null
|
* @var ProcessWire|null
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -1505,7 +1512,6 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
|
|||||||
* #pw-internal
|
* #pw-internal
|
||||||
*
|
*
|
||||||
* @param ProcessWire $wire
|
* @param ProcessWire $wire
|
||||||
* @return $this
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setWire(ProcessWire $wire) {
|
public function setWire(ProcessWire $wire) {
|
||||||
|
@@ -71,23 +71,38 @@ class WireHooks {
|
|||||||
protected $staticHooks = array();
|
protected $staticHooks = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A static cache of all hook method/property names for an optimization.
|
* A cache of all hook method/property names for an optimization.
|
||||||
*
|
*
|
||||||
* Hooked methods end with '()' while hooked properties don't.
|
* Hooked methods end with '()' while hooked properties don't.
|
||||||
*
|
*
|
||||||
* This does not distinguish which instance it was added to or whether it was removed.
|
* This does not distinguish which instance it was added to or whether it was removed.
|
||||||
* But will use keys in the form 'fromClass::method' (with value 'method') in cases where a fromClass was specified.
|
|
||||||
* This cache exists primarily to gain some speed in our __get and __call methods.
|
* This cache exists primarily to gain some speed in our __get and __call methods.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $hookMethodCache = array();
|
protected $hookMethodCache = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as hook method cache but for "Class::method"
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $hookClassMethodCache = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of all local hooks combined, for debugging purposes
|
* Cache of all local hooks combined, for debugging purposes
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $allLocalHooks = array();
|
protected $allLocalHooks = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached parent classes and interfaces
|
||||||
|
*
|
||||||
|
* @var array of class|interface => [ 'parentClass', 'parentClass', 'interface', 'interface', 'etc.' ]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $parentClasses = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Config
|
* @var Config
|
||||||
*
|
*
|
||||||
@@ -135,6 +150,9 @@ class WireHooks {
|
|||||||
|
|
||||||
$hooks = array();
|
$hooks = array();
|
||||||
|
|
||||||
|
// see if we can do a quick exit
|
||||||
|
if($method && $method !== '*' && !$this->isHookedOrParents($object, $method)) return $hooks;
|
||||||
|
|
||||||
// first determine which local hooks when should include
|
// first determine which local hooks when should include
|
||||||
if($type !== self::getHooksStatic) {
|
if($type !== self::getHooksStatic) {
|
||||||
$localHooks = $object->getLocalHooks();
|
$localHooks = $object->getLocalHooks();
|
||||||
@@ -217,8 +235,11 @@ class WireHooks {
|
|||||||
* As a result, a true return value indicates something "might" be hooked, as opposed to be
|
* As a result, a true return value indicates something "might" be hooked, as opposed to be
|
||||||
* being definitely hooked.
|
* being definitely hooked.
|
||||||
*
|
*
|
||||||
* If checking for a hooked method, it should be in the form "Class::method()" or "method()".
|
* If checking for a hooked method, it should be in the form `Class::method()` or `method()` (with parenthesis).
|
||||||
* If checking for a hooked property, it should be in the form "Class::property" or "property".
|
* If checking for a hooked property, it should be in the form `Class::property` or `property`.
|
||||||
|
*
|
||||||
|
* If you need to check if a method/property is hooked, including any of its parent classes, use
|
||||||
|
* the `WireHooks::isMethodHooked()`, `WireHooks::isPropertyHooked()`, or `WireHooks::hasHook()` methods instead.
|
||||||
*
|
*
|
||||||
* @param string $method Method or property name in one of the following formats:
|
* @param string $method Method or property name in one of the following formats:
|
||||||
* Class::method()
|
* Class::method()
|
||||||
@@ -228,23 +249,114 @@ class WireHooks {
|
|||||||
* @param Wire|null $instance Optional instance to check against (see hasHook method for details)
|
* @param Wire|null $instance Optional instance to check against (see hasHook method for details)
|
||||||
* Note that if specifying an $instance, you may not use the Class::method() or Class::property options for $method argument.
|
* Note that if specifying an $instance, you may not use the Class::method() or Class::property options for $method argument.
|
||||||
* @return bool
|
* @return bool
|
||||||
|
* @see WireHooks::isMethodHooked(), WireHooks::isPropertyHooked(), WireHooks::hasHook()
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function isHooked($method, Wire $instance = null) {
|
public function isHooked($method, Wire $instance = null) {
|
||||||
if($instance) return $this->hasHook($instance, $method);
|
if($instance) return $this->hasHook($instance, $method);
|
||||||
$hooked = false;
|
|
||||||
if(strpos($method, ':') !== false) {
|
if(strpos($method, ':') !== false) {
|
||||||
if(array_key_exists($method, $this->hookMethodCache)) $hooked = true; // fromClass::method() or fromClass::property
|
$hooked = isset($this->hookClassMethodCache[$method]); // fromClass::method() or fromClass::property
|
||||||
} else {
|
} else {
|
||||||
if(in_array($method, $this->hookMethodCache)) $hooked = true; // method() or property
|
$hooked = isset($this->hookMethodCache[$method]); // method() or property
|
||||||
}
|
}
|
||||||
return $hooked;
|
return $hooked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to isHooked() method but also checks parent classes for the hooked method as well
|
||||||
|
*
|
||||||
|
* This method is designed for fast determinations of whether something is hooked
|
||||||
|
*
|
||||||
|
* @param string|Wire $class
|
||||||
|
* @param string $method Name of method or property
|
||||||
|
* @param string $type May be either 'method', 'property' or 'either'
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function isHookedOrParents($class, $method, $type = 'either') {
|
||||||
|
|
||||||
|
$property = '';
|
||||||
|
$className = is_object($class) ? wireClassName($class) : $class;
|
||||||
|
|
||||||
|
if($type == 'method' || $type == 'either') {
|
||||||
|
if(strpos($method, '(') === false) $method .= '()';
|
||||||
|
if($type == 'either') $property = rtrim($method, '()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if($type == 'method') {
|
||||||
|
if(!isset($this->hookMethodCache[$method])) return false; // not hooked for any class
|
||||||
|
$hooked = isset($this->hookClassMethodCache["$className::$method"]);
|
||||||
|
} else if($type == 'property') {
|
||||||
|
if(!isset($this->hookMethodCache[$property])) return false; // not hooked for any class
|
||||||
|
$hooked = isset($this->hookClassMethodCache["$className::$property"]);
|
||||||
|
} else {
|
||||||
|
if(!isset($this->hookMethodCache[$method])
|
||||||
|
&& !isset($this->hookMethodCache[$property])) return false;
|
||||||
|
$hooked = isset($this->hookClassMethodCache["$className::$property"]) ||
|
||||||
|
isset($this->hookClassMethodCache["$className::$method"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$hooked) {
|
||||||
|
foreach($this->getClassParents($class) as $parentClass) {
|
||||||
|
if($type == 'method') {
|
||||||
|
if(isset($this->hookClassMethodCache["$parentClass::$method"])) {
|
||||||
|
$hooked = true;
|
||||||
|
$this->hookClassMethodCache["$class::$method"] = true;
|
||||||
|
}
|
||||||
|
} else if($type == 'property') {
|
||||||
|
if(isset($this->hookClassMethodCache["$parentClass::$property"])) {
|
||||||
|
$hooked = true;
|
||||||
|
$this->hookClassMethodCache["$class::$property"] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(isset($this->hookClassMethodCache["$parentClass::$method"])) {
|
||||||
|
$hooked = true;
|
||||||
|
$this->hookClassMethodCache["$class::$method"] = true;
|
||||||
|
}
|
||||||
|
if(!$hooked && isset($this->hookClassMethodCache["$parentClass::$property"])) {
|
||||||
|
$hooked = true;
|
||||||
|
$this->hookClassMethodCache["$class::$property"] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($hooked) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hooked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to isHooked() method but also checks parent classes for the hooked method as well
|
||||||
|
*
|
||||||
|
* This method is designed for fast determinations of whether something is hooked
|
||||||
|
*
|
||||||
|
* @param string|Wire $class
|
||||||
|
* @param string $method Name of method
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function isMethodHooked($class, $method) {
|
||||||
|
return $this->isHookedOrParents($class, $method, 'method');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to isHooked() method but also checks parent classes for the hooked property as well
|
||||||
|
*
|
||||||
|
* This method is designed for fast determinations of whether something is hooked
|
||||||
|
*
|
||||||
|
* @param string|Wire $class
|
||||||
|
* @param string $property Name of property
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function isPropertyHooked($class, $property) {
|
||||||
|
return $this->isHookedOrParents($class, $property, 'property');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to isHooked(), returns true if the method or property hooked, false if it isn't.
|
* Similar to isHooked(), returns true if the method or property hooked, false if it isn't.
|
||||||
*
|
*
|
||||||
* Accomplishes the same thing as the isHooked() method, but this is more accruate,
|
* Accomplishes the same thing as the isHooked() method, but this is more accurate,
|
||||||
* and potentially slower than isHooked(). Less for optimization use, more for accuracy use.
|
* and potentially slower than isHooked(). Less for optimization use, more for accuracy use.
|
||||||
*
|
*
|
||||||
* It checks for both static hooks and local hooks, but only accepts a method() or property
|
* It checks for both static hooks and local hooks, but only accepts a method() or property
|
||||||
@@ -270,9 +382,7 @@ class WireHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// quick exit when possible
|
// quick exit when possible
|
||||||
if(!in_array($method, $this->hookMethodCache)) {
|
if(!isset($this->hookMethodCache[$method])) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$_method = rtrim($method, '()');
|
$_method = rtrim($method, '()');
|
||||||
$localHooks = $object->getLocalHooks();
|
$localHooks = $object->getLocalHooks();
|
||||||
@@ -285,12 +395,10 @@ class WireHooks {
|
|||||||
$hooked = true;
|
$hooked = true;
|
||||||
} else {
|
} else {
|
||||||
// check parent classes and interfaces
|
// check parent classes and interfaces
|
||||||
$classes = wireClassParents($object, false);
|
foreach($this->getClassParents($object) as $class) {
|
||||||
$interfaces = wireClassImplements($object);
|
|
||||||
if(is_array($interfaces)) $classes = array_merge($interfaces, $classes);
|
|
||||||
foreach($classes as $class) {
|
|
||||||
if(!empty($this->staticHooks[$class][$_method])) {
|
if(!empty($this->staticHooks[$class][$_method])) {
|
||||||
$hooked = true;
|
$hooked = true;
|
||||||
|
$this->hookClassMethodCache["$class::$method"] = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,6 +407,31 @@ class WireHooks {
|
|||||||
return $hooked;
|
return $hooked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of parent classes and interfaces for the given object
|
||||||
|
*
|
||||||
|
* @param Wire|string $object Maybe either object instance or class name
|
||||||
|
* @param bool $cache Allow use of cache for getting or storing? (default=true)
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getClassParents($object, $cache = true) {
|
||||||
|
if(is_string($object)) {
|
||||||
|
$className = $object;
|
||||||
|
} else {
|
||||||
|
$className = $object->className();
|
||||||
|
}
|
||||||
|
if($cache && isset($this->parentClasses[$className])) {
|
||||||
|
$classes = $this->parentClasses[$className];
|
||||||
|
} else {
|
||||||
|
$classes = wireClassParents($object, false);
|
||||||
|
$interfaces = wireClassImplements($object);
|
||||||
|
if(is_array($interfaces)) $classes = array_merge($interfaces, $classes);
|
||||||
|
if($cache) $this->parentClasses[$className] = $classes;
|
||||||
|
}
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook a function/method to a hookable method call in this object
|
* Hook a function/method to a hookable method call in this object
|
||||||
@@ -381,7 +514,6 @@ class WireHooks {
|
|||||||
$options['fromClass'] = $fromClass;
|
$options['fromClass'] = $fromClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$argOpen = strpos($method, '(');
|
$argOpen = strpos($method, '(');
|
||||||
if($argOpen && strpos($method, ')') > $argOpen+1) {
|
if($argOpen && strpos($method, ')') > $argOpen+1) {
|
||||||
// extract argument selector match string(s), arg 0: Something::something(selector_string)
|
// extract argument selector match string(s), arg 0: Something::something(selector_string)
|
||||||
@@ -468,10 +600,10 @@ class WireHooks {
|
|||||||
);
|
);
|
||||||
$hooks[$method][$priority] = $hook;
|
$hooks[$method][$priority] = $hook;
|
||||||
|
|
||||||
// cacheValue is just the method() or property, cacheKey includes optional fromClass::
|
// cache record known hooks so they can be detected quickly
|
||||||
$cacheValue = $options['type'] == 'method' ? "$method()" : "$method";
|
$cacheValue = $options['type'] == 'method' ? "$method()" : "$method";
|
||||||
$cacheKey = ($options['fromClass'] ? $options['fromClass'] . '::' : '') . $cacheValue;
|
if($options['fromClass']) $this->hookClassMethodCache["$options[fromClass]::$cacheValue"] = true;
|
||||||
$this->hookMethodCache[$cacheKey] = $cacheValue;
|
$this->hookMethodCache[$cacheValue] = true;
|
||||||
|
|
||||||
// keep track of all local hooks combined when debug mode is on
|
// keep track of all local hooks combined when debug mode is on
|
||||||
if($local && $this->config->debug) {
|
if($local && $this->config->debug) {
|
||||||
@@ -534,7 +666,8 @@ class WireHooks {
|
|||||||
|
|
||||||
$realMethod = "___$method";
|
$realMethod = "___$method";
|
||||||
if($type == 'method') $result['methodExists'] = method_exists($object, $realMethod);
|
if($type == 'method') $result['methodExists'] = method_exists($object, $realMethod);
|
||||||
if(!$result['methodExists'] && !$this->hasHook($object, $method . ($type == 'method' ? '()' : ''))) {
|
// if(!$result['methodExists'] && !$this->hasHook($object, $method . ($type == 'method' ? '()' : ''))) {
|
||||||
|
if(!$result['methodExists'] && !$this->isHookedOrParents($object, $method, $type)) {
|
||||||
return $result; // exit quickly when we can
|
return $result; // exit quickly when we can
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,6 +690,7 @@ class WireHooks {
|
|||||||
if(!$hook['options'][$when]) continue;
|
if(!$hook['options'][$when]) continue;
|
||||||
|
|
||||||
if(!empty($hook['options']['objMatch'])) {
|
if(!empty($hook['options']['objMatch'])) {
|
||||||
|
/** @var Selectors $objMatch */
|
||||||
$objMatch = $hook['options']['objMatch'];
|
$objMatch = $hook['options']['objMatch'];
|
||||||
// object match comparison to determine at runtime whether to execute the hook
|
// object match comparison to determine at runtime whether to execute the hook
|
||||||
if(is_object($objMatch)) {
|
if(is_object($objMatch)) {
|
||||||
@@ -571,6 +705,7 @@ class WireHooks {
|
|||||||
$argMatches = $hook['options']['argMatch'];
|
$argMatches = $hook['options']['argMatch'];
|
||||||
$matches = true;
|
$matches = true;
|
||||||
foreach($argMatches as $argKey => $argMatch) {
|
foreach($argMatches as $argKey => $argMatch) {
|
||||||
|
/** @var Selectors $argMatch */
|
||||||
$argVal = isset($arguments[$argKey]) ? $arguments[$argKey] : null;
|
$argVal = isset($arguments[$argKey]) ? $arguments[$argKey] : null;
|
||||||
if(is_object($argMatch)) {
|
if(is_object($argMatch)) {
|
||||||
// Selectors object
|
// Selectors object
|
||||||
@@ -594,15 +729,16 @@ class WireHooks {
|
|||||||
if(!$matches) continue; // don't run hook
|
if(!$matches) continue; // don't run hook
|
||||||
}
|
}
|
||||||
|
|
||||||
$event = new HookEvent();
|
$event = new HookEvent(array(
|
||||||
|
'object' => $object,
|
||||||
|
'method' => $method,
|
||||||
|
'arguments' => $arguments,
|
||||||
|
'when' => $when,
|
||||||
|
'return' => $result['return'],
|
||||||
|
'id' => $hook['id'],
|
||||||
|
'options' => $hook['options']
|
||||||
|
));
|
||||||
$this->wire->wire($event);
|
$this->wire->wire($event);
|
||||||
$event->object = $object;
|
|
||||||
$event->method = $method;
|
|
||||||
$event->arguments = $arguments;
|
|
||||||
$event->when = $when;
|
|
||||||
$event->return = $result['return'];
|
|
||||||
$event->id = $hook['id'];
|
|
||||||
$event->options = $hook['options'];
|
|
||||||
|
|
||||||
$toObject = $hook['toObject'];
|
$toObject = $hook['toObject'];
|
||||||
$toMethod = $hook['toMethod'];
|
$toMethod = $hook['toMethod'];
|
||||||
@@ -624,6 +760,7 @@ class WireHooks {
|
|||||||
}
|
}
|
||||||
$toMethod($event);
|
$toMethod($event);
|
||||||
} else {
|
} else {
|
||||||
|
/** @var Wire $toObject */
|
||||||
if($hook['toPublic']) {
|
if($hook['toPublic']) {
|
||||||
// public
|
// public
|
||||||
$returnValue = $toObject->$toMethod($event);
|
$returnValue = $toObject->$toMethod($event);
|
||||||
@@ -632,6 +769,7 @@ class WireHooks {
|
|||||||
$returnValue = $toObject->_callMethod($toMethod, array($event));
|
$returnValue = $toObject->_callMethod($toMethod, array($event));
|
||||||
}
|
}
|
||||||
// @todo allow for use of $returnValue as alternative to $event->return
|
// @todo allow for use of $returnValue as alternative to $event->return
|
||||||
|
if($returnValue) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($profilerEvent) $profiler->stop($profilerEvent);
|
if($profilerEvent) $profiler->stop($profilerEvent);
|
||||||
@@ -660,9 +798,9 @@ class WireHooks {
|
|||||||
/**
|
/**
|
||||||
* Start timing a hook and return the timer name
|
* Start timing a hook and return the timer name
|
||||||
*
|
*
|
||||||
* @param $object
|
* @param Wire $object
|
||||||
* @param $method
|
* @param String $method
|
||||||
* @param $arguments
|
* @param array $arguments
|
||||||
* @return string
|
* @return string
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -694,8 +832,8 @@ class WireHooks {
|
|||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @param Wire $object
|
* @param Wire $object
|
||||||
* @param string|null $hookId
|
* @param string|null $hookID
|
||||||
* @return $this
|
* @return Wire
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function removeHook(Wire $object, $hookID) {
|
public function removeHook(Wire $object, $hookID) {
|
||||||
@@ -707,6 +845,9 @@ class WireHooks {
|
|||||||
$object->setLocalHooks($localHooks);
|
$object->setLocalHooks($localHooks);
|
||||||
} else {
|
} else {
|
||||||
unset($this->staticHooks[$hookClass][$method][$priority]);
|
unset($this->staticHooks[$hookClass][$method][$priority]);
|
||||||
|
if(empty($this->staticHooks[$hookClass][$method])) {
|
||||||
|
unset($this->hookClassMethodCache["$hookClass::$method"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $object;
|
return $object;
|
||||||
|
@@ -390,7 +390,7 @@ class FieldtypePageTable extends FieldtypeMulti implements Module {
|
|||||||
|
|
||||||
if(!is_array($value) || !count($value) || empty($field->template_id)) return $this->getBlankValue($page, $field);
|
if(!is_array($value) || !count($value) || empty($field->template_id)) return $this->getBlankValue($page, $field);
|
||||||
|
|
||||||
$template_id = $field->template_id;
|
$template_id = $field->get('template_id');
|
||||||
|
|
||||||
if(!is_array($template_id)) {
|
if(!is_array($template_id)) {
|
||||||
$template_id = $template_id ? array($template_id) : array();
|
$template_id = $template_id ? array($template_id) : array();
|
||||||
@@ -402,16 +402,26 @@ class FieldtypePageTable extends FieldtypeMulti implements Module {
|
|||||||
$template = null;
|
$template = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($field->sortfields) {
|
$loadOptions = array('cache' => false);
|
||||||
|
if($template) $loadOptions['template'] = $template;
|
||||||
|
|
||||||
|
$sortfields = $field->get('sortfields');
|
||||||
|
|
||||||
|
if($sortfields) {
|
||||||
$selector = $template ? "template=$template, " : "";
|
$selector = $template ? "template=$template, " : "";
|
||||||
$selector .= "include=unpublished, id=" . implode('|', $value);
|
$selector .= "include=unpublished, id=" . implode('|', $value);
|
||||||
foreach(explode(',', $field->sortfields) as $sortfield) {
|
foreach(explode(',', $sortfields) as $sortfield) {
|
||||||
$selector .= ", sort=" . $this->wire('sanitizer')->name(trim($sortfield));
|
$selector .= ", sort=" . $this->wire('sanitizer')->name(trim($sortfield));
|
||||||
}
|
}
|
||||||
$items = $this->wire('pages')->find($selector);
|
$options = array(
|
||||||
|
'cache' => false,
|
||||||
|
'caller' => $this->className() . '::wakeupValue',
|
||||||
|
'loadOptions' => $loadOptions
|
||||||
|
);
|
||||||
|
$items = $this->wire('pages')->find($selector, $options);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$items = $this->wire('pages')->getById($value, $template);
|
$items = $this->wire('pages')->getById($value, $loadOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $items;
|
return $items;
|
||||||
|
@@ -640,7 +640,17 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// load the repeater pages
|
// load the repeater pages
|
||||||
$a = $this->wire('pages')->find($selector);
|
$options = array(
|
||||||
|
'cache' => false,
|
||||||
|
'caller' => $this->className() . '::wakeupValue',
|
||||||
|
'loadOptions' => array(
|
||||||
|
'cache' => false,
|
||||||
|
'parent_id' => $parent_id,
|
||||||
|
'template' => $this->wire('templates')->get($template_id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$a = $this->wire('pages')->find($selector, $options);
|
||||||
$class = $this->getPageArrayClass();
|
$class = $this->getPageArrayClass();
|
||||||
$pageArray = $this->wire(new $class($page, $field));
|
$pageArray = $this->wire(new $class($page, $field));
|
||||||
$pageArray->import($a);
|
$pageArray->import($a);
|
||||||
|
@@ -588,9 +588,10 @@ var InputfieldSelector = {
|
|||||||
if(s.field == '_custom') {
|
if(s.field == '_custom') {
|
||||||
if(s.isOrGroup) {
|
if(s.isOrGroup) {
|
||||||
s.value = s.value.replace('(', '').replace(')', '');
|
s.value = s.value.replace('(', '').replace(')', '');
|
||||||
selector += s.field + '=' + '(' + s.value + ')';
|
selector += s.field + '=' + '(' + $.trim(s.value) + ')';
|
||||||
} else {
|
} else {
|
||||||
selector += s.value;
|
//selector += s.value;
|
||||||
|
selector += s.field + '="' + $.trim(s.value) + '"';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selector += s.field + s.operator + $.trim(s.value);
|
selector += s.field + s.operator + $.trim(s.value);
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -273,7 +273,10 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
|
|
||||||
} else if($action == 'subfield' && ($fieldName = $input->get->field)) {
|
} else if($action == 'subfield' && ($fieldName = $input->get->field)) {
|
||||||
$fieldName = $sanitizer->name($fieldName);
|
$fieldName = $sanitizer->name($fieldName);
|
||||||
if(strpos($fieldName, '.')) list($fieldName, $subfieldName) = explode('.', $fieldName);
|
if(strpos($fieldName, '.')) {
|
||||||
|
list($fieldName, $subfieldName) = explode('.', $fieldName);
|
||||||
|
if($subfieldName) {} // ignore
|
||||||
|
}
|
||||||
$out = $this->renderSelectSubfield($fieldName);
|
$out = $this->renderSelectSubfield($fieldName);
|
||||||
|
|
||||||
} else if($action == 'opval' && ($fieldName = $input->get->field)) {
|
} else if($action == 'opval' && ($fieldName = $input->get->field)) {
|
||||||
@@ -617,6 +620,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
// consider multi-language
|
// consider multi-language
|
||||||
if(strpos($name, 'data') === 0 && $this->wire('languages')) {
|
if(strpos($name, 'data') === 0 && $this->wire('languages')) {
|
||||||
list($unused, $languageID) = explode('data', "x$name");
|
list($unused, $languageID) = explode('data', "x$name");
|
||||||
|
if($unused) {}
|
||||||
if(ctype_digit($languageID)) {
|
if(ctype_digit($languageID)) {
|
||||||
$language = $this->wire('languages')->get((int) $languageID);
|
$language = $this->wire('languages')->get((int) $languageID);
|
||||||
if($language && $language->id) {
|
if($language && $language->id) {
|
||||||
@@ -630,7 +634,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
} else if(!empty($subfield['label'])) {
|
} else if(!empty($subfield['label'])) {
|
||||||
$label = $subfield['label'];
|
$label = $subfield['label'];
|
||||||
} else if(strpos($name, 'data') === 0 && ctype_digit(substr($name, 4)) && $this->wire('languages')) {
|
} else if(strpos($name, 'data') === 0 && ctype_digit(substr($name, 4)) && $this->wire('languages')) {
|
||||||
|
$label = $this->wire('languages')->get((int) substr($name, 4))->get('title|name');
|
||||||
} else {
|
} else {
|
||||||
$f = $this->wire('fields')->get($name);
|
$f = $this->wire('fields')->get($name);
|
||||||
$label = $f ? $f->getLabel() : $name;
|
$label = $f ? $f->getLabel() : $name;
|
||||||
@@ -646,6 +650,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
$_subfields = array();
|
$_subfields = array();
|
||||||
foreach($subfields as $key => $subfield) {
|
foreach($subfields as $key => $subfield) {
|
||||||
list($label, $name) = explode("\t", $key);
|
list($label, $name) = explode("\t", $key);
|
||||||
|
if($label) {}
|
||||||
$_subfields[$name] = $subfield;
|
$_subfields[$name] = $subfield;
|
||||||
}
|
}
|
||||||
$subfields = $_subfields;
|
$subfields = $_subfields;
|
||||||
@@ -839,6 +844,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
if($settings['showFieldLabels']) {
|
if($settings['showFieldLabels']) {
|
||||||
$customFields = array();
|
$customFields = array();
|
||||||
foreach($settings['customFields'] as $field) {
|
foreach($settings['customFields'] as $field) {
|
||||||
|
/** @var Field $field */
|
||||||
$label = $field->getLabel();
|
$label = $field->getLabel();
|
||||||
while(isset($customFields[$label])) $label .= ' ';
|
while(isset($customFields[$label])) $label .= ' ';
|
||||||
$customFields[$label] = $field;
|
$customFields[$label] = $field;
|
||||||
@@ -1183,8 +1189,18 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
&& ($field->get('findPagesCode') || $field->get('findPagesSelector'))) {
|
&& ($field->get('findPagesCode') || $field->get('findPagesSelector'))) {
|
||||||
// see if we can locate options purely with the parent or template
|
// see if we can locate options purely with the parent or template
|
||||||
$findSelector = array("include=unpublished, limit=500, sort=title, sort=name, ");
|
$findSelector = array("include=unpublished, limit=500, sort=title, sort=name, ");
|
||||||
if($field->get('parent_id')) $findSelector[] = "parent_id=" . (int) $field->get('parent_id');
|
$parent_ids = $field->get('parent_ids');
|
||||||
if($field->get('template_id')) $findSelector[] = "templates_id=" . (int) $field->get('template_id');
|
$template_ids = $field->get('template_ids');
|
||||||
|
if($parent_ids && count($parent_ids)) {
|
||||||
|
$findSelector[] = "parent_id=" . implode('|', $parent_ids);
|
||||||
|
} else if($field->get('parent_id')) {
|
||||||
|
$findSelector[] = "parent_id=" . (int) $field->get('parent_id');
|
||||||
|
}
|
||||||
|
if($template_ids && count($template_ids)) {
|
||||||
|
$findSelector[] = "templates_id=" . implode('|', $template_ids);
|
||||||
|
} else if($field->get('template_id')) {
|
||||||
|
$findSelector[] = "templates_id=" . (int) $field->get('template_id');
|
||||||
|
}
|
||||||
foreach($this->wire('pages')->find(implode(', ', $findSelector)) as $item) {
|
foreach($this->wire('pages')->find(implode(', ', $findSelector)) as $item) {
|
||||||
$options[$item->id] = $inputfield->getPageLabel($item); // $item->get('title|name');
|
$options[$item->id] = $inputfield->getPageLabel($item); // $item->get('title|name');
|
||||||
}
|
}
|
||||||
@@ -1386,6 +1402,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
if(strpos($limitField, '.') === false) continue;
|
if(strpos($limitField, '.') === false) continue;
|
||||||
if(strpos($limitField, $fieldName) !== 0) continue;
|
if(strpos($limitField, $fieldName) !== 0) continue;
|
||||||
list($limitField, $limitSubfield) = explode('.', $limitField);
|
list($limitField, $limitSubfield) = explode('.', $limitField);
|
||||||
|
if($limitField) {} // ignore
|
||||||
if($limitSubfield) $limitSubfields[$limitSubfield] = $limitSubfield;
|
if($limitSubfield) $limitSubfields[$limitSubfield] = $limitSubfield;
|
||||||
}
|
}
|
||||||
// render all the subfield options
|
// render all the subfield options
|
||||||
@@ -1625,7 +1642,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
*
|
*
|
||||||
* @param array|string $key
|
* @param array|string $key
|
||||||
* @param int|string $value
|
* @param int|string $value
|
||||||
* @return $this
|
* @return InputfieldSelector|WireData
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setAttribute($key, $value) {
|
public function setAttribute($key, $value) {
|
||||||
@@ -1913,6 +1930,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function getModuleConfigInputfields(array $data) {
|
public function getModuleConfigInputfields(array $data) {
|
||||||
|
if($data) {} // ignore
|
||||||
$form = $this->wire(new InputfieldWrapper());
|
$form = $this->wire(new InputfieldWrapper());
|
||||||
$f = $this->wire('modules')->get('InputfieldSelector');
|
$f = $this->wire('modules')->get('InputfieldSelector');
|
||||||
$f->name = 'test';
|
$f->name = 'test';
|
||||||
|
@@ -1504,7 +1504,8 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
|||||||
$this->finalSelector = $selector;
|
$this->finalSelector = $selector;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$results = $selector ? $this->wire('pages')->find($selector) : $this->wire('pages')->newPageArray();
|
$options = array('allowCustom' => true);
|
||||||
|
$results = $selector ? $this->wire('pages')->find($selector, $options) : $this->wire('pages')->newPageArray();
|
||||||
|
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
$this->error($e->getMessage());
|
$this->error($e->getMessage());
|
||||||
|
Reference in New Issue
Block a user