RSS
 

Lister tous les modèles d’une application CakePHP (plugins inclus)

03 fév

Voici aujourd’hui un rapide zoom sur une méthode de CakePHP qui permet de facilement récupérer les différents types de fichiers d’une application (helpers, modèles, contrôleurs ou encore plugins). Cette méthode existe depuis un bon moment et était accessible par Configure::listObjects(). Dans la version 1.3 de CakePHP celle-ci a été améliorée et renommée en App::objects().

Je vous invite à lire la documentation pour comprendre comment utiliser cette méthode, le but de cet article étant avant tout de proposer une utilisation concrète résolvant une de ses limites. En effet, seuls les objets de l’application sont retournés par l’application ce qui peut poser problème si on veut par exemple récupérer tous les modèles de l’application ET de ces plugins.

Cet article illustre la récupération des Modèles d’une application, mais il est évident que cette technique peut être facilement généralisée ou modifiée pour tout autre type d’objet (helpers, contrôleurs …).

CakePHP permet donc de récupérer de maniere simple tous les objets d’un certain type en faisant par exemple App::objects(‘model’);

Par contre cette méthode ne renvoie pas la liste des objets inclus dans les plugins. Prenons l’exemple d’une application ayant un modèle Article, et un plugin « comments » contenant le modèle Comment. L’instruction ci-dessus ne retournera que le modèle Article.

J’ai récemment souhaité effectuer un traitement sur tous les modèles d’une application ayant un certain Comportement (par exemple : $actsAs = array(‘Commentable’); ). Le filtrage des modèles n’est pas très compliqué (un appel à array_filter avec une méthode simple de callback), en revanche il fallait trouver une solution pour lister tous les modèles de l’application. Voici donc le petit bout de code qui fait le travail à votre place :

/**
 * Returns a list of all application models (including plugins)
 *
 * @return array List of models
 */
	private function __getModels() {
		$models = App::objects('model');
		$plugins = App::objects('plugin');
		if (!empty($plugins)) {
			foreach ($plugins as $plugin) {
				$pluginModels = App::objects('model', App::pluginPath($plugin) . 'models' . DS, false);
				if (!empty($pluginModels)) {
					foreach ($pluginModels as $model) {
						$models[] = "$plugin.$model";
					}
				}
			}
		}
		return $models;
	}

Remarques sur le code :

  • par défaut CakePHP met en cache les résultats des appels à App::objects c’est pour cette raison  que l’appel effectué dans le foreach désactive le cache en passant false comme dernier argument.
  • notez que nous nommons les modèles contenus dans les plugins de la forme Plugin.Modele, cela permet d’identifier chaque modèle de manière unique et permet de les charger facilement par la suite en utilisant ClassRegistry::init().

En espérant que vous trouverez de l’utilité à cette technique un jour ou l’autre … en attendant si vous avez des questions, n’hésitez pas ! :)

Pensez à utiliser mon flux RSS pour vous tenir au courant des futurs articles ! Vous pouvez aussi me retrouver sur Twitter pour une actualité plus fréquente.

 
8 Comments

Posted in En vrac

 

Tags: ,

  • scharrier

    Je ne sais pas si ça a été modifié en 1.3, mais le Configure::listObjects() de la 1.2 posait un problème : il ne prenait pas en compte les modèles « virtuels » (autrement dit les modèles créés à la volée par Cake, pour les tables simples).

    (Oui, je suis d'accord, c'est une mauvaise pratique que de ne pas créer tous les modèles … c'est néanmoins déstabilisant)

  • http://www.pierre-martin.fr/ Pierre Martin

    Je ne pense pas que cela ait ete resolu en 1.3 car App::objects() se base sur la liste des fichiers contenus dans les dossiers lies au type d'objet demande. Cf le code ci-dessous:

    foreach ((array)$path as $dir) {
    if ($dir != APP) {
    $items = $_this->__list($dir, $types[$type]['suffix'], $extension);
    $objects = array_merge($items, array_diff($objects, $items));
    }
    }

    Donc oui, je pense que pour utiliser ce genre de methodes il n'y a pas d'autre choix que de generer les modeles qui vont bien …
    Les modeles virtuels etant utilises vraiment en dernier recours il est plutot deconseille de se baser dessus (a part pour les HABTM simples).

  • cherif_gsoul

    Trés bien, mais est ce qu'on peut avoir la liste des contrôleurs de la même manière?

  • http://www.pierre-martin.fr/ Pierre Martin

    Bonjour,

    Oui il faut procéder de la même manière. En gros, renommer les occurences de « model » en « controller » dans le code donné devrait suffire (aux majuscules et pluriels près ;) )

  • cherif_gsoul

    merci pour votre réponse.
    regardez ce fragment de code qui est dans un composant que je suis entrain de développer pour lister les contrôleurs et les méthodes qui les appartient:

    //———————————————————

    $controllers = Configure::listObjects('controller');
    $plugins = Configure::listObjects('plugin');
    if (!empty($plugins)) {
    foreach ($plugins as $plugin) {
    $pPath= APP . 'plugins' . DS. $plugin . DS . 'controllers' . DS;
    $pluginControllers = Configure::listObjects('controller',
    $pPath ,false);
    if (!empty($plugincontrollers)) {
    foreach ($pluginControllers as $controller) {
    $models[] = « $plugin.$controller »;
    }
    }
    }
    }
    return $controllers;

    //——————————————-

    ça marche bien avec les app/controllers mais il retourne rien comme contorller dans les plugins malgré qu'il existe des plugins avec des controlleurs. Est ce que j'ai bien mets le $path care je pense ma faute est la?

  • http://www.pierre-martin.fr/ Pierre Martin

    Bonjour,

    En effet, avec CakePHP 1.2 la methode App::pluginPath() n'existe pas. Il faut donc contourner ceci en faisant une construction du checmin a la main.

    Quelques petites erreurs se sont egalement glissees dans votre code : majuscule oubliee pour le nom de variable dans empty($plugincontrollers), oubli de renommage de $models[] en $controllers[] dans le foreach et non conversion du nom de plugin en chemin (avec underscores) lors de la construction du chemin.

    Voici donc la methode corrigee fonctionnant avec CakePHP 1.2 :

    $controllers = Configure::listObjects('controller');$plugins = Configure::listObjects('plugin');if (!empty($plugins)) {	foreach ($plugins as $plugin) {		$pPath = APP . 'plugins' . DS . Inflector::underscore($plugin) . DS . 'controllers' . DS;		$pluginControllers = Configure::listObjects('controller', $pPath, false);		if (!empty($pluginControllers)) {			foreach ($pluginControllers as $controller) {				$controllers[] = "$plugin.$controller";			}		}	}}return $controllers;

    Bonne journee,
    Pierre

    PS: J'ai edite votre commentaire pour formater le code (ajout de balises pre)

  • cherif_gsoul

    merci beaucoup pierre c'est bien marché j'essaie d'utiliser les fonctionnalité de cakephp le max possible et vous m'avez orienter vers une autre classe qui gère les chaine des caractéres et les chemin (inflector).

  • Pingback: List all the models and plugins of a cakephp Application | Variable 3 Technologies