diff --git a/wire/core/Modules.php b/wire/core/Modules.php
index 28ab7657..15f31da1 100644
--- a/wire/core/Modules.php
+++ b/wire/core/Modules.php
@@ -465,12 +465,12 @@ class Modules extends WireArray {
/**
* Get data from the verbose module info cache
*
- * @param int|string $moduleID
+ * @param int|string|null $moduleID
* @param string $property
* @return array|mixed|null
*
*/
- protected function moduleInfoCacheVerbose($moduleID = 0, $property = '') {
+ protected function moduleInfoCacheVerbose($moduleID = null, $property = '') {
return $this->moduleInfoCache($moduleID, $property, true);
}
@@ -672,7 +672,10 @@ class Modules extends WireArray {
$className = wireClassName($className, true);
}
$debugKey = $this->debug ? $this->debugTimerStart("newModule($moduleName)") : null;
- if(!class_exists($className, false)) $this->includeModule($moduleName);
+ if(!class_exists($className, false)) {
+ $result = $this->includeModule($moduleName);
+ if(!$result) return null;
+ }
if(!class_exists($className, false)) {
// attempt 2.x module in dedicated namespace or root namespace
$className = $this->getModuleNamespace($moduleName) . $moduleName;
@@ -1122,16 +1125,19 @@ class Modules extends WireArray {
}
// if the filename doesn't end with .module or .module.php, then stop and move onto the next
- if(!strpos($filename, '.module') || (substr($filename, -7) !== '.module' && substr($filename, -11) !== '.module.php')) return false;
+ if(strpos($filename, '.module') === false) return false;
+ list(, $ext) = explode('.module', $filename, 2);
+ if(!empty($ext) && $ext !== '.php') return false;
// if the filename doesn't start with the requested path, then continue
if(strpos($pathname, $basepath) !== 0) return '';
// if the file isn't there, it was probably uninstalled, so ignore it
- if(!file_exists($pathname)) return '';
+ // if(!file_exists($pathname)) return '';
// if the module isn't installed, then stop and move on to next
- if(!array_key_exists($basename, $installed)) {
+ if(!isset($installed[$basename]) && !array_key_exists($basename, $installed)) {
+ // array_key_exists is used as secondary to check the null case
$this->installable[$basename] = $pathname;
return '';
}
@@ -1146,11 +1152,11 @@ class Modules extends WireArray {
// this is an Autoload module.
// include the module and instantiate it but don't init() it,
// because it will be done by Modules::init()
- $moduleInfo = $this->getModuleInfo($basename);
// determine if module has dependencies that are not yet met
- if(count($moduleInfo['requires'])) {
- foreach($moduleInfo['requires'] as $requiresClass) {
+ $requiresClasses = $this->getModuleInfoProperty($basename, 'requires');
+ if(!empty($requiresClasses)) {
+ foreach($requiresClasses as $requiresClass) {
$nsRequiresClass = $this->getModuleClass($requiresClass, true);
if(!wireClassExists($nsRequiresClass, false)) {
$requiresInfo = $this->getModuleInfo($requiresClass);
@@ -1167,22 +1173,22 @@ class Modules extends WireArray {
return $basename;
}
}
-
// if not defined in getModuleInfo, then we'll accept the database flag as enough proof
// since the module may have defined it via an isAutoload() function
- if(!isset($moduleInfo['autoload'])) $moduleInfo['autoload'] = true;
/** @var bool|string|callable $autoload */
- $autoload = $moduleInfo['autoload'];
+ $autoload = $this->moduleInfoCache($basename, 'autoload');
+ if(empty($autoload)) $autoload = true;
if($autoload === 'function') {
// function is stored by the moduleInfo cache to indicate we need to call a dynamic function specified with the module itself
$i = $this->getModuleInfoExternal($basename);
if(empty($i)) {
$this->includeModuleFile($pathname, $basename);
- $className = $moduleInfo['namespace'] . $basename;
+ $namespace = $this->getModuleNamespace($basename);
+ $className = $namespace . $basename;
if(method_exists($className, 'getModuleInfo')) {
$i = $className::getModuleInfo();
} else {
- $i = array();
+ $i = $this->getModuleInfo($className);
}
}
$autoload = isset($i['autoload']) ? $i['autoload'] : true;
@@ -1207,10 +1213,13 @@ class Modules extends WireArray {
}
}
- if(is_null($module)) {
+ if($module === null) {
// placeholder for a module, which is not yet included and instantiated
- if(!$moduleInfo) $moduleInfo = $this->getModuleInfo($basename);
- $module = $this->newModulePlaceholder($basename, $moduleInfo['namespace'], $pathname, $info['flags'] & self::flagsSingular, $autoload);
+ // if(!$moduleInfo) $moduleInfo = $this->getModuleInfo($basename);
+ $ns = $moduleInfo ? $moduleInfo['namespace'] : $this->moduleInfoCache($basename, 'namespace');
+ if(empty($namespace)) $ns = __NAMESPACE__ . "\\";
+ $singular = $info['flags'] & self::flagsSingular;
+ $module = $this->newModulePlaceholder($basename, $ns, $pathname, $singular, $autoload);
}
$this->moduleIDs[$basename] = $info['id'];
@@ -1701,14 +1710,17 @@ class Modules extends WireArray {
// still can't figure out what file is? fail
if(!$file) return false;
}
-
+
if(!$this->includeModuleFile($file, $moduleName)) {
// module file failed to include(), try to identify and include file again
if($fast) {
$filePrev = $file;
$file = $this->getModuleFile($moduleName, array('fast' => false));
if($file && $file !== $filePrev) {
- $this->includeModuleFile($file, $moduleName);
+ if($this->includeModuleFile($file, $moduleName)) {
+ // module is missing a module file
+ return false;
+ }
}
} else {
// we already tried this earlier, no point in doing it again
@@ -2935,7 +2947,7 @@ class Modules extends WireArray {
* - `namespace` (string): PHP namespace that module lives in.
*
* The following properties are also included when "verbose" mode is requested. When not in verbose mode, these
- * properties are present but blank:
+ * properties may be present but with empty values:
*
* - `versionStr` (string): formatted module version string.
* - `file` (string): module filename from PW installation root, or false when it can't be found.
@@ -3001,7 +3013,7 @@ class Modules extends WireArray {
$moduleName = '';
$moduleID = 0;
$fromCache = false; // was the data loaded from cache?
-
+
if(!$getAll && !$getSystem) {
$moduleName = $this->getModuleClass($module);
$moduleID = (string) $this->getModuleID($module); // typecast to string for cache
@@ -3068,9 +3080,16 @@ class Modules extends WireArray {
if(empty($this->moduleInfoCache)) $this->loadModuleInfoCache();
$modulesInfo = $this->moduleInfoCache();
if($options['verbose']) {
- if(empty($this->moduleInfoCacheVerbose)) $this->loadModuleInfoCacheVerbose();
foreach($this->moduleInfoCacheVerbose() as $moduleID => $moduleInfoVerbose) {
- $modulesInfo[$moduleID] = array_merge($modulesInfo[$moduleID], $moduleInfoVerbose);
+ if($options['noCache']) {
+ $modulesInfo[$moduleID] = $this->getModuleInfo($moduleID, $options);
+ } else {
+ $modulesInfo[$moduleID] = array_merge($modulesInfo[$moduleID], $moduleInfoVerbose);
+ }
+ }
+ } else if($options['noCache']) {
+ foreach(array_keys($modulesInfo) as $moduleID) {
+ $modulesInfo[$moduleID] = $this->getModuleInfo($moduleID, $options);
}
}
if(!$options['minify']) {
@@ -3159,12 +3178,12 @@ class Modules extends WireArray {
}
// populate defaults for properties omitted from cache
- if(is_null($info['autoload'])) $info['autoload'] = false;
- if(is_null($info['singular'])) $info['singular'] = false;
- if(is_null($info['configurable'])) $info['configurable'] = false;
- if(is_null($info['core'])) $info['core'] = false;
- if(is_null($info['installed'])) $info['installed'] = true;
- if(is_null($info['namespace'])) $info['namespace'] = strlen(__NAMESPACE__) ? "\\" . __NAMESPACE__ . "\\" : "";
+ if($info['autoload'] === null) $info['autoload'] = false;
+ if($info['singular'] === null) $info['singular'] = false;
+ if($info['configurable'] === null) $info['configurable'] = false;
+ if($info['core'] === null) $info['core'] = false;
+ if($info['installed'] === null) $info['installed'] = true;
+ if($info['namespace'] === null) $info['namespace'] = strlen(__NAMESPACE__) ? "\\" . __NAMESPACE__ . "\\" : "";
if(!empty($info['requiresVersions'])) $info['requires'] = array_keys($info['requiresVersions']);
if($moduleName == 'SystemUpdater') $info['configurable'] = 1; // fallback, just in case
@@ -3272,11 +3291,13 @@ class Modules extends WireArray {
if($options['minify']) {
// when minify, any values that match defaults from infoTemplate are removed
- if(!$options['verbose']) foreach($this->moduleInfoVerboseKeys as $key) unset($info[$key]);
- foreach($info as $key => $value) {
- if(!array_key_exists($key, $infoTemplate)) continue;
- if($value !== $infoTemplate[$key]) continue;
- unset($info[$key]);
+ if(!$options['verbose']) {
+ foreach($this->moduleInfoVerboseKeys as $key) unset($info[$key]);
+ foreach($info as $key => $value) {
+ if(!array_key_exists($key, $infoTemplate)) continue;
+ if($value !== $infoTemplate[$key]) continue;
+ unset($info[$key]);
+ }
}
}
@@ -3324,6 +3345,19 @@ class Modules extends WireArray {
*
*/
public function getModuleInfoProperty($class, $property, array $options = array()) {
+
+ if(empty($options['noCache'])) {
+ // shortcuts where possible
+ switch($property) {
+ case 'namespace':
+ return $this->getModuleNamespace($class);
+ case 'requires':
+ $v = $this->moduleInfoCache($class, 'requires');
+ if(empty($v)) return array(); // early exist when known not to exist
+ break; // fallback to calling getModuleInfo
+ }
+ }
+
if(in_array($property, $this->moduleInfoVerboseKeys)) {
$info = $this->getModuleInfoVerbose($class, $options);
$info['verbose'] = true;
@@ -3334,6 +3368,7 @@ class Modules extends WireArray {
// try again, just in case we can find it in verbose data
$info = $this->getModuleInfoVerbose($class, $options);
}
+
return isset($info[$property]) ? $info[$property] : null;
}
@@ -3658,7 +3693,7 @@ class Modules extends WireArray {
if(!$hasDuplicate) {
// see if we can determine it from already stored paths
- $path = $config->paths->$moduleName;
+ $path = $config->paths($moduleName);
if($path) {
$file = $path . $moduleName . ($this->moduleFileExts[$moduleName] === 2 ? '.module.php' : '.module');
if(!$options['fast'] && !file_exists($file)) $file = false;
@@ -3748,7 +3783,7 @@ class Modules extends WireArray {
if(!$file && !empty($options['guess'])) {
// make a guess about where module would be if we had been able to find it
- $file = $config->paths->siteModules . "$moduleName/$moduleName.module";
+ $file = $config->paths('siteModules') . "$moduleName/$moduleName.module";
}
if($file) {
diff --git a/wire/core/ModulesDuplicates.php b/wire/core/ModulesDuplicates.php
index f01908d9..215d8f44 100644
--- a/wire/core/ModulesDuplicates.php
+++ b/wire/core/ModulesDuplicates.php
@@ -6,7 +6,7 @@
* Provides functions for managing sitautions where more than one
* copy of the same module is intalled. This is a helper for the Modules class.
*
- * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
+ * ProcessWire 3.x, Copyright 2023 by Ryan Cramer
* https://processwire.com
*
*/
@@ -73,7 +73,7 @@ class ModulesDuplicates extends Wire {
public function hasDuplicate($className, $pathname = '') {
if(!isset($this->duplicates[$className])) return false;
if($pathname) {
- $rootPath = $this->wire('config')->paths->root;
+ $rootPath = $this->wire()->config->paths->root;
if(strpos($pathname, $rootPath) === 0) $pathname = str_replace($rootPath, '/', $pathname);
return in_array($pathname, $this->duplicates[$className]);
}
@@ -90,7 +90,7 @@ class ModulesDuplicates extends Wire {
*/
public function addDuplicate($className, $pathname, $current = false) {
if(!isset($this->duplicates[$className])) $this->duplicates[$className] = array();
- $rootPath = $this->wire('config')->paths->root;
+ $rootPath = $this->wire()->config->paths->root;
if(strpos($pathname, $rootPath) === 0) $pathname = str_replace($rootPath, '/', $pathname);
if(!in_array($pathname, $this->duplicates[$className])) {
$this->duplicates[$className][] = $pathname;
@@ -153,11 +153,12 @@ class ModulesDuplicates extends Wire {
public function getDuplicates($className = '') {
if(!$className) return $this->duplicates;
-
- $className = $this->wire('modules')->getModuleClass($className);
+
+ $modules = $this->wire()->modules;
+ $className = $modules->getModuleClass($className);
$files = isset($this->duplicates[$className]) ? $this->duplicates[$className] : array();
$using = isset($this->duplicatesUse[$className]) ? $this->duplicatesUse[$className] : '';
- $rootPath = $this->wire('config')->paths->root;
+ $rootPath = $this->wire()->config->paths->root;
foreach($files as $key => $file) {
$file = rtrim($rootPath, '/') . $file;
@@ -167,7 +168,7 @@ class ModulesDuplicates extends Wire {
}
if(count($files) > 1 && !$using) {
- $using = $this->wire('modules')->getModuleFile($className);
+ $using = $modules->getModuleFile($className);
$using = str_replace($rootPath, '/', $using);
}
@@ -191,8 +192,9 @@ class ModulesDuplicates extends Wire {
*
*/
public function setUseDuplicate($className, $pathname) {
- $className = $this->wire('modules')->getModuleClass($className);
- $rootPath = $this->wire('config')->paths->root;
+ $modules = $this->wire()->modules;
+ $className = $modules->getModuleClass($className);
+ $rootPath = $this->wire()->config->paths->root;
if(!isset($this->duplicates[$className])) {
throw new WireException("Module $className does not have duplicates");
}
@@ -204,9 +206,9 @@ class ModulesDuplicates extends Wire {
throw new WireException("Duplicate module file does not exist: $pathname");
}
$this->duplicatesUse[$className] = $pathname;
- $configData = $this->wire('modules')->getModuleConfigData($className);
+ $configData = $modules->getModuleConfigData($className);
$configData['-dups-use'] = $pathname;
- $this->wire('modules')->saveModuleConfigData($className, $configData);
+ $modules->saveModuleConfigData($className, $configData);
}
/**
@@ -214,8 +216,9 @@ class ModulesDuplicates extends Wire {
*
*/
public function updateDuplicates() {
-
- $rootPath = $this->wire('config')->paths->root;
+
+ $modules = $this->wire()->modules;
+ $rootPath = $this->wire()->config->paths->root;
// store duplicate information in each module's data field
foreach($this->getDuplicates() as $moduleName => $files) {
@@ -228,7 +231,7 @@ class ModulesDuplicates extends Wire {
$files[$key] = $file;
}
$files = array_unique($files);
- $configData = $this->wire('modules')->getModuleConfigData($moduleName);
+ $configData = $modules->getModuleConfigData($moduleName);
if((empty($configData['-dups']) && !empty($files))
|| (empty($configData['-dups-use']) || $configData['-dups-use'] != $using)
|| (isset($configData['-dups']) && implode(' ', $configData['-dups']) != implode(' ', $files))
@@ -237,13 +240,13 @@ class ModulesDuplicates extends Wire {
$this->duplicatesUse[$moduleName] = $using;
$configData['-dups'] = $files;
$configData['-dups-use'] = $using;
- $this->wire('modules')->saveModuleConfigData($moduleName, $configData);
+ $modules->saveModuleConfigData($moduleName, $configData);
}
}
// update any modules that no longer have duplicates
$removals = array();
- $query = $this->wire('database')->prepare("SELECT `class`, `flags` FROM modules WHERE `flags` & :flag");
+ $query = $this->wire()->database->prepare("SELECT `class`, `flags` FROM modules WHERE `flags` & :flag");
$query->bindValue(':flag', Modules::flagsDuplicate, \PDO::PARAM_INT);
$query->execute();
@@ -258,10 +261,10 @@ class ModulesDuplicates extends Wire {
}
foreach($removals as $class => $flags) {
- $this->wire('modules')->setFlags($class, $flags);
- $configData = $this->wire('modules')->getModuleConfigData($class);
+ $modules->setFlags($class, $flags);
+ $configData = $modules->getModuleConfigData($class);
unset($configData['-dups'], $configData['-dups-use']);
- $this->wire('modules')->saveModuleConfigData($class, $configData);
+ $modules->saveModuleConfigData($class, $configData);
}
}
@@ -275,7 +278,9 @@ class ModulesDuplicates extends Wire {
*
*/
public function recordDuplicate($basename, $pathname, $pathname2, &$installed) {
- $rootPath = $this->wire('config')->paths->root;
+ $config = $this->wire()->config;
+ $modules = $this->wire()->modules;
+ $rootPath = $config->paths->root;
// ensure paths start from root of PW install
if(strpos($pathname, $rootPath) === 0) $pathname = str_replace($rootPath, '/', $pathname);
if(strpos($pathname2, $rootPath) === 0) $pathname2 = str_replace($rootPath, '/', $pathname2);
@@ -295,7 +300,7 @@ class ModulesDuplicates extends Wire {
if(isset($installed[$basename]['flags'])) {
$flags = $installed[$basename]['flags'];
} else {
- $flags = $this->wire('modules')->getFlags($basename);
+ $flags = $modules->getFlags($basename);
}
if($flags & Modules::flagsDuplicate) {
// flags already represent duplicate status
@@ -303,14 +308,14 @@ class ModulesDuplicates extends Wire {
// make database aware this module has multiple files by adding the duplicate flag
$this->numNewDuplicates++; // trigger update needed
$flags = $flags | Modules::flagsDuplicate;
- $this->wire('modules')->setFlags($basename, $flags);
+ $modules->setFlags($basename, $flags);
}
$err = sprintf($this->_('There appear to be multiple copies of module "%s" on the file system.'), $basename) . ' ';
- $this->wire('log')->save('modules', $err);
- $user = $this->wire('user');
+ $this->wire()->log->save('modules', $err);
+ $user = $this->wire()->user;
if($user && $user->isSuperuser()) {
$err .= $this->_('Please edit the module settings to tell ProcessWire which one to use:') . ' ' .
- "urls->admin . 'module/edit?name=' . $basename . "'>$basename";
+ "$basename";
$this->warning($err, Notice::allowMarkup);
}
//$this->message("recordDuplicate($basename, $pathname) $this->numNewDuplicates"); //DEBUG
@@ -327,10 +332,11 @@ class ModulesDuplicates extends Wire {
*
*/
public function getDuplicatesConfigData($className, array $configData = array()) {
+ $config = $this->wire()->config;
// ensure original duplicates info is retained and validate that it is still current
if(isset($this->duplicates[$className])) {
foreach($this->duplicates[$className] as $key => $file) {
- $pathname = rtrim($this->wire('config')->paths->root, '/') . $file;
+ $pathname = rtrim($config->paths->root, '/') . $file;
if(!file_exists($pathname)) {
unset($this->duplicates[$className][$key]);
}
@@ -341,7 +347,7 @@ class ModulesDuplicates extends Wire {
} else {
$configData['-dups'] = $this->duplicates[$className];
if(isset($this->duplicatesUse[$className])) {
- $pathname = rtrim($this->wire('config')->paths->root, '/') . $this->duplicatesUse[$className];
+ $pathname = rtrim($config->paths->root, '/') . $this->duplicatesUse[$className];
if(file_exists($pathname)) {
$configData['-dups-use'] = $this->duplicatesUse[$className];
} else {