Table des matières

Plonger dans le développement PrestaShop

Accéder à la base de données

La structure de la base de données

Les tables de la base de données de PrestaShop sont nommées avec le préfixe ps_. Notez que cet aspect peut être personnalisé durant l'installation initiale.

Tous les noms de table sont en lettres caractères minuscules, et les mots sont séparés par le caractère souligne ("_").

Quand une table crée un lien entre deux entités, les noms des deux entités sont mentionnés dans le nom de la table.  Par exemple,  ps_category_product fait le lien entre les produits et leur catégorie.

Quelques détails à noter :

La classe ObjectModel

C'est là l'objet principal du modèle objet de PrestaShop. Il peut être surchargé en prenant quelques précautions.

C'est une classe de type Active Record (http://fr.wikipedia.org/wiki/Active_record_%28patron_de_conception%29). Les attributs d'une table ou d'une vue sont encapsulés dans une classe. Ainsi l'objet, instance de la classe, est lié à un enregistrement de la base. Après l'instanciation d'un objet, un nouvel enregistrement est ajouté à la base au moment de l'écriture. Chaque objet récupère ses données depuis la base; quand un objet est mis à jour, l'enregistrement auquel il est lié l'est aussi. La classe implémente des accesseurs pour chaque attribut.

Définir le modèle

Vous devez utiliser la variable statique $definition afin de définir le modèle.

Par exemple :

/**
* Exemple du modèle CMS (CMSCore) 
*/
public static $definition = array(
  'table' => 'cms',
  'primary' => 'id_cms',
  'multilang' => true,
  'fields' => array(
    'id_cms_category'  => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
    'position'         => array('type' => self::TYPE_INT),
    'active'           => array('type' => self::TYPE_BOOL),
    // Lang fields
    'meta_description' => 
        array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255),
    'meta_keywords'    => 
        array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255),
    'meta_title'       => 
        array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 128),
    'link_rewrite'     =>
        array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isLinkRewrite', 'required' => true, 'size' => 128),
    'content'          => 
        array('type' => self::TYPE_HTML,   'lang' => true, 'validate' => 'isString', 'size' => 3999999999999),
  ),
);

Un modèle pour de nombreuses boutiques et langues

Pour disposer d'un objet dans plusieurs langues :

'multilang' => true

Pour disposer d'un objet dépendant de la boutique en cours :

'multishop' => true

Pour disposer d'un d'objet dépendant de la boutique en cours, et dans plusieurs langues :

'multilang_shop' => true

Les principales méthodes

La moindre surcharge de ces classes peut avoir une influence sur la manière dont les autres classes et méthodes se comportent. À utiliser avec précaution.

Nom et paramètres de la méthode

Description

__construct($id = NULL, $id_lang = NULL)

Construit l'objet.

add($autodate = true, $nullValues = false)

Enregistre l'objet en cours dans la base de données (ajout ou mise à jour).

delete()

Supprime l'objet en cours de la base de données.

deleteSelection($selection)

Supprime plusieurs objets de la base de données.

getFields()

Prépare les champs pour les classes ObjectModel (ajout, mise à jour).

getValidationRules($className = _CLASS_)

Renvoie les règles de validation objet (validité des champs).

save($nullValues = false, $autodate = true)

Enregistre l'objet en cours dans la base de données (ajout ou mise à jour).

toggleStatus()

Modifie l'état de l'objet dans la base de données.

update($nullValues = false)

Met à jour l'objet en cours dans la base de données.

validateFields($die = true, $errorReturn = false)

Vérifie la validité des champs avant une interaction avec la base de données.

La classe DBQuery

La classe DBQuery permet de construire des requêtes, et donc vous aide à mettre en place vos requêtes SQL. Par exemple :

$sql = new DbQuery();
$sql->select('*');
$sql->from('cms', 'c');
$sql->innerJoin('cms_lang', 'l', 'c.id_cms = l.id_cms AND l.id_lang = '.(int)$id_lang);
$sql->where('c.active = 1');
$sql->orderBy('position');
return Db::getInstance()->executeS($sql);

Voici certaines méthodes de cette classe :

Method name and parametersDescription
__toString()Générer et récupérer la requête.
string build()Générer et récupérer la requête.
from(string $table, mixed $alias = null)Régler la table de la clause FROM.
groupBy(string $fields)Ajouter une restriction GROUP BY.
having(string $restriction)

Ajouter une restriction sur la clause HAVING (les restrictions seront séparées par une déclaration AND).

innerJoin(string $table, string $alias = null, string $on = null)

Ajouter une clause INNER JOIN, par exemple $this->innerJoin('product p ON ...')

join(string $join)

Ajouter une clause JOIN, par exemple $this->join('RIGHT JOIN'._DB_PREFIX_.'product p ON ...');

leftJoin(string $table, string $alias = null, string $on = null)Ajouter une clause LEFT JOIN
leftOuterJoin(string $table, string $alias = null, string $on = null)

Ajouter une clause LEFT OUTER JOIN.

limit(string $limit, mixed $offset = 0)Limiter les résultats de la requête.
naturalJoin(string $table, string $alias = null)Ajouter une clause NATURAL JOIN.
orderBy(string $fields)Ajouter une restriction ORDER B.
select(string $fields)Ajouter des champs à la sélection de la requête.
where(string $restriction)

Ajouter une restriction dans la clause WHERE (les restrictions seront séparées par une déclaration AND).

Le Répartiteur (dispatcher)

Le Répartiteur est l'une des principales nouveautés techniques de la version 1.5. Il gère les redirections d'URL. Au lieu d'utiliser une multitude de fichiers à la racine du dossier de PrestaShop, comme product.php, order.php ou category.php, un seul est utilisé : index.php. Partant de là, les adresses internes auront cet aspect : index.php?controller=category, index.php?controller=product, etc.

Par ailleurs, le Répartiteur a été conçu pour prendre en compte la réécriture d'URL. Ainsi, quand la réécriture d'URL est désactivée, PrestaShop utilisera la forme d'adresse suivante :

http://myprestashop.com/index.php?controller=category&id_category=3&id_lang=1
http://myprestashop.com/index.php?controller=product&id_product=1&id_lang=1

...et lorsque la réécriture d'URL est activée (aussi appelée "URL simplifiées"), le Répartiteur de PrestaShop sera capable d'utiliser la forme suivante :

http://myprestashop.com/en/3-music-ipods
http://myprestashop.com/en/1-ipod-nano.html

Ce système offre plusieurs avantages :

Le Répartiteur utilise trois nouvelles classes abstraites : Controller, FrontController et AdminController (ces deux dernières héritant de la première).

De nouvelles routes peuvent être créées en surchargeant la méthode loadRoutes().
L'administrateur de la boutique peut changer l'URL d'un contrôleur en passant par la page de préférences "SEO & URLs".

Contrôleurs

Dans l'architecture MVC, un contrôleur gère la synchronisation des évènements entre la Vue et le Modèle, et les garde à jour. Il reçoit les évènements de tous les utilisateurs, et déclenche les actions à accomplir.
Si une action a besoin de voir des données modifiées, le contrôleur "demandera" au Modèle de modifier ces données, et en retour le Modèle notifiera la Vue que les données ont été changées, afin que la Vue puisse se mettre à jour.

Tous les contrôleurs de PrestaShop sont en fait des surcharges de la classe Controller par le biais d'une autre classe qui en hérite, comme AdminController, ModuleAdminController, FrontController ou ModuleFrontController.

La classe FrontController

Quelques-unes des propriétés de la classe :

PropriétéDescription
$templateNom du modèle pour le contenu de la page.
$css_filesTableau contenant une liste des fichiers CSS.
$js_filesTableau contenant une liste des fichiers JavaScript.
$errorsTableau des erreurs qui ont survenu.
$guestAllowedIndique si le client qui s'est déconnecté peut accéder à cette page.
$initializedIndique si la fonction init() a été appelée.
$isoLe code ISO de la langue actuellement sélectionnée.
$nLe nombre d'éléments par page.
$orderByLe champ à utiliser pour le tri.
$orderWayIndique si le tri doit être ascendant ou descendant ("ASC" ou "DESC").
$pLe numéro de la page actuelle.
$ajaxSi le paramètre ajax est détecté dans la requête, cette variable sera à true.

Ordre d'exécution des fonctions du contrôleur

  1. __contruct() : configure toutes les variables des membres du contrôleur.
  2. init() : initialise le contrôleur.
  3. setMedia() ou setMobileMedia() : ajoute tous les détails liés à JavaScript et aux CSS à la page, afin qu'ils puissent être combinés, compressés et mis en cache (voire l'outil CCC de PrestaShop, dans la page "Performances" du back-office).
  4. postProcess() : gère ajaxProcess.
  5. initHeader() : appelé avant initContent().
  6. initContent() : initialise le contenu.
  7. initFooter() : appelé après initContent().
  8. display() ou displayAjax() : affiche le contenu.

Contrôleurs existants

Nom de fichier du contrôleurDescription
AddressController.phpUtilisé par address.php pour modifier l'adresse d'un client.
AddressesController.phpUtilisé par addresses.php pour récupérer les adresses d'un client.
AuthController.phpUtilisé par authentication.php pour la connexion d'un client.
BestSalesController.phpUtilisé par best-sales.php pour récupérer les meilleures ventes.
CartController.phpUtilisé par cart.php pour gérer le panier du client.
CategoryControllerUtilisé par category.php pour récupérer les catégories de produits.
CMSController.phpUtilisé par cms.php pour récupérer une page CMS.
CompareController.phpUtilisé par products-comparison.php pour comparer les produits.
ContactController.phpUtilisé par contact-form.php pour envoyer des messages.
DiscountController.phpUtilisé par discount.php pour récupérer les réductions d'un client.
GuestTrackingController.phpUtilisé par guest-tracking.php pour gérer les commandes de clients non-inscrits (guest).
HistoryController.phpUtilisé par history.php pour récupérer les commandes d'un client.
IdentityController.phpUtilisé par identity.php pour récupérer les informations personnelles d'un client.
IndexController.phpUtilisé par index.php pour afficher la page d'accueil.
ManufacturerController.phpUtilisé par manufacturer.php pour récupérer les fabricants.
MyAccountController.phpUtilisé par my-account.php pour gérer le compte d'un client.
NewProductsController.phpUtilisé par new-products.php pour récupérer les nouveaux produits.
OrderConfirmationController.phpUtilisé par order-confirmation.php pour confirmer une commande.
OrderController.phpUtilisé par order.php pour gérer la commande en cinq étapes.
OrderDetailController.phpUtilisé par order-detail.php pour récupérer la commande d'un utilisateur.
OrderFollowController.phpUtilisé par order-follow.php pour récupérer les retours d'un client.
OrderOpcController.phpUtilisé par order-opc.php pour gérer la commande en une étape.
OrderReturnController.phpUtilisé par order-return.php pour récupérer un retour marchandise.
OrderSlipController.phpUtilisé par order-slip.php pour récupérer les bons d'achat d'un client.
PageNotFoundController.phpUtilisé par 404.php pour gérer la page "page introuvable".
ParentOrderController.phpGère le code de commande partagé.
PasswordController.phpUtilisé par password.php pour mettre à zéro un mot de passe perdu.
PricesDropController.phpUtilisé par prices-drop.php pour obtenir les produits ayant une réduction.
ProductController.phpUtilisé par product.php pour récupérer un produit.
SearchController.phpUtilisé par search.php pour obtenir des résultats de recherche.
SitemapController.phpUtilisé par sitemap.php pour récupérer le sitemap.
StoresController.phpUtilisé par stores.php pour récupérer les informations de la boutique.
StoresController.phpUtilisé par supplier.php pour récupérer les fournisseurs.

Surcharger un contrôleur

Grâce à l'héritage objet, vous pouvez modifier le comportement d'un contrôleur, ou en ajouter de nouveaux.

Les contrôleurs de PrestaShop sont tous stockés dans le dossier /controllers, et utilisent le suffixe "Core".

Par exemple, lorsque vous travaillez avec le contrôleur de catégorie :

Si vous souhaitez modifier un contrôleur, vous devez d'abord créer une nouvelle classe sans le suffixe "Core", et placer ce fichier dans le dossier /override/controllers.

Par exemple, lorsque vous surchargez le contrôleur de catégorie :

Vues

PrestaShop utilise le moteur de template Smarty pour générer ses vues : http://www.smarty.net/

Les vues sont stockées dans des fichiers .tpl.

Le nom d'une vue est généralement le même que le nom du code qui l'utilise. Par exemple, 404.php utilise 404.tpl.

Il n'y a pas de concept d'héritage dans les vues, donc pas moyen de surcharger une vue.

Si vous souhaitez modifier un vue, vous devez réécrire son fichier template, et le placer dans le dossier du thème.

Cookies

PrestaShop utilise des cookies cryptés pour stocker toutes ses informations de session, pour les visiteurs/clients comme pour les employés/administrateurs.

La classe Cookie (/classes/Cookie.php) est utilisée pour lire et écrire les cookies.

Pour accéder aux cookies depuis le code de PrestaShop, vous pouvez faire comme suit :

$this->context->cookie;

Toutes les informations stockées dans le cookie sont disponibles par le biais de ce code :

$this->context->cookie->variable;

Si vous avez besoin d'accéder au cookie de PrestaShop depuis du code en dehors de PrestaShop, vous pouvez utiliser ce code :

include_once('chemin_vers_prestashop/config/config.inc.php');
include_once('chemin_vers_prestashop/config/settings.inc.php');
include_once('chemin_vers_prestashop/classes/Cookie.php');
$cookie = new Cookie('ps'); // Utilisez "psAdmin" pour accéder au cookie d'un employé.

Données stockées dans le cookie d'un visiteur/client

 

TokenDescription
date_addL'heure et la date de création du cookie (au format YYYY-MM-DD HH:MM:SS).
id_langL'identifiant de la langue sélectionnée.
id_currencyL'identifiant de la devise sélectionnée.
last_visited_categoryL'identifiant de la dernière catégorie de produits visitée.
ajax_blockcart_displayIndique si le block panier est ouvert ou fermé.
viewedLes identifiants des derniers produits vus, séparés par une virgule.
id_wishlistL'identifiant de la liste d'idées cadeaux actuellement affichée dans le bloc.
checkedTOSIndique si la case "Conditions générales de vente" a bien été cochée (oui : 1 ; non : 0).
id_guestL'identifiant invité du visiteur non connecté.
id_connectionsL'identifiant de connexion de la session en cours du visiteur.
id_customerL'identifiant du visiteur une fois connecté.
customer_lastnameLe nom de famille du client.
customer_firstnameLe prénom du client.
loggedIndique si le client est connecté ou non.
passwdLe hash MD5 de _COOKIE_KEY_ dans config/settings.inc.php, et le mot de passe utilisé par le client pour se connecter.
emailL'adresse e-mail que le client a utilisé pour se connecter.
id_cartL'identifiant du panier actuellement affiché dans le bloc Panier.
checksumLe checksum Blowfish utilisé pour déterminer si le cookie a été modifié par un tiers.
Si ce checksum ne correspond pas, le client sera déconnecté et son cookie effacé.

Données stockées dans le cookie d'un employé/administrateur

 

TokenDescription
date_addL'heure et la date de création du cookie (au format YYYY-MM-DD HH:MM:SS).
id_langL'identifiant de la langue sélectionnée.
id_employeeL'identifiant de l'employé.
lastnameLe nom de famille de l'employé.
firstnameLe prénom de l'employé.
emailL'adresse e-mail que l'employé a utilisé pour se connecter.
profileL'identifiant du profil qui détermine les menus auxquels l'employé à accès.
passwdLe hash MD5 de _COOKIE_KEY_ dans config/settings.inc.php, et le mot de passe utilisé par l'employé pour se connecter.
checksum

Le checksum Blowfish utilisé pour déterminer si le cookie a été modifié par un tiers.
Si ce checksum ne correspond pas, le client sera déconnecté et son cookie effacé.

Les hooks

Les hooks sont une manière d'associer du code à des évènements PrestaShop spécifiques.

La plupart du temps, ils sont utilisés pour insérer du contenu dans une page.

Par exemple, la page d'accueil du thème par défaut de PrestaShop dispose des hooks suivants :

Hook nameDescription
displayHeaderAffiche le contenu dans l'en-tête de la page.
displayTopAffiche le contenu dans la zone supérieure de la page.
displayLeftColumnAffiche le contenu dans la colonne latérale gauche de la page.
displayHomeAffiche le contenu dans la zone centrale de la page.
displayRightColumnAffiche le contenu dans la colonne latérale droite de la page.
displayFooter

Affiche le contenu dans le pied de page de la page.

Les hooks peuvent également être utilisés pour lancer des actions spécifiques en fonction des circonstances (ex. : envoyer un e-mail au client).

Vous pouvez obtenir une liste complète des hooks disponibles dans PrestaShop 1.5 en lisant le chapitre "Les hooks de PrestaShop 1.5" de ce Guide du Développeur.

Utiliser les hooks

...au sein d'un contrôleur

Un hook peut facilement s'appeler depuis un contrôleur : vous devez simplement utiliser son nom dans la méthode hookExec() : Module::hookExec('NomDuHook');

Par exemple :

$this->context->smarty->assign('HOOK_LEFT_COLUMN', Module::hookExec('leftColumn'));

...au sein d'un module

Pour associer votre code à un hook, vous devez créer une méthode publique, commençant par le mot-clé "hook" suivi, au choix, de "display" ou "action", et le nom du hook que vous souhaitez utiliser.

Cette méthode doit ne recevoir qu'un argument : un tableau des informations contextuelles envoyées au hook.

public function hookDisplayNomDuHook($params)
{
    // Votre code.
}

Pour que votre module réponde à l'appel du hook, ce hook doit être enregistré dans PrestaShop. L'enregistrement de hook se fait avec la méthode registerHook(). L'enregistrement se fait généralement pendant l'installation du module.

public function install()
{
    return parent::install() && $this->registerHook('NomDuHook');
}

Créer votre propre hook

Vous pouvez créer de nouveaux hooks pour PrestaShop en ajoutant un enregistrement de hook comme vu précédemment. Il n'est plus nécessaire de réaliser une insertion en base de données comme pour les versions précédentes.