1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-07 15:26:54 +02:00

Optimizations to WireArray and some descending classes

This commit is contained in:
Ryan Cramer
2024-05-31 14:27:23 -04:00
parent b9d8a741ee
commit 34bca47a07
9 changed files with 140 additions and 59 deletions

View File

@@ -5,7 +5,7 @@
*
* WireArray of Fieldgroup instances as used by Fieldgroups class.
*
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
*
@@ -25,6 +25,7 @@ class FieldgroupsArray extends WireArray {
*
*/
public function getItemKey($item) {
/** @var Fieldgroup $item */
return $item->id;
}

View File

@@ -6,7 +6,7 @@
* #pw-summary Maintains a collection of Fieldtype modules.
* #pw-var $fieldtypes
*
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
* @property FieldtypeCheckbox $FieldtypeCheckbox
@@ -88,13 +88,24 @@ class Fieldtypes extends WireArray {
*/
protected $isAPI = false;
/**
* Construct
*
*/
public function __construct() {
parent::__construct();
$this->usesNumericKeys = false;
$this->indexedByName = true;
$this->nameProperty = 'className';
}
/**
* Construct the $fieldtypes API var (load all Fieldtype modules into it)
*
*/
public function init() {
$this->isAPI = true;
foreach($this->wire()->modules->findByPrefix('Fieldtype', 3) as $name => $module) {
foreach($this->wire()->modules->findByPrefix('Fieldtype', 3) as /* $name => */ $module) {
$this->add($module);
}
}
@@ -153,16 +164,6 @@ class Fieldtypes extends WireArray {
return $item->className();
}
/**
* Does this WireArray use numeric keys only?
*
* @return bool
*
*/
protected function usesNumericKeys() {
return false;
}
/**
* Per the WireArray interface, return a blank copy
*
@@ -229,5 +230,3 @@ class Fieldtypes extends WireArray {
public function getNext($item, $strict = true) { $this->preload(); return parent::getNext($item, $strict); }
public function getPrev($item, $strict = true) { $this->preload(); return parent::getPrev($item, $strict); }
}

View File

@@ -5,13 +5,19 @@
*
* The default numeric indexing of a WireArray is not overridden.
*
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
*/
class InputfieldsArray extends WireArray {
public function __construct() {
parent::__construct();
$this->usesNumericKeys = true;
$this->indexedByName = false;
}
/**
* Per WireArray interface, only Inputfield instances are accepted.
*
@@ -31,6 +37,7 @@ class InputfieldsArray extends WireArray {
*
*/
public function find($selector) {
/** @var WireArray|InputfieldsArray $a */
$a = parent::find($selector);
foreach($this as $item) {
if(!$item instanceof InputfieldWrapper) continue;
@@ -44,8 +51,4 @@ class InputfieldsArray extends WireArray {
return null; // Inputfield is abstract, so there is nothing to return here
}
public function usesNumericKeys() {
return true;
}
}

View File

@@ -508,6 +508,12 @@ class Notices extends WireArray {
const logAllNotices = false; // for debugging/dev purposes
public function __construct() {
parent::__construct();
$this->usesNumericKeys = true;
$this->indexedByName = false;
}
/**
* Initialize Notices API var
*
@@ -549,7 +555,8 @@ class Notices extends WireArray {
*/
protected function allowNotice(Notice $item) {
$user = $this->wire()->user;
// intentionally not using $this->wire()->user; in case this gets called early in boot
$user = $this->wire('user');
if($item->flags & Notice::debug) {
if(!$this->wire()->config->debug) return false;

View File

@@ -74,6 +74,16 @@ class PageArray extends PaginatedArray implements WirePaginatable {
*/
protected $keyIndex = array();
/**
* Construct
*
*/
public function __construct() {
parent::__construct();
$this->indexedByName = false;
$this->usesNumericKeys = true;
}
/**
* Template method that descendant classes may use to validate items added to this WireArray
*
@@ -142,18 +152,6 @@ class PageArray extends PaginatedArray implements WirePaginatable {
}
}
/**
* Does this PageArray use numeric keys only? (yes it does)
*
* Defined here to override the slower check in WireArray
*
* @return bool
*
*/
protected function usesNumericKeys() {
return true;
}
/**
* Per WireArray interface, return a blank Page
*

View File

@@ -124,6 +124,8 @@ class Pagefiles extends WireArray implements PageFieldValueInterface {
public function __construct(Page $page) {
$this->setPage($page);
parent::__construct();
$this->usesNumericKeys = false;
$this->indexedByName = true;
}
/**

View File

@@ -109,6 +109,8 @@ class Selectors extends WireArray {
*/
public function __construct($selector = null) {
parent::__construct();
$this->usesNumericKeys = false;
$this->indexedByName = false;
if(!is_null($selector)) $this->init($selector);
}

View File

@@ -5,7 +5,7 @@
*
* WireArray of Template instances as used by Templates class.
*
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
*/
@@ -21,6 +21,7 @@ class TemplatesArray extends WireArray {
}
public function getItemKey($item) {
/** @var Template $item */
return $item->id;
}

View File

@@ -11,7 +11,7 @@
*
* @todo can we implement next() and prev() like on Page, as alias to getNext() and getPrev()?
*
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
* @method WireArray and($item)
@@ -88,12 +88,47 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
*/
protected $sortFlags = 0; // 0 == SORT_REGULAR
/**
* For WireArray that holds WireData objects, property that contains the items name
*
* @var string
* @since 3.0.240
*
*/
protected $nameProperty = 'name';
/**
* Is this WireArray indexed by the name property?
*
* This will be auto-detected at runtime unless specifically set in the constructor.
*
* @var bool|null Bool once known, null if not yet known
* @since 3.0.240
*
*/
protected $indexedByName = null;
/**
* Does this WireArray use numeric keys?
*
* This will be auto-detected at runtime unless specifically set in the constructor.
*
* @var bool|null
* @since 3.0.240
*
*/
protected $usesNumericKeys = null;
/**
* Construct
*
*/
public function __construct() {
if($this->className() === 'WireArray') $this->duplicateChecking = false;
if($this->className() === 'WireArray') {
$this->duplicateChecking = false;
$this->indexedByName = false;
$this->usesNumericKeys = true;
}
parent::__construct();
}
@@ -296,7 +331,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
$key = key($this->data);
}
$this->trackChange("add", null, $item);
if($this->trackChanges) $this->trackChange("add", null, $item);
$this->trackAdd($item, $key);
return $this;
@@ -461,7 +496,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
throw new WireException("Key '$key' is not an allowed key for " . get_class($this));
}
$this->trackChange($key, isset($this->data[$key]) ? $this->data[$key] : null, $value);
if($this->trackChanges) $this->trackChange($key, isset($this->data[$key]) ? $this->data[$key] : null, $value);
$this->data[$key] = $value;
$this->trackAdd($value, $key);
return $this;
@@ -602,7 +637,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
if(isset($this->data[$k])) {
$match = $this->data[$k];
} else if($numericKeys) {
$match = $this->getItemThatMatches('name', $k);
$match = $this->getItemThatMatches($this->nameProperty, $k);
}
if($match) break;
}
@@ -613,7 +648,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
// if the WireArray uses numeric keys, then it's okay to
// match a 'name' field if the provided key is a string
if($this->usesNumericKeys()) {
$match = $this->getItemThatMatches('name', $key);
$match = $this->getItemThatMatches($this->nameProperty, $key);
}
}
@@ -760,7 +795,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
$match = $this->findOne($key);
} else if($this->usesNumericKeys()) {
$match = $this->getItemThatMatches('name', $key);
$match = $this->getItemThatMatches($this->nameProperty, $key);
}
}
@@ -997,7 +1032,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
reset($this->data);
$key = key($this->data);
}
$this->trackChange('prepend', null, $item);
if($this->trackChanges) $this->trackChange('prepend', null, $item);
$this->trackAdd($item, $key);
return $this;
}
@@ -1058,7 +1093,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
$key = key($this->data);
$item = array_shift($this->data);
if(is_null($item)) return null;
$this->trackChange('shift', $item, null);
if($this->trackChanges) $this->trackChange('shift', $item, null);
$this->trackRemove($item, $key);
return $item;
}
@@ -1094,7 +1129,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
$key = key($this->data);
$item = array_pop($this->data);
if(is_null($item)) return null;
$this->trackChange('pop', $item, null);
if($this->trackChanges) $this->trackChange('pop', $item, null);
$this->trackRemove($item, $key);
return $item;
}
@@ -1119,7 +1154,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
$data[$key] = $this->data[$key];
}
$this->trackChange('shuffle', $this->data, $data);
if($this->trackChanges) $this->trackChange('shuffle', $this->data, $data);
$this->data = $data;
@@ -1219,7 +1254,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
if(array_key_exists($key, $this->data)) {
$item = $this->data[$key];
unset($this->data[$key]);
$this->trackChange("remove", $item, null);
if($this->trackChanges) $this->trackChange("remove", $item, null);
$this->trackRemove($item, $key);
} else if(!$obj && is_string($key) && Selectors::stringHasSelector($key)) {
foreach($this->find($key) as $item) {
@@ -1330,6 +1365,13 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
if(empty($properties)) return $this;
if($propertiesStr === $this->nameProperty && $this->indexedByName) {
// optimization when it's a very simple sort by name
ksort($this->data, $this->sortFlags);
if($this->trackChanges) $this->trackChange("sort:$propertiesStr");
return $this;
}
// shortcut for random (only allowed as the sole sort property)
// no warning/error for issuing more properties though
// TODO: warning for random+more properties (and trackChange() too)
@@ -2000,7 +2042,20 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
*
*/
protected function trackAdd($item, $key) {
if($key) {}
if($key !== null && $key !== false) {
if($this->usesNumericKeys === null) {
$this->usesNumericKeys = is_int($key);
}
if($this->indexedByName === null) {
$this->indexedByName = false;
if($item instanceof WireData) {
$name = $item->get($this->nameProperty);
if($name === $key && isset($this->data[$name]) && $this->data[$name] === $item) {
$this->indexedByName = true;
}
}
}
}
if($this->trackChanges()) $this->itemsAdded[] = $item;
// wire this WireArray to the same instance of $item, if it isnt already wired
if($this->_wire === null && $item instanceof Wire && $item->isWired()) $item->wire($this);
@@ -2118,16 +2173,29 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
*/
protected function usesNumericKeys() {
static $testItem = null;
static $usesNumericKeys = null;
if($this->usesNumericKeys !== null) {
return $this->usesNumericKeys;
}
if(!is_null($usesNumericKeys)) return $usesNumericKeys;
if(is_null($testItem)) $testItem = $this->makeBlankItem();
if(is_null($testItem)) return true;
if(!empty($this->data)) {
reset($this->data);
$key = key($this->data);
if($key !== null) {
$this->usesNumericKeys = is_int($key);
return $this->usesNumericKeys;
}
}
$testItem = $this->makeBlankItem();
if($testItem === null) {
$this->usesNumericKeys = true;
} else {
$key = $this->getItemKey($testItem);
$usesNumericKeys = is_int($key) ? true : false;
return $usesNumericKeys;
$this->usesNumericKeys = is_int($key);
}
return $this->usesNumericKeys;
}
/**
@@ -2552,7 +2620,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
}
} else {
// array or string or null
if(is_null($func)) $func = 'name';
if(is_null($func)) $func = $this->nameProperty;
$result = $this->explode($func);
}
@@ -2658,7 +2726,7 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
$item = $item->debugInfoSmall();
} else if($item instanceof WireData) {
$_item = $item;
$item = $item->get('name');
$item = $item->get($this->nameProperty);
if(!$item) $item = $_item->get('id');
if(!$item) $item = $_item->className();
} else {