From 756c9298a5f4364fed63655eeaad7660343e63bc Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Wed, 11 Jul 2018 16:02:40 -0400 Subject: [PATCH] Add SearchableModule interface to Module definition, add getProcessPage() to Process module base class (which returns the Page object the Process page lives on), plus a couple of minor phpdoc improvements in core classes --- wire/core/Module.php | 88 ++++++++++++++++++++++++++++++++- wire/core/Process.php | 15 ++++++ wire/core/WireCache.php | 5 +- wire/core/WireSaveableItems.php | 16 +++++- 4 files changed, 121 insertions(+), 3 deletions(-) diff --git a/wire/core/Module.php b/wire/core/Module.php index de993144..d1e064d7 100644 --- a/wire/core/Module.php +++ b/wire/core/Module.php @@ -5,7 +5,7 @@ * * Provides the base interfaces required by modules. * - * ProcessWire 3.x, Copyright 2016 by Ryan Cramer + * ProcessWire 3.x, Copyright 2018 by Ryan Cramer * https://processwire.com * * #pw-summary Module is the primary PHP interface for module types in ProcessWire. @@ -214,6 +214,11 @@ * - **Callable function:** The module will automatically load only if the given callable function * returns true. * + * - `searchable` (string): When present, indicates that module implements a search() method + * consistent with the SearchableModule interface. The value of the 'searchable' property should + * be the name that the search results are referred to, using ascii characters of a-z, 0-9, and + * underscore. See the SearchableModule interface in this file for more details. + * * ----------------------------------------------------------------------------------------------- * * ## Module Methods @@ -488,3 +493,84 @@ interface _Module { public function getModuleConfigArray(); } +/** + * Interface SearchableModule + * + * Interface for modules that implement a method and expected array return value + * for completing basic text searches (primarily for admin search engine). + * + * It is optional to add this interface to "implements" section of the module class definition. + * However, you must specify a "searchable: name" property in your getModuleInfo() method in + * order for ProcessWire to recognize the module is searchable. See below for more info: + * + * ~~~~~~ + * public static function getModuleInfo() { + * return array( + * 'searchable' => 'name', + * + * // You'll need the above 'searchable' property returned by your getModuleInfo(). + * // The value of 'name' should be the name by which search results should be referred to + * // if the user wants to limit the search to this module. For instance, if your module + * // was called “ProcessWidgets”, you’d probably choose the name “widgets” for this. + * // If the module represents an API variable, the name should be the same as the API variable. + * // ... + * ); + * } + * ~~~~~ + * + */ +interface SearchableModule { + + /** + * Search for items containing $text and return an array representation of them + * + * You may implement also implement this method as hookable, i.e. ___search(), but not that you’ll + * want to skip the "implements SearchableModule" in your class definition. + * + * Must return PHP array in the format below. For each item in the 'items' array, Only the 'title' + * and 'url' properties are required for each item (the rest are optional). + * + * $result = array( + * 'title' => 'Title of these items', + * 'total' => 999, // total number of items found, or omit if pagination not supported or active + * 'url' => '', // optional URL to view all items, or omit for a PW-generated one + * 'items' => array( + * [0] => array( + * 'id' => 123, // Unique ID of item (optional) + * 'name' => 'Name of item', // (optional) + * 'title' => 'Title of item', // (*required) + * 'subtitle' => 'Secondary/subtitle of item', // (optional) + * 'summary' => 'Summary or description of item', // (optional) + * 'url' => 'URL to view or edit the item', // (*required) + * 'icon' => 'Optional icon name to represent the item, i.e. "gear" or "fa-gear"', // (optional) + * 'group' => 'Optionally group with other items having this group name, overrides $result[title]', // (optional) + * 'status' => int, // refers to Page status, omit if not a Page item (optional) + * 'modified' => int, // modified date of item as unix timestamp (optional) + * [1] => array( + * ... + * ), + * ) + * ); + * + * Please note: When ProcessWire calls this method, if the module is not already loaded (autoload), + * it instantiates the module but DOES NOT call the init() or ready() methods. That’s because the + * search method is generally self contained. If you need either of those methods to be called, + * and your module is not autoload, you should call the method(s) from your search() method. + * + * @param string $text Text to search for + * @param array $options Options array provided to search() calls: + * - `edit` (bool): True if any 'url' returned should be to edit items rather than view them + * - `multilang` (bool): If true, search all languages rather than just current (default=true). + * - `start` (int): Start index (0-based), if pagination active (default=0). + * - `limit` (int): Limit to this many items, or 0 for no limit. (default=0). + * - `type` (string): If search should only be of a specific type, i.e. "pages", "modules", etc. then it is + * specified here. This corresponds with the getModuleInfo()['searchable'] name or item 'group' property. + * - `operator` (string): Selector operator type requested, if more than one is supported (default is %=). + * - `property` (string): If search should limit to a particular property/fieldj, it is named here. + * - `verbose` (bool): True if output can optionally be more verbose, false if not. (default=false) + * @return array + * + */ + public function search($text, array $options = array()); +} + diff --git a/wire/core/Process.php b/wire/core/Process.php index 34304eab..6753964c 100644 --- a/wire/core/Process.php +++ b/wire/core/Process.php @@ -558,4 +558,19 @@ abstract class Process extends WireData implements Module { public function getViewVars() { return $this->_viewVars; } + + /** + * Return the Page that this process lives on + * + * @return Page|NullPage + * + */ + public function getProcessPage() { + $page = $this->wire('page'); + if($page->process === $this) return $page; + $moduleID = $this->wire('modules')->getModuleID($this); + if(!$moduleID) return new NullPage(); + $page = $this->wire('pages')->get("process=$moduleID, include=all"); + return $page; + } } diff --git a/wire/core/WireCache.php b/wire/core/WireCache.php index e6f553b7..a075c7c3 100644 --- a/wire/core/WireCache.php +++ b/wire/core/WireCache.php @@ -584,6 +584,7 @@ class WireCache extends Wire { $query = $this->wire('database')->prepare($sql, "cache.delete($name)"); $query->bindValue(':name', $name); $query->execute(); + $query->closeCursor(); $success = true; $this->log($this->_('Cleared cache') . ' - ' . $name); } catch(\Exception $e) { @@ -790,7 +791,7 @@ class WireCache extends Wire { * Run maintenance for a template that was just saved or deleted * * @param Template $template - * @return bool + * @return bool Returns true if any caches were deleted, false if not * */ protected function maintenanceTemplate(Template $template) { @@ -804,6 +805,8 @@ class WireCache extends Wire { $result = $query->execute(); $qty = $result ? $query->rowCount() : 0; if($qty) $this->log(sprintf($this->_('Maintenance expired %d cache(s) for saved template'), $qty)); + + return $qty > 0; } /** diff --git a/wire/core/WireSaveableItems.php b/wire/core/WireSaveableItems.php index d57b2b07..b911b5ae 100644 --- a/wire/core/WireSaveableItems.php +++ b/wire/core/WireSaveableItems.php @@ -36,6 +36,8 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate { /** * Return a new blank item + * + * @return Saveable|Wire * */ abstract public function makeBlankItem(); @@ -190,6 +192,9 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate { * Should the given item key/field be saved in the database? * * Template method used by ___save() + * + * @param string $key + * @return bool * */ protected function saveItemKey($key) { @@ -369,6 +374,9 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate { * Encode the 'data' portion of the table. * * This is a front-end to wireEncodeJSON so that it can be overridden if needed. + * + * @param array $value + * @return string * */ protected function encodeData(array $value) { @@ -379,6 +387,9 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate { * Decode the 'data' portion of the table. * * This is a front-end to wireDecodeJSON that it can be overridden if needed. + * + * @param string $value + * @return array * */ protected function decodeData($value) { @@ -387,6 +398,9 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate { /** * Enforce no locally-scoped fuel for this class + * + * @param bool|null $useFuel + * @return bool * */ public function useFuel($useFuel = null) { @@ -508,7 +522,7 @@ abstract class WireSaveableItems extends Wire implements \IteratorAggregate { * * @param string $text * @param int|bool $flags See Notices::flags - * @return $this + * @return Wire|WireSaveableItems * */ public function error($text, $flags = 0) {