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

Update base Wire class to support a new wired() method that is called when the ProcessWire instance is assigned to the object. This usually happens immediately after __construct(), but depends on how the object was instantiated. This solves the problem of needing to access API variables in a constructor and potentially having the wrong API variable instance in a multi-instance environment.

This commit is contained in:
Ryan Cramer
2020-05-29 13:41:46 -04:00
parent 810cae271f
commit c770f573be
3 changed files with 99 additions and 18 deletions

View File

@@ -1481,8 +1481,9 @@ $config->lazyPageChunkSize = 250;
* Uncomment and paste into /site/config.php if you want to use this * Uncomment and paste into /site/config.php if you want to use this
* *
* $config->InputfieldWrapper = array( * $config->InputfieldWrapper = array(
* 'useDependencies' => true, * 'useDependencies' => true,
* 'requiredLabel' => 'Missing required value', * 'requiredLabel' => 'Missing required value',
* 'columnWidthSpacing' => 0,
* ); * );
* *
*/ */
@@ -1680,6 +1681,8 @@ $config->versionName = '';
* column width spacing for inputfields: used by some admin themes to communicate to InputfieldWrapper * column width spacing for inputfields: used by some admin themes to communicate to InputfieldWrapper
* *
* Value is null, 0, or 1 or higher. This should be kept at null in this file. * Value is null, 0, or 1 or higher. This should be kept at null in this file.
*
* This can also be specified with $config->InputfieldWrapper('columnWidthSpacing', 0); (3.0.158+)
* *
*/ */
$config->inputfieldColumnWidthSpacing = null; $config->inputfieldColumnWidthSpacing = null;

View File

@@ -733,12 +733,14 @@ class ProcessWire extends Wire {
if($profiler) $profiler->maintenance(); if($profiler) $profiler->maintenance();
if($config->templateCompile) { if($config->templateCompile) {
$compiler = new FileCompiler($this->wire('config')->paths->templates); $compiler = new FileCompiler($config->paths->templates);
$this->wire($compiler);
$compiler->maintenance(); $compiler->maintenance();
} }
if($config->moduleCompile) { if($config->moduleCompile) {
$compiler = new FileCompiler($this->wire('config')->paths->siteModules); $compiler = new FileCompiler($config->paths->siteModules);
$this->wire($compiler);
$compiler->maintenance(); $compiler->maintenance();
} }
} }
@@ -795,7 +797,16 @@ class ProcessWire extends Wire {
$this->fileSave = ''; $this->fileSave = '';
return true; return true;
} }
/**
* Call method
*
* @param string $method
* @param array $arguments
* @return mixed
* @throws WireException
*
*/
public function __call($method, $arguments) { public function __call($method, $arguments) {
if(method_exists($this, "___$method")) return parent::__call($method, $arguments); if(method_exists($this, "___$method")) return parent::__call($method, $arguments);
$value = $this->__get($method); $value = $this->__get($method);
@@ -816,6 +827,35 @@ class ProcessWire extends Wire {
if(empty($name)) return $this->fuel; if(empty($name)) return $this->fuel;
return $this->fuel->$name; return $this->fuel->$name;
} }
/**
* Called if any Wire-derived object makes API calls before being wired
*
* This is for debugging purposes only and is not called unless `ProcessWire::objectNotWired` is hooked.
* It is called only once per non-wired object. Uncomment code within to use.
*
* #pw-internal
*
* @param Wire $obj Object that accessed API var without being assigned ProcessWire instance
* @param string|Wire The $name argument that was passed to $obj->wire($name, $value)
* @param mixed $value The $value argument passed to $object->wire($name, $value)
* @since 3.0.158
*
*/
public function _objectNotWired(Wire $obj, $name, $value) {
// Uncomment code below to enable (use in admin)
/*
if(is_string($name) && $this->wire($name)) {
$msg = $obj->className() . " accessed API var \$$name before being wired";
$this->warning("$msg\n" . Debug::backtrace(array(
'limit' => 2,
'getString' => true,
'getCnt' => false,
'getFile' => 'basename',
)));
}
*/
}
/*** MULTI-INSTANCE *************************************************************************************/ /*** MULTI-INSTANCE *************************************************************************************/

View File

@@ -124,7 +124,11 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
* *
*/ */
private $_instanceNum = 0; private $_instanceNum = 0;
/**
* Construct
*
*/
public function __construct() {} public function __construct() {}
/** /**
@@ -1586,7 +1590,7 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
/** /**
* ProcessWire instance * ProcessWire instance
* *
* @var ProcessWire|null * @var ProcessWire|bool|null
* *
*/ */
protected $_wire = null; protected $_wire = null;
@@ -1594,16 +1598,18 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
/** /**
* Set the current ProcessWire instance for this object (PW 3.0) * Set the current ProcessWire instance for this object (PW 3.0)
* *
* Specify no arguments to get, or specify a ProcessWire instance to set.
*
* #pw-internal * #pw-internal
* *
* @param ProcessWire $wire * @param ProcessWire $wire
* *
*/ */
public function setWire(ProcessWire $wire) { public function setWire(ProcessWire $wire) {
$wired = $this->_wire;
if($wired === $wire) return;
$this->_wire = $wire; $this->_wire = $wire;
if($wired) return;
$this->getInstanceNum(); $this->getInstanceNum();
$this->wired();
} }
/** /**
@@ -1617,7 +1623,7 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
* *
*/ */
public function getWire() { public function getWire() {
return $this->_wire; return $this->_wire ? $this->_wire : null;
} }
/** /**
@@ -1695,18 +1701,18 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
*/ */
public function wire($name = '', $value = null, $lock = false) { public function wire($name = '', $value = null, $lock = false) {
if($this->_wire === null) { if($this->_wire) {
// this instance is wired
$wire = $this->_wire;
} else {
// this object has not yet been wired! use last known current instance as fallback // this object has not yet been wired! use last known current instance as fallback
// note this condition is unsafe in multi-instance mode // note this condition is unsafe in multi-instance mode
$wire = ProcessWire::getCurrentInstance(); $wire = ProcessWire::getCurrentInstance();
if(!$wire) return null; if(!$wire) return null;
if($name && $this->_wire === null) {
// For live hunting objects that are using the fallback, uncomment the following: $this->_wire = false; // false prevents this from being called another time for this object
// echo "<hr /><p>Non-wired object: '$name' in " . get_class($this) . ($value ? " (value=$value)" : "") . "</p>"; $wire->_objectNotWired($this, $name, $value);
// echo "<pre>" . print_r(debug_backtrace(), true) . "</pre>"; }
} else {
// this instance is wired
$wire = $this->_wire;
} }
if(is_object($name)) { if(is_object($name)) {
@@ -1743,6 +1749,38 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable {
return $value; return $value;
} }
/**
* Initialization called when object injected with ProcessWire instance (aka “wired”)
*
* - Can be used for any constructor-type initialization that depends on API vars.
* - Called automatically when object is “wired”, do not call it on your own.
* - Expects to be called only once per object instance.
* - Typically called after `__construct()` but before any other method calls.
* - Please note: If object is never “wired” then this method will not be called!
*
* ~~~~~
* class Test extends Wire {
* function wired() {
* echo "Wired to ProcessWire instance: ";
* echo $this->wire()->getProcessWireInstanceID();
* }
* }
*
* // objects in ProcessWire are “wired” like this:
* $o = new Test();
* $this->wire($o); // outputs "ProcessWire instance: n"
*
* // or on one line, like this…
* $this->wire(new Test()); // outputs "ProcessWire instance: n"
* ~~~~~
*
* #pw-internal
*
* @since 3.0.158
*
*/
public function wired() { }
/** /**
* Get an object property by direct reference or NULL if it doesn't exist * Get an object property by direct reference or NULL if it doesn't exist
* *