plugin, héritage de class

Bonjour,

Attention sujet bien poilu ;)

Je dev un plugin pour pluxml (désolé dev interne à ma boite et très spécifique) qui comporte plusieurs modules. Une 1ere version a été mis en prod avec une class de presque 2000 lignes de codes et 1 an plus tard on me demande d'ajouter un module... Ouchhh voyant la taille de la class je prend peur et je me dis qu'ajouter un module va rendre la maintenance très complexe du coups je me lance dans l'idée de faire une class par module.

Je commence l'analyse en séparant les fonctions utilitaires et les fonctions propres à chaque modules et j'arrive à deux classes. Je déplace tout ce petit monde dans des fichiers séparé et je regarde comment sont montés les class de pluxml, en me basant sur plxMotor et plxShow, pour en reproduire la même logique.

Mon plugin s'appelle portail, le répertoire ce présente sous cette forme :
[== Indéfini ==]

-- portail
   |_ css
       |_ ...
   |_ js
       |_ ...
   |_ include
       |_ portail.php
       |_ portailAdv.php
       |_ ...
   |_ portail.php

dans portail.php pour le moment j'ai ce code :
[== PHP ==]
<?php

include(PLX_PLUGINS.'portail/include/portail.php');
include(PLX_PLUGINS.'portail/include/portailAdv.php');

$portail = portail::getInstance();
$portailAdv = portailAdv::getInstance();

?>

Dans include/portail.php (oui doublons de noms mais pour le moment j'ai pas trouvé mieux ;) ) j'ai ce code :
[== PHP ==]
class portail extends plxPlugin {
	private static $instance;

	/**
	 * Méthode qui se charger de créer le Singleton portail
	 *
	 * @return	objet			return une instance de la classe portail
	 * @author	Stephane F
	 **/
	public static function getInstance(){
		if (!isset(self::$instance)) {
			self::$instance = false;
			self::$instance = new portail();
		}
		return self::$instance;
	}

	public function __construct($default_lang) {
		parent::__construct($default_lang);

		if(!empty($this->getParam('dbname'))) {
			try {
				$this->database = new Medoo([
						'database_type' => 'mysql',
						'database_name' => $this->getParam('dbname'),
						'server' => $this->getParam('dbhost'),
						'port' => $this->getParam('dbport'),
						'username' => $this->getParam('dbuser'),
						'password' => $this->getParam('dbpass'),
						'logging' => $this->getParam('debug')
				]);

				$this->addHook('portailRoutage', 'portailRoutage');
				$this->addHook('portailSidebarMenu', 'portailSidebarMenu');
			}
			catch (Exception $e) {
				echo $e->getMessage();
			}
		}

		# droit d'accès
		$this->setConfigProfil(PROFIL_ADMIN);
	}

	public function toto() {
		echo "portail.php";
	}

Dans include/portailAdv.php j'ai ce code
[== PHP ==]
class portailAdv {

  public $portail = false;
	private $lang;

	private static $instance = null;

	/**
	 * Méthode qui se charger de créer le Singleton plxShow
	 *
	 * @return	objet			return une instance de la classe plxShow
	 * @author	Stephane F
	 **/
	public static function getInstance(){
		if (!isset(self::$instance))
			self::$instance = new portailAdv();
		return self::$instance;
	}

	protected function __construct($default_lang) {
		$this->portail = portail::getInstance();

		$this->portail->toto();
	}

L'appel de la fonction toto me permet de vérifier si j'ai bien accès à la class mère portail depuis portailAdv et magie oui ça marche. Maintenant je fais le test inverse. Imaginons que la fonction toto se trouve dans la class portailAdv mais que je veuille l'appeler depuis la class mère portail.

Avec l'appel depuis la class portail :
[== PHP ==]
$portail->toto();

J'ai le message :
PHP Fatal error: Call to a member function toto() on null in xxxx/plugins/portail/include/portail.php on line 52, referer: http:/xxxx/index.php?static18/portail

Toujours depuis la class portail :
[== PHP ==]
portailAdv::toto();

Je n'ai pas d'erreur mais un avertissement dans les logs
PHP Deprecated: Non-static method portailAdv::toto() should not be called statically, assuming $this from incompatible context in xxxx/plugins/portail/include/portail.php on line 876, referer: http://xxx/index.php?static18/portail

J'ai testé la navigation sur le reste de mon site pour voir si une des class de pluxml créait le même message, pas d'erreur donc c'est mon implémentation qui déconne. Cela reste un avertissement mais à terme ça sera bloquant car marqué comme deprecated de php 7.0.

Avez-vous une idée du pourquoi problème ?

J'ai un string de l'array

Réponses

  • bazooka07bazooka07 PluXml Lead Developer, Moderator
    décembre 2018 modifié
    Ton affaire a l'air compliqué et je ne suis pas sûr d'avoir tout capté.

    AMHA, tu prends le problème par le mauvais bout.
    la class Portail est un plugin et doit jouer un rôle prédominant.
    Les modules doivent être totalement indépendants de PluXml. S'ils ont besoin de connaître le contexte, passer un paramètre aux méthodes qui en ont besoin

    Le fichier Portail.php devrait ressembler à quelque chose comme ceci :
    [== PHP ==]
    <?php
    defined('PLX_ROOT') or exit;
    
    // déclaration de la class Module1 :
    include __DIR__ . '/inc/module1.php';
    
    // déclaration de la class Module2 :
    include __DIR__ . '/inc/module2.php';
    
    class Portail extends plxPlugin {
    	private $__module1 = false;
    	private $__module2 = false;
    	
    	public function __construct($lang) {
    		parent::__construct($lang);
    		
    		if(!class_exists('Module1')) { die('class module1 absent'); }
    		$self->__module1 = new Module1();
    			
    		if(!class_exists('Module2')) { die('class module2 absent'); }
    		$self->__module2 = new Module2();
    		
    		// Déclaration des hooks
    		$this->addHook('portailRoutage', 'portailRoutage');
    		$this->addHook('portailSidebarMenu', 'portailSidebarMenu');
    	}
    	
    	public function portailRoutage() {
    		
    	}
    	
    	public function portailSidebarMenu() {
    		
    	}
    }
    ?>
    
  • Merci bazooka07 je vais tester.

    Juste une question. Les modules de mon plugin sont effectivement indépendant de PluXml mais j'utilise régulièrement des fonctions du core de PluXml. Du coups avec ton code est-ce que j'aurais accès au fonction de pluxml ?

    J'ai un string de l'array

  • bazooka07bazooka07 PluXml Lead Developer, Moderator
    décembre 2018 modifié
    Cela dépend.
    Si ce sont des fonctions statiques, il n'y a pas de souci particulier. Il suffit juste de préciser la class avec le double caractère ":". Par exemple :
    plxUtils::printSelect(...)

    Si tu as besoin des données, articles, photos, page statiques, .., il y a 2 façons de faire :
    - soit utiliser les variables globales $plxAdmin déclarée dans le fichier core/admin/prepend.php côté back-office, et $plxMotor + $plxShow déclarées dans le fichier index.php pour le front-office.
    - soit utiliser les hooks natifs de PluXml avec de l'injection de code qui appelle une fonction de ton plugin. Tu ne pourras pas le faire avec tes modules, sauf s'il y a des méthodes statiques.
  • flipflipflipflip Member
    décembre 2018 modifié
    Re-bonjour,

    J'essaie de comprendre le code que tu m'as proposé et il faut dire que pour le moment les class sont un peu obscurs pour moi ;)

    Voici le code que j'obtiens.

    portail.php
    [== PHP ==]
    <?php
    defined('PLX_ROOT') or exit;
    
    include __DIR__.'/include/Medoo.php';
    use Medoo\Medoo;
    
    include __DIR__.'/include/portailUtils.php';
    include __DIR__.'/include/portailAdv.php';
    
    class portail extends plxPlugin {
    	private $__portailUtils = false;
    	private $__portailAdv = false;
    
    	public function __construct($lang) {
    		parent::__construct($lang);
    
    		if(!class_exists('portailUtils')) { die('class portailUtils absent'); }
    		$self->__portailUtils = new portailUtils();
    
    		if(!class_exists('portailAdv')) { die('class portailAdv absent'); }
    		$self->__portailAdv = new portailAdv();
    
        if(!empty($this->getParam('dbname'))) {
          try {
            $this->database = new Medoo([
                'database_type' => 'mysql',
                'database_name' => $this->getParam('dbname'),
                'server' => $this->getParam('dbhost'),
                'port' => $this->getParam('dbport'),
                'username' => $this->getParam('dbuser'),
                'password' => $this->getParam('dbpass'),
                'logging' => $this->getParam('debug')
            ]);
            // Déclaration des hooks
            $this->addHook('portailRoutage', 'portailRoutage');
            //$this->addHook('portailSidebarMenu', 'portailSidebarMenu');
          }
          catch (Exception $e) {
            echo $e->getMessage();
          }
        }
    	}
    
    	public function portailRoutage() {
    		global $plxShow, $plxMotor;
    		$error = false;
    
    		if($this->getParam('debug')) {
    			echo '<pre>';
    			var_dump($_SESSION);
    			var_dump($_POST);
    			var_dump($_GET);
    			echo '</pre>';
    		}
    
    		// Vérification de la durée de vie de la
    		// session php
    		if($this->portailUtils->getConnect()) {
    			//portailUtils::sessionTimeout();
    			$_SESSION['portail']['lastaction'] = time();
    		}
           }
    }
    ?>
    
    

    include/portailUtils.php
    [== PHP ==]
    <?php
    class portailUtils {
    
    [...]
    	public function getConnect() {
    		global $plxMotor;
    
    		if(isset($_SESSION['portail']) AND
    			isset($_SESSION['portail']['logged']) AND
    			$_SESSION['portail']['logged'] == true AND
    			isset($_SESSION['portail']['ip'])) {
    			// Désactivé dans le cas d'un dev sur docker AND $_SESSION['portail']['ip'] == $_SERVER['REMOTE_ADDR']) {
    			return true;
    		} else {
    			return false;
    		}
    	}
    }
    ?>
    
    
    Du côté de portail.php j'ai besoin d'utiliser getConnect() mais pas moyen de l'appeler sans erreur
    $__portailUtils->getConnect() ---> PHP Fatal error: Call to a member function getConnect() on null in /var/www/html/plugins/portail/portail.php on line 72
    $this->__portailUtils->getConnect() --> PHP Fatal error: Call to a member function getConnect() on null in /var/www/html/plugins/portail/portail.php on line 72
    $this->portailUtils->getConnect() ---> PHP Fatal error: Call to a member function getConnect() on null in /var/www/html/plugins/portail/portail.php on line 72
    $portailUtils->getConnect() ---> PHP Fatal error: Call to a member function getConnect() on null in /var/www/html/plugins/portail/portail.php on line 72
    $portail->getConnect() ---> PHP Fatal error: Call to a member function getConnect() on null in /var/www/html/plugins/portail/portail.php on line 72
    portailUtils::getConnect() ---> PHP Deprecated: Non-static method portailUtils::getConnect() should not be called statically, assuming $this from incompatible context in /var/www/html/plugins/portail/portail.php on line 72

    Dans le dernier ça passe avec de nouveau l'erreur de Deprecated. Là je suis arrivé au bout de mes connaissances en dev ;)

    J'ai un string de l'array

  • StéphaneStéphane Member, Former PluXml Project Manager
    Salut

    Tu appelles

    $this->portailUtils->getConnect()

    or $this->portailUtils n'est pas défini dans ta classe portail

    tu as déclaré

    $self->__portailUtils = new portailUtils();

    Consultant PluXml

    Ancien responsable et développeur de PluXml (2010 à 2018)

  • Je viens de faire le test en appelant $self->__portailUtils->getConnect() mais même punition
    PHP Fatal error: Call to a member function getConnect() on null in /var/www/html/plugins/portail/portail.php on line 72

    J'ai un string de l'array

  • StéphaneStéphane Member, Former PluXml Project Manager
    et pourquoi $self->__portailUtils = new portailUtils(); et pas $this->__portailUtils = new portailUtils();

    Consultant PluXml

    Ancien responsable et développeur de PluXml (2010 à 2018)

  • Merci Stéphane pour ta proposition, j'ai modifié le code en conséquence et ça marche... Enfin presque.

    Maintenant depuis la class portail j'accède sans problème à portailUtils et portailAdv mais depuis portailsUtils je ne vois pas trop comment accéder à une fonction dans portailAdv.

    Ci-dessous le code

    portail.php
    [== PHP ==]
    <?php
    
    defined('PLX_ROOT') or exit;
    
    include __DIR__.'/include/portailUtils.php';
    include __DIR__.'/include/portailAdv.php';
    
    class portail extends plxPlugin {
    	private $__portailUtils = false;
    	private $__portailAdv = false;
    
    	public function __construct($lang) {
    		parent::__construct($lang);
    
    		if(!class_exists('portailUtils')) { die('class portailUtils absent'); }
    		$this->__portailUtils = new portailUtils();
    
    		if(!class_exists('portailAdv')) { die('class portailAdv absent'); }
    		$this->__portailAdv = new portailAdv();
    	}
    }
    

    Rien de particulier pour les class portailUtils et portailAdv.

    J'ai un string de l'array

  • Je te conseille de lire le blog de Tom Butler (https://r.je).
    Pour ce qui te concerne, il faudrait utiliser les namespaces, et un autoloader...
Connectez-vous ou Inscrivez-vous pour répondre.