PHP & les hook

Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 26 avril 2016 à 15:45 - Dernière réponse :
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 1 mai 2016 à 11:48
Bonjour,

Je vous explique d'abord mon problème : je suis entrain de développer un site sur le jeu Euro Truck Simulator 2 : ETS2Routes (http://www.ets2routes.com pour ceux qui veulent voir ce qui a déjà été fait). Dans le cadre de ce projet (que je compte présenter au jury les 7 et 8 juillet 2016 dans le cadre de ma formation pro à Objectif3D), je souhaite gérer les différents éléments sous forme de modules.

A ce niveau là, pas de soucis je m'en sorts très bien, mais je souhaiterais pouvoir faire comme le permettent les CMS comme Wordpress/Drupal/Joomla : qu'un module puisse interagir sur une page sans devoir modifier cette page pour appeler le module.

Actuellement, sur la page d'accueil j'affiches les news et je suis obligé donc dans le Core\Indexcontroller.php d'appeler le contrôleur de mon module (actuellement Modules\News\NewsController.php), mais si demain je veux changer ben je suis obligé de modifier ma page.

Je sais que Wordpress, permet via add_filter et add_action, de faire un hook pour que le plugin puisse ajouter par exemple des metabox sur la page sans modifier cette dernière.

Je souhaiterais pouvoir avoir un comportement de ce style, mais hélas je ne vois pas comment faire. J'ai déjà plus ou moins contourné mon soucis pour l'ajout d'un CSS propre au module, en créant une classe Core\HookController.php, et dont on appel la méthode addCSS, qui stocke dans un tableau le nom du CSS a charger.

Cela me permet actuellement, d'afficher dans ma page un CSS en plus à partir du module et sans modifier ma page. Mais je sais pas si faire à coup de méthodes et tableaux comme ça, si ça va pas alourdir et rendre imbuvable au final.

Merci d'avance pour votre aide.

P.S. : Le code intégral du site est disponible sur http://www.ets2routes.com/git qui vous fera retombé sur mon dépôt GIT sur bitbucket, du fait que le projet est open-source. Si vous avez donc besoin de voir les sources, c'est librement accessible à tous ;).
Afficher la suite 

Votre réponse

22 réponses

Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
- 27 avril 2016 à 10:24
0
Merci
Salut,

Pour gérer dynamiquement ta page il faut te tourner vers le javascript:
Php est interpreté par le serveur et renvoi un formulaire, ce qui sous entend que tu ne peux pas "updater" ta page en partie ( en fait si, tu peux utiliser les frame mais c'est déconseillé et pas adapté à ton besoin je penses.
Le javascript te permet d'effectuer des actions depuis le poste client ce qui te permet de gérer l'affichage sans recharger son intégralité.

Donc pour faire court: fais des recherche concernant le javascript associé à la gestion des champs et les sockets (pour la communication)

naga
Commenter la réponse de nagaD.scar
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 27 avril 2016 à 10:39
0
Merci
Bonjour Naga,

Merci pour ta réponse. Je sais que le JavaScript avec l'AJAX permet d'éviter le rechargement de page, mais mon problème ne concerne pas ça du tout.

En fait sur Wordpress (et c'est en PHP pas en JS que c'est fait, mais je comprend pas leur fonction add_filter, le hic est là), tu peux faire un "add_metabox" par exemple dans ton plugin. Cela aura pour effet, quand tu arriveras sur la page "modifiée" par ce add_metabox, d'avoir une zone de la page où s'affiche ton propre module. Wordpress appel cela des Hook, et vu ce que cela fait ça correspond bien à la définition d'un hook : interception d'un événement.

Le problème étant que je ne comprend pas comment Wordpress fait. Tout ce que je sais, c'est qu'avec ce add_metabox, quand ton plugin est chargé, l'instruction add_metabox si elle est exécutée, va rajouter une nouvelle entrée dans la page demandée afin d'afficher ton plugin.


J'ai un peut contourner mon soucis avec mon addCSS pour ajouter un CSS propre à mon module sur mes pages, j'ai prévu dans mon template, qu'il puisse y avoir d'autres CSS, et cette méthode de ma classe HookController, récupère le nom passé en paramètre et l'enregistre dans un tableau PHP.

A partir de là, au moment où ma page est chargée, je me retrouve bien avec mon nouveau CSS d'ajouté.

Mais je sais pas si cela peut s'appliquer au reste, ou si c'est un cas isolé non utilisable (ou trop pénible à utiliser) pour ajouter ce même comportement pour l'intégration d'un module.
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
- 27 avril 2016 à 11:12
Ok donc si je comprend bien, ce que tu souhaite faire c'est générer ta page (via php) en incluant ou non des modules ? (je ne penses pas car je pense que tu l'aurai fait)

En fait il n'y a pas 50 possibilités:
- On génère notre page en php et on envoi au client un contenu htlm+css -> pas de dynamisme côté client

- On envoi un contenu html+css+javascript ( généré ou non en php) -> dynamisme côté client

- On utilise des frame: les zone pour être mises à jours individuellement (elles fonctionnent comme des pages indépendantes grosso modo) MAIS A NE PAS UTILISER: c'est devenu obsolète



A noté que le css peu apporter un peu de dynamisme visuel mais en aucuns cas effectuer de communication avec le serveur (sur les toutes dernières versions de css et html il me semble qu'ils ont rajouté du js implicite pour pouvoir le faire sans utiliser directement le js mais je n'ai aucunes certitudes ou connaissances dessus) : masquer ou rendre visible des élément, effectuer un mouvement, mais dans tous les cas les éléments existent dans ta page.

Word press, ainsi que "tous" (je ne les connais pas tous) les cms incluent le js => c'est très simple de générer du javascript via le php (exactement meme principe que pour du css, html, etc). Ce qui sous entend que de ton côté tu ne fais que des appels JS mais qu'à aucuns moment ca prouve qu'il n'y a pas de javascript "derrière" (pour ca c'est simple, il te suffit de regarder le code html généré)

Tu peux toujours t'inspirer des fonctions de word press pour ton dev, tu as toutes les sources ( si tu n'as pas de version dispo chez toi) ici:

http://phpxref.ftwr.co.uk/wordpress/nav.html?index.html

Ou juste le source de la fonction add_filter:
https://developer.wordpress.org/reference/functions/add_filter/

qui inclue la fonction _wp_filter_build_unique_id :
https://developer.wordpress.org/reference/functions/_wp_filter_build_unique_id


naga
Commenter la réponse de cs_christophedlr
Messages postés
23257
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
17 novembre 2018
- 27 avril 2016 à 11:51
0
Merci
Bonjour,

Je pense que ce que tu cherches ressemble à ça :
https://wiki.dolibarr.org/index.php/Syst%C3%A8me_de_Hooks
http://www.edouardlabre.com/developpement-internet/les-hooks/
http://www.failover.co/blog/writing-pluggable-php-application-part-3
https://processwire.com/talk/topic/4834-simple-hooks-tutorial-turn-a-pagearray-into-a-list-of-links/


Si tu parviens à mettre en place ce genre de mécanisme .. n'hésites pas à revenir ici nous montrer le résultat .... ça peut en intéresser plus d'un (moi y compris ^^ )

Messages postés
23257
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
17 novembre 2018
>
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
- 27 avril 2016 à 14:41

(dans le cas présent, la différence entre le dynamisme coté serveur et le dynamisme client)

Oui .. mais je ne trouve pas décon**t de gérer les "modules" à afficher côté serveur.
Ce n'est "que" du paramétrage fait par l'admin du site qui décide si un "plugin" doit être affiché ou non sur une page.


Donc du coup la classe que je donnes en lien devrai convenir ^^

Oui. je l'avais vu également.
Mais je trouve plus intéressant de regarder les tutos pour comprendre comment ça fonctionne plutôt que d'utiliser une class toute faite, qui, si on n'en a pas compris le fonctionnement ne servira à rien de toutes manières ^^
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
>
Messages postés
23257
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
17 novembre 2018
- 27 avril 2016 à 15:10
@jordane45 en fait ce que fait la classe est plutot simple, si ce n'est qu'il a une manière une peu "sale" de déclarer ses conteneurs (je pense surtout à "function_name" qui peu être un tableau [classe + fonction]).

Ensuite le seul interêt que je trouve c'est de pouvoir changer les fonctions invoquées via un alias (donc pas besoin de chercher dans le contenu).

Et il y a un inconvénient: l'affichage. Le css doit soit gérer la page en fonction du nombre de module : calculer les emplacements (et dans ce cas il faudra ajouter à la classe lors du "add_" un script qui régénère un css propre à l'affichage, ce qui sous entend des paramètres de tailles au minimum (je rajouterai des niveau d'importance pour déterminer ce qui s'affichera en haut ou bas de page) , ce qu'il n'est pas bien compliqué mais demande un temps de réflexion.

Je pense pas avoir le temps de le faire pour le moment, mais le plus simple sera d'avoir une classe "process" avec le callback vers la fonction du module, la hauteur et largeur du module, la priorité et une fonction run qui appelera le callback -> ca permettra d'avoir une class de hook plus compréhensible.


Ensuite au moment de la génération, tu appels tous modules que tu souhaites via la class des hook et en dernier générer la mise en page avant l 'envoi client.


Je suis pas sûr d'être super clair (surtout que j ecrivais en meme temps que je reflechissais ^^), demande moi si besoin.
naga
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
>
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
- 27 avril 2016 à 15:13
Il est vrai que j'ai du mal à cerné que tu dis, mais bon en même temps je suis sur une installation de Debian 8 pour le boulot donc bon je fais tout en même temps là lol.
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
>
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 27 avril 2016 à 15:26
je vais essayer de faire un squelette de classe pour que ca soit un peu plus clair d'ici vendredi (je promets rien mais je vais essayer ;) )
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 27 avril 2016 à 14:49
C'est exactement cela que je veux faire, j'ai fait un petit début pour les CSS mais je pense que c'est une façon de faire un peut dégueulasse.

Mais oui tu as très bien compris ce que je souhaite faire, c'est exactement cela.
Commenter la réponse de jordane45
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 27 avril 2016 à 14:55
0
Merci
Merci pour ce lien que je vais étudier attentivement ce week-end dès que j'ai du temps (en semaine je suis en stage, et je m'arrache déjà les cheveux sur le code qu'on me fait faire alors bon lol).

Mais oui en effet, cette classe semble correspondre à ce que je veux (dommage que le principe d'encapsulation n'est pas forcément respecté pour ce que j'ai lu en diagonale lol). Je verrais pour faire des tests ce week-end et voir si ça correspond bien.

Par contre j'aime bien faire mes propres codes en effet, mais si j'arrive à l'utiliser et la comprendre, elle pourrait me servir de base pour faire mon propre truc.


Je vous recontacte dès que j'ai testé et je vous dis si c'est ça que je veux. En attendant, si vous avez des idées je reste preneur, car le but n'est pas non plus d'avoir du tout fait mais comprendre comment c'est fait (d'où le fait que j'aime bien tout faire moi même lol).
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
- 27 avril 2016 à 15:30
Je me reprends, mais la classe en lien est un peu "sale" à mon gout, par contre le squelette est correcte et il permet de comprendre la notion d'invoke de fonction ( en c# par exemple, ca se nome reflexion - en php, comme en javascript, c est ultra simplifier du fait qu'une variable est un conteneur - le contenu pouvant être tout et n importe quoi).
Commenter la réponse de cs_christophedlr
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
- 29 avril 2016 à 09:24
0
Merci
Hello !

Voila comme promis j'ai fais les deux classes avec un petit test pour illustrer. C'est ultra simple (je laisse les améliorations a faire en fonction de ce que vous voulez vraiment faire) , mais le principe est la.

<?php

class Conteneur {

	var $Alias; //alias - pour class hook 
	var $isSet = false; //module inclu dans la page? - pour class hook
	var $iHauteur; //Hauteur du module
	var $iLargeur; //largeur du module
	var $sFunction; //fonction à appeler pour la génération
	
	
	function set( $tAlias,$tHauteur,$tLargeur,$tFunction){
		$this->Alias=$tAlias;
		$this->iHauteur=$tHauteur;
		$this->iLargeur=$tLargeur;
		$this->sFunction=$tFunction;
	}
	
	function set_hauteur( $tHauteur ) {$this->iHauteur=$tHauteurs;}
	function get_hauteur( $tHauteur ) { return $this->iHauteur; }
	function set_largeur( $tLargeur ) {$this->iLargeur=$tLargeur;}
	function get_largeur( $tLargeur ) { return $this->iLargeur; }
	
	function run( $param ) {
		$this->isSet=true;
		return call_user_func($this->sFunction,$param);	
	}
}

class Hook {
	var $tConteneurs; //tableau de conteneurs
	
	
	//add ou set (implicite) un conteneur
	function add( $Conteneur ) { $this->tConteneurs[$Conteneur->Alias]=$Conteneur; }
	//appel de la fonction 
	function call( $Alias , $param) { return $this->tConteneurs[$Alias]->run($param); }
	
	function getListSet () {
		$tRet = array();
		foreach($this->tConteneurs as $cont){
			if( $cont->isSet ){ $tRet[$cont->Alias] = $cont;}
		}
		return $tRet;
	}
}

//-- tester 

function test_1( $var ) { echo $var; return true; }
function test_2( $tvar ) {
	print_r($tvar);
	foreach($tvar as $var) {
		echo '<br />' . $var;
	}
	return true;
}

$oCont1=new Conteneur();
$oCont1->set('test_1',10,10,'test_1');
$oCont2=new Conteneur();
$oCont2->set('test_2',10,10,'test_2');

$oHook = new Hook();
$oHook->add($oCont1);
$oHook->add($oCont2);

$oHook->call('test_1','test var');
echo '<br />' ;
echo '<br />' ;
$oHook->call('test_2',array("foo", "bar", "hello", "world"));
echo '<br />' ;
echo '<br />' ;

print_r($oHook);





un test a rajouter sera de donner comme fonction une fonction d'une autre classe.
On pourra aussi rajouter un parametre pour savoir si l'appel de la fonction est avec une variable unique ou non (regarder différences call_user_func / call_user_func_array).

Demandez si besoin.

naga
Messages postés
23257
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
17 novembre 2018
>
Messages postés
4269
Date d'inscription
samedi 8 septembre 2007
Dernière intervention
29 août 2018
- 29 avril 2016 à 10:08
Hello
pour le css ... tu peux aussi te servir de bootstrap. ...
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
>
Messages postés
23257
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
17 novembre 2018
- 29 avril 2016 à 10:42
Oui c'est déjà ce que j'utilise, ce bon vieux Bootstrap, mais je le personnalise un peut car il correspond pas parfaitement à mes besoins.
Messages postés
23257
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
17 novembre 2018
>
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 29 avril 2016 à 15:46

mais je le personnalise un peut car il correspond pas parfaitement à mes besoins.

Comme tout le monde en fait .. :-)
Déjà ... je l'ai passé sur 48 colonnes .... histoire d'affiner les positionnement ....
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
>
Messages postés
23257
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
17 novembre 2018
- 29 avril 2016 à 16:05
Moi non je suis resté sur 12 colonnes, ce qui me suffit. Mais il fait souvent des padding disgracieux, donc un coup de CSS de surchage et hop (ca fait des chopicaic ^^).

Après il y a d'autres trucs que je change : couleur de fond des éléments, taille, police...
Mais il me fournis déjà une très bonne base, merci aux devs ;).
Messages postés
257
Date d'inscription
samedi 3 janvier 2004
Dernière intervention
30 mai 2016
- 1 mai 2016 à 11:48
Bon, depuis ce matin je planche sur cette histoire de hook pour mon site, et j'ai résolu le problème.

Pour ceux que cela intéresse de voir comment j'ai fais, voici le code complet de la classe :
<?php

namespace Core;

/**
 * Hook controller for add fonctionalities from modules
 * @license http://cecill.info/licences/Licence_CeCILL_V2-en.html CeCILL V2
 * @author Christophe Daloz - De Los Rios <christophedlr@gmail.com>
 * @copyright ETS2Routes Dev Team 2016
 */
class HookController {
	private static $instance = null;
	private $list;
	
	private function __construct() {
		$this->list['css'] = array();
		$this->list['after_body'] = array();
		$this->list['before_body'] = array();
	}
	
	/**
	 * Get instance of HookController
	 * @return \Core\HookController
	 */
	public static function getInstance() {
		if ( is_null(self::$instance) ) {
			self::$instance = new HookController();
		}
		
		return self::$instance;
	}
	
	/**
	 * Add fonctionalities from modules
	 * @param string $actionName
	 * <div>Name of action, composed by controllername_action</div>
	 * 
	 * @param string|array $action
	 * <div>Function action or string action (URL for CSS by example)</div>
	 * 
	 * @param string|null $area
	 * <div>Area of insert action (add template). By default, area is null</div>
	 */
	public function addAction($actionName, $action, $area = null) {
		$explode = explode('_', $actionName);
		$ctr_file = ucfirst($explode[0]).'Controller';
		
		switch ( $explode[1] ) {
			case 'tpl':
				$result = call_user_func( $action );
				$this->addTemplate($ctr_file, $result, $area);
			break;
			
			case 'css':
				$this->addCSS($ctr_file, $action);
			break;
		}
	}
	
	/**
	 * Add new CSS in selected controller
	 * @param string $ctr
	 * <div>Controller to add CSS</div>
	 * 
	 * @param string $url
	 * <div>URL of CSS</div>
	 */
	private function addCSS($ctr, $url) {
		$this->list['css'][$ctr][] = $url;
	}
	/**
	 * Add template in selected controller
	 * @param string $ctr
	 * <div>Controller to add template</div>
	 * 
	 * @param string $data
	 * <div>Template at add in controller</div>
	 * 
	 * @param string $area
	 * <div>after or before controller add</div>
	 */
	private function addTemplate($ctr, $data, $area) {
		if ( $area === 'before' ) {
			$this->list['before_body'][$ctr][] = $data;
		}
		else if ( $area === 'after' ) {
			$this->list['after_body'][$ctr][] = $data;
		}
	}
	
	/**
	 * Get list of hook
	 * @param string $element
	 * <div>Name of hook element</div>
	 */
	public function getList($element) {
		if ( isset($this->list[$element]) ) {
			return $this->list[$element];
		}
	}
}



La classe est un singleton, ce qui permet de garder en mémoire les informations. Il me restera juste à gérer la suppression d'un hook et le tout sera parfait.

En gros voilà le fonctionnement :
Une fois qu'on à notre instance du singleon (getInstance), il suffit de faire appel à addAction.

On lui passe jusqu'à 3 paramètres : le nom de l'action, l'action à réaliser et une zone (par défaut à null).

Le nom de l'action se compose ainsi : nomclasse_action. Je ne gère pour l'instant que deux actions : css et tpl pour l'ajout d'un CSS et l'ajout d'un template (donc une vue à afficher, je rappel que je suis en MVC).

Le système va, ajouter dans un tableau correspondant au nom de l'action, une entrée dans le tableau correspondant à la classe. Bien que maintenant que j'y pense, le plus logique serait l'inverse : un tableau pour la classe concernée, contenant un tableau correspondant à l'action.

Le second paramètre lui, est une chaîne de caractère ou un tableau. Si vous appelez une simple fonction, ou quand vous voulez rajouter un CSS (auquel cas il n'a besoin que de l'URL, c'est ce que ce paramètre aura), c'est une chaîne de caractères.
Si maintenant, vous appelez une méthode donc depuis une classe, c'est un tableau contenant valeurs (tableau indexé) : l'instance de la classe ou $this si c'est la classe courante, et le nom de la méthode a appeler.

Enfin le troisième paramètre, accepte actuellement que 2 zones : after et before (chaîne de caractères attention). Cela signifie que dans le cas d'un template, il affichera la vue au-dessus ou en-dessous de la vue sur laquelle on place le hook.


Le fonctionnement est actuellement donc très simple, mais les fonctions n'admettent actuellement pas de paramètres. Dans le cas du tableau pour appeler une méthode d'une classe, il est facile de rajouter un troisième paramètre,contenant un tableau avec les paramètres (par exemple, ou un simple func_get_args, ce qui est bien aussi), mais dans le cas d'une simple chaîne de caractères impossible.

Il me reste donc juste à penser à ça, mais je m'en occuperais quand j'en aurais besoin.

Quand j'aurais plus avancé, je publierais la classe finale de hook pour ceux qui ont ce genre de besoins ;).
Commenter la réponse de nagaD.scar

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.