From 099acacc61e93579504d7b25971b8d6bdbf3030f Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Fri, 12 Apr 2019 10:28:23 -0400 Subject: [PATCH] Improvements to the __debugInfo() return values for some classes as well as those requested in processwire/processwire-issues#575 --- wire/core/Field.php | 24 +++++-- wire/core/Fields.php | 38 +++++++++++ wire/core/Page.php | 2 + wire/core/PaginatedArray.php | 20 ++++-- wire/core/Wire.php | 25 ++++++-- wire/core/WireArray.php | 28 ++++++-- wire/core/WireDebugInfo.php | 64 +++++++++++++++---- wire/core/WireInputData.php | 4 ++ .../FieldtypeOptions/SelectableOption.php | 8 +++ .../SelectableOptionArray.php | 25 +++++++- .../FieldtypeRepeater/RepeaterPageArray.php | 10 +++ 11 files changed, 214 insertions(+), 34 deletions(-) diff --git a/wire/core/Field.php b/wire/core/Field.php index 6d444ecb..4bf13bf1 100644 --- a/wire/core/Field.php +++ b/wire/core/Field.php @@ -12,7 +12,7 @@ * #pw-body Field objects are managed by the `$fields` API variable. * #pw-use-constants * - * ProcessWire 3.x, Copyright 2018 by Ryan Cramer + * ProcessWire 3.x, Copyright 2019 by Ryan Cramer * https://processwire.com * * @property int $id Numeric ID of field in the database #pw-group-properties @@ -22,6 +22,7 @@ * @property Fieldtype|null $type Fieldtype module that represents the type of this field #pw-group-properties * @property Fieldtype $prevFieldtype Previous Fieldtype, of type was changed #pw-group-properties * @property int $flags Bitmask of flags used by this field #pw-group-properties + * @property-read string $flagsStr Names of flags used by this field (readonly) #pw-group-properties * @property string $label Text string representing the label of the field #pw-group-properties * @property string $description Longer description text for the field #pw-group-properties * @property string $notes Additional notes text about the field #pw-group-properties @@ -140,10 +141,10 @@ class Field extends WireData implements Saveable, Exportable { */ protected $settings = array( 'id' => 0, - 'type' => null, - 'flags' => 0, 'name' => '', 'label' => '', + 'flags' => 0, + 'type' => null, ); /** @@ -368,6 +369,7 @@ class Field extends WireData implements Saveable, Exportable { else if($key == 'icon') return $this->getIcon(true); else if($key == 'useRoles') return ($this->settings['flags'] & self::flagAccess) ? true : false; else if($key == 'flags') return $this->settings['flags']; + else if($key == 'flagsStr') return $this->wire('fields')->getFlagNames($this->settings['flags'], true); else if($key == 'tagList') return $this->getTags(); else if($key == 'tags') return $this->getTags(true); @@ -1296,7 +1298,7 @@ class Field extends WireData implements Saveable, Exportable { * * #pw-internal * - * @param array $tagList Array of tags to add + * @param array|string $tagList Array of tags to add (or space-separated string) * @param bool $reindex Set to false to set given $tagsList exactly as-is (assumes it's already in correct format) * @return array Array of tags that were set * @since 3.0.106 @@ -1377,8 +1379,9 @@ class Field extends WireData implements Saveable, Exportable { * */ public function __debugInfo() { - $info = parent::__debugInfo(); - $info['settings'] = $this->settings; + $info = $this->settings; + $info['flags'] = $info['flags'] ? "$this->flagsStr ($info[flags])" : ""; + $info = array_merge($info, parent::__debugInfo()); if($this->prevTable) $info['prevTable'] = $this->prevTable; if($this->prevFieldtype) $info['prevFieldtype'] = (string) $this->prevFieldtype; if(!empty($this->trackGets)) $info['trackGets'] = $this->trackGets; @@ -1389,5 +1392,14 @@ class Field extends WireData implements Saveable, Exportable { return $info; } + public function debugInfoSmall() { + return array( + 'id' => $this->id, + 'name' => $this->name, + 'label' => $this->getLabel(), + 'type' => $this->type ? wireClassName($this->type) : '', + ); + } + } diff --git a/wire/core/Fields.php b/wire/core/Fields.php index 93b9a9c6..dcaa1157 100644 --- a/wire/core/Fields.php +++ b/wire/core/Fields.php @@ -95,6 +95,8 @@ class Fields extends WireSaveableItems { '_custom', ); + protected $flagNames = array(); + /** * Field names that are native/permanent to this instance of ProcessWire (configurable at runtime) * @@ -117,6 +119,17 @@ class Fields extends WireSaveableItems { */ public function __construct() { $this->fieldsArray = new FieldsArray(); + $this->flagNames = array( + Field::flagAutojoin => 'autojoin', + Field::flagGlobal => 'global', + Field::flagSystem => 'system', + Field::flagPermanent => 'permanent', + Field::flagAccess => 'access', + Field::flagAccessAPI => 'access-api', + Field::flagAccessEditor => 'access-editor', + Field::flagFieldgroupContext => 'fieldgroup-context', + Field::flagSystemOverride => 'system-override', + ); // convert so that keys are names so that isset() can be used rather than in_array() if(isset(self::$nativeNamesSystem[0])) self::$nativeNamesSystem = array_flip(self::$nativeNamesSystem); } @@ -922,9 +935,34 @@ class Fields extends WireSaveableItems { return $items; } + /** + * Get all flag names or get all flag names for given flags or Field + * + * #pw-internal + * + * @param int|Field|null $flags Specify flags or Field or omit to get all flag names + * @param bool $getString Get a string of flag names rather than array? (default=false) + * @return array|string When array is returned, array is of strings indexed by flag value (int) + * + */ + public function getFlagNames($flags = null, $getString = false) { + if($flags === null) { + $a = $this->flagNames; + } else { + $a = array(); + if($flags instanceof Field) $flags = $flags->flags; + foreach($this->flagNames as $flag => $name) { + if($flags & $flag) $a[$flag] = $name; + } + } + return $getString ? implode(' ', $a) : $a; + } + /** * Overridden from WireSaveableItems to retain keys with 0 values and remove defaults we don't need saved * + * #pw-internal + * * @param array $value * @return string of JSON * diff --git a/wire/core/Page.php b/wire/core/Page.php index 8eb3668c..ecfd6d90 100644 --- a/wire/core/Page.php +++ b/wire/core/Page.php @@ -87,6 +87,7 @@ * @property int $numLinks Total number of pages manually linking to this page in Textarea/HTML fields. #pw-group-traversal * @property int $hasLinks Number of visible pages (to current user) linking to this page in Textarea/HTML fields. #pw-group-traversal * @property int $instanceID #pw-internal + * @property bool $quietMode #pw-internal * * @property Page|null $_cloning Internal runtime use, contains Page being cloned (source), when this Page is the new copy (target). #pw-internal * @property bool|null $_hasAutogenName Internal runtime use, set by Pages class when page as auto-generated name. #pw-internal @@ -673,6 +674,7 @@ class Page extends WireData implements \Countable, WireMatchable { 'publishable' => 'm', 'published' => 's', 'publishedStr' => '', + 'quietMode' => 'p', 'references' => 'n', 'referencing' => 't', 'render' => '', diff --git a/wire/core/PaginatedArray.php b/wire/core/PaginatedArray.php index ead7396f..766bbcfe 100644 --- a/wire/core/PaginatedArray.php +++ b/wire/core/PaginatedArray.php @@ -308,11 +308,21 @@ class PaginatedArray extends WireArray implements WirePaginatable { * */ public function __debugInfo() { - $info = parent::__debugInfo(); - if($this->getLimit()) $info['pager'] = $this->getPaginationString(); - $info['total'] = $this->getTotal(); - $info['start'] = $this->getStart(); - $info['limit'] = $this->getLimit(); + $limit = $this->getLimit(); + $count = $this->count(); + $total = $this->getTotal(); + if($limit || $total > $count) { + $info = array( + 'count' => $count, + 'total' => $total, + 'start' => $this->getStart(), + 'limit' => $limit, + 'pager' => $this->getPaginationString(), + ); + $info = array_merge($info, parent::__debugInfo()); + } else { + $info = parent::__debugInfo(); + } return $info; } } \ No newline at end of file diff --git a/wire/core/Wire.php b/wire/core/Wire.php index 9f10fcaf..712e3d83 100644 --- a/wire/core/Wire.php +++ b/wire/core/Wire.php @@ -1758,11 +1758,26 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable { * */ public function __debugInfo() { - static $debugInfo = null; - if(is_null($debugInfo)) { - $debugInfo = $this->wire(new WireDebugInfo()); - } - return $debugInfo->getDebugInfo($this); + /** @var WireDebugInfo $debugInfo */ + $debugInfo = $this->wire(new WireDebugInfo()); + return $debugInfo->getDebugInfo($this, true); + } + + /** + * Minimal/small debug info + * + * Same as __debugInfo() but with no hooks info, no change tracking info, and less verbose + * + * #pw-internal + * + * @return array + * @since 3.0.130 + * + */ + public function debugInfoSmall() { + /** @var WireDebugInfo $debugInfo */ + $debugInfo = $this->wire(new WireDebugInfo()); + return $debugInfo->getDebugInfo($this, true); } diff --git a/wire/core/WireArray.php b/wire/core/WireArray.php index 9a9453a9..febc908b 100644 --- a/wire/core/WireArray.php +++ b/wire/core/WireArray.php @@ -2495,20 +2495,36 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count * */ public function __debugInfo() { + + $info = array( + 'count' => $this->count(), + 'items' => array(), + ); - $info = parent::__debugInfo(); - $info['count'] = $this->count(); + $info = array_merge($info, parent::__debugInfo()); if(count($this->data)) { $info['items'] = array(); foreach($this->data as $key => $value) { + if(is_object($value) && $value instanceof Wire) $key = $value->className() . ":$key"; $info['items'][$key] = $this->debugInfoItem($value); } } - + if(count($this->extraData)) $info['extraData'] = $this->extraData; - if(count($this->itemsAdded)) $info['itemsAdded'] = $this->itemsAdded; - if(count($this->itemsRemoved)) $info['itemsRemoved'] = $this->itemsRemoved; + + $trackers = array( + 'itemsAdded' => $this->itemsAdded, + 'itemsRemoved' => $this->itemsRemoved + ); + + foreach($trackers as $key => $value) { + if(!count($value)) continue; + $info[$key] = array(); + foreach($value as $k => $v) { + $info[$key][] = $this->debugInfoItem($v); + } + } return $info; } @@ -2525,7 +2541,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count public function debugInfoItem($item) { if(is_object($item)) { if($item instanceof Page) { - $item = '/' . ltrim($item->path(), '/'); + $item = $item->debugInfoSmall(); } else if($item instanceof WireData) { $_item = $item; $item = $item->get('name'); diff --git a/wire/core/WireDebugInfo.php b/wire/core/WireDebugInfo.php index 6f9ff52a..4fb56417 100644 --- a/wire/core/WireDebugInfo.php +++ b/wire/core/WireDebugInfo.php @@ -12,22 +12,30 @@ class WireDebugInfo extends Wire { * Get all debug info for the given Wire object * * @param Wire $obj + * @param bool $small Return non-verbose debug info? (default=false) * @return array * */ - public function getDebugInfo(Wire $obj) { + public function getDebugInfo(Wire $obj, $small = false) { - $className = $obj->className(); $info = array(); - if(method_exists($this, $className)) { - $info = array_merge($info, $this->$className($obj)); + if($obj instanceof Page) { + $info = $this->Page($obj, $small); + } else if($this->className() != 'WireDebugInfo') { + // if other classes extend and implement their own class-specific methods + $className = $obj->className(); + if(method_exists($this, $className)) { + $info = $this->$className($obj, $small); + } } - $changes = $obj->getChanges(); - if(count($changes)) $info['changes'] = $changes; - $hooks = $this->getHooksInfo($obj); - if(count($hooks)) $info['hooks'] = $hooks; + if(!$small) { + $changes = $obj->getChanges(); + if(count($changes)) $info['changes'] = $changes; + $hooks = $this->getHooksInfo($obj); + if(count($hooks)) $info['hooks'] = $hooks; + } return $info; } @@ -60,7 +68,9 @@ class WireDebugInfo extends Wire { } $filename = ''; if(!empty($hook['toObject'])) { - $value .= $hook['toObject']->className() . "->"; + /** @var Wire $toObject */ + $toObject = $hook['toObject']; + $value .= $toObject->className() . "->"; $ref = new \ReflectionClass($hook['toObject']); $filename = $ref->getFileName(); } @@ -74,6 +84,7 @@ class WireDebugInfo extends Wire { } } if($filename) $value .= " in " . basename($filename); + if($priority != "100.0") $value .= " ($priority)"; if(!isset($hooks[$key])) { $hooks[$key] = $value; } else { @@ -88,11 +99,42 @@ class WireDebugInfo extends Wire { * Debug info specific to Page objects * * @param Page $page + * @param bool $small * @return array * */ - public function Page(Page $page) { + public function Page(Page $page, $small = false) { + + if($small) { + // minimal debug info + $info = array( + 'id' => $page->id, + 'name' => $page->name, + 'parent' => $page->parent && $page->parent->id ? $page->parent->path() : '', + 'status' => implode(', ', $page->status(true)), + 'template' => $page->template ? $page->template->name : '', + 'numChildren' => $page->numChildren(), + ); + + if(empty($info['numChildren'])) unset($info['numChildren']); + if(empty($info['status'])) unset($info['status']); + + foreach($page->getArray() as $fieldName => $fieldValue) { + if(is_object($fieldValue)) { + $className = wireClassName($fieldValue); + if(method_exists($fieldValue, '__toString')) { + $fieldValue = (string) $fieldValue; + if($fieldValue !== $className) $fieldValue = "($className) $fieldValue"; + } else { + $fieldValue = $className; + } + } + $info[$fieldName] = $fieldValue; + } + return $info; + } + // verbose debug info $info = array( 'instanceID' => $page->instanceID, 'id' => $page->id, @@ -139,7 +181,7 @@ class WireDebugInfo extends Wire { unset($info['parentPrevious']); } - if($page->isNew) $info['isNew'] = 1; + if($page->isNew()) $info['isNew'] = 1; $info['isLoaded'] = (int) $page->isLoaded(); $info['outputFormatting'] = (int) $page->outputFormatting(); if($page->quietMode) $info['quietMode'] = 1; diff --git a/wire/core/WireInputData.php b/wire/core/WireInputData.php index 3171ef94..0f0a9200 100644 --- a/wire/core/WireInputData.php +++ b/wire/core/WireInputData.php @@ -310,5 +310,9 @@ class WireInputData extends Wire implements \ArrayAccess, \IteratorAggregate, \C return $sanitizer->sanitize($arguments[0], $method); } } + + public function __debugInfo() { + return $this->data; + } } diff --git a/wire/modules/Fieldtype/FieldtypeOptions/SelectableOption.php b/wire/modules/Fieldtype/FieldtypeOptions/SelectableOption.php index 497cbf6b..668e2911 100644 --- a/wire/modules/Fieldtype/FieldtypeOptions/SelectableOption.php +++ b/wire/modules/Fieldtype/FieldtypeOptions/SelectableOption.php @@ -143,6 +143,14 @@ class SelectableOption extends WireData { // implements LanguagesValueInterface public function __toString() { return (string) $this->id; } + + public function debugInfoSmall() { + return array( + 'id' => $this->id, + 'title' => $this->getTitle(), + 'value' => $this->getValue(), + ); + } /** * Sets the value for a given language diff --git a/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionArray.php b/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionArray.php index 96fc8883..8863315c 100644 --- a/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionArray.php +++ b/wire/modules/Fieldtype/FieldtypeOptions/SelectableOptionArray.php @@ -29,7 +29,7 @@ class SelectableOptionArray extends WireArray { /** * Field these options apply to (always applicable) * - * @var null + * @var Field|null * */ protected $field = null; @@ -248,5 +248,28 @@ class SelectableOptionArray extends WireArray { public function hasID($id) { return $this->getOptionByProperty('id', (int) $id); } + + /** + * Return debug info for one item from this WireArray + * + * #pw-internal + * + * @param mixed $item + * @return mixed|null|string + * + */ + public function debugInfoItem($item) { + if($item instanceof SelectableOption) $item = $item->debugInfoSmall(); + return $item; + } + + public function __debugInfo() { + $info = parent::__debugInfo(); + $info['of'] = (int) $this->of; + if($this->page) $info['page'] = $this->page->path(); + if($this->field) $info['field'] = $this->field->name; + return $info; + } + } diff --git a/wire/modules/Fieldtype/FieldtypeRepeater/RepeaterPageArray.php b/wire/modules/Fieldtype/FieldtypeRepeater/RepeaterPageArray.php index 42552f32..b4a4f599 100644 --- a/wire/modules/Fieldtype/FieldtypeRepeater/RepeaterPageArray.php +++ b/wire/modules/Fieldtype/FieldtypeRepeater/RepeaterPageArray.php @@ -130,6 +130,16 @@ class RepeaterPageArray extends PageArray { parent::trackRemove($item, $key); } + public function __debugInfo() { + $info = array( + 'field' => $this->field ? $this->field->debugInfoSmall() : '', + ); + if($this->parent && $this->parent->id) { + $info['parent'] = $this->parent->debugInfoSmall(); + } + $info = array_merge($info, parent::__debugInfo()); + return $info; + } }