[+] MO: modules can now have override classes installed automatically #PSCFV-2036 (thank to phrasespot)
This commit is contained in:
@@ -196,5 +196,10 @@ class Autoload
|
|||||||
|
|
||||||
return $classes;
|
return $classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getClassPath($classname)
|
||||||
|
{
|
||||||
|
return isset($this->index[$classname]) ? $this->index[$classname] : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-4
@@ -2056,9 +2056,10 @@ FileETag INode MTime Size
|
|||||||
* @return array List of file found
|
* @return array List of file found
|
||||||
* @since 1.5.0
|
* @since 1.5.0
|
||||||
*/
|
*/
|
||||||
public static function scandir($path, $ext = 'php', $dir = '')
|
public static function scandir($path, $ext = 'php', $dir = '', $recursive = false)
|
||||||
{
|
{
|
||||||
$real_path = $path.$dir;
|
$path = rtrim(rtrim($path, '\\'), '/').'/';
|
||||||
|
$real_path = rtrim(rtrim($path.$dir, '\\'), '/').'/';
|
||||||
$files = scandir($real_path);
|
$files = scandir($real_path);
|
||||||
if (!$files)
|
if (!$files)
|
||||||
return array();
|
return array();
|
||||||
@@ -2068,12 +2069,18 @@ FileETag INode MTime Size
|
|||||||
$real_ext = '';
|
$real_ext = '';
|
||||||
if (!empty($ext))
|
if (!empty($ext))
|
||||||
$real_ext = '.'.$ext;
|
$real_ext = '.'.$ext;
|
||||||
|
|
||||||
$real_ext_length = strlen($real_ext);
|
$real_ext_length = strlen($real_ext);
|
||||||
|
|
||||||
|
$subdir = ($dir) ? $dir.'/' : '';
|
||||||
foreach ($files as $file)
|
foreach ($files as $file)
|
||||||
|
{
|
||||||
if (strpos($file, $real_ext) && strpos($file, $real_ext) == (strlen($file) - $real_ext_length))
|
if (strpos($file, $real_ext) && strpos($file, $real_ext) == (strlen($file) - $real_ext_length))
|
||||||
$filtered_files[] = $dir.DIRECTORY_SEPARATOR.$file;
|
$filtered_files[] = $subdir.$file;
|
||||||
|
|
||||||
|
if ($recursive && $file[0] != '.' && is_dir($real_path.$file))
|
||||||
|
foreach (Tools::scandir($path, $ext, $subdir.$file, $recursive) as $subfile)
|
||||||
|
$filtered_files[] = $subfile;
|
||||||
|
}
|
||||||
return $filtered_files;
|
return $filtered_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+141
-4
@@ -206,6 +206,10 @@ abstract class ModuleCore
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Install overrides
|
||||||
|
if (!$this->installOverrides())
|
||||||
|
return false;
|
||||||
|
|
||||||
// Install module and retrieve the installation id
|
// Install module and retrieve the installation id
|
||||||
$result = Db::getInstance()->insert($this->table, array('name' => $this->name, 'active' => 1, 'version' => $this->version));
|
$result = Db::getInstance()->insert($this->table, array('name' => $this->name, 'active' => 1, 'version' => $this->version));
|
||||||
if (!$result)
|
if (!$result)
|
||||||
@@ -468,6 +472,10 @@ abstract class ModuleCore
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uninstall overrides
|
||||||
|
if (!$this->uninstallOverrides())
|
||||||
|
return false;
|
||||||
|
|
||||||
// Retrieve hooks used by the module
|
// Retrieve hooks used by the module
|
||||||
$sql = 'SELECT `id_hook` FROM `'._DB_PREFIX_.'hook_module` WHERE `id_module` = '.(int)$this->id;
|
$sql = 'SELECT `id_hook` FROM `'._DB_PREFIX_.'hook_module` WHERE `id_module` = '.(int)$this->id;
|
||||||
$result = Db::getInstance()->executeS($sql);
|
$result = Db::getInstance()->executeS($sql);
|
||||||
@@ -1697,13 +1705,13 @@ abstract class ModuleCore
|
|||||||
$result = Db::getInstance()->getRow('
|
$result = Db::getInstance()->getRow('
|
||||||
SELECT `position`
|
SELECT `position`
|
||||||
FROM `'._DB_PREFIX_.'hook_module`
|
FROM `'._DB_PREFIX_.'hook_module`
|
||||||
WHERE `id_hook` = '.(int)($id_hook).'
|
WHERE `id_hook` = '.(int)$id_hook.'
|
||||||
AND `id_module` = '.(int)($this->id).'
|
AND `id_module` = '.(int)$this->id.'
|
||||||
AND `id_shop` = '.(int)Context::getContext()->shop->id);
|
AND `id_shop` = '.(int)Context::getContext()->shop->id);
|
||||||
|
|
||||||
return $result['position'];
|
return $result['position'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add a warning message to display at the top of the admin page
|
* add a warning message to display at the top of the admin page
|
||||||
*
|
*
|
||||||
@@ -1727,5 +1735,134 @@ abstract class ModuleCore
|
|||||||
return false;
|
return false;
|
||||||
$this->context->controller->informations[] = $msg;
|
$this->context->controller->informations[] = $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install overrides files for the module
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function installOverrides()
|
||||||
|
{
|
||||||
|
if (!is_dir($this->getLocalPath().'override'))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
$result = true;
|
||||||
|
foreach (Tools::scandir($this->getLocalPath().'override', 'php', '', true) as $file)
|
||||||
|
{
|
||||||
|
$class = basename($file, '.php');
|
||||||
|
if (Autoload::getInstance()->getClassPath($class.'Core'))
|
||||||
|
$result &= $this->addOverride($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uninstall overrides files for the module
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function uninstallOverrides()
|
||||||
|
{
|
||||||
|
if (!is_dir($this->getLocalPath().'override'))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
$result = true;
|
||||||
|
foreach (Tools::scandir($this->getLocalPath().'override', 'php', '', true) as $file)
|
||||||
|
{
|
||||||
|
$class = basename($file, '.php');
|
||||||
|
if (Autoload::getInstance()->getClassPath($class.'Core'))
|
||||||
|
$result &= $this->removeOverride($class);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add all methods in a module override to the override class
|
||||||
|
*
|
||||||
|
* @param string $classname
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function addOverride($classname)
|
||||||
|
{
|
||||||
|
$path = Autoload::getInstance()->getClassPath($classname.'Core');
|
||||||
|
|
||||||
|
// Check if override file is writable
|
||||||
|
$override_path = _PS_ROOT_DIR_.'/'.Autoload::getInstance()->getClassPath($classname);
|
||||||
|
if (!is_writable($override_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Make a reflection of the override class and the module override class
|
||||||
|
$override_file = file($override_path);
|
||||||
|
eval(preg_replace(array('#^\s*<\?php#', '#class\s+'.$classname.'\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i'), array('', 'class '.$classname.'OverrideOriginal'), implode('', $override_file)));
|
||||||
|
$override_class = new ReflectionClass($classname.'OverrideOriginal');
|
||||||
|
|
||||||
|
$module_file = file($this->getLocalPath().'override/'.$path);
|
||||||
|
eval(preg_replace(array('#^\s*<\?php#', '#class\s+'.$classname.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'), array('', 'class '.$classname.'Override'), implode('', $module_file)));
|
||||||
|
$module_class = new ReflectionClass($classname.'Override');
|
||||||
|
|
||||||
|
// Check if none of the methods already exists in the override class
|
||||||
|
foreach ($module_class->getMethods() as $method)
|
||||||
|
if ($override_class->hasMethod($method->name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Insert the methods from module override in override
|
||||||
|
$copy_from = array_slice($module_file, $module_class->getStartLine() + 1, $module_class->getEndLine() - $module_class->getStartLine() - 2);
|
||||||
|
array_splice($override_file, $override_class->getEndLine() - 1, 0, $copy_from);
|
||||||
|
$code = implode('', $override_file);
|
||||||
|
file_put_contents($override_path, $code);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all methods in a module override from the override class
|
||||||
|
*
|
||||||
|
* @param string $classname
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function removeOverride($classname)
|
||||||
|
{
|
||||||
|
$path = Autoload::getInstance()->getClassPath($classname.'Core');
|
||||||
|
|
||||||
|
// Check if override file is writable
|
||||||
|
$override_path = _PS_ROOT_DIR_.'/'.Autoload::getInstance()->getClassPath($classname);
|
||||||
|
if (!is_writable($override_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Make a reflection of the override class and the module override class
|
||||||
|
$override_file = file($override_path);
|
||||||
|
eval(preg_replace(array('#^\s*<\?php#', '#class\s+'.$classname.'\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i'), array('', 'class '.$classname.'OverrideOriginal_remove'), implode('', $override_file)));
|
||||||
|
$override_class = new ReflectionClass($classname.'OverrideOriginal_remove');
|
||||||
|
|
||||||
|
$module_file = file($this->getLocalPath().'override/'.$path);
|
||||||
|
eval(preg_replace(array('#^\s*<\?php#', '#class\s+'.$classname.'(\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?)?#i'), array('', 'class '.$classname.'Override_remove'), implode('', $module_file)));
|
||||||
|
$module_class = new ReflectionClass($classname.'Override_remove');
|
||||||
|
|
||||||
|
// Remove methods from override file
|
||||||
|
$override_file = file($override_path);
|
||||||
|
foreach ($module_class->getMethods() as $method)
|
||||||
|
{
|
||||||
|
if (!$override_class->hasMethod($method->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$method = $override_class->getMethod($method->name);
|
||||||
|
$length = $method->getEndLine() - $method->getStartLine() + 1;
|
||||||
|
array_splice($override_file, $method->getStartLine() - 1, $length, array_pad(array(), $length, '#--remove--#'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewrite nice code
|
||||||
|
$code = '';
|
||||||
|
foreach ($override_file as $line)
|
||||||
|
{
|
||||||
|
if ($line == '#--remove--#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$code .= $line;
|
||||||
|
}
|
||||||
|
file_put_contents($override_path, $code);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user