1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-13 18:24:57 +02:00

Various minor pending updates and optimiations to several classes

This commit is contained in:
Ryan Cramer
2019-11-08 10:29:58 -05:00
parent dd87518987
commit b972aab11b
13 changed files with 301 additions and 157 deletions

View File

@@ -29,7 +29,61 @@ class WirePermissionException extends WireException {}
* Thrown when a requested page does not exist, or can be thrown manually to show the 404 page
*
*/
class Wire404Exception extends WireException {}
class Wire404Exception extends WireException {
/**
* 404 is because core determined requested resource by URL does not physically exist
*
* #pw-internal
*
*/
const codeNonexist = 404;
/**
* 404 is a result of a resource that might exist but there is there is no access
*
* Similar to a WirePermissionException except always still a 404 externally
*
* #pw-internal
*
*/
const codePermission = 4041;
/**
* 404 is a result of a secondary non-file asset that does not exist, even if page does
*
* For example: /foo/bar/?id=123 where /foo/bar/ exists but 123 points to non-existent asset.
*
* #pw-internal
*
*/
const codeSecondary = 4042;
/**
* 404 is a result of content not available in requested language
*
* #pw-internal
*
*/
const codeLanguage = 4043;
/**
* 404 is a result of a physical file that does not exist on the file system
*
* #pw-internal
*
*/
const codeFile = 4044;
/**
* Anonymous 404 with no code provided
*
* #pw-internal
*
*/
const codeAnonymous = 0;
}
/**
* Thrown when ProcessWire is unable to connect to the database at boot

View File

@@ -452,6 +452,54 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre
return $p[$c];
}
/**
* Prepare Inputfield for attributes used during rendering
*
* #pw-internal
*
* @param Inputfield $inputfield
* @param array $markup
* @since 3.0.144
*
*/
private function attributeInputfield(Inputfield $inputfield, &$markup) {
$inputfieldClass = $inputfield->className();
$markupTemplate = array('attr' => array(), 'wrapAttr' => array());
$classParents = $this->classParents($inputfield);
$classParents[] = $inputfieldClass;
$classKeys = array('class', 'wrapClass', 'headerClass', 'contentClass');
$classes = array();
$attr = array();
$wrapAttr = array();
foreach($classParents as $classParent) {
if(!isset($markup[$classParent])) continue;
$markupParent = array_merge($markupTemplate, $markup[$classParent]);
foreach($classKeys as $classKey) {
if(!empty($markupParent[$classKey])) {
$classes[$classKey] = $markupParent[$classKey];
}
}
foreach($markupParent['attr'] as $k => $v) {
$attr[$k] = $v;
}
foreach($markupParent['wrapAttr'] as $k => $v) {
$wrapAttr[$k] = $v;
}
}
foreach($attr as $attrName => $attrVal) {
$inputfield->attr($attrName, $attrVal);
}
foreach($wrapAttr as $attrName => $attrVal) {
$inputfield->wrapAttr($attrName, $attrVal);
}
foreach($classes as $classKey => $class) {
$inputfield->addClass($class, $classKey);
}
}
/**
* Render this Inputfield and the output of its children.
*
@@ -512,24 +560,7 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre
if($collapsed == Inputfield::collapsedHidden) continue;
if($collapsed == Inputfield::collapsedNoLocked || $collapsed == Inputfield::collapsedYesLocked) $renderValueMode = true;
// allow adding custom classes and/or attributes at runtime (since 3.0.143)
$classParents = $this->classParents($inputfield);
$classParents[] = $inputfieldClass;
foreach($classParents as $classParent) {
if(!isset($_markup[$classParent])) continue;
$markupParent = $_markup[$classParent];
foreach(array('class', 'wrapClass', 'headerClass', 'contentClass') as $classKey) {
if(!empty($markupParent[$classKey])) $inputfield->addClass($markupParent[$classKey], $classKey);
}
foreach(array('attr', 'wrapAttr') as $attrKey) {
if(!empty($markupParent[$attrKey]) && is_array($markupParent[$attrKey])) {
foreach($markupParent[$attrKey] as $k => $v) {
$inputfield->$attrKey($k, $v);
}
}
}
}
$this->attributeInputfield($inputfield, $_markup);
$ffOut = $this->renderInputfield($inputfield, $renderValueMode);
if(!strlen($ffOut)) continue;
$collapsed = (int) $inputfield->getSetting('collapsed'); // retrieve again after render
@@ -576,7 +607,7 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre
if($appendMarkup) $ffOut .= $appendMarkup;
}
// The inputfield's classname is always used in it's LI wrapper
// The inputfield classname is always used in its wrapping element
$ffAttrs = array(
'class' => str_replace(
array('{class}', '{name}'),
@@ -621,116 +652,116 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre
}
}
}
// if inputfield produced no output, then move to next
if(!$ffOut) continue;
// if the inputfield resulted in output, wrap it in an LI
if($ffOut) {
$attrs = '';
$label = $inputfield->getSetting('label');
$skipLabel = $inputfield->getSetting('skipLabel');
$skipLabel = is_bool($skipLabel) || empty($skipLabel) ? (bool) $skipLabel : (int) $skipLabel; // force as bool or int
if(!strlen($label) && $skipLabel !== Inputfield::skipLabelBlank && $inputfield->className() != 'InputfieldWrapper') {
$label = $inputfield->attr('name');
// wrap the inputfield output
$attrs = '';
$label = $inputfield->getSetting('label');
$skipLabel = $inputfield->getSetting('skipLabel');
$skipLabel = is_bool($skipLabel) || empty($skipLabel) ? (bool) $skipLabel : (int) $skipLabel; // force as bool or int
if(!strlen($label) && $skipLabel !== Inputfield::skipLabelBlank && $inputfield->className() != 'InputfieldWrapper') {
$label = $inputfield->attr('name');
}
if(($label || $quietMode) && $skipLabel !== Inputfield::skipLabelMarkup) {
$for = $skipLabel || $quietMode ? '' : $inputfield->attr('id');
// if $inputfield has a property of entityEncodeLabel with a value of boolean FALSE, we don't entity encode
$entityEncodeLabel = $inputfield->getSetting('entityEncodeLabel');
if(is_int($entityEncodeLabel) && $entityEncodeLabel >= Inputfield::textFormatBasic) {
// uses an Inputfield::textFormat constant
$label = $inputfield->entityEncode($label, $entityEncodeLabel);
} else if($entityEncodeLabel !== false) {
$label = $inputfield->entityEncode($label);
}
if(($label || $quietMode) && $skipLabel !== Inputfield::skipLabelMarkup) {
$for = $skipLabel || $quietMode ? '' : $inputfield->attr('id');
// if $inputfield has a property of entityEncodeLabel with a value of boolean FALSE, we don't entity encode
$entityEncodeLabel = $inputfield->getSetting('entityEncodeLabel');
if(is_int($entityEncodeLabel) && $entityEncodeLabel >= Inputfield::textFormatBasic) {
// uses an Inputfield::textFormat constant
$label = $inputfield->entityEncode($label, $entityEncodeLabel);
} else if($entityEncodeLabel !== false) {
$label = $inputfield->entityEncode($label);
}
$icon = $inputfield->getSetting('icon');
$icon = $icon ? str_replace('{name}', $this->wire('sanitizer')->name(str_replace(array('icon-', 'fa-'), '', $icon)), $markup['item_icon']) : '';
$toggle = $collapsed == Inputfield::collapsedNever ? '' : $markup['item_toggle'];
if($toggle && strpos($toggle, 'title=') === false) {
$toggle = str_replace("class=", "title='" . $this->_('Toggle open/close') . "' class=", $toggle);
}
if($skipLabel === Inputfield::skipLabelHeader || $quietMode) {
// label only shows when field is collapsed
$label = str_replace('{out}', $icon . $label . $toggle, $markup['item_label_hidden']);
} else {
// label always visible
$label = str_replace(array('{for}', '{out}'), array($for, $icon . $label . $toggle), $markup['item_label']);
}
$headerClass = trim($inputfield->getSetting('headerClass') . " $classes[item_label]");
if($headerClass) {
if(strpos($label, '{class}') !== false) {
$label = str_replace('{class}', ' ' . $headerClass, $label);
} else {
$label = preg_replace('/( class=[\'"][^\'"]+)/', '$1 ' . $headerClass, $label, 1);
}
} else if(strpos($label, '{class}') !== false) {
$label = str_replace('{class}', '', $label);
}
} else if($skipLabel === Inputfield::skipLabelMarkup) {
// no header and no markup for header
$label = '';
$icon = $inputfield->getSetting('icon');
$icon = $icon ? str_replace('{name}', $this->wire('sanitizer')->name(str_replace(array('icon-', 'fa-'), '', $icon)), $markup['item_icon']) : '';
$toggle = $collapsed == Inputfield::collapsedNever ? '' : $markup['item_toggle'];
if($toggle && strpos($toggle, 'title=') === false) {
$toggle = str_replace("class=", "title='" . $this->_('Toggle open/close') . "' class=", $toggle);
}
if($skipLabel === Inputfield::skipLabelHeader || $quietMode) {
// label only shows when field is collapsed
$label = str_replace('{out}', $icon . $label . $toggle, $markup['item_label_hidden']);
} else {
// no header
// $inputfield->addClass('InputfieldNoHeader', 'wrapClass');
// label always visible
$label = str_replace(array('{for}', '{out}'), array($for, $icon . $label . $toggle), $markup['item_label']);
}
$columnWidth = (int) $inputfield->getSetting('columnWidth');
$columnWidthAdjusted = $columnWidth;
if($columnWidthSpacing) {
$columnWidthAdjusted = $columnWidth + ($columnWidthTotal ? -1 * $columnWidthSpacing : 0);
}
if($columnWidth >= 9 && $columnWidth <= 100) {
$ffAttrs['class'] .= ' ' . $classes['item_column_width'];
if(!$columnWidthTotal) {
$ffAttrs['class'] .= ' ' . $classes['item_column_width_first'];
}
$columnWidthTotal += $columnWidth;
if(!$useColumnWidth || $useColumnWidth > 1) {
if($columnWidthTotal >= 95 && $columnWidthTotal < 100) {
$columnWidthAdjusted += (100 - $columnWidthTotal);
$columnWidthTotal = 100;
}
$ffAttrs['data-colwidth'] = "$columnWidthAdjusted%";
}
if($useColumnWidth) {
$ffAttrs['style'] = "width: $columnWidthAdjusted%;";
}
//if($columnWidthTotal >= 100 && !$requiredIf) $columnWidthTotal = 0; // requiredIf meant to be a showIf?
if($columnWidthTotal >= 100) $columnWidthTotal = 0;
} else {
$columnWidthTotal = 0;
}
if(!isset($ffAttrs['id'])) $ffAttrs['id'] = 'wrap_' . $inputfield->attr('id');
$ffAttrs['class'] = str_replace('Inputfield_ ', '', $ffAttrs['class']);
$wrapClass = $inputfield->getSetting('wrapClass');
if($wrapClass) $ffAttrs['class'] .= " " . $wrapClass;
foreach($inputfield->wrapAttr() as $k => $v) {
if(!empty($ffAttrs[$k])) {
$ffAttrs[$k] .= " $v";
$headerClass = trim($inputfield->getSetting('headerClass') . " $classes[item_label]");
if($headerClass) {
if(strpos($label, '{class}') !== false) {
$label = str_replace('{class}', ' ' . $headerClass, $label);
} else {
$ffAttrs[$k] = $v;
$label = preg_replace('/( class=[\'"][^\'"]+)/', '$1 ' . $headerClass, $label, 1);
}
} else if(strpos($label, '{class}') !== false) {
$label = str_replace('{class}', '', $label);
}
foreach($ffAttrs as $k => $v) {
$k = $this->entityEncode($k);
$v = $this->entityEncode(trim($v));
$attrs .= " $k='$v'";
}
$markupItemContent = $markup['item_content'];
$contentClass = trim($inputfield->getSetting('contentClass') . " $classes[item_content]");
if($contentClass) {
if(strpos($markupItemContent, '{class}') !== false) {
$markupItemContent = str_replace('{class}', ' ' . $contentClass, $markupItemContent);
} else {
$markupItemContent = preg_replace('/( class=[\'"][^\'"]+)/', '$1 ' . $contentClass, $markupItemContent, 1);
}
} else if(strpos($markupItemContent, '{class}') !== false) {
$markupItemContent = str_replace('{class}', '', $markupItemContent);
}
if($inputfield->className() != 'InputfieldWrapper') $ffOut = str_replace('{out}', $ffOut, $markupItemContent);
$out .= str_replace(array('{attrs}', '{out}'), array(trim($attrs), $label . $ffOut), $markup['item']);
$lastInputfield = $inputfield;
} // if($ffOut)
} else if($skipLabel === Inputfield::skipLabelMarkup) {
// no header and no markup for header
$label = '';
} else {
// no header
// $inputfield->addClass('InputfieldNoHeader', 'wrapClass');
}
}
$columnWidth = (int) $inputfield->getSetting('columnWidth');
$columnWidthAdjusted = $columnWidth;
if($columnWidthSpacing) {
$columnWidthAdjusted = $columnWidth + ($columnWidthTotal ? -1 * $columnWidthSpacing : 0);
}
if($columnWidth >= 9 && $columnWidth <= 100) {
$ffAttrs['class'] .= ' ' . $classes['item_column_width'];
if(!$columnWidthTotal) {
$ffAttrs['class'] .= ' ' . $classes['item_column_width_first'];
}
$columnWidthTotal += $columnWidth;
if(!$useColumnWidth || $useColumnWidth > 1) {
if($columnWidthTotal >= 95 && $columnWidthTotal < 100) {
$columnWidthAdjusted += (100 - $columnWidthTotal);
$columnWidthTotal = 100;
}
$ffAttrs['data-colwidth'] = "$columnWidthAdjusted%";
}
if($useColumnWidth) {
$ffAttrs['style'] = "width: $columnWidthAdjusted%;";
}
//if($columnWidthTotal >= 100 && !$requiredIf) $columnWidthTotal = 0; // requiredIf meant to be a showIf?
if($columnWidthTotal >= 100) $columnWidthTotal = 0;
} else {
$columnWidthTotal = 0;
}
if(!isset($ffAttrs['id'])) $ffAttrs['id'] = 'wrap_' . $inputfield->attr('id');
$ffAttrs['class'] = str_replace('Inputfield_ ', '', $ffAttrs['class']);
$wrapClass = $inputfield->getSetting('wrapClass');
if($wrapClass) $ffAttrs['class'] .= " " . $wrapClass;
foreach($inputfield->wrapAttr() as $k => $v) {
if(!empty($ffAttrs[$k])) {
$ffAttrs[$k] .= " $v";
} else {
$ffAttrs[$k] = $v;
}
}
foreach($ffAttrs as $k => $v) {
$k = $this->entityEncode($k);
$v = $this->entityEncode(trim($v));
$attrs .= " $k='$v'";
}
$markupItemContent = $markup['item_content'];
$contentClass = trim($inputfield->getSetting('contentClass') . " $classes[item_content]");
if($contentClass) {
if(strpos($markupItemContent, '{class}') !== false) {
$markupItemContent = str_replace('{class}', ' ' . $contentClass, $markupItemContent);
} else {
$markupItemContent = preg_replace('/( class=[\'"][^\'"]+)/', '$1 ' . $contentClass, $markupItemContent, 1);
}
} else if(strpos($markupItemContent, '{class}') !== false) {
$markupItemContent = str_replace('{class}', '', $markupItemContent);
}
if($inputfield->className() != 'InputfieldWrapper') $ffOut = str_replace('{out}', $ffOut, $markupItemContent);
$out .= str_replace(array('{attrs}', '{out}'), array(trim($attrs), $label . $ffOut), $markup['item']);
$lastInputfield = $inputfield;
} // foreach($children as $inputfield)
if($out) {
$ulClass = $classes['list'];

View File

@@ -5,10 +5,13 @@
* Class to hold combined password/salt info. Uses Blowfish when possible.
* Specially used by FieldtypePassword.
*
* ProcessWire 3.x, Copyright 2018 by Ryan Cramer
* ProcessWire 3.x, Copyright 2019 by Ryan Cramer
* https://processwire.com
*
* @method setPass($value)
* @method setPass($value) Protected internal use method
* @property string $salt
* @property string $hash
* @property-write string $pass
*
*/

View File

@@ -108,7 +108,11 @@ abstract class Process extends WireData implements Module {
*
*/
private $_viewVars = array();
/**
* Construct
*
*/
public function __construct() { }
/**
@@ -324,6 +328,9 @@ abstract class Process extends WireData implements Module {
*/
public function ___upgrade($fromVersion, $toVersion) {
// any code needed to upgrade between versions
if($fromVersion && $toVersion && false === true) {
throw new WireException('Uncallable exception for phpdoc');
}
}
/**
@@ -352,13 +359,18 @@ abstract class Process extends WireData implements Module {
$name = $this->wire('sanitizer')->pageName($name);
if(!strlen($name)) $name = strtolower(preg_replace('/([A-Z])/', '-$1', str_replace('Process', '', $this->className())));
$adminPage = $this->wire('pages')->get($this->wire('config')->adminRootPageID);
if($parent instanceof Page) $parent = $parent; // nice
else if(ctype_digit("$parent")) $parent = $this->wire('pages')->get((int) $parent);
else if(strpos($parent, '/') !== false) $parent = $this->wire('pages')->get($parent);
else if($parent) $parent = $adminPage->child("include=all, name=" . $this->wire('sanitizer')->pageName($parent));
if($parent instanceof Page) {
// already have what we need
} else if(ctype_digit("$parent")) {
$parent = $this->wire('pages')->get((int) $parent);
} else if(strpos($parent, '/') !== false) {
$parent = $this->wire('pages')->get($parent);
} else if($parent) {
$parent = $adminPage->child("include=all, name=" . $this->wire('sanitizer')->pageName($parent));
}
if(!$parent || !$parent->id) $parent = $adminPage; // default
$page = $parent->child("include=all, name=$name"); // does it already exist?
if($page->id && $page->process == $this) return $page; // return existing copy
if($page->id && "$page->process" == "$this") return $page; // return existing copy
$page = $this->wire('pages')->newPage();
$page->template = $template ? $template : 'admin';
$page->name = $name;
@@ -389,7 +401,7 @@ abstract class Process extends WireData implements Module {
if(!$moduleID) return 0;
$n = 0;
foreach($this->wire('pages')->find("process=$moduleID, include=all") as $page) {
if($page->process != $this) continue;
if("$page->process" != "$this") continue;
$page->process = null;
$this->message(sprintf($this->_('Trashed Page: %s'), $page->path));
$this->wire('pages')->trash($page);
@@ -408,7 +420,7 @@ abstract class Process extends WireData implements Module {
* #pw-internal @todo work on documenting this method further
*
* @param array $options For descending classes to modify behavior (see $defaults in method)
* @return string rendered JSON string
* @return string|array rendered JSON string or array if `getArray` option is true.
* @throws Wire404Exception if getModuleInfo() doesn't specify useNavJSON=true;
*
*/
@@ -431,7 +443,9 @@ abstract class Process extends WireData implements Module {
$options = array_merge($defaults, $options);
$moduleInfo = $this->modules->getModuleInfo($this);
if(empty($moduleInfo['useNavJSON'])) throw new Wire404Exception();
if(empty($moduleInfo['useNavJSON'])) {
throw new Wire404Exception('No JSON nav available', Wire404Exception::codeSecondary);
}
$page = $this->wire('page');
$data = array(

View File

@@ -79,10 +79,10 @@
* @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 WireInput|WireInputData|WireInputDataCookie|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
* @method WireInputDataCookie|string|int|array|null inputCookie($key = '', $sanitizer = '') Access the $input->cookie() API variable as a function. #pw-group-api-helpers
*
*/
@@ -437,7 +437,15 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
*
*/
public function __call($method, $arguments) {
$hooks = $this->wire('hooks');
if(empty($arguments) && Fuel::isCommon($method)) {
// faster version of _callWireAPI for when conditions allow
if($this->_wire && !method_exists($this, "___$method")) {
// get a common API var with no arguments as method call more quickly
$val = $this->_wire->fuel($method);
if($val !== null) return $val;
}
}
$hooks = $this->wire('hooks'); /** @var WireHooks $hooks */
if($hooks) {
$result = $hooks->runHooks($this, $method, $arguments);
if(!$result['methodExists'] && !$result['numHooksRun']) {
@@ -465,15 +473,17 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
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);
if(count($arguments)) {
$funcName = 'wire' . ucfirst($method);
if(__NAMESPACE__) $funcName = __NAMESPACE__ . "\\$funcName";
if(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;

View File

@@ -867,6 +867,27 @@ class WireInput extends Wire {
if($method) return strtoupper($method) === $requestMethod;
return $requestMethod;
}
/**
* Is the current request of the specified type?
*
* This is a more readable/shorter alias of `$input->requestMethod('type')` for syntax convenience.
* Internally, it determines the request type without accessing any input data, so it is efficient.
*
* ~~~~~
* // The following are equivalent:
* $isPost = $input->is('post');
* $isPost = $input->requestMethod('post');
* ~~~~~
*
* @param string $method Specify one of: post, get, head, put, delete, options, patch (not case sensitive)
* @return bool
* @since 3.0.145
*
*/
public function is($method) {
return empty($method) ? false : $this->requestMethod($method);
}
/**
* Provides the implementation for get/post/cookie method validation and fallback features

View File

@@ -102,8 +102,8 @@ class FieldtypePassword extends Fieldtype {
*
* @param Page $page
* @param Field $field
* @param string|int|array $value
* @return string|int|array|object $value
* @param array $value
* @return Password
*
*/
public function ___wakeupValue(Page $page, Field $field, $value) {

View File

@@ -415,7 +415,7 @@ class LanguageSupportPageNames extends WireData implements Module, ConfigurableM
if($event) {}
if($this->force404) {
$this->force404 = false; // prevent another 404 on the 404 page
throw new Wire404Exception();
throw new Wire404Exception('Not available in requested language', Wire404Exception::codeLanguage);
// $page = $event->wire('page');
// if(!$page || ($page->id != $event->wire('config')->http404PageID)) {
// throw new Wire404Exception();

View File

@@ -487,8 +487,12 @@ class ProcessPageAdd extends Process implements ConfigurableModule, WirePageEdit
if(!$this->parent_id) return $this->renderChooseTemplate();
$this->parent = $this->pages->get((int) $this->parent_id);
if(!$this->parent->id) throw new Wire404Exception("Unable to load parent page $this->parent_id");
if(!$this->isAllowedParent($this->parent, true, $this->template)) throw new WireException($this->errors('string'));
if(!$this->parent->id) {
throw new Wire404Exception("Unable to load parent page $this->parent_id", Wire404Exception::codeSecondary);
}
if(!$this->isAllowedParent($this->parent, true, $this->template)) {
throw new WireException($this->errors('string'));
}
if(count($this->parent->template->childTemplates) == 1) {
// only one type of template is allowed for the parent

View File

@@ -390,7 +390,7 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod
if(!$id) {
$this->session->redirect('./bookmarks/');
throw new Wire404Exception($this->noticeUnknown); // Init error: no page provided
throw new Wire404Exception($this->noticeUnknown, Wire404Exception::codeSecondary); // Init error: no page provided
}
$this->page = $this->loadPage($id);

View File

@@ -186,7 +186,7 @@ class ProcessPageList extends Process implements ConfigurableModule {
if($this->openPage->id && $this->speed > 50) $this->speed = floor($this->speed / 2);
$this->page = $pages->get("id=" . ($this->id > 0 ? $this->id : 1) . ", status<" . Page::statusMax);
if(!$this->page) throw new Wire404Exception("Unable to load page {$this->id}");
if(!$this->page) throw new Wire404Exception("Unable to load page {$this->id}", Wire404Exception::codeSecondary);
if(!$this->page->listable()) throw new WirePermissionException("You don't have access to list page {$this->page->url}");
$this->page->setOutputFormatting(false);

View File

@@ -2216,7 +2216,9 @@ class ProcessPageLister extends Process implements ConfigurableModule {
} else {
$bookmarkID = '';
}
if(!$bookmarkID || !$this->checkBookmark($bookmarkID)) throw new Wire404Exception();
if(!$bookmarkID || !$this->checkBookmark($bookmarkID)) {
throw new Wire404Exception('Unknown Lister action', Wire404Exception::codeNonexist);
}
return $this->execute();
}

View File

@@ -162,7 +162,9 @@ class ProcessPageView extends Process {
$_page = $page;
$page = $this->checkAccess($page);
if(!$page || $_page->id == $config->http404PageID) {
return $this->pageNotFound($_page, $this->requestURL, true, 'access not allowed');
$s = 'access not allowed';
$e = new Wire404Exception($s, Wire404Exception::codePermission);
return $this->pageNotFound($_page, $this->requestURL, true, $s, $e);
}
if(!$this->delayRedirects) {
@@ -851,10 +853,10 @@ class ProcessPageView extends Process {
// use the static hasPath first to make sure this page actually has a files directory
// this ensures one isn't automatically created when we call $page->filesManager->path below
if(!PagefilesManager::hasPath($page)) throw new Wire404Exception($err);
if(!PagefilesManager::hasPath($page)) throw new Wire404Exception($err, Wire404Exception::codeFile);
$filename = $page->filesManager->path() . $basename;
if(!is_file($filename)) throw new Wire404Exception($err);
if(!is_file($filename)) throw new Wire404Exception($err, Wire404Exception::codeFile);
if($page->isPublic()) {
// deprecated, only necessary for method 2 in checkRequestFile
@@ -881,7 +883,10 @@ class ProcessPageView extends Process {
*/
protected function ___pageNotFound($page, $url, $triggerReady = false, $reason = '', $exception = null) {
if(!$exception) $exception = new Wire404Exception($reason); // create but do not throw
if(!$exception) {
// create exception but do not throw
$exception = new Wire404Exception($reason, Wire404Exception::codeNonexist);
}
$this->failed($exception, $reason, $page, $url);
$this->responseType = self::responseTypeError;