Prestashop : Récupérer une configuration directement depuis un template

J’ai récemment rencontré la problématique de devoir utiliser des variables de configuration dans plusieurs templates non liés d’un site prestashop.
Plutôt que de surcharger l’ensemble des controllers impacté , je suis passé par la solution d’ajouter une nouvelle fonctionnalité directement dans Smarty.
Tout ça sans surcharge et via un module qui fonctionne sur PS 1.6 et 1.7

Le code est relativement simple :

class HhConfigTemplate extends Module
{
    public function __construct()
    {
        $this->author    = 'hhennes';
        $this->name      = 'hhconfigtemplate';
        $this->tab       = 'front_office_features';
        $this->version   = '0.1.0';
        $this->bootstrap = true;
        parent::__construct();
 
        $this->displayName = $this->l('HH Config Template');
        $this->description = $this->l('HH Config Template');
    }
 
    public function install()
    {
        if (!parent::install()
            || ! $this->registerHook('displayHeader')
           ) {
            return false;
        }
 
        return true;
    }
 
    public function uninstall()
    {
        return parent::uninstall();
    }
 
    /**
     * Hook Header Ajout d'une fonction dans smarty
     * @param $params
     */
    public function hookDisplayHeader($params)
    {
        //Enregistrement de la fonction "Configuration" dans Smarty qui appelle la fonction "getConfiguration" de cette classe
        smartyRegisterFunction($this->context->smarty, 'function', 'Configuration', array($this, 'getConfiguration'));
    }
 
    /**
     * Récupération d'une configuration
     * @param array $params
     * @return string
     */
    public static function getConfiguration($params)
    {
        if ( isset($params['key'])) {
            return Configuration::get($params['key'],
                isset($params['id_lang']) ? $params['id_lang'] : null,
                isset($params['id_shop_group']) ? $params['id_shop_group'] : null,
                isset($params['id_shop']) ? $params['id_shop'] : null
            );
        } else {
            return '';
        }
    }
}

Dans le template il suffit ensuite de mettre le code suivant par exemple pour récupérer la valeur :

{Configuration key="PS_PRODUCT_PICTURE_WIDTH"}

Vous pouvez également définir l’identifiant de la langue, du groupe de boutique, ou de la boutique, comme vous pouvez le voir dans la fonction getConfiguration() 😉

Pas de commentaires

Magento 2 : Ajouter des nouveaux attributs aux formulaires de création de compte

Cet article est une mise à jour d’un article précédent sur Magento 1 : Magento 1 : Ajouter des nouveaux attributs aux formulaires de création de compte

Nous allons voir comment rajouter un attribut client aux formulaire de création de compte et d’édition du compte client.
Celui-ci sera nommé « Sample »
(La partie checkout a été totalement réécrite dans magento 2 et fera l’objet d’un article ultérieur)

Pour cela nous allons créer un module Hhennes_Customer qui sera situé dans le dossier app/code/Hhennes/Customer.
La structure de notre module sera la suivante :

Structure module magento 2

Pour commencer comme pour tout module magento 2, il faut déclarer notre module en créant le fichier module.xml avec le contenu suivant dans le dossier /etc/ de notre module :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
 <module name="Hhennes_Customer" setup_version="0.1.0">
 <sequence>
 <module name="Mage_Customer"/> <!-- Dépendance au module Mage Customer -->
 </sequence>
 </module>
</config>

Ansi que le fichier registration.php à la racine avec le contenu suivant :

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Hhennes_Customer',
__DIR__
);

Pour installer notre module il faut le fichier « InstallData.php » dans un dossier « Setup » avec le contenu suivant

<!--?php namespace Hhennes\Customer\Setup; use Magento\Eav\Setup\EavSetup; use Magento\Eav\Setup\EavSetupFactory; use Magento\Eav\Model\Config; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Framework\Setup\ModuleContextInterface; class InstallData implements InstallDataInterface { protected $eavSetupFactory; protected $eavConfig; /** * Injection des dépendances à la création des * InstallData constructor * @param EavSetupFactory $eavSetupFactory * @param Config $eavConfig */ public function __construct( EavSetupFactory $eavSetupFactory , Config $eavConfig ) { $this->eavSetupFactory = $eavSetupFactory;
        $this->eavConfig = $eavConfig;
 
    }
 
	 /**
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
 
		//Création de l'attribut
        $eavSetup->addAttribute(
            \Magento\Customer\Model\Customer::ENTITY,
            'sample',
            [
                'type' => 'text',
                'label' => 'Sample attribute',
                'input' => 'text',
                'required'=> false,
                'default' => '',
                'sort_order' => 100,
                'system' => false,
                'position' => 100,
            ]
        );
 
		//Ajout de l'attribut aux formulaires clients
        $autoLoginAttribute = $this->eavConfig->getAttribute(\Magento\Customer\Model\Customer::ENTITY,'sample');
        $autoLoginAttribute->setData('used_in_forms',
            ['adminhtml_customer','customer_account_create','customer_account_edit']
        );
        $autoLoginAttribute->save();
    }
}
</pre>
<p>La partie back-office du module est à présent complète.<br ?-->
Il faut gérer l'affichage via la création de layouts et de templates et l'ensemble fonctionne quasiment comme dans Magento 1
Les pages de création et d'édition de compte comportent le code suivant :
<?php echo $block->getChildHtml('form_additional_info'); ?>

qui permet de rajouter des éléments supplémentaires.

Les controller concernés sont donc les suivants : customer_account_create customer_account_edit, nous allons donc créer les fichiers de layouts associés dans le dossier view/frontend/layout/

customer_account_create.xml avec le contenu suivant :

<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="form.additional.info">
<block class="Magento\Framework\View\Element\Template" name="form_additional_sample" template="Hhennes_Customer::form/sample_attribute.phtml"/>
</referenceContainer>
</body>
</page>

customer_account_edit.xml avec le contenu suivant :

<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="form.additional.info">
<block class="Magento\Customer\Block\Form\Edit" name="form_additional_sample" template="Hhennes_Customer::form/sample_attribute_edit.phtml"/>
</referenceContainer>
</body>
</page>

Notez bien la différence dans le premier cas le bloc est de type Magento\Framework\View\Element\Template alors que dans le second il est de type Magento\Customer\Block\Form\Edit

Pour finir il faut créer les fichier phtml dans le dossier view/frontend/template/form/sample_attribute.phtml

<?php
<div class="field">
<label class="label" for="sample"><span><?php /* @escapeNotVerified */ echo __('Sample Data') ?></span></label>
<input type="text" name="sample" title="<?php /* @escapeNotVerified */ echo __('Sample Data') ?>" class="input-text" autocomplete="off" value=""/>
</div>

et sample_attribute_edit.phtml

<?php
<div class="field">
<label class="label" for="sample"><span><?php /* @escapeNotVerified */ echo __('Sample Data') ?></span></label>
<input type="text" name="sample" title="<?php /* @escapeNotVerified */ echo __('Sample Data') ?>" class="input-text" autocomplete="off"
value="<?php echo $block->getCustomer()->getCustomAttribute('sample')->getValue() ?>"/>
</div>

Si tout va bien votre champ devrait être visible sur les pages de création et d’édition de compte.

Nouveau champs account

Note : Attention à date d’aujourd’hui dans le thème luma, les champs additionnels sont affichés à la suite du mot de passe, et il est nécessaire d’afficher celui-ci pour les voir.

Pas de commentaires

Module Catpcha pour prestashop 1.7

Je viens enfin de rendre compatible mon module de captcha eicaptcha avec la version 1.7 de prestashop 🙂
En raison des nombreux changements sur l’infrastructure j’ai quasiment procédé à une réécriture complète du module.

Celui-ci permets d’ajouter un captcha sur le formulaire de contact, et sur le formulaire de création de compte.
( La possibilité de le rajouter sur le formulaire de commentaire produit, et envoyer à un ami est supprimée pour l’instant )

Aperçu :

Formulaire de contact

Formulaire de création de compte

 

Récupération du module :

Via ssh : (recommandée )

git clone https://github.com/nenes25/eicaptcha.git -b 17
cd eicaptcha
composer install

Télécharger directement l’archive et l’envoyer en ftp : eicaptcha-17-beta

 

Changements techniques :

La gestion du formulaire de contact est géré dans prestashop 1.7 via un widget du module contactform.
Ce module surcharge donc le module contactform pour vérifier la complétion du captcha via un nouveau hook actionContactFormSubmitBefore.

context->controller->errors)) {
           parent::sendMessage();
       }
    }

Lors de la création de compte la gestion du hook natif actionSubmitAccountBefore a été changée.
De ce fait je n’ai pas pu l’utiliser et j’ai du surcharger également le fichier AuthController pour rajouter un nouveau hook personnalisé pour gérer la vérification du captcha.

 

Le module est fonctionnel, mais étant encore en beta, des changements et des optimisations sont encore possibles dans les prochains jours / semaines, n’hésitez pas donc pas à remonter des issues sur github.
https://github.com/nenes25/eicaptcha

Le code est disponible sur la branche 17 du dépôt.

Pas de commentaires

Prestashop : Gérer les dépendances de vos modules

Un petit article rapide qui présente une fonctionnalité qui existe depuis très longtemps  ( version 1.5  de prestashop ), la dépendances de modules.
Pour la mettre en place c’est tout simple.

Il vous suffit de rajouter la propriété « dependencies » dans la fonction construct de votre module.
Avec le nom du module tel que défini dans son fichier.

public function __construct()
    {
        $this->name = 'samplemodule';
        $this->tab = 'others';
        $this->version = '0.1.0';
        $this->author = 'hhennes';
        $this->bootstrap = true;
        parent::__construct();
 
        $this->displayName = $this->l('sample module');
        $this->description = $this->l('sample module');
 
        //Mettre ici le nom des modules dont dépends votre module
        $this->dependencies = array('blockcategories');
    }

Avant d’installer votre module Prestashop vérifiera automatiquement si le ou les modules requis sont bien installés.
Ceci permettra d’éviter les erreurs si votre module dépends d’information d’un autre module 🙂

Pas de commentaires

Prestashop : Ajouter des champs dans un formulaire d’administration

Depuis la version 1.6 de Prestashop, il est possible de rajouter rapidement et facilement le formulaire d’édition d’un objet dans l’administration via un module personnalisé.
Et ceci sans surcharge particulière en utilisant tout simplement les hooks existants.

Les objets éditables via cette méthodes sont notamment les suivants :

  • Catégories Produits
  • Adresses clients
  • Clients
  • … ( Presque tous les éléments admin sauf les produits sous Prestashop 1.7 )

Cette modification est réalisable via les hooks dynamiques suivants :

Dans la fonction renderForm de la classe AdminController

Hook::exec('action'.$this->controller_name.'FormModifier')

Dans la fonction postProcess de la classe AdminController via aux choix les hooks suivants :

//Avant l'exécution de l'action du controller admin
Hook::exec('actionAdmin'.ucfirst($this->action).'Before', array('controller' => $this));
Hook::exec('action'.get_class($this).ucfirst($this->action).'Before', array('controller' => $this));
 
 //Après l'exécution de l'action du controller admin
 Hook::exec('actionAdmin'.ucfirst($this->action).'After', array('controller' => $this, 'return' => $return));
 Hook::exec('action'.get_class($this).ucfirst($this->action).'After', array('controller' => $this, 'return' => $return));

Vu comme ça les hooks paraissent un peu barbares mais il n’en est rien :-), ce sera beaucoup plus parlant avec un exemple.

Exemple

Pour illustrer comment réaliser cela nous allons modifier le formulaire d’édition d’une catégorie produit.
Nous souhaitons rajouter plusieurs paramètres personnalisés puis les sauvegarder ensuite.

Le controller admin concerné pour les catégorie est AdminCategories.
Les hooks à implémenter seront donc les suivants :

  • actionAdminCategoriesFormModifier ($this->controller_name = AdminCategories  => Modification du formulaire )
  • actionAdminCategoriesControllerSaveBefore ( get_class($this) = AdminCategoriesController // $this->action = Save  => Exécutée avant l’action « Save du controller » )
  • actionAdminCategoriesControllerSaveAfter ( get_class($this) = AdminCategoriesController // $this->action = Save  => Exécutée avant l’action « Save du controller » )

Nous pourrions également utiliser les hooks généraux

  • actionAdminSaveBefore
  • actionAdminSaveAfter

Cependant je ne le recommande pas dans ce cas, car il sont exécutés lors des enregistrements de l’ensemble des entités en back office.
Dans notre cas il vaut mieux cibler plus précisément l’action.

Mise en oeuvre

Pour mettre en oeuvre ces concepts, nous allons créer un module Hh_SampleAdminForm

Voici la base ( déclaration / installation / désinstallation )

public function __construct()
    {
        $this->name = 'hh_sampleadminform';
        $this->tab = 'others';
        $this->version = '0.1.0';
        $this->author = 'hhennes';
        $this->bootstrap = true;
        parent::__construct();
 
        $this->displayName = $this->l('Sample Admin form');
        $this->description = $this->l('Sample module for admin form hooks');
        $this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
    }
 
    /**
     * Installation du module
     * @return bool
     */
    public function install()
    {
        if ( ! parent::install()
            || !$this->registerHook('actionAdminCategoriesControllerSaveAfter')
            || !$this->registerHook('actionAdminCategoriesFormModifier')
        ) {
            return false;
        }
 
        return true;
    }
 
    /**
     * Désinstallation du module
     * @return bool
     */
    public function uninstall()
    {
        return parent::uninstall();
    }

Affichage des nouveaux champs

Passons ensuite à l’affichage de nos nouveaux paramètres.
Il existe plusieurs possibilités :

  • Ajouter au formulaire existant
  • Créer un nouveau fieldset

Les codes reprennent l’utilisation d’un helperForm Standard.
Les paramètres passés à la fonction étant les suivants :

Hook::exec('action'.$this->controller_name.'FormModifier', array(
                'fields' => &$this->fields_form,
                'fields_value' => &$fields_value,
                'form_vars' => &$this->tpl_form_vars,
            ));

Attention au fait que les variables sont passées par référence ( signe & ) ce qui signifie qu’on peut les modifier directement dans le hook.

public function hookActionAdminCategoriesFormModifier($params)
    {
 
        //Ajout d'un champ au fieldset par défaut
        $params['fields'][0]['form']['input'][] =  array(
                        'type' => 'text',
                        'label' => $this->l('Custom field 1'),
                        'name' => $this->name.'_newfield1',
                    );
 
        //Création d'un nouveau fieldset
        $params['fields'][$this->name] = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('Sample Category Fieldset'),
                    'icon' => 'icon-tags',
                ),
                'description' => $this->l('New sample fieldset'),
                'input' => array(
                    array(
                        'type' => 'text',
                        'label' => $this->l('Custom field New Fieldset 1'),
                        'name' => $this->name.'_newfieldset1',
                    ),
                    array(
                        'type' => 'text',
                        'label' => $this->l('Custom field New Fieldset 2'),
                        'name' => $this->name.'_newfieldset2',
                    ),
                )
            )
        );
 
        //Pour remonter les valeurs des champs
        $params['fields_value'][$this->name.'_newfield1'] = 'Custom value 1';
        $params['fields_value'][$this->name.'_newfieldset1'] = 'Custom value fieldset 1';
        $params['fields_value'][$this->name.'_newfieldset2'] = 'Custom value fieldset 2';
    }

Le rendu est le suivant :

Nouveaux champs admin prestashop

Enregistrement des données

Il est temps à présent de passer à l’enregistrement des données.
Les hooks actionAdminCategoriesControllerSaveAfter et actionAdminCategoriesControllerSaveBefore étant redondants pour notre example je n’utiliserais que l’After
Pour le traitement des données nous n’auront qu’a récupérer les variables posts envoyées par le formulaire

 public function hookActionAdminCategoriesControllerSaveAfter($params)
    {
        //Récupération des variables custom soumises via le formulaire
        $custom1 = Tools::getValue($this->name.'_newfield1');
        $fiedlset1 = Tools::getValue($this->name.'_newfieldset1');
        $fiedlset2 = Tools::getValue($this->name.'_newfieldset2');
 
        //Faites ensuite le traitement souhaité
    }

Et voila nous avons rajouté facilement des informations à un formulaire admin sans faire de surcharge de classe 😉

 

12 commentaires

Fichier .gitignore pour site prestashop de production

Une petite ressource rapide, voici un fichier .gitignore optimisé pour gérer votre site Prestashop ( < 1.7 ) en mode projet

.idea/
/admin-dev/autoupgrade/backup
/admin-dev/backups
/admin-dev/export
/cache/
!/cache/index.php
!/cache/*/index.php
/config/xml/
!/config/xml/index.php
!/config/xml/.htaccess
!/config/xml/themes/index.php
/download
!/download/index.php
!/download/.htaccess
/img/
!/img/index.php
!/img/admin
!/img/jquery-ui
!/img/*/index.php
!/img/*/.htaccess
/log
!/log/index.php
!/log/.htaccess
/modules/*/config*.xml
/themes/*/cache
!/themes/*/cache/index.php
/tools/tcpdf/cache
!/tools/tcpdf/cache/index.php
/upload
!/upload/.htaccess

Il exclus les fichiers des dossiers liés aux contenus du site, mais conserve les fichiers index.php pour que les dossiers soient tout de même bien présent dans le dépot 🙂
Il faut également remplacer « admin-dev » par le chemin de votre admin
N’hésitez pas à soumettre vos optimisations.

Pas de commentaires

Prestashop 1.7 : Les widgets

La version 1.7 apporte une nouveauté intéressante dans le développement des modules : les widgets

Le principe est relativement simple et pratique, vous pouvez à n’importe quel endroit dans un template afficher le contenu de votre module via le code suivant.
Les exemples ci-dessous sont basé sur le module hh_samplemodule ( sur la branche 17 disponible sur github )

{widget name="hh_samplemodule"}

Vous pouvez également passer n’importe quel paramètre et le récupérer dans votre code

{widget name="hh_samplemodule" hook="top" var1="test" var2="test2" allvars="test"}

Comment l’implémenter dans votre module :

C’est très simple il suffit d’implémenter l’interface WidgetInterface via le code suivant :

class Hh_Samplemodule extends Module implements WidgetInterface

Puis de définir les fonctions renderWiget et getWidgetVariables via le code suivant par exemple

 /**
     * Affichage du widget
     * @param type $hookName
     * @param array $configuration : Ensemble des variables du widget
     * @return array
     */
    public function renderWidget($hookName = null, array $configuration = []) {
        //En fonction des variables du widget 
        //vous pouvez mettre en place des conditions d'affichage
        $this->smarty->assign($this->getWidgetVariables($hookName, $configuration));
        return $this->display(__FILE__, 'views/templates/widget/sample.tpl');
 
    }
 
    /**
     * Récupération des variables du widget
     * @param type $hookName
     * @param array $configuration
     * @return array
     */
    public function getWidgetVariables($hookName = null , array $configuration = [] ){
 
        return  [
            'test' => 'test_var',
            'test2'=> 'test_var2'
            ];
 
    }
Pas de commentaires

Magento : Configurer plusieurs boutiques sur une seule instance

Nativement la plateforme Magento permets de créer plusieurs sites webs totalement différents tout en utilisant le même code et le même dossier sur votre serveur et cela avec des urls différentes !

Il est cependant ensuite nécessaire de réaliser un mapping pour que Magento trouve quelle boutique charger avec quelle url

En partant des pré-requis suivants :

  • votre configuration apache ou nginx est déjà en place et que l’ensemble des noms de domaines pointent bien vers le même dossier
  • Nous allons tester 3 sites
    • www.shop.fr ( Site FR / Code du magasin magento : fr )
    • www.shop.de ( Site DE / Code du magasin magento : de )
    • www.shop.com ( Site EN / Code du magasin magento : en )
  • Les configurations des magasins sont en place dans magento

Nous allons voir ensemble les différentes possibilités qui existent pour réaliser cela.

Serveur Apache : fichier .htacess
Editer le fichier .htacess situé à la racine de magento et rajouter les lignes suivantes

SetEnv MAGE_RUN_TYPE store
SetEnvIf Host www\.shop\.fr MAGE_RUN_CODE=fr
SetEnvIf Host www\.shop\.de MAGE_RUN_CODE=de
SetEnvIf Host www\.shop\.com MAGE_RUN_CODE=en

Serveur nginx : fichier conf
Dans le fichier de configuration de votre vhost avant le noeud « server » rajouter la map suivante :

map $http_host $magecode {
       www.shop.fr fr;
       www.shop.de de;
       www.shop.com en;
    }

Puis dans la configuration des fichiers php , rajouter les éléments suivants :

location ~ \.php$ { ## Execute PHP scripts
        ...
        fastcgi_param  MAGE_RUN_CODE $magecode;
        fastcgi_param  MAGE_RUN_TYPE store;
        ..
    }

Toutes plateformes : fichier index.php
Avant l’appel du code

/* Store or website code */
$mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
 
/* Run store or run website */
$mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';

Ajouter les lignes suivantes :

$mageRunType = 'store';
switch($_SERVER['HTTP_HOST']) {
    case 'www.shop.fr':
        $mageRunCode = 'fr';
    break;
    case 'www.shop.de':
        $mageRunCode = 'de';
    break;
    case 'www.shop.com':
        $mageRunCode = 'en';
    break;
 
}

 

A vous de choisir parmi ces solutions celle qui correspond le mieux à vos besoins ou à vos accès sur l’hébergement 😉

Pas de commentaires

Détecter vos contenus mixtes avec les CSP

Je continue ma série d’articles sur le https avec une problématique assez chronophage qui est la détection des contenus mixtes sur une page https.
Avec les nouvelles sécurité des navigateurs si une image , une feuille de style ou un fichier javascript n’est pas appellé en https il ne sera pas interprété.

Et donc votre site ne sera pas affiché correctement.
La tâche d’identification de ces contenus est relativement longue et implique de passer sur toutes les pages de votre site si vous souhaitez le faire manuellement.
La bonne nouvelle est que ce n’est pas nécessaire 🙂

Avec les headers Content Security Policy ( CSP ) il est possible de détecter automatiquement les éléments bloquants.
Mon exemple est relativement basique, pour des informations complètes sur les CSP vous pouvez consulter le site suivant : https://content-security-policy.com/

Comme le nom ( header ) le défini, nous allons ajouter l’entête spécifique à notre document.

Content-Security-Policy-Report-Only "default-src https://your-site.com https: 'unsafe-inline';report-uri https://your-site.com/csp-https-report.php"

Celle-ci signifie que nous souhaitons avoir un rapport d’erreur sur l’url https://your-site.com/csp-https-report.php, dès qu’un média ( js/image/font/css ) n’est pas appelé en https

Cette entête peut être rajoutée de différente manière

Apache : dans le fichier htaccess

 Header set Content-Security-Policy-Report-Only "default-src https://your-site.com https: 'unsafe-inline';report-uri https://your-site.com/csp-https-report.php"

Nginx : dans votre fichier de conf

 add_header Content-Security-Policy-Report-Only "default-src https://your-site.com https: 'unsafe-inline';report-uri https://your-site.com/csp-https-report.php";

Directement dans votre document php

 header('Content-Security-Policy-Report-Only "default-src https://your-site.com https: 'unsafe-inline';report-uri https://your-site.com/csp-https-report.php";');

Voici à présent le contenu du fichier php qui va traiter ces retours.
Il ajoute tout simplement les erreurs dans un fichier de log, qui vous permettra de corriger les erreurs.

 <?php
$data = file_get_contents('php://input');
if ($data = json_decode($data, true)) {
   //On mets les résultats dans un fichiers de log
   $fp = fopen('https-errors.log','a+');
   fputs($fp,date("Y-m-d H:i:s").' Erreur https '.$data['csp-report']['blocked-uri'].' - source '.$data['csp-report']['document-uri']."\n");
   fclose($fp);
}
?>

En consultant ce fichier de log, vous pourrez donc identifier facilement les éléments qui posent problème ! 🙂

Pas de commentaires

Prestashop : Passer au déploiement continu

Vous mettez encore à jour vos sites via Ftp ? Vous perdez du temps à déployer votre code lors de chaque livraison de nouvelle fonctionnalité ?
Il est temps d’optimiser cela et de passer au déploiement continu !

Pour l’exemple nous allons voir comment mettre en place du déploiement continu sur un site prestashop de base ( version 1.6.1.x ).
L’exemple est assez basique, mais peut servir de base pour des stratégies de déploiement plus complexes.

Les prérequis étant les suivants :

  • site hébergé sur un hébergement avec accès SSH

Pour mettre en place ce processus nous allons utiliser les outils suivants :

  • git
  • gilab

Les étapes à réaliser seront les suivantes :

 1/ Création du projet sur gitlab

Pour commencer il faut s’inscrire sur gitlab.com.
Vous pouvez ensuite créer votre projet en mode public ou privé selon vos besoins.
Je ne détaille pas le processus de création qui est relativement aisé, nous reviendrons plus tard sur les configurations spécifiques.
Il est également possible d’héberger sa propre plateforme gitlab, mais ce n’est pas l’objet de cet article.

 2/ Installation de Prestashop en local

Notre site de développement local étant configuré, il est est temps de versionner le projet avec git.
Pour cela vous pouvez exécuter la commande suivante dans le dossier d’installation.

git init .

Pour éviter de versionner les fichiers non nécessaires, vous pouvez ensuite mettre en place le fichier .gitignore suivant :

 # Editors, tools and OS's
 
.buildpath
.project
.settings
.idea
.svn
.DS_Store
.sass-cache
config.codekit
*.sublime-project
*.sublime-workspace
nbproject
bower_components
composer.lock
 
# Cache, temp and personal files
 
cache/*
!cache/index.php
!cache/*/index.php
download/*
!download/index.php
!download/.htaccess
img/*
!img/admin/*
!img/admin/jquery-ui/*
!img/index.php
!img/*/index.php
log/*
!log/index.php
upload/*
!upload/index.php
!upload/.htaccess
admin-dev/autoupgrade/*
admin-dev/backups/*
admin-dev/import/*
 
themes/*/cache/*
admin-dev/themes/*/cache/*
 
# Config
 
config/settings.inc.php
config/settings.old.php
config/xml/*
!config/xml/themes/default.xml
 
# Themes, modules and overrides
admin-dev/themes/default/sass/ie.sass
admin-dev/themes/default/sass/print.sass
admin-dev/themes/default/screen.sass
admin-dev/themes/default/css/ie.css
admin-dev/themes/default/css/print.css
admin-dev/themes/default/css/screen.css
 
# Translations and emails templates
 
translations/*
!translations/index.php
!translations/fr/
mails/*
!mails/fr/
themes/default-bootstrap/lang/*
themes/default-bootstrap/modules/*/translations/*.php
themes/default-bootstrap/mails/*
!themes/default-bootstrap/mails/en/
themes/default-bootstrap/modules/*/mails/*
!themes/default-bootstrap/modules/*/mails/en
 
# MISC
 
*sitemap.xml
robots.txt

Puis ajouter l’ensemble des fichiers au dépôt

git add .
git commit -m "Creation du projet"

Votre versionning local est maintenant en place, vous pouvez déjà développer et historiser vos modifications.

Pour finaliser la configuration de git nous allons ajouter notre dépôt gitlab en dépôt distant

 git remote add origin https://youruser@gitlab.com/youruser/your-project.git

( Note : vous pouvez ajouter l’url en https ou en ssh selon vos préférences )

Poussez vos modifications sur le dépôt distant avant de passer à l’étape suivante :

 git push origin master

 

 3/ Installation initiale de prestashop distant

 

Après avoir créés le vhost et la base de données nécessaire à l’installation du projet.
– Rendez-vous dans le dossier ou vous souhaitez installer le projet et clonez le depuis gitlab

git clone https://youruser@gitlab.com/youruser/your-project.git

– Importer votre base de données sur le serveur en changeant bien les urls dans la table ps_shop_url
– Récupérer votre fichier local config/settings.inc.php et modifier le avec les informations du serveur

Votre serveur de prod est à présent installé, votre projet et gité.
Il est déjà possible de procéder à des mises à jour assez facilement manuellement, via des git push et des git pull sur les différents environnements.
C’est déjà bien mais cela nécessite encore de se connecter en ssh au serveur pour puller les changements.
Avec gitlab il est possible de faire tout ça de manière automatique 🙂

 

 4/ Configuration gitlab et serveur

 

– Mise en place d’une deploy key

Pour commencer il faut pouvoir puller les mises à jour du serveur sans avoir de mot de passe à saisir.
C’est possible avec gitlab avec le principe des deploys-keys qui se base sur une authentification ssh.

Pour commencer il faut donc générer une clé ssh (sans passphrase ) sur votre serveur
Via la commande suivante :

 ssh-keygen -t rsa -b 4096 -C "cle gitlab"

Laissez ensuite les options par défaut, et n’entrez pas de passphrase.
Récupérer le contenu de votre clé publique via la commande

cat ~/.ssh/id_rsa.pub

Dans gitlab rendez-vous dans « Settings / Repository »

Gitlab deploy key

Donner un titre à votre clé, puis copier la clé publique.
Vous pouvez ensuite à votre choix autoriser ou non l’accès en écriture au dépot.

Une fois votre clé ajoutée au dépot, vous pouvez changer l’url du remote pour prendre l’accès SSH

git remote set-url origin git@gitlab.com:youruser/your-project.git

Puis à tester un git pull pour vérifier que tout fonctionne sans saisie de mot de passe.
Ceci devrait donner un résultat comme cela

Gitlab ssh key

– Création des variables du projet

Il est temps à présent de configurer les variables nécessaires au déploiement continu de votre projet.
Pour cela rendez-vous dans « Settings » puis CI/CD Pipelines » , puis dans la partie « Secret Variables »

Nous allons définir les variables suivantes ( à adapter avec vos accès ) :

SSH_HOST : (hôte de connexion ssh ) ex: [email protected]
PROJECT_PATH : ( chemin du projet sur le serveur ) ex: /var/www/mywebsite/

SSH_KEY : ( clé ssh ) :
Pour cette variable c’est un peu particulier, il va falloir autoriser le runner de déploiement à se connecter à votre serveur via ssh pour lancer les commandes de mise à jour.
Il est donc nécessaire de créer une clé ssh ( sans passphrase ) permettant l’accès à votre serveur, et de coller la clé privée dans ce champ.

Il est possible d’utiliser des runners privés, mais dans notre cas nous utiliserons les runners accessibles à l’ensemble des projets gitlab.

La configuration est à présent terminée, il est temps de voir le plus intéressant, le fichier gitlab-ci 😉

 

 5/ Création du fichier .gitlab-ci.yml

 

Le fichier .gitlab-ci.yml est l’élément le plus important de votre déploiement continu, c’est lui qui va contenir les instructions de déploiement.
Je ne vais pas vous détailler tout son fonctionnement, ce serait trop long et la documentation officielle le fait très bien : https://docs.gitlab.com/ce/ci/yaml/README.html

Ce fichier doit être créé à la racine de votre projet, et vous pouvez y mettre le contenu suivant :

stages:
    - deploy
 
before_script:
 - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
 - eval $(ssh-agent -s)
 - mkdir -p ~/.ssh
 - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
 - ssh-add <(echo "$SSH_KEY")
 
 
deploy:production:
    stage: deploy
    only:
        - master
    tags:
        - gitlab-org
    script:
        - ssh $SSH_HOST -C " cd $PROJECT_PATH && git pull "

Voici bloc par bloc les explications de ce fichier

stages:
    - deploy

Définitions des étapes du déploiement continu, dans notre cas une seule étape : le déploiement.

before_script:
 - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
 - eval $(ssh-agent -s)
 - mkdir -p ~/.ssh
 - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
 - ssh-add <(echo "$SSH_KEY")

Code exécuté avant notre script, il vérifie si ssh est installé sur le runner,
puis insère notre clé privée issue de nos variables de configuration

deploy:production:
    stage: deploy
    only:
        - master
    tags:
        - gitlab-org
    script:
        - ssh $SSH_HOST -C " cd $PROJECT_PATH && git pull "

Définition de notre job de déploiement :
lors de l’étape deploy, uniquement dans la branche master.
Le runnder gitlab-org est appellé et se connecte à notre serveur pour faire un git pull dans le dossier du projet.

Commitez ce fichier et pousser le sur le dépôt gitlab.
Votre premier déploiement continu devrait fonctionner 🙂

Vous pouvez voir les résultats du déploiement dans l’onglet « Pipelines » de votre projet.

Pipeline gitlab

Si tout est vert, c’est que tout à bien fonctionné.
Sinon il faut cliquer sur le détails du pipeline pour voir les messages d’erreurs et rejouer le déploiement 😉

2 commentaires
Magento certified developper
Modules Prestashop
Compte Github