Bonjour à tous,
Je viens à nouveau demander votre aide, car je ne suis pas sûr de faire quelque chose de logique.
En effet j'essai de poursuivre ce tuto MVC et je souhaite faire en sorte de pouvoir créer des modules. (J'ai cherché sur le forum et les solutions sont très vagues)
Du coup j'ai essayé quelque chose.
Pour la structure, j'ai ajouté un dossier "Module" à la racine.
Un module peut être soit affiché en admin, soit en front, mais pas les deux. Chaque module doit avoir un fichier controller, un model et une ou plusieurs vues.
Un module est affiché lors du chargement d'un controller.
Pour être plus claire, si je charge par exemple PostController.php, je veux charger loginModuleController.php
Un module peut être présent sur plusieurs controller différent et dispose d'un statu online o/n
Pour savoir si un module doit être appellé sur une page, je le stock dans la fonction __contruct du contrôler
exemple ci-dessous pour PostController.php (pour le moment en dur, mais après ce sera via bdd)
public function __construct($request = NULL) {
parent::__construct($request);
$this->request->module = array(
"admin" => array(
'login' => array(
'position' => 'top',
'online' => 1
)
),
"site" => array(
'waaa' => array(
'position' => 'top',
'online' => 0
)
)
);
debug($request);
}
Du coup, j'ai essayé de modifier la fonction render et la fonction __construct du controller principal.
Je stock dans mon objet Request() les informations concernant mes modules et leurs positions.
function __construct($request = NULL) {
$this->Session = new Session();
$this->Form = new Form($this);
if ($request) {
$this->request = $request; // on stock la request dans l'instance
// on va stocker dans l'objet request les modules à charger avec le controller
$this->request->module = $this->module;
// on va charger le fichier hook pour pouvoir chager des comportements différents
require ROOT . DS . 'config' . DS . 'hook.php';
}
}
Une fois que j'ai ces informations, je demande à la fonction render de me récupérer les fichiers en question.
public function render($view, $modules = array()) {
// on vérifie si la vue a été rendue
if ($this->rendered) {
return false;
}
// on va vérifier en premier lieu si $view commence pas un "/", car dans ce cas, ca veut dire que c'est un dossier spécifique qu'il faut charger (ex. page d'erreur 404)
if (strpos($view, '/') === 0) {
$view = ROOT . DS . 'view' . $view . '.php';
} else {
$view = ROOT . DS . 'view' . DS . $this->request->controller . DS . $view . '.php';
}
//debug($view);
extract($this->vars); // les variables sont au même niveau que notre vue.
ob_start();
require $view;
//debug(ob_flush()); // contenu mis en cache
$layout_mainbody = ob_get_clean();
// on va stocker nos modules dans l'objet request
$modules = $this->request->module;
//debug($modules);
// si module n'est pas un tableau vide
if (!empty($modules)) {
// on vérifie les clés valeur de chaque module
foreach ($modules as $k => $o) {
// on vérifie si les clés ne son pas vides
//debug($k);
if (!empty($o)) {
// on va parcourir chaque module du tableau
foreach ($o as $v => $p) {
//debug($p);
// on vérifie si $v n'est pas vide
if (!empty($v) && $p'online'] == 1) {
// debug($p);
// là on va inclure les fichiers et lancer le buffer
$rendu = ROOT . DS . 'module' . DS . $k . DS . $v . DS . $v . 'ModuleController.php';
//debug($rendu);
//ob_start();
if (file_exists($rendu)) {
// on va vérifier la position demandée et créer une zone d'affiche en fonction
switch ($p'position']) {
case 'top' :
ob_start();
require $rendu;
debug(ob_flush());
$layout_top = ob_get_clean();
break;
default: "c'est cuit";
}
}
}
}
}
}
//debug($p'position']);
}
require ROOT . DS . 'view' . DS . 'layout' . DS . $this->layoutDirectory . DS . $this->layout . '.php';
// on oublie pas d'indiquer que la vue a été rendue
$this->rendered = true;
}
Mais là rien ne s'affiche dans mon template !
Le fichier est bien chargé pourtant.
Si je regarde les contenus mis en tampon via la fonction debug(), pour $layout_mainbody, c'est ok
Mais pour le $layout_top, le debug m'affiche las valeur 1.
J'arrête pas de regarder les fonctions dans tous les sens et je n'y arrive pas.
Quelqu'un pourrait-il m'aider à y voir plus claire?
Est-ce que c'est la bonne méthode déjà !
Aussi, je me rends compte que mon require ne se lance qu'une seule fois.
Si j'avais eu 2 modules à afficher, seul le deuxième aurait fonctionné ? Est-ce parce que je n'ai pas utilisé une fonction récursive?
Merci pour toutes vos lumières
Fabien
Salut,
Ca y est, ça fonctionne !! :)
Bon alors j'ai pas mal cherché et j'ai trouvé comment appeler les variables de mes modules depuis ma vue.
Tout se passe bien. Si deux modules sont chargés sur une même page et dans une même position, tout s'affiche correctement.
J'ai modifié deux nouvelles choses par rapport au code du tuto original, c'est du sauvage mais ça fonctionne:
Voici la nouvelle variable $vars
private static $vars = array();
private $mods = array();
et j'ai modifié la fonction set afin qu'elle intègres les variables des modules
public function set($key, $value = null) {
if (is_array($key)) {
$this->mods +=$key;
// on va vérifier si self::$vars est vide
if (!empty(self::$vars)) {
//debug(self::$vars);
self::$vars = array_merge_recursive(self::$vars, $this->mods);
//debug(self::$vars);
//debug('le premier est ' . gettype(self::$vars));
} else {
self::$vars = $this->mods;
//debug(self::$vars);
//debug('le deuxieme est ' . gettype(self::$vars));
}
} else {
$this->mods$key] = $value;
}
}
Du coup je suis content !! Toutes les variables sont chargées dans $vars et du coup je peux tout appeler dans mes différents modules, comme je le sens.
La prochaine étape consiste à associer à chaque module une config.
Par contre, est-ce que je dois stocker les données de config dans ma bdd?? Je vais voir comment je fais ça !!
Du coup, pas de preg_xxx pour éviter de pomper de la ressource.
Je te tiens au courant de mes avancées.
Fabien
// on va stocker nos modules dans l'objet request
$modules = $this->request->module;
je pense tu devrais plutôt poser:
// on va stocker nos modules dans l'objet request
$this->request->module = $modules;
mais je ne vois pas trop l’intérêt vu que non seulement tu le fait en plus dans le render c-à-d au moment d'afficher la sortie html, mais en plus tu continue à utiliser ta variable "$modules".
je ne suis pas sur non plus que la façon dont tu procède soit la bonne. pour mois tu ne peut pas arriver à qq chose d'abouti sans totalement repenser la structure de tes tables voire même sans en créer de nouvelles.
çà fait qq jours je travaille sur le même projet mais avec une autre approche;
-j'ai d'abords commencé par crée une classe gestionnaire de configuration qui est déjà fonctionnelle(supportant 4 format: php (array),ini,json,xml), de manière à pouvoir manager toute la configuration du site depuis le backoffice. Ainsi en plus de la configuration globale du site, chaque module, chaque Template pourra avoir son propre fichier de configuration; utile si je veux lire à la volée les differentes positions disponibles pour une Template par exemple.
B/ LE PRINCIPE
-à l'appel d'un elt de menu on recupere les modules et les posts qui sont rattachés à cette page.
-le tableau obtenu est réorganisé de maniere à les cles soient les different positions liées à chaque contenu.
-au niveau du template on crée des tag specifique avec un attribut "name" unique pour chaque position.
Salut,
Merci pour ces précisions.
Je voulais également créer une classe config un peu plus poussée, mais je voulais en premier lieu m'occuper de charger des modules.
Comme tu le dis, je vais essayer de repenser la façon dont je gère ma classe render.
Je vais prendre des jours, mais bon je vais y arriver !!!
Fabien
pour ma part le fait de commencer par la la mise en place d'un gestionnaire de configuration qui fonctionne te permet de savoir exactement comment structurer ton code et les données de configuration à sauvegarder. t’évitant ainsi de revoir par la suite tout ton code pour des besoins d'adaptation.
d'ailleurs il a fallu que je revisite mon code deja existant une fois le developpement de mon config-manager terminé.
Salut,
Bon alors j'ai creusé et je suis presque arrivé à mes fins.
En tout cas c'est le début.
Je me suis inspiré de ce que tu m'as dit pour commencer, même si je ne me suis pas concentré sur la class Configuration des modules.
J'ai fait 5 modifications :
j'ai ajouté 2 nouvelles tables dans la bdd (light pour le moment)
La première table me permet de sauvegarder la config des modules, et la deuxième sert aux modules qui ont besoin d'enregistrer des contenus en bases (à voir comment j'articule tout ceci après)
J'ai modifié mes controller, afin que dans chaque méthode je puisse charger la liste des modules associés à une vue.
En gros, si je suis sur le controller PostsController, en admin et sur la vue d'index, je cherche dans ma table "module" tous les modules qui devront s'afficher sur la page.
$mod = $this->Module->find(array(
'fields' => 'module,position',
'conditions' => array(
'type' => '1'
)
));
$this->request->modules = $mod;
j'ai modifié le Dispatcher, afin que les actions passées à la fonction render du controller ne soit plus un string mais un array.
J'ai ajouté une fonction loadModule, afin de récupérer les informations qui sont envoyées via mon controller (ex. PostsController)
function __construct() {
$this->request = new Request();
Router::parse($this->request->url, $this->request);
// on charge notre fonction controller pour récupérer les fchiers xxController à appeler
$controller = $this->loadController();
// on est obligé de composer avec l'update de PHP 5.4 qui n'apprécie pas l'utilisation de string dans les index des array
$action] = $this->request->action;
if ($this->request->prefix) { // est-ce que j'ai un prefixe
$action[0] = $this->request->prefix . '_' . $action[0];
}
if (!in_array($action[0], array_diff(get_class_methods($controller), get_class_methods('Controller')))) {
$this->error("Le controller " . $this->request->controller . " n'a pas de methode " . $action[0] . " !");
}
call_user_func_array(array($controller, $action[0]), $this->request->params);
// on fait pareil pour les modules, pour récupérer les controllers des modules
$moduleController = $this->loadModule();
// on va récupérer l'action de notre module
foreach ($this->request->modules as $k => $v) {
$action[1]$k] = $v;
if ($this->request->prefix) {
$action[1]$k]->action = !isset($this->request->mod) ? 'admin_view' : 'admin_edit';
} else {
$action[1]$k]->action = 'view';
}
}
// on va lui demander de rendre la vue automatiquement
$controller->render($action);
//debug($controller);
}
function loadModule() {
// on va récupérer de façon automatique le nom du module
$modules = $this->request->modules;
//debug($modules);
$name = array();
$file = array();
foreach ($modules as $k => $v) {
$name$k] = ucfirst($this->request->modules$k]->module) . 'Controller';
$file$k] = ROOT . DS . 'module' . DS . 'mod_' . $this->request->modules$k]->module . DS . $name$k] . '.php';
// on inclue les fichiers une seule fois
if (!fileexists($file$k])) {
// dans ce cas on lance une erreur
$this->error("Le module " . 'mod' . $this->request->modules$k]->module . " n'est pas disponible !");
}
require_once $file$k];
// je vais créer un nouvel objet
$modulesController$k] = new $name$k]();
}
// je vais renvoyer cet objet dans mon render pour pouvoir y accéder
//debug($modulesController);
return $modulesController;
}
J'ai modifié le controller, afin que la fonction render puisse accepter des tableaux au niveau des action.
J'ai deux types d'actions, la première concerne le contenu du mainbody, et la deuxième est le tableau de tous les modules à charger.
Puis via des boucles foreach + switch pour qu'à chaque position de mon template soit associé une variable
public function render($action) {
//debug($action[0]);
// on vérifie si la vue a été rendue
if ($this->rendered) {
return false;
}
extract($this->vars); // les variables sont au même niveau que notre vue.
if (isset($action[0]) && !empty($action[0])) {
// on va vérifier en premier lieu si $view commence pas un "/", car dans ce cas, ca veut dire que c'est un dossier spécifique qu'il faut charger (ex. page d'erreur 404)
if (strpos($action[0], '/') === 0) {
$view = ROOT . DS . 'view' . $action[0] . '.php';
} else {
$view = ROOT . DS . 'view' . DS . $this->request->controller . DS . $action[0] . '.php';
}
ob_start();
//if (isset($view))
if (file_exists($view))
require $view;
$layout_mainbody = ob_get_clean();
}
if (isset($action[1]) && !empty($action[1])) {
// on transforme notre objet en array
$convert = objectToArray($action[1]); // fonction récupérée sur le net pour faire la converion objet to array http://www.if-not-true-then-false.com/2009/php-tip-convert-stdclass-object-to-multidimensional-array-and-convert-multidimensional-array-to-stdclass-object/
// on va vérifier tous nos modules présents. mais on vérifie en premier qu'on envoie bien un tableau
if (isarray($convert)) {
$zone = array();
foreach ($convert as $k => $v) {
debug($v);
$zone$k] = ROOT . DS . 'module' . DS . 'mod' . $v'module'] . DS . 'view' . DS . $v'action'] . '.php';
ob_start();
require $zone$k];
switch ($v'position']) {
case 1:
$layout_top$k] = ob_get_clean();
break;
case 2:
$layout_top1$k] = ob_get_clean();
break;
default: $layout_mainbody$k] = ob_get_clean();
break;
}
}
debug($zone);
}
}
// on appelle notre template
require ROOT . DS . 'view' . DS . 'layout' . DS . $this->layoutDirectory . DS . $this->layout . '.php';
// on oublie pas d'indiquer que la vue a été rendue
$this->rendered = true;
}
j'ai ajouté dans l'object request, une variable "mod" qui va me servir en cas d'édition de mon module en mode admin.
public $mod; // par défaut on récupère l'id du module à modifier
et ci-dessous le code ajouté dans mon __construct
// on vérifie si un argument est passé en paramètre
if (isset($_GET'mod'])) {
if (is_numeric($_GET'mod'])) {
$this->mod = $_GET'mod'];
}
}
Je suis parti sur un concept simple pour mes modules.
Chaque module dispose de 3 vue "admin_edit, admin_view et view".
Je suis contenant, j'ai créé 2 modules différents, et ils s'affichent.
Bon le seul problème, c'est que je n'ai pas accès aux variables de mon controller de module.
Je vais aller vérifier ce que j'ai fait pour m'assurer qu'il n'y a pas quelque chose que j'aurai oublié.
Bon, mon code est sans "crade" mais bon, on est là pour apprendre.
Si vous avez des suggestions je suis preneur.
Fabien
salut au lieu de passer par l'objet request qui t'oblige à revoir le code existant,
pourquoi ne poser ceci:
$this->loadModel('Post');
$d'posts'] = $this->Content->findFirst( array(
'fields'=>'id,slug,content,name',
'conditions'=>array('id'=>intval($id),
'type'=>'post',
'online'=>1
)
));
$this->loadModel('Module');
$d'modules']= $this->Module->find(array(
'fields' => 'module,position',
'conditions' => array(
'type' => '1'
)
));
$this->set($d);
et de faire le traitement des modules dans le render et les vues? du moins c'est comme çà que moi je voit les choses.
sachant que ce topic :
http://www.grafikart.fr/forum/topic/5960
te permettrait grace aux jointures de selectionner le tout en une seule requete et de faire le tri apres.
ce qui donnerai a peu pres ceci:
$datas=array( '0'=>array('pos'=>'as','content'=>'aaaa','title'=>'kk'),
'1'=>array('pos'=>'pc','content'=>'bbbbb','title'=>'nv'),
'2'=>array('pos'=>'','content'=>'attttttt','title'=>'qs'),
'3'=>array('pos'=>'de','content'=>'hrhrhr','title'=>'po'),
'4'=>array('content'=>'dodododdodo','title'=>'pofff'),
);
$modules = array();
foreach($datas as $key=>$val)
{
if(isset($val'pos']) and !empty($val'pos'])){ //les posts n'ont pas de position
$pos=$val'pos'];
unset($val'pos']);
$modules$pos]] = $val;
unset($datas$key]);
}
}
$datas = array_values($datas);
foreach($datas as $k=>$v)
{
!isset($v'pos']) or unset($v'pos']);
$datas$k]=$v;
}
$d'modules']=$modules;
$d'posts'] = $datas;
$this->set($d);
ke se passera-til si plusieurs modules sont publiés à la même position? d’après ce que je vois seul le dernier sera affiché.
Désolé que pour l'instant je ne puisse que te donner de piste sur ce projet car je l'ai laissé de coté au profit un autre qui m'ai rentable.
Salut,
Merci pour ta réponses.
Alors, je vois très bien ce que tu me dis là concernant la gestion du module via la vue (un peu comme la fonction getMenu() du tuto qui te permet de récupérer depuis une vue, un contrôler.
Moi je veux éviter d'avoir une multiplication de fonctions dans les vues.
En plus, j'ai déjà modifié toutes mes fonctions, donc mon code n'est plus iso à celui du tuto.
Concernant les modules, je n'ai pas mis tout mon code. Dans ma BDD j'ai 2 modules et tous les deux s'affichent dans ma position $layout_top et sans souci
J'ai modifié la position de l'un des 2 modules dans la base, et ajouté le contenair correspondant dans mon template et tout s'ffiche correctement.
J'ai commencé à faire plusieurs débug différent.
Mes controller de modules sont bien chargés, car si j'oublie volontairement un ; => j'ai directe un PHP Warning
Par contre, les méthode de ma classe sont inconnues au bataillons après chargement.
J'ai essayé d'afficher les methodes de mes classes et elles sont bien chargées.
Je vais continuer à creuser. Mais je ne comprends pas pourquoi le contenu de mon module ne s'exécute pas !
J'ai mis un die(); pour couper l'exécution de la methode admin_view() de mon module, mais rien ne se passe.
Je vais continuer à creuser (en espérant trouver du pétrole :) !!)
Je te tiens au courant
Merci beaucoup
quand je parle de traitement des modules au niveau des vues (ou du template), il s'agit de faire un truc du genre:
if(this->isloadedPosition($position)) $this->printPosition($position);
biensur ces methodes devant être créer dans le contrôleur principal.
la méthode "printPosition" bien que complexe consistera à faire des preg_replace au niveau du template.
la methode "isloadedPosition" peut se resumer à :
//créer dans le controlleur principal l'objet "modules" et apres l'extraction dans le render, poser:
$this->modules=$modules;
public function isloadedPosition($position)
{
return array_key_exists($position,$this->modules);
}
apres pour la disponibilité des methodes ou des variables de tes modules tout depend de comment tu les appelle. si c'est depuis une fonction, ou une methode, normale qu'elles ne soient pas disponible au delà de celle-ci.
Pour l'appel des méthodes, j'utilise les fonction render() et la fonction set() du tuto.
ex. si je charge PostsController et mes modules Posts2Controller et Posts3Controller, j'ai bien mon contenu du PostsController qui s'affiche sans souci, j'ai bien l'html de mes modules qui s'affichent, mais je n'ai pas accès aux variables des methodes de Posts2Controller et Post3Controller.
Là je n'ai pas la possibilité de tester tes propositions de suite. Je vais regarder ce soir et je te tiens au courant.
Merci beaucoup
Salut,
J'ai fouillé dans tous les coins et je me suis rendu compte, que je ne faisais pas call_user_func_array() dans mon dispatcher, comme pour le controller principal.
call_user_func_array(array($controller, $action[0]), $this->request->params);
Du coup j'ai essayé d'ajouter cette fonction lors du chargement de chaque module, mais j'ai une belle erreur php
call_user_func_array(array($action[1]$k]->controller, $action[1]$k]->action), $moduleController$k]->request->params);
Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method PagesController::admin_view() should not be called statically in /Applications/MAMP/htdocs/artisans/core/Dispatcher.php on line 78
Warning: call_user_func_array() expects parameter 2 to be array, null given in /Applications/MAMP/htdocs/artisans/core/Dispatcher.php on line 78
Notice: Trying to get property of non-object in /Applications/MAMP/htdocs/artisans/core/Dispatcher.php on line 78
Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Page2Controller::admin_view() should not be called statically in /Applications/MAMP/htdocs/artisans/core/Dispatcher.php on line 78
Warning: call_user_func_array() expects parameter 2 to be array, null given in /Applications/MAMP/htdocs/artisans/core/Dispatcher.php on line 78
Je vais essayer comprendre ce qui ne va pas et je vous tiens au courant.
Fabien
Bon alors j'ai vu juste, c'est bien l'appel aux méthodes de mes modules que je ne faisais pas.
Du coup, là j'appelle bien les controllers de mes modules.
call_user_func_array(array($moduleController$k], $action[1]$k]->action), array());
J'ai été voir la doc php pour comprendre.
Bon là j'ai une autre erreur, mais je ferai le debug demain, car là j'ai pas le courage
Notice: Trying to get property of non-object in /Applications/MAMP/htdocs/artisans/module/mod_pages/PagesController.php on line 31
Warning: PDOStatement::execute(): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-10,10' at line 1 in /Applications/MAMP/htdocs/artisans/core/Model.php on line 102
Salut,
Je suis de retour et avec de bonnes nouvelles pour moi !
Bon mon système de module a bien avancé, même si je me suis pas mal cassé la tête pour le faire.
J'ai appris pas mal de nouvelles choses du coup, fonctions récursives, ob_start(), uploader un fichier zip et le décompresser...
Voila un peu ou j'en suis, pour faire simple, je vais tout détailler :)
Je gère mes modules via 2 tables principales, puis une spécifique à chaque module que je vais créer.
En gros, j'ai :
J'ai choisi cette façon de faire, car je n'avais pas envie de répéter toujours les mêmes champs dans la table à chaque fois que je créai un nouveau type de module !!!
Du coup, lorsque je liste tous les modules actif/inactifs, j'appelle uniquement ma table modules, sans aller chercher toutes les caractéristiques propres à un ou plusieurs types de modules !
Je ne sais pas si c'est la bonne méthode, mais en tous cas pour le moment ça à l'air de fonctionner.
J'ai également modifié ma structure de module.
Chaque module est un MVC, et est stocké dans le répertoire "module"
Je gère également les templates, pour que mes modules apparaissent là où j'ai décidé.
Ca a été un peu coton de faire en sorte que mes paramètres standards de modules et propres au module apparaissent dans le même élément <form>
Je rappelle juste que pour qu'un module soit fonctionnel, il a des caractéristiques standard stockées dans la table préfix_modules et ses caractéristiques propres stockées dans préfix_mon_module
Voici également l'arborescence de mon module perso
repertoire : <u>mon module</u> / Files : MonmoduleController.php;index.html;mod_monmodule.xml;monmoduleQuery.sql
Sous-rep : <u>model</u> / Files : monmodule.php;
Sous_rep : <u>view</u> / Files : admin-edit.php;admin_index.php;admin_view.php
ensuite ca varie selon le module évidemment.
J'envoie le fichier zipé via mon champ file.
Le fichier est dézipé dans un répertoire temporaire.
Je scanne le fichier .xml et fait plusieurs vérif pour m'assurer que tout est ok (bon y a encore des vérifs à mettre en place)
Je lance la requete sql, pour créer la nouvelle table de moduleperso, insérer une ligne dans la table des extensions, insérer une ligne dans la table des modules, insérer une ligne dans la table moduleperso nouvellement crée !
je supprime alors le fichier .sql
je copy le répertoire du fichier temporaire vers le dossier des modules et supprimer le fichier temporaire
et le tour est joué !!
bon, ce qui me reste à faire maintenant, ce sont les jointures de tables pour que la sauvegarde d'un module s'effectue dans la table des modules et dans la table du module perso.
En gros, voila où j'en suis !!!
Si vous avez des questions ou suggestions je suis preneur !!!
Fabien