Jump to content

Astuce-Comment réécrire votre module


Recommended Posts

Prestashop 1.4 offre aux développeurs la possibilité de modifier le comportement standard de fonctions sans modification de base. Nouveau Prestashop 1.5 va encore plus loin en présentant la possibilité de réécrire les fichiers lors de l'installation d'un module.

 

Voici comment la fonction d'installation était en Prestashop 1.4:

 

/**
* Insert module into datable
*/
public function install()
{
if (!Validate::isModuleName($this->name))
	die(Tools::displayError());
$result = Db::getInstance()->getRow('
SELECT `id_module`
FROM `'._DB_PREFIX_.'module`
WHERE `name` = \''.pSQL($this->name).'\'');
if ($result)
	return false;
$result = Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table, array('name' => $this->name, 'active' => 1), 'INSERT');
if (!$result)
	return false;
$this->id = Db::getInstance()->Insert_ID();
return true;
}

 

C'est à dire, le système vérifiait la table module pour les enregistrements sur le module installé et s'il n'y en avait pas du tout, il faisait et un retournait son ID. En Prestashop 1.5 cette fonction ressemble à ce qui suit:

 

 

/**
* Insert module into datable
*/
public function install()
{
// Check module name validation
if (!Validate::isModuleName($this->name))
	die(Tools::displayError());

// Check PS version compliancy
if (version_compare(_PS_VERSION_, $this->ps_versions_compliancy['min']) < 0 || version_compare(_PS_VERSION_, $this->ps_versions_compliancy['max']) >= 0)
{
	$this->_errors[] = $this->l('The version of your module is not compliant with your PrestaShop version.');
	return false;
}

// Check module dependencies
if (count($this->dependencies) > 0)
	foreach ($this->dependencies as $dependency)
		if (!Db::getInstance()->getRow('SELECT `id_module` FROM `'._DB_PREFIX_.'module` WHERE `name` = \''.pSQL($dependency).'\''))
		{
			$error = $this->l('Before installing this module, you have to installed these/this module(s) first :').'<br />';
			foreach ($this->dependencies as $d)
				$error .= '- '.$d.'<br />';
			$this->_errors[] = $error;
			return false;
		}

// Check if module is installed
$result = Db::getInstance()->getRow('SELECT `id_module` FROM `'._DB_PREFIX_.'module` WHERE `name` = \''.pSQL($this->name).'\'');
if ($result)
{
	$this->_errors[] = $this->l('This module has already been installed.');
	return false;
}

// Install overrides
try {
	$this->installOverrides();
} catch (Exception $e) {
	$this->_errors[] = sprintf(Tools::displayError('Unable to install override: %s'), $e->getMessage());
	$this->uninstallOverrides();
	return false;
}

// Install module and retrieve the installation id
$result = Db::getInstance()->insert($this->table, array('name' => $this->name, 'active' => 1, 'version' => $this->version));
if (!$result)
{
	$this->_errors[] = $this->l('Technical error : PrestaShop could not installed this module.');
	return false;
}
$this->id = Db::getInstance()->Insert_ID();

Cache::clean('Module::isInstalled'.$this->name);

// Enable the module for current shops in context
$this->enable();

// Permissions management
Db::getInstance()->execute('
	INSERT INTO `'._DB_PREFIX_.'module_access` (`id_profile`, `id_module`, `view`, `configure`) (
		SELECT id_profile, '.(int)$this->id.', 1, 1
		FROM '._DB_PREFIX_.'access a
		WHERE id_tab = (
			SELECT `id_tab` FROM '._DB_PREFIX_.'tab
			WHERE class_name = \'AdminModules\' LIMIT 1)
		AND a.`view` = 1)');

Db::getInstance()->execute('
	INSERT INTO `'._DB_PREFIX_.'module_access` (`id_profile`, `id_module`, `view`, `configure`) (
		SELECT id_profile, '.(int)$this->id.', 1, 0
		FROM '._DB_PREFIX_.'access a
		WHERE id_tab = (
			SELECT `id_tab` FROM '._DB_PREFIX_.'tab
			WHERE class_name = \'AdminModules\' LIMIT 1)
		AND a.`view` = 0)');

// Adding Restrictions for client groups
Group::addRestrictionsForModule($this->id, Shop::getShops(true, null, true));

return true;
}

 

Nouvelle version de Prestashop offre la possibilité de spécifier les versions du système votre module est compatible avec. $ this-> ps_versions_compliancy ['min'] et $ this-> ps_versions_compliancy ['max'] sont utilisées dans ce but, si la version du système client n'est pas compatible avec votre module, le message suivant s'affiche pour un utilisateur: La version de votre module n'est pas compatible avec votre version de PrestaShop. Les fonctions installOverrides () et addOverride () sont responsables pour le redéfinissent des contrôleurs et des classes pendant l'installation du module.

 

 

 

/**
* Install overrides files for the module
*
* @return bool
*/
public function installOverrides()
{
// Get local path for module
if (!is_dir($this->getLocalPath().'override'))
	return true;

$result = true;
foreach (Tools::scandir($this->getLocalPath().'override', 'php', '', true) as $file)
{
	$class = basename($file, '.php');
	// Add all methods in a module override to the override class
	if (Autoload::getInstance()->getClassPath($class.'Core'))
		$result &= $this->addOverride($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 there is already an override file, if not, we just need to copy the file
if (!($classpath = Autoload::getInstance()->getClassPath($classname)))
{
	$override_src = $this->getLocalPath().'override'.DIRECTORY_SEPARATOR.$path;
	$override_dest = _PS_ROOT_DIR_.DIRECTORY_SEPARATOR.'override'.DIRECTORY_SEPARATOR.$path;
	if (!is_writable(dirname($override_dest)))
		throw new Exception(sprintf(Tools::displayError('directory (%s) not writable'), dirname($override_dest)));
	copy($override_src, $override_dest);
	return true;
}

// Check if override file is writable
$override_path = _PS_ROOT_DIR_.'/'.Autoload::getInstance()->getClassPath($classname);
if (!is_writable($override_path))
	throw new Exception(sprintf(Tools::displayError('file (%s) not writable'), $override_path));

// 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'.DIRECTORY_SEPARATOR.$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->getName()))
		throw new Exception(sprintf(Tools::displayError('The method %1$s in the class %2$s is already overriden.'), $method->getName(), $classname));

// Check if none of the properties already exists in the override class
foreach ($module_class->getProperties() as $property)
	if ($override_class->hasProperty($property->getName()))
		throw new Exception(sprintf(Tools::displayError('The property %1$s in the class %2$s is already defined.'), $property->getName(), $classname));

// 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;
}

 

Afin de réécrire un module, il faut créer le dossier "override" dans le module et y placer le fichier avec la logique changé. La structure de dossiers doit être enregistré. Par exemple, pour surcharger CmsController.php, vous devez utiliser la structure suivante des dossiers override / controllers / front/ CmsController.php avec le contenu suivant dans le dossier

 

 

class CmsController extends CmsControllerCore {

public function setMedia(){
	parent::setMedia();

	die('Test override function');
}

}

 

 

Lorsque le module est installé, le système va rechercher le fichier dont il a besoin pour réécrire. Les choses ne sont pas si bien rangées quand même. Prestashop ne remplacera pas simplement le fichier override / controllers / front/ fichier CmsController.php avec celui qui se trouve dans le même dossier avec votre module. Que faire si le fichier principal contient déjà une sorte de logique changé? Le mécanisme de protection apparait ici: le système compare son fichier principal à celui réécrit (ex. public_html / override / controllers / front/ CmsController.php) et le fichier dans votre module. Si les noms de fonctions ne sont pas les mêmes dans ces fichiers, il y aura une erreur de l'installation et l'utilisateur verra, par exemple, le message suivant: La méthode dans la classe CmsController setMedia est déjà réécrite.

 

Je voudrais vous avertir des méfaits de la réécriture, après tout. Elle suscite des problèmes pour les développeurs: si le magasin de l'utilisateur est fortement personnalisé et même classe (ou une fonction, ce qui est pire) est remplacée par plusieurs modules à la fois, la logique doit être combinée en un seul fichier. Autrement dit, si Prestashop affiche une erreur "cette fonction est déjà réécrite", il n'y aura rien autre à faire, sauf que modifier le fichier principal avec la réécriture. Donc, si vous êtes en mesure d'utiliser le Hook dans votre module - faire-le et vous allez éviter la réécriture.

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

Salut dev1-tn,

 

La nativité du module n'a aucune conséquence sur l'override, Valérie explique ici comment modifier un module développé pour une version 1.4 dans lequel un fichier de surcharge a été ajouté, sur une 1.4 il fallait mettre le fichier manuellement dans le répertoire override, avec la 1.5 il suffit d'ajouter les classes ou controllers dans un dossier override du module pour que tout ce fasse automatiquement en prenant compte des risques cités plus haut.

 

Cordialement

Franck

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...