1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-09 16:26:59 +02:00

Merge working branch to dev

This commit is contained in:
Ryan Cramer
2016-10-28 05:43:08 -04:00
19 changed files with 1269 additions and 88 deletions

View File

@@ -111,9 +111,22 @@ $config->advanced = false;
*
* If true, disables save functions in Process modules (admin).
*
* @var bool
*
*/
$config->demo = false;
/**
* Enable core API variables to be accessed as function calls?
*
* Benefits are better type hinting, always in scope, and potentially shorter API calls.
* See the file /wire/core/FunctionsAPI.php for details on these functions.
*
* @var bool
*
*/
$config->useFunctionsAPI = false;
/*** 2. DATES & TIMES *************************************************************************/

View File

@@ -14,64 +14,64 @@ namespace PHPSTORM_META {
$STATIC_METHOD_TYPES = [
\wire('') => [
'' == '@',
'config' instanceof Config,
'wire' instanceof ProcessWire,
'log' instanceof WireLog,
'notices' instanceof Notices,
'sanitizer' instanceof Sanitizer,
'database' instanceof WireDatabasePDO,
'db' instanceof DatabaseMysqli,
'cache' instanceof MarkupCache,
'modules' instanceof Modules,
'procache' instanceof ProCache,
'fieldtypes' instanceof Fieldtypes,
'fields' instanceof Fields,
'fieldgroups' instanceof Fieldgroups,
'templates' instanceof Templates,
'pages' instanceof Pages,
'permissions' instanceof Permissions,
'roles' instanceof Roles,
'users' instanceof Users,
'user' instanceof User,
'session' instanceof Session,
'input' instanceof WireInput,
'languages' instanceof Languages,
'page' instanceof Page,
'hooks' instanceof WireHooks,
'files' instanceof WireFileTools,
'datetime' instanceof WireDateTime,
'mail' instanceof WireMailTools
'config' instanceof \ProcessWire\Config,
'wire' instanceof \ProcessWire\ProcessWire,
'log' instanceof \ProcessWire\WireLog,
'notices' instanceof \ProcessWire\Notices,
'sanitizer' instanceof \ProcessWire\Sanitizer,
'database' instanceof \ProcessWire\WireDatabasePDO,
'db' instanceof \ProcessWire\DatabaseMysqli,
'cache' instanceof \ProcessWire\MarkupCache,
'modules' instanceof \ProcessWire\Modules,
'procache' instanceof \ProCache,
'fieldtypes' instanceof \ProcessWire\Fieldtypes,
'fields' instanceof \ProcessWire\Fields,
'fieldgroups' instanceof \ProcessWire\Fieldgroups,
'templates' instanceof \ProcessWire\Templates,
'pages' instanceof \ProcessWire\Pages,
'permissions' instanceof \ProcessWire\Permissions,
'roles' instanceof \ProcessWire\Roles,
'users' instanceof \ProcessWire\Users,
'user' instanceof \ProcessWire\User,
'session' instanceof \ProcessWire\Session,
'input' instanceof \ProcessWire\WireInput,
'languages' instanceof \ProcessWire\Languages,
'page' instanceof \ProcessWire\Page,
'hooks' instanceof \ProcessWire\WireHooks,
'files' instanceof \ProcessWire\WireFileTools,
'datetime' instanceof \ProcessWire\WireDateTime,
'mail' instanceof \ProcessWire\WireMailTools
],
\Wire::wire('') => [
// this one does not appear to work, leaving in case someone knows how to make it work
'' == '@',
'config' instanceof Config,
'wire' instanceof ProcessWire,
'log' instanceof WireLog,
'notices' instanceof Notices,
'sanitizer' instanceof Sanitizer,
'database' instanceof WireDatabasePDO,
'db' instanceof DatabaseMysqli,
'cache' instanceof MarkupCache,
'modules' instanceof Modules,
'procache' instanceof ProCache,
'fieldtypes' instanceof Fieldtypes,
'fields' instanceof Fields,
'fieldgroups' instanceof Fieldgroups,
'templates' instanceof Templates,
'pages' instanceof Pages,
'permissions' instanceof Permissions,
'roles' instanceof Roles,
'users' instanceof Users,
'user' instanceof User,
'session' instanceof Session,
'input' instanceof WireInput,
'languages' instanceof Languages,
'page' instanceof Page,
'hooks' instanceof WireHooks,
'files' instanceof WireFileTools,
'datetime' instanceof WireDateTime,
'mail' instanceof WireMailTools
'config' instanceof \ProcessWire\Config,
'wire' instanceof \ProcessWire\ProcessWire,
'log' instanceof \ProcessWire\WireLog,
'notices' instanceof \ProcessWire\Notices,
'sanitizer' instanceof \ProcessWire\Sanitizer,
'database' instanceof \ProcessWire\WireDatabasePDO,
'db' instanceof \ProcessWire\DatabaseMysqli,
'cache' instanceof \ProcessWire\MarkupCache,
'modules' instanceof \ProcessWire\Modules,
'procache' instanceof \ProCache,
'fieldtypes' instanceof \ProcessWire\Fieldtypes,
'fields' instanceof \ProcessWire\Fields,
'fieldgroups' instanceof \ProcessWire\Fieldgroups,
'templates' instanceof \ProcessWire\Templates,
'pages' instanceof \ProcessWire\Pages,
'permissions' instanceof \ProcessWire\Permissions,
'roles' instanceof \ProcessWire\Roles,
'users' instanceof \ProcessWire\Users,
'user' instanceof \ProcessWire\User,
'session' instanceof \ProcessWire\Session,
'input' instanceof \ProcessWire\WireInput,
'languages' instanceof \ProcessWire\Languages,
'page' instanceof \ProcessWire\Page,
'hooks' instanceof \ProcessWire\WireHooks,
'files' instanceof \ProcessWire\WireFileTools,
'datetime' instanceof \ProcessWire\WireDateTime,
'mail' instanceof \ProcessWire\WireMailTools
]
];
}

View File

@@ -116,6 +116,7 @@
* @property array $preloadCacheNames Cache names to preload at beginning of request #pw-group-system
* @property bool $allowExceptions Allow Exceptions to propagate? (default=false, specify true only if you implement your own exception handler) #pw-group-system
* @property bool $usePoweredBy Use the x-powered-by header? Set to false to disable. #pw-group-system
* @property bool $useFunctionsAPI Allow most API variables to be accessed as functions? (see /wire/core/FunctionsAPI.php) #pw-group-system
*
* @property string $userAuthSalt Salt generated at install time to be used as a secondary/non-database salt for the password system. #pw-group-session
* @property string $userAuthHashType Default is 'sha1' - used only if Blowfish is not supported by the system. #pw-group-session

View File

@@ -770,3 +770,76 @@ function wireIsCallable($var, $syntaxOnly = false, &$callableName = '') {
if(is_string($var)) $var = wireClassName($var, true);
return is_callable($var, $syntaxOnly, $callableName);
}
/**
* Get or set an output region (primarily for front-end output usage)
*
* ~~~~~
* // define a region
* region('content', '<p>this is some content</p>');
*
* // prepend some text to region
* region('+content', '<h2>Good morning</h2>');
*
* // append some text to region
* region('content+', '<p><small>Good night</small></p>');
*
* // output a region
* echo region('content');
*
* // get all regions in an array
* $regions = region('*');
*
* // clear the 'content' region
* region('content', '');
*
* // clear all regions
* region('*', '');
* ~~~~~
*
* @param string $key Name of region to get or set.
* - Specify "*" to retrieve all defined regions in an array.
* - Prepend a "+" to the region name to have it prepend your given value to any existing value.
* - Append a "+" to the region name to have it append your given value to any existing value.
* @param null|string $value If setting a region, the text that you want to set.
* @return string|null|bool|array Returns string of text when getting a region, NULL if region not set, or TRUE if setting region.
*
*/
function wireRegion($key, $value = null) {
static $regions = array();
if(empty($key) || $key === '*') {
// all regions
if($value === '') $regions = array(); // clear
return $regions;
}
if(is_null($value)) {
// get region
$result = isset($regions[$key]) ? $regions[$key] : null;
} else {
// set region
$pos = strpos($key, '+');
if($pos !== false) $key = trim($key, '+');
if(!isset($regions[$key])) $regions[$key] = '';
if($pos === 0) {
// prepend
$regions[$key] = $value . $regions[$key];
} else if($pos) {
// append
$regions[$key] .= $value;
} else if($value === '') {
// clear region
unset($regions[$key]);
} else {
// insert/replace
$regions[$key] = $value;
}
$result = true;
}
return $result;
}

419
wire/core/FunctionsAPI.php Normal file
View File

@@ -0,0 +1,419 @@
<?php namespace ProcessWire;
/**
* ProcessWire functions API maps function names to common API variables
*
* Provides an alternative to the API variables by providing functions of the same
* name, with these benefits:
*
* - They are always in scope
* - Makes life simpler in an IDE that recognizes phpdoc, as it can more easily
* recognize the types an return values.
* - In some cases it makes for shorter API calls.
*
* The primary drawback is that the function calls are not mapped to a specific
* instance, so in a multi-instance environment it's possible these function calls
* may not be referring to the correct ProcessWire instance. For this reason, we
* think these functions are primarily useful for front-end/website usages, and
* not as useful for back-end and module development.
*
* Note: This file is only used if $config->useFunctionsAPI == true;
*
*/
/**
* Access the $pages API variable as a function
*
* ~~~~
* // A call with no arguments returns the $pages API variable
* $pages = pages();
* $pageArray = pages()->find("selector");
* $page = pages()->get(123);
*
* // Providing selector as argument maps to $pages->find()
* $pageArray = pages("template=basic-page");
*
* // Providing argument of single page ID, path or name maps to $pages->get()
* $page = pages(123);
* $page = pages("/path/to/page/");
* $page = pages("page-name");
* ~~~~
*
* @param string|array $selector Specify one of the following:
* - Nothing, makes it return the $pages API variable.
* - Selector (string) to find matching pages, makes function return PageArray - equivalent to $pages->find("selector");
* - Page ID (int) to return a single matching Page - equivalent to $pages->get(123);
* - Page name (string) to return a single page having the given name - equivalent to $pages->get("name");
* @return Pages|PageArray|Page|NullPage
*
*/
function pages($selector = '') {
return wirePages($selector);
}
/**
* Access the $page API variable as a function
*
* ~~~~
* $page = page(); // Simply get $page API var
* $body = page()->body; // Get body field value
* $body = page('body'); // Same as above
* $headline = page('headline|title'); // Get headline or title
* page('headline', 'Setting headline value'); // Set headline
* ~~~~
*
* @param string $key Optional property to get or set
* @param null $value Optional value to set
* @return Page|mixed
*
*/
function page($key = '', $value = null) {
return wirePage($key, $value);
}
/**
* Access the $config API variable as a function
*
* ~~~~~
* $config = config(); // Simply get $config API var
* $debug = config()->debug; // Get value of debug
* $debug = config('debug'); // Same as above
* config()->debug = true; // Set value of debug
* config('debug', true); // Same as above
* ~~~~~
*
* @param string $key
* @param null $value
* @return Config|mixed
*
*/
function config($key = '', $value = null) {
return wireConfig($key, $value);
}
/**
* Access the $modules API variable as a function
*
* ~~~~~
* $modules = modules(); // Simply get $modules API var
* $module = modules()->get('ModuleName'); // Get a module
* $module = modules('ModuleName'); // Shortcut to get a module
* ~~~~~
*
* @param string $name Optionally retrieve the given module name
* @return Modules|Module|ConfigurableModule|null
*
*/
function modules($name = '') {
return wireModules($name);
}
/**
* Access the $user API variable as a function
*
* @param string $key Optional property to get or set
* @param null $value Optional value to set
* @return User|mixed
*
*/
function user($key = '', $value = null) {
return wireUser($key, $value);
}
/**
* Access the $users API variable as a function
*
* See the pages() function for full usage details.
*
* @param string|array $selector Optional selector to send to find() or get()
* @return Users|PageArray|User|mixed
* @see pages()
*
*/
function users($selector = '') {
return wireUsers($selector);
}
/**
* Access the $session API variable as a function
*
* @param string $key Optional property to get or set
* @param null $value Optional value to set
* @return Session|mixed
*
*/
function session($key = '', $value = null) {
return wireSession($key, $value);
}
/**
* Access the $fields API variable as a function
*
* @param string $name Optional field name to retrieve
* @return Fields|Field|null
*
*/
function fields($name = '') {
return wireFields($name);
}
/**
* Access the $templates API variable as a function
*
* @param string $name Optional template to retrieve
* @return Templates|Template|null
*
*/
function templates($name = '') {
return wireTemplates($name);
}
/**
* Access the $database API variable as a function
*
* @return WireDatabasePDO
*
*/
function database() {
return wireDatabase();
}
/**
* Access the $permissions API varaible as a function
*
* See the pages() function for usage details.
*
* @param string $selector
* @return Permissions|Permission|PageArray|null|NullPage
*
*/
function permissions($selector = '') {
return wirePermissions($selector);
}
/**
* Access the $roles API varaible as a function
*
* See the pages() function for usage details.
*
* @param string $selector
* @return Roles|Role|PageArray|null|NullPage
*
*/
function roles($selector = '') {
return wireRoles($selector);
}
/**
* Access the $sanitizer API variable as a function
*
* ~~~~~
* // Example usages
* $clean = sanitizer()->pageName($dirty);
* $clean = sanitizer('pageName', $dirty); // same as above
* ~~~~~
*
* @param string $name Optionally enter a sanitizer function name
* @param string $value If $name populated, enter the value to sanitize
* @return Sanitizer|string|int|array|null|mixed
*
*/
function sanitizer($name = '', $value = '') {
return wireSanitizer($name, $value);
}
/**
* Access the $datetime API variable as a function
*
* ~~~~~
* // Example usages
* $str = datetime()->relativeTimeStr('2016-10-10');
* $str = datetime('Y-m-d');
* $str = datetime('Y-m-d', time());
* ~~~~~
*
* @param string $format Optional date format
* @param string|int $value Optional date to format
* @return WireDateTime|string|int
*
*/
function datetime($format = '', $value = '') {
return wireDatetime($format, $value);
}
/**
* Access the $files API variable as a function
*
* @return WireFileTools
*
*/
function files() {
return wireFiles();
}
/**
* Access the $cache API variable as a function
*
* If called with no arguments it returns the $cache API variable.
* If called with arguments, it can be used the same as `WireCache::get()`.
*
* @param string $name
* @param callable|int|string|null $expire
* @param callable|int|string|null $func
* @return WireCache|string|array|PageArray|null
* @see WireCache::get()
*
*/
function cache($name = '', $expire = null, $func = null) {
return wireCache($name, $expire, $func);
}
/**
* Access the $languages API variable as a function
*
* Returns the $languages API variable, or a Language object if given a language name.
*
* ~~~~
* // Examples
* $languages = languages(); // Languages if active, null if not
* $en = languages()->getDefault();
* $de = languages('de');
* ~~~~
*
* @param string|int $name Optional Language name or ID for language to retrieve
* @return Languages|Language|NullPage|null
*
*/
function languages($name = '') {
return wireLanguages($name);
}
/**
* Access the $input API variable as a function
*
* - Default behavior is to return the $input API var.
* - If given just a $type (like "get" or "post"), it will return a WireInputData object for that type.
* - If given a $type and $key it will return the input variable.
* - If all arguments given, the returned value will also be run through the given sanitizer.
*
* ~~~~~
* // Examples
* $input = input(); // Returns $input API var (WireInput)
* $post = input('post'); // Returns $input->post (WireInputData)
* $value = input('get', 'sort'); // Returns $input->get('sort');
* $value = input('get', 'sort', 'fieldName'); // Returns $input->get('sort') run through $sanitizer->fieldName().
* ~~~~~
*
* @param string $type Optionally indicate "get", "post", "cookie" or "whitelist"
* @param string $key If getting a value, specify name of property containing value
* @param string $sanitizer Optionally specify sanitizer name to run value through
* @return WireInput|WireInputData array|string|int|null
*
*/
function input($type = '', $key = '', $sanitizer = '') {
return wireInput($type, $key, $sanitizer);
}
/**
* Access the $input->get API variable as a function
*
* This is the same as the input() function except that the $type "get" is already implied.
*
* @param string $key
* @param string $sanitizer
* @return WireInputData|string|int|array|null
*
*/
function inputGet($key = '', $sanitizer = '') {
return wireInputGet($key, $sanitizer);
}
/**
* Access the $input->post API variable as a function
*
* This is the same as the input() function except that the $type "post" is already implied.
*
* @param string $key
* @param string $sanitizer
* @return WireInputData|string|int|array|null
*
*/
function inputPost($key = '', $sanitizer = '') {
return wireInputPost($key, $sanitizer);
}
/**
* Access the $input->cookie API variable as a function
*
* This is the same as the input() function except that the $type "cookie" is already implied.
*
* @param string $key
* @param string $sanitizer
* @return WireInputData|string|int|array|null
*
*/
function inputCookie($key = '', $sanitizer = '') {
return wireInputCookie($key, $sanitizer);
}
/**
* Function that returns a $config->urls->[name] value o
*
* @param string $key
* @return null|Paths|string
*
*/
function urls($key = '') {
return wireUrls($key);
}
/**
* Function that returns a $config->paths->[name] value o
*
* @param string $key
* @return null|Paths|string
*
*/
function paths($key = '') {
return wirePaths($key);
}
/**
* Get or set a region for front-end output
*
* ~~~~~
* // define a region
* region('content', '<p>this is some content</p>');
*
* // prepend some text to region
* region('+content', '<h2>Good morning</h2>');
*
* // append some text to region
* region('content+', '<p><small>Good night</small></p>');
*
* // output a region
* echo region('content');
*
* // get all regions in an array
* $regions = region('*');
*
* // clear the 'content' region
* region('content', '');
*
* // clear all regions
* region('*', '');
*
* ~~~~~
*
* @param string $key Name of region to get or set.
* - Specify "*" to retrieve all defined regions in an array.
* - Prepend a "+" to the region name to have it prepend your given value to any existing value.
* - Append a "+" to the region name to have it append your given value to any existing value.
* @param null|string $value If setting a region, the text that you want to set.
* @return string|null|bool|array Returns string of text when getting a region, NULL if region not set, or TRUE if setting region.
*
*/
function region($key = '', $value = null) {
return wireRegion($key, $value);
}

View File

@@ -0,0 +1,486 @@
<?php namespace ProcessWire;
/**
* ProcessWire functions API maps function names to common API variables
*
* Provides an alternative to the API variables by providing functions of the same
* name, with these benefits:
*
* - They are always in scope
* - Makes life simpler in an IDE that recognizes phpdoc, as it can more easily
* recognize the types an return values.
* - In some cases it makes for shorter API calls.
*
* The primary drawback is that the function calls are not mapped to a specific
* instance, so in a multi-instance environment it's possible these function calls
* may not be referring to the correct ProcessWire instance. For this reason, we
* think these functions are primarily useful for front-end/website usages, and
* not as useful for back-end and module development.
*
* Shorter versions of these functions (without the leading "wire") can be found in
* FunctionsAPI.php file, which is used only if $config->useFunctionsAPI is true.
* The functions in this file are always available regardless of that setting.
*
*
*/
/**
* Common helper for API functions dealing with pages
*
* @param $_apiVar
* @param $selector
* @return null|NullPage|Page|PageArray|Pages|PagesType
*
*/
function _wirePagesAPI($_apiVar, $selector) {
/** @var Pages|PagesType $pages */
$pages = wire($_apiVar);
if(!$pages) return null;
if(!$selector) return $pages;
if(is_array($selector) || is_object($selector)) {
return $pages->find($selector);
} else if(ctype_digit("$selector")) {
// i.e. "123"
return $pages->get((int) $selector);
} else if(wireSanitizer('pageName', $selector) === $selector) {
// i.e. "contact"
return $pages->get("name=$selector");
} else if(strpos($selector, '/') !== false && wireSanitizer('pagePathName', $selector) === $selector) {
// i.e. "/path/to/page/"
return $pages->get($selector);
} else {
return $pages->find($selector);
}
}
/**
* Common helper for API functions dealing with WireData objects
*
* @param $_apiVar
* @param $key
* @param $value
* @return mixed|null|WireData|Page
*
*/
function _wireDataAPI($_apiVar, $key, $value) {
/** @var WireData $item */
$item = wire($_apiVar);
if(!$item) return null;
if(strlen($key)) {
if(is_null($value)) {
return $item->get($key);
} else {
$item->set($key, $value);
}
}
return $item;
}
/**
* Access the $pages API variable as a function
*
* ~~~~
* // A call with no arguments returns the $pages API variable
* $pages = pages();
* $pageArray = pages()->find("selector");
* $page = pages()->get(123);
*
* // Providing selector as argument maps to $pages->find()
* $pageArray = pages("template=basic-page");
*
* // Providing argument of single page ID, path or name maps to $pages->get()
* $page = pages(123);
* $page = pages("/path/to/page/");
* $page = pages("page-name");
* ~~~~
*
* @param string|array $selector Specify one of the following:
* - Nothing, makes it return the $pages API variable.
* - Selector (string) to find matching pages, makes function return PageArray - equivalent to $pages->find("selector");
* - Page ID (int) to return a single matching Page - equivalent to $pages->get(123);
* - Page name (string) to return a single page having the given name - equivalent to $pages->get("name");
* @return Pages|PageArray|Page|NullPage
*
*/
function wirePages($selector = '') {
return _wirePagesAPI('pages', $selector);
}
/**
* Access the $page API variable as a function
*
* ~~~~
* $page = page(); // Simply get $page API var
* $body = page()->body; // Get body field value
* $body = page('body'); // Same as above
* $headline = page('headline|title'); // Get headline or title
* page('headline', 'Setting headline value'); // Set headline
* ~~~~
*
* @param string $key Optional property to get or set
* @param null $value Optional value to set
* @return Page|mixed
*
*/
function wirePage($key = '', $value = null) {
return _wireDataAPI('page', $key, $value);
}
/**
* Access the $config API variable as a function
*
* ~~~~~
* $config = config(); // Simply get $config API var
* $debug = config()->debug; // Get value of debug
* $debug = config('debug'); // Same as above
* config()->debug = true; // Set value of debug
* config('debug', true); // Same as above
* ~~~~~
*
* @param string $key
* @param null $value
* @return Config|mixed
*
*/
function wireConfig($key = '', $value = null) {
return _wireDataAPI('config', $key, $value);
}
/**
* Access the $modules API variable as a function
*
* ~~~~~
* $modules = modules(); // Simply get $modules API var
* $module = modules()->get('ModuleName'); // Get a module
* $module = modules('ModuleName'); // Shortcut to get a module
* ~~~~~
*
* @param string $name Optionally retrieve the given module name
* @return Modules|Module|ConfigurableModule|null
*
*/
function wireModules($name = '') {
/** @var Modules $modules */
$modules = wire('modules');
return strlen($name) ? $modules->getModule($name) : $modules;
}
/**
* Access the $user API variable as a function
*
* @param string $key Optional property to get or set
* @param null $value Optional value to set
* @return User|mixed
*
*/
function wireUser($key = '', $value = null) {
return _wireDataAPI('user', $key, $value);
}
/**
* Access the $users API variable as a function
*
* See the pages() function for full usage details.
*
* @param string|array $selector Optional selector to send to find() or get()
* @return Users|PageArray|User|mixed
* @see pages()
*
*/
function wireUsers($selector = '') {
return _wirePagesAPI('users', $selector);
}
/**
* Access the $session API variable as a function
*
* @param string $key Optional property to get or set
* @param null $value Optional value to set
* @return Session|mixed
*
*/
function wireSession($key = '', $value = null) {
return _wireDataAPI('session', $key, $value);
}
/**
* Access the $fields API variable as a function
*
* @param string $name Optional field name to retrieve
* @return Fields|Field|null
*
*/
function wireFields($name = '') {
/** @var Fields $fields */
$fields = wire('fields');
return strlen($name) ? $fields->get($name) : $fields;
}
/**
* Access the $templates API variable as a function
*
* @param string $name Optional template to retrieve
* @return Templates|Template|null
*
*/
function wireTemplates($name = '') {
/** @var Templates $templates */
$templates = wire('templates');
return strlen($name) ? $templates->get($name) : $templates;
}
/**
* Access the $database API variable as a function
*
* @return WireDatabasePDO
*
*/
function wireDatabase() {
return wire('database');
}
/**
* Access the $permissions API varaible as a function
*
* See the pages() function for usage details.
*
* @param string $selector
* @return Permissions|Permission|PageArray|null|NullPage
*
*/
function wirePermissions($selector = '') {
return _wirePagesAPI('permissions', $selector);
}
/**
* Access the $roles API varaible as a function
*
* See the pages() function for usage details.
*
* @param string $selector
* @return Roles|Role|PageArray|null|NullPage
*
*/
function wireRoles($selector = '') {
return _wirePagesAPI('roles', $selector);
}
/**
* Access the $sanitizer API variable as a function
*
* ~~~~~
* // Example usages
* $clean = sanitizer()->pageName($dirty);
* $clean = sanitizer('pageName', $dirty); // same as above
* ~~~~~
*
* @param string $name Optionally enter a sanitizer function name
* @param string $value If $name populated, enter the value to sanitize
* @return Sanitizer|string|int|array|null|mixed
*
*/
function wireSanitizer($name = '', $value = '') {
$sanitizer = wire('sanitizer');
return strlen($name) ? $sanitizer->$name($value) : $sanitizer;
}
/**
* Access the $datetime API variable as a function
*
* ~~~~~
* // Example usages
* $str = datetime()->relativeTimeStr('2016-10-10');
* $str = datetime('Y-m-d');
* $str = datetime('Y-m-d', time());
* ~~~~~
*
* @param string $format Optional date format
* @param string|int $value Optional date to format
* @return WireDateTime|string|int
*
*/
function wireDatetime($format = '', $value = '') {
/** @var WireDateTime $datetime */
$datetime = wire('datetime');
return strlen($format) ? $datetime->formatDate($value ? $value : time(), $format) : $datetime;
}
/**
* Access the $files API variable as a function
*
* @return WireFileTools
*
*/
function wireFiles() {
return wire('files');
}
/**
* Access the $cache API variable as a function
*
* If called with no arguments it returns the $cache API variable.
* If called with arguments, it can be used the same as `WireCache::get()`.
*
* @param string $name
* @param callable|int|string|null $expire
* @param callable|int|string|null $func
* @return WireCache|string|array|PageArray|null
* @see WireCache::get()
*
*/
function wireCache($name = '', $expire = null, $func = null) {
/** @var WireCache $cache */
$cache = wire('cache');
return strlen($name) ? $cache->get($name, $expire, $func) : $cache;
}
/**
* Access the $languages API variable as a function
*
* Returns the $languages API variable, or a Language object if given a language name.
*
* ~~~~
* // Examples
* $languages = languages(); // Languages if active, null if not
* $en = languages()->getDefault();
* $de = languages('de');
* ~~~~
*
* @param string|int $name Optional Language name or ID for language to retrieve
* @return Languages|Language|NullPage|null
*
*/
function wireLanguages($name = '') {
/** @var Languages $languages */
$languages = wire('languages');
if(!$languages) return null;
if(strlen($name)) return $languages->get($name);
return $languages;
}
/**
* Access the $input API variable as a function
*
* - Default behavior is to return the $input API var.
* - If given just a $type (like "get" or "post"), it will return a WireInputData object for that type.
* - If given a $type and $key it will return the input variable.
* - If all arguments given, the returned value will also be run through the given sanitizer.
*
* ~~~~~
* // Examples
* $input = input(); // Returns $input API var (WireInput)
* $post = input('post'); // Returns $input->post (WireInputData)
* $value = input('get', 'sort'); // Returns $input->get('sort');
* $value = input('get', 'sort', 'fieldName'); // Returns $input->get('sort') run through $sanitizer->fieldName().
* ~~~~~
*
* @param string $type Optionally indicate "get", "post", "cookie" or "whitelist"
* @param string $key If getting a value, specify name of property containing value
* @param string $sanitizer Optionally specify sanitizer name to run value through
* @return WireInput|WireInputData array|string|int|null
*
*/
function wireInput($type = '', $key = '', $sanitizer = '') {
/** @var WireInput $input */
$input = wire('input');
if(!strlen($type)) return $input;
$type = strtolower($type);
if(!strlen($key)) return $input->$type;
$value = $input->$type($key);
if(strlen($sanitizer)) $value = wireSanitizer($sanitizer, $value);
return $value;
}
/**
* Access the $input->get API variable as a function
*
* This is the same as the input() function except that the $type "get" is already implied.
*
* @param string $key
* @param string $sanitizer
* @return WireInputData|string|int|array|null
*
*/
function wireInputGet($key = '', $sanitizer = '') {
return wireInput('get', $key, $sanitizer);
}
/**
* Access the $input->post API variable as a function
*
* This is the same as the input() function except that the $type "post" is already implied.
*
* @param string $key
* @param string $sanitizer
* @return WireInputData|string|int|array|null
*
*/
function wireInputPost($key = '', $sanitizer = '') {
return wireInput('post', $key, $sanitizer);
}
/**
* Access the $input->cookie API variable as a function
*
* This is the same as the input() function except that the $type "cookie" is already implied.
*
* @param string $key
* @param string $sanitizer
* @return WireInputData|string|int|array|null
*
*/
function wireInputCookie($key = '', $sanitizer = '') {
return wireInput('cookie', $key, $sanitizer);
}
/**
* Access the $log API variable as a function
*
* Default behavior is to return the $log API variable.
* If both arguments are provided, it assumes you want to log a message.
*
* @param string $logName If logging a message, specify the name of the log.
* @param string $message If logging a message, specify the message text.
* @return WireLog|bool Returns bool if saving log entry, WireLog otherwise.
*
*/
function wireLog($logName = '', $message = '') {
/** @var WireLog $log */
$log = wire('log');
if(strlen($message)) {
if(!strlen($logName)) $logName = 'unknown';
return $log->save($logName, $message);
}
return $log;
}
/**
* Function that returns a $config->urls->[name] value o
*
* @param string $key
* @return null|Paths|string
*
*/
function wireUrls($key = '') {
if(empty($key)) return wire('config')->urls;
return wire('config')->urls($key);
}
/**
* Function that returns a $config->paths->[name] value o
*
* @param string $key
* @return null|Paths|string
*
*/
function wirePaths($key = '') {
if(empty($key)) return wire('config')->paths;
return wire('config')->paths($key);
}

View File

@@ -653,8 +653,11 @@ class Modules extends WireArray {
$module = $this->newModule($className);
if($module) {
$this->set($className, $module);
$this->initModule($module);
if($this->debug) $this->message("Conditional autoload: $className LOADED");
if($this->initModule($module)) {
if($this->debug) $this->message("Conditional autoload: $className LOADED");
} else {
if($this->debug) $this->warning("Failed conditional autoload: $className");
}
}
} else {
@@ -1211,7 +1214,9 @@ class Modules extends WireArray {
if($module && $needsInit) {
// if the module is configurable, then load it's config data
// and set values for each before initializing the module
if(empty($options['noInit'])) $this->initModule($module, false);
if(empty($options['noInit'])) {
if(!$this->initModule($module, false)) $module = null;
}
}
return $module;
@@ -2910,34 +2915,38 @@ class Modules extends WireArray {
* #pw-changelog 3.0.16 Changed from more verbose name `getModuleConfigData()`, which can still be used.
*
* @param string|Module $class
* @param string $property Optionally just get value for a specific property (omit to get all config)
* @return array Module configuration data
* @see Modules::saveConfig()
* @since 3.0.16 Use method getModuleConfigData() with same arguments for prior versions (can also be used on any version).
*
*/
public function getConfig($class) {
public function getConfig($class, $property = '') {
$emptyReturn = $property ? null : array();
$className = $class;
if(is_object($className)) $className = wireClassName($className->className(), false);
if(!$id = $this->moduleIDs[$className]) return array();
if(!isset($this->configData[$id])) return array(); // module has no config data
if(is_array($this->configData[$id])) return $this->configData[$id];
if(!$id = $this->moduleIDs[$className]) return $emptyReturn;
if(!isset($this->configData[$id])) return $emptyReturn; // module has no config data
// first verify that module doesn't have a config file
$configurable = $this->isConfigurable($className);
if(!$configurable) return array();
if(is_array($this->configData[$id])) {
$data = $this->configData[$id];
} else {
// first verify that module doesn't have a config file
$configurable = $this->isConfigurable($className);
if(!$configurable) return $emptyReturn;
$database = $this->wire('database');
$query = $database->prepare("SELECT data FROM modules WHERE id=:id", "modules.getConfig($className)"); // QA
$query->bindValue(":id", (int) $id, \PDO::PARAM_INT);
$query->execute();
$data = $query->fetchColumn();
$query->closeCursor();
if(strlen($data)) $data = wireDecodeJSON($data);
if(empty($data)) $data = array();
$this->configData[$id] = $data;
}
$database = $this->wire('database');
$query = $database->prepare("SELECT data FROM modules WHERE id=:id", "modules.getConfig($className)"); // QA
$query->bindValue(":id", (int) $id, \PDO::PARAM_INT);
$query->execute();
$data = $query->fetchColumn();
$query->closeCursor();
if(empty($data)) $data = array();
else $data = wireDecodeJSON($data);
if(empty($data)) $data = array();
$this->configData[$id] = $data;
if($property) return isset($data[$property]) ? $data[$property] : null;
return $data;
}
@@ -3427,19 +3436,36 @@ class Modules extends WireArray {
* #pw-changelog 3.0.16 Changed name from the more verbose saveModuleConfigData(), which will still work.
*
* @param string|Module $class Module or module name
* @param array $data Associative array of configuration data
* @param array|string $data Associative array of configuration data, or name of property you want to save.
* @param mixed|null $value If you specified a property in previous arg, the value for the property.
* @return bool True on success, false on failure
* @throws WireException
* @see Modules::getConfig()
* @since 3.0.16 Use method saveModuleConfigData() with same arguments for prior versions (can also be used on any version).
*
*/
public function ___saveConfig($class, array $data) {
public function ___saveConfig($class, $data, $value = null) {
$className = $class;
if(is_object($className)) $className = $className->className();
$moduleName = wireClassName($className, false);
if(!$id = $this->moduleIDs[$moduleName]) throw new WireException("Unable to find ID for Module '$moduleName'");
if(is_string($data)) {
// a property and value have been provided
$property = $data;
$data = $this->getConfig($class);
if(is_null($value)) {
// remove the property
unset($data[$property]);
} else {
// populate the value for the property
$data[$property] = $value;
}
} else {
// data must be an associative array of configuration data
if(!is_array($data)) return false;
}
// ensure original duplicates info is retained and validate that it is still current
$data = $this->duplicates()->getDuplicatesConfigData($moduleName, $data);
@@ -3451,6 +3477,7 @@ class Modules extends WireArray {
$query->bindValue(":id", (int) $id, \PDO::PARAM_INT);
$result = $query->execute();
$this->log("Saved module '$moduleName' config data");
return $result;
}

View File

@@ -1001,6 +1001,12 @@ class Page extends WireData implements \Countable, WireMatchable {
// check if it's a field.subfield property
if(strpos($key, '.') && ($value = $this->getFieldSubfieldValue($key)) !== null) return $value;
if(strpos($key, '_OR_')) {
// convert '_OR_' to '|'
$value = $this->getFieldFirstValue(str_replace('_OR_', '|', $key));
if($value !== null) return $value;
}
// optionally let a hook look at it
if($this->wire('hooks')->isHooked('Page::getUnknown()')) $value = $this->getUnknown($key);
}

View File

@@ -206,6 +206,8 @@ class PagesLoader extends Wire {
$pagesIDs = array();
if($debug) Debug::timer("$caller($selectorString)", true);
$profiler = $this->wire('profiler');
$profilerEvent = $profiler ? $profiler->start("$caller($selectorString)", "Pages") : null;
if($lazy) {
if(strpos($selectorString, 'limit=') === false) $options['getTotal'] = false;
@@ -308,6 +310,8 @@ class PagesLoader extends Wire {
}
}
if($profilerEvent) $profiler->stop($profilerEvent);
if($this->pages->hasHook('found()')) $this->pages->found($pages, array(
'pageFinder' => $pageFinder,
'pagesInfo' => $pagesInfo,

View File

@@ -151,7 +151,9 @@ class ProcessController extends Wire {
if(!empty($info['permission'])) $permissionName = $info['permission'];
$this->hasPermission($permissionName, true); // throws exception if no permission
if(!$this->process) $this->process = $this->modules->get($processName);
if(!$this->process) {
$this->process = $this->modules->getModule($processName);
}
// set a proces fuel, primarily so that certain Processes can determine if they are the root Process
// example: PageList when in PageEdit

View File

@@ -208,6 +208,10 @@ class ProcessWire extends Wire {
if($process == 'ProcessPageView') $process->finished();
});
if($config->useFunctionsAPI) {
include($config->paths->core . 'FunctionsAPI.php');
}
$this->setStatus(self::statusBoot);
}

View File

@@ -71,6 +71,20 @@ class TemplateFile extends WireData {
*/
protected $halt = false;
/**
* Last tracked profile event
*
* @var mixed
*
*/
protected $profilerEvent = null;
/**
* @var WireProfilerInterface|null
*
*/
protected $profiler = null;
/**
* Variables that will be applied globally to this and all other TemplateFile instances
*
@@ -180,6 +194,27 @@ class TemplateFile extends WireData {
self::$globals[$name] = $value;
}
/**
* Start profiling a render
*
* @param string $filename
*
*/
protected function start($filename) {
if($this->profiler) {
$f = str_replace($this->wire('config')->paths->root, '/', $filename);
$this->profilerEvent = $this->profiler->start($f, $this);
}
}
/**
* Stop profiling a render
*
*/
protected function stop() {
if($this->profilerEvent) $this->profiler->stop($this->profilerEvent);
}
/**
* Render the template -- execute it and return it's output
*
@@ -201,6 +236,7 @@ class TemplateFile extends WireData {
$this->savedInstance = ProcessWire::getCurrentInstance();
ProcessWire::setCurrentInstance($this->wire());
$this->profiler = $this->wire('profiler');
$this->savedDir = getcwd();
if($this->chdir) {
@@ -208,19 +244,29 @@ class TemplateFile extends WireData {
} else {
chdir(dirname($this->filename));
}
$fuel = array_merge($this->getArray(), self::$globals); // so that script can foreach all vars to see what's there
$fuel = array_merge($this->getArray(), self::$globals); // so that script can foreach all vars to see what's there
extract($fuel);
ob_start();
foreach($this->prependFilename as $_filename) {
if($this->halt) break;
if($this->profiler) $this->start($_filename);
require($_filename);
if($this->profiler) $this->stop();
}
if($this->profiler) $this->start($this->filename);
if(!$this->halt) $returnValue = require($this->filename);
if($this->profiler) $this->stop();
foreach($this->appendFilename as $_filename) {
if($this->halt) break;
if($this->profiler) $this->start($_filename);
require($_filename);
if($this->profiler) $this->stop();
}
$out = "\n" . ob_get_contents() . "\n";
ob_end_clean();
@@ -229,6 +275,7 @@ class TemplateFile extends WireData {
$out = trim($out);
if(!strlen($out) && !$this->halt && $returnValue && $returnValue !== 1) return $returnValue;
return $out;
}

View File

@@ -14,7 +14,7 @@
* modifying arguments or return values. Several other hook methods are also provided for Wire derived
* classes that are hooking into others.
* #pw-body
* #pw-order-groups common,identification,hooks,notices,changes,hooker
* #pw-order-groups common,identification,hooks,notices,changes,hooker,api-helpers
*
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
* https://processwire.com
@@ -55,6 +55,32 @@
* @method callUnknown($method, $arguments) See Wire::___callUnknown()
* @method Wire trackException(\Exception $e, $severe = true, $text = null)
*
* The following map API variables to function names and apply only if another function in the class does not
* already have the same name, which would override. All defined API variables can be accessed as functions
* that return the API variable, whether documented below or not.
*
* @method Pages|PageArray|Page|NullPage pages($selector = '') Access the $pages API variable as a function. #pw-group-api-helpers
* @method Page|Mixed page($key = '', $value = null) Access the $page API variable as a function. #pw-group-api-helpers
* @method Config|mixed config($key = '', $value = null) Access the $config API variable as a function. #pw-group-api-helpers
* @method Modules|Module|ConfigurableModule|null modules($name = '') Access the $modules API variable as a function. #pw-group-api-helpers
* @method User|mixed user($key = '', $value = null) Access the $user API variable as a function. #pw-group-api-helpers
* @method Users|PageArray|User|mixed users($selector = '') Access the $users API variable as a function. #pw-group-api-helpers
* @method Session|mixed session($key = '', $value = null) Access the $session API variable as a function. #pw-group-api-helpers
* @method Field|Fields|null fields($name = '') Access the $fields API variable as a function. #pw-group-api-helpers
* @method Templates|Template|null templates($name = '') Access the $templates API variable as a function. #pw-group-api-helpers
* @method WireDatabasePDO database() Access the $database API variable as a function. #pw-group-api-helpers
* @method Permissions|Permission|PageArray|null|NullPage permissions($selector = '') Access the $permissions API variable as a function. #pw-group-api-helpers
* @method Roles|Role|PageArray|null|NullPage roles($selector = '') Access the $roles API variable as a function. #pw-group-api-helpers
* @method Sanitizer|string|int|array|null|mixed sanitizer($name = '', $value = '') Access the $sanitizer API variable as a function. #pw-group-api-helpers
* @method WireDateTime|string|int datetime($format = '', $value = '') Access the $datetime API variable as a function. #pw-group-api-helpers
* @method WireFileTools files() Access the $files API variable as a function. #pw-group-api-helpers
* @method WireCache|string|array|PageArray|null cache($name = '', $expire = null, $func = null) Access the $cache API variable as a function. #pw-group-api-helpers
* @method Languages|Language|NullPage|null languages($name = '') Access the $languages API variable as a function. #pw-group-api-helpers
* @method WireInput|WireInputData array|string|int|null input($type = '', $key = '', $sanitizer = '') Access the $input API variable as a function. #pw-group-api-helpers
* @method WireInputData|string|int|array|null inputGet($key = '', $sanitizer = '') Access the $input->get() API variable as a function. #pw-group-api-helpers
* @method WireInputData|string|int|array|null inputPost($key = '', $sanitizer = '') Access the $input->post() API variable as a function. #pw-group-api-helpers
* @method WireInputData|string|int|array|null inputCookie($key = '', $sanitizer = '') Access the $input->cookie() API variable as a function. #pw-group-api-helpers
*
*/
abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
@@ -371,13 +397,47 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
$hooks = $this->wire('hooks');
if($hooks) {
$result = $hooks->runHooks($this, $method, $arguments);
if(!$result['methodExists'] && !$result['numHooksRun']) return $this->callUnknown($method, $arguments);
if(!$result['methodExists'] && !$result['numHooksRun']) {
$result = $this->_callWireAPI($method, $arguments);
if(!$result) return $this->callUnknown($method, $arguments);
}
} else {
return $this->___callUnknown($method, $arguments);
$result = $this->_callWireAPI($method, $arguments);
if(!$result) return $this->___callUnknown($method, $arguments);
}
return $result['return'];
}
/**
* Helper to __call() method that maps a call to an API variable when appropriate
*
* @param string $method
* @param array $arguments
* @return array|bool
* @internal
*
*/
protected function _callWireAPI($method, $arguments) {
$var = $this->_wire ? $this->_wire->fuel()->$method : null;
if(!$var) return false;
// requested method maps to an API variable
$result = array('return' => null);
$funcName = 'wire' . ucfirst($method);
if(__NAMESPACE__) $funcName = __NAMESPACE__ . "\\$funcName";
if(count($arguments) && function_exists($funcName)) {
// a function exists with this API var name
$wire = ProcessWire::getCurrentInstance();
// ensure function call maps to this PW instance
if($wire !== $this->_wire) ProcessWire::setCurrentInstance($this->_wire);
$result['return'] = call_user_func_array($funcName, $arguments);
if($wire !== $this->_wire) ProcessWire::setCurrentInstance($wire);
} else {
// if no arguments provided, just return API var
$result['return'] = $var;
}
return $result;
}
/**
* If method call resulted in no handler, this hookable method is called.
*

View File

@@ -540,6 +540,7 @@ class WireHooks {
$hooks = $this->getHooks($object, $method);
$cancelHooks = false;
$profiler = $this->wire->wire('profiler');
foreach(array('before', 'after') as $when) {
@@ -606,6 +607,15 @@ class WireHooks {
$toObject = $hook['toObject'];
$toMethod = $hook['toMethod'];
if($profiler) {
$profilerEvent = $profiler->start($hook['id'], $this, array(
'event' => $event,
'hook' => $hook,
));
} else {
$profilerEvent = false;
}
if(is_null($toObject)) {
if(!is_callable($toMethod) && strpos($toMethod, "\\") === false && __NAMESPACE__) {
$_toMethod = "\\" . __NAMESPACE__ . "\\$toMethod";
@@ -624,6 +634,8 @@ class WireHooks {
// @todo allow for use of $returnValue as alternative to $event->return
}
if($profilerEvent) $profiler->stop($profilerEvent);
$result['numHooksRun']++;
if($event->cancelHooks === true) $cancelHooks = true;

View File

@@ -182,8 +182,14 @@ class WireInputData extends Wire implements \ArrayAccess, \IteratorAggregate, \C
return count($this->data);
}
public function remove($key) {
unset($this->data[$key]);
return $this;
}
public function removeAll() {
$this->data = array();
return $this;
}
public function __isset($key) {

View File

@@ -11,6 +11,8 @@
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
* https://processwire.com
*
* @method bool save($name, $text, $options = array())
*
*/
class WireLog extends Wire {

View File

@@ -29,6 +29,7 @@ $corePreloads = array(
'FilenameArray.php',
'Paths.php',
'Config.php',
'FunctionsWireAPI.php',
'Functions.php',
'LanguageFunctions.php',
'WireShutdown.php',

View File

@@ -500,7 +500,10 @@ class PageRender extends WireData implements Module, ConfigurableModule {
// own additional variables in it if they want to
$output->set('options', $options);
$profiler = $this->wire('profiler');
$profilerEvent = $profiler ? $profiler->start($page->path, $this, array('page' => $page)) : null;
$data = $output->render();
if($profilerEvent) $profiler->stop($profilerEvent);
}
if($data && $cacheAllowed && $cacheFile) $cacheFile->save($data);

View File

@@ -95,6 +95,7 @@ class ProcessPageEditImageSelect extends Process implements ConfigurableModule {
'flipHorizontal' => $this->_('Flip horizontal'),
'flipVertical' => $this->_('Flip vertical'),
'noAccess' => $this->_('You do not have access to edit images on this page.'),
'demoMode' => "Image editing functions are disabled in demo mode",
);
}
@@ -106,7 +107,12 @@ class ProcessPageEditImageSelect extends Process implements ConfigurableModule {
*/
public function init() {
if($this->config->demo) throw new WireException("Sorry, image editing functions are disabled in demo mode");
// throw new WireException($this->labels['demoMode']);
if($this->config->demo) {
if($this->wire('input')->urlSegmentStr != 'variations') {
throw new WireException($this->labels['demoMode']);
}
}
$this->modules->get("ProcessPageList");
@@ -1323,7 +1329,16 @@ class ProcessPageEditImageSelect extends Process implements ConfigurableModule {
$this->wire('modules')->get('JqueryMagnific');
return "<br />" . $form->render();
$out = $form->render();
if($this->wire('config')->demo) {
$out = "<p class='detail'>Note: " . $this->labels['demoMode'] . "</p>" . $out;
} else {
$out = "<br />" . $out;
}
return $out;
}
/**