Formation Magento 2 : Chapitre 7 – Partie A

Si vous avez suivi correctement le TP de la partie précédente, vous avez mis en place la page de visualisation d’un département.
Nous avons ajouté dans le template de cette page la liste des offres d’emploi disponibles pour ce département.

Nous allons rendre cette affichage configurable dans le BO.
Si le paramètre est à Oui, on affichera la liste.
Sinon, on ne l’affichera pas.

Ajout de la configuration dans le BO

Cette configuration se passe dans Stores > Configuration :

link_store_config

Nous allons ajouter un onglet, qui sera composé d’un élement dans le menu.
Au clic sur cet élément, nous aurons une page de configuration avec un champ nous permettant d’activer ou non l’affichage de la liste dans la page département.

Créez le fichier :
app/code/Maxime/Jobs/etc/adminhtml/system.xml

Avec ce contenu :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <tab id="jobs" translate="label" sortOrder="1000">
            <label>Jobs</label>
        </tab>
        <section id="jobs" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
            <label>Jobs</label>
            <tab>jobs</tab>
            <resource>Maxime_Jobs::jobs</resource>
            <group id="department" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Department configuration</label>
                <field id="view_list" translate="label comment" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Show job list</label>
                    <comment>Show department's job list of the viewing department</comment>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
            </group>
       </section>
    </system>
</config>

– La balise « tab », permet comme son nom l’indique de créer le nouvel onglet. Le sortOrder permet d’ajuster sa position dans la liste. Vous pouvez essayer de le changer. N’hésitez pas à voir dans le core de Magento 2 quelles valeurs ont été mises pour les autres onglets afin de mettre le votre là où vous le souhaitez.
– La balise « section » permet d’ajouter un élément à l’onglet que nous venons de créer. On l’associe à l’onglet créé avec la balise tab. Le label défini le texte à afficher dans le menu. Et la resource permet de créer le droit nécessaire pour visualiser le menu.
– Dans cette section nous y ajoutons un « group », car une section peut en contenir plusieurs. Ici nous n’en avons qu’un et nous mettons comme label « Department Configuration ».
– Enfin dans les groups on y met notre « field », qui est notre champ de configuration. Ce champ est de type select, on définit son label et un commentaire pour le champ. Enfin on lui donne un source_model, qui permet de récupérer dynamiquement les options de notre select. Ici ce model natif de Magento 2 retourne un tableau « Yes/No ».

Il est aussi possible d’ajouter des éléments de type section / group / field respectivement dans des tabs / sections / groups natifs de Magento. Par exemple, il est possible d’ajouter un nouveau groupe avec de nouveaux champs dans la tab « Catalog » et dans la section « Catalog »

Gestion de la portée du champ

Vous remarquerez la présence des attributs : showInDefault, showInWebsite, showInStore
Cela permet d’annoncer la portée du champ.

En effet une boutique Magento de découpe en Website, Store et Store View.
store_admin

Nous aborderons ce point plus tard dans la formation, mais sachez que Magento peut contenir plusieurs websites, qui lui même peut contenir plusieurs stores, qui lui aussi peut contenir plusieurs store views.

Ici nous n’avons qu’un seul store view, mais comme notre champ doit être éditable d’un store view à un autre, nous mettons les valeurs de ces 3 attributs à 1.

Magento va procéder de la sorte lors de la récupération :
– Si le champ a une portée à la vue boutique (showInStore), et qu’une valeur est définie, on la prend
– Sinon on regarde si le champ a une portée au website (showInWebsite), et qu’une valeur est définie, on la prend
– Sinon on prend la valeur par défaut (showInDefault)

Ceci est un schéma pour notre champ, après ce comportement peut-tout à fait être changé à votre guise. Un champ peut par exemple n’être que visible à la vue boutique, mais pas ailleurs !

Pour modifier la portée de la configuration lorsque vous modifiez les valeurs manuellement dans le BO Magento, il faut modifier le scope avec ce menu :

scope_store

Pour ce tuto, nous allons rester en « Default Scope ».
Maintenant si vous actualisez la page du backoffice, notre menu… ne s’affichera pas !

Ajout de l’ACL

Il ne s’affiche pas car nous n’avons pas déclaré le droit (ACL) pour le voir.
Pour cela reprenez le fichier :
app/code/Maxime/Jobs/etc/acl.xml

Et modifiez son contenu par celui-ci :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
    <acl>
        <resources>
            <resource id="Magento_Backend::admin">
                <!-- Admin menu -->
                <resource id="Maxime_Jobs::job_head" title="Jobs" sortOrder="100" >
                    <resource id="Maxime_Jobs::department" title="Departments" sortOrder="10">
                        <resource id="Maxime_Jobs::department_save" title="Save Department" sortOrder="10" />
                        <resource id="Maxime_Jobs::department_delete" title="Delete Department" sortOrder="20" />
                    </resource>
                    <resource id="Maxime_Jobs::job" title="Jobs" sortOrder="20">
                        <resource id="Maxime_Jobs::job_save" title="Save Job" sortOrder="10" />
                        <resource id="Maxime_Jobs::job_delete" title="Delete Job" sortOrder="20" />
                    </resource>
                </resource>

                <!-- Admin config -->
                <resource id="Magento_Backend::stores">
                    <resource id="Magento_Backend::stores_settings">
                        <resource id="Magento_Config::config">
                            <resource id="Maxime_Jobs::jobs" title="Jobs Section" />
                        </resource>
                    </resource>
                </resource>
            </resource>
        </resources>
    </acl>
</config>

Vous pouvez voir que nous avons ajouté un nouveau noeud : Magento_Backend::stores
Les 3 premiers niveaux ajoutés sont natifs magento.
Le dernier noeud est celui de notre module : Maxime_Jobs::jobs
Cet « id » correspond au noeud « resource » que nous avons déclaré dans le fichier précédent.

Maintenant, si vous rechargez la page, notre menu est visible, et on peut accéder à l’édition de la configuration :

edit_job_config

Ne la sauvegardez pas, nous allons voir comment la mettre en place par défaut (pratique lors de vos déploiement !)

Ajout de la valeur par défaut de la config

Créez le fichier :
app/code/Maxime/Jobs/etc/config.xml

Et mettez ce contenu :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <jobs>
            <department>
                <view_list>1</view_list>
            </department>
        </jobs>
    </default>
</config>

– Le noeud default précise que la configuration saisie est à la portée « par défaut »
– Ensuite viennent les noeuds correspondants à la section, le group et le field déclarés dans le system.xml
– Dans le noeud du field, on met la valeur par défaut : 1 dans notre cas.

Si vous actualisez la page, le menu sera pré-sélectionné sur « Yes ».

On peut également définir des valeurs par défaut pour un website ou un store, voici un exemple avec les 3 portées :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <jobs>
            <department>
                <view_list>1</view_list>
            </department>
        </jobs>
    </default>

    <websites>
        <websitecode>
            <jobs>
                <department>
                    <view_list>1</view_list>
                </department>
            </jobs>
        </websitecode>
    </websites>

    <stores>
        <storeviewcode>
            <jobs>
                <department>
                    <view_list>1</view_list>
                </department>
            </jobs>
        </storeviewcode>
    </stores>
</config>

Le websitecode est à remplacer par le code du website en BO :
website_conf

Le storeviewcode est à remplacer par le code du store view en BO :
store_view_conf

Maintenant modifiez le paramètre que nous avons créé à « No » puis sauvegardez.
Vous remarquerez que notre valeur par défaut en XML n’est plus prise en compte.

En effet, si le champ à été modifié manuellement, la valeur est stockés dans la table :
core_config_data

Avec le champ « path » contenant le chemin de notre config :
bdd_conf

Il peut y avoir plusieurs lignes si le champ est sauvegardé sur différentes portées (scopes) : Default, website, store view.

bdd_socpes_values

Si vous supprimez la ligne, la valeur définie dans le config.xml sera reprise.

Du coup un question se pose :
Lors d’une mise en prod, si vous souhaitez modifier la config qui est sauvegardée en BDD, et non la config par défaut – dont on est pas sûr qu’elle sera utilisé si sa valeur est surchargée en BDD – comment faire ?

Mettre à jour la configuration avec Magento 2

Pour la mise à jour de données, que doit-on utiliser ?

LES SETUPS !

Modifiez la version de notre module :
app/code/Maxime/Jobs/etc/module.xml

Mettez l’attribut « setup_version » à « 1.0.0.3 »

Reprenez le setup UpgradeData :
app/code/Maxime/Jobs/Setup/UpgradeData.php

Changez le code de la classe par celui-ci :

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Maxime\Jobs\Setup;

use Maxime\Jobs\Model\Department;
use Maxime\Jobs\Model\Job;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Config\Model\ResourceModel\Config;

/**
 * @codeCoverageIgnore
 */
class UpgradeData implements UpgradeDataInterface
{

    protected $_department;
    protected $_job;

    protected $_resourceConfig;

    public function __construct(Department $department, Job $job, Config $resourceConfig){
        $this->_department = $department;
        $this->_job = $job;
        $this->_resourceConfig = $resourceConfig;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $installer = $setup;
        $installer->startSetup();

        // Action to do if module version is less than 1.0.0.1
        if (version_compare($context->getVersion(), '1.0.0.1') < 0) {
            $departments = [
                [
                    'name' => 'Marketing',
                    'description' => 'Sed cautela nimia in peiores haeserat plagas, ut narrabimus postea,
                aemulis consarcinantibus insidias graves apud Constantium, cetera medium principem sed
                siquid auribus eius huius modi quivis infudisset ignotus, acerbum et inplacabilem et in
                hoc causarum titulo dissimilem sui.'
                ],
                [
                    'name' => 'Technical Support',
                    'description' => 'Post hanc adclinis Libano monti Phoenice, regio plena gratiarum et
                venustatis, urbibus decorata magnis et pulchris; in quibus amoenitate celebritateque
                nominum Tyros excellit, Sidon et Berytus isdemque pares Emissa et Damascus saeculis condita
                priscis.'
                ],
                [
                    'name' => 'Human Resource',
                    'description' => 'Duplexque isdem diebus acciderat malum, quod et Theophilum insontem atrox
                interceperat casus, et Serenianus dignus exsecratione cunctorum, innoxius, modo non reclamante publico vigore,
                discessit.'
                ]
            ];

            /**
             * Insert departments
             */
            $departmentsIds = array();
            foreach ($departments as $data) {
                $department = $this->_department->setData($data)->save();
                $departmentsIds[] = $department->getId();
            }


            $jobs = [
                [
                    'title' => 'Sample Marketing Job 1',
                    'type' => 'CDI',
                    'location' => 'Paris, France',
                    'date'  => '2016-01-05',
                    'status' => $this->_job->getEnableStatus(),
                    'description' => 'Duplexque isdem diebus acciderat malum, quod et Theophilum insontem atrox
                interceperat casus, et Serenianus dignus exsecratione cunctorum, innoxius, modo non reclamante publico vigore,
                discessit.',
                    'department_id' => $departmentsIds[0]
                ],
                [
                    'title' => 'Sample Marketing Job 2',
                    'type' => 'CDI',
                    'location' => 'Paris, France',
                    'date'  => '2016-01-10',
                    'status' => $this->_job->getDisableStatus(),
                    'description' => 'Duplexque isdem diebus acciderat malum, quod et Theophilum insontem atrox
                interceperat casus, et Serenianus dignus exsecratione cunctorum, innoxius, modo non reclamante publico vigore,
                discessit.',
                    'department_id' => $departmentsIds[0]
                ],
                [
                    'title' => 'Sample Technical Support Job 1',
                    'type' => 'CDD',
                    'location' => 'Lille, France',
                    'date'  => '2016-02-01',
                    'status' => $this->_job->getEnableStatus(),
                    'description' => 'Duplexque isdem diebus acciderat malum, quod et Theophilum insontem atrox
                interceperat casus, et Serenianus dignus exsecratione cunctorum, innoxius, modo non reclamante publico vigore,
                discessit.',
                    'department_id' => $departmentsIds[1]
                ],
                [
                    'title' => 'Sample Human Resource Job 1',
                    'type' => 'CDI',
                    'location' => 'Paris, France',
                    'date'  => '2016-01-01',
                    'status' => $this->_job->getEnableStatus(),
                    'description' => 'Duplexque isdem diebus acciderat malum, quod et Theophilum insontem atrox
                interceperat casus, et Serenianus dignus exsecratione cunctorum, innoxius, modo non reclamante publico vigore,
                discessit.',
                    'department_id' => $departmentsIds[2]
                ]
            ];

            foreach ($jobs as $data) {
                $this->_job->setData($data)->save();
            }
        }


        // Action to do if module version is less than 1.0.0.3
        if (version_compare($context->getVersion(), '1.0.0.3') < 0) {
            $this->_resourceConfig->saveConfig('jobs/department/view_list', 1, 'default', 0);
        }

        $installer->endSetup();
    }
}

– Nous avons ajouté l’attribut $_resourceConfig à notre classe
– Via le construct on vient le setter avec l’objet que l’on souhaite
– Puis dans le upgrade, nous faisons un saveConfig pour mettre à jour la donnée

Le saveConfig comporte les paramètres :
– Chemin de la config
– Valeur de la config
– Portée de la valeur
– ID du store ou du website, 0 si scope est défault.

Il est possible de changer le scope :
– stores : Pour la store view
– websites : Pour le website

Dans ce cas le dernier paramètre du saveConfig sera l’ID de votre website ou de votre store view.

Lancez ensuite la commande d’upgrade à la racine de votre Magento :
./bin/magento setup:upgrade

Si nous allons en BDD nous aurons le résultat suivant :
config_saved_update

Voilà comment déployer facilement des configurations en BDD

Récupérer la valeur d’une configuration en front

Notre valeur est maintenant mise en place, nous allons nous en servir pour afficher ou non la liste des offres d’emploi.

Reprenez le fichier :
app/code/Maxime/Jobs/Block/Department/View.php

Et remplacez le avec ce contenu :

<?php
namespace Maxime\Jobs\Block\Department;
class View extends \Magento\Framework\View\Element\Template
{
    protected $_jobCollection = null;

    protected $_department;

    protected $_job;

    const LIST_JOBS_ENABLED = 'jobs/department/view_list';

    /**
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Maxime\Jobs\Model\Department $department
     * @param \Maxime\Jobs\Model\Job $job
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Maxime\Jobs\Model\Department $department,
        \Maxime\Jobs\Model\Job $job,
        array $data = []
    ) {
        $this->_department = $department;

        $this->_job = $job;

        parent::__construct(
            $context,
            $data
        );
    }

    /**
     * @return $this
     */
    protected function _prepareLayout()
    {
        parent::_prepareLayout();

        // Get department
        $department = $this->getLoadedDepartment();

        // Title is department's name
        $title = $department->getName();
        $description = __('Look at the jobs we have got for you');
        $keywords = __('job,hiring');

        $this->getLayout()->createBlock('Magento\Catalog\Block\Breadcrumbs');

        if ($breadcrumbsBlock = $this->getLayout()->getBlock('breadcrumbs')) {
            $breadcrumbsBlock->addCrumb(
                'jobs',
                [
                    'label' => __('We are hiring'),
                    'title' => __('We are hiring'),
                    'link' => $this->getListJobUrl() // No link for the last element
                ]
            );
            $breadcrumbsBlock->addCrumb(
                'job',
                [
                    'label' => $title,
                    'title' => $title,
                    'link' => false // No link for the last element
                ]
            );
        }

        $this->pageConfig->getTitle()->set($title);
        $this->pageConfig->setDescription($description);
        $this->pageConfig->setKeywords($keywords);


        $pageMainTitle = $this->getLayout()->getBlock('page.main.title');
        if ($pageMainTitle) {
            $pageMainTitle->setPageTitle($title);
        }

        return $this;
    }

    protected function _getDepartment()
    {
        if (!$this->_department->getId()) {
            // our model is already set in the construct
            // but I put this method to load in case the model is not loaded
            $entityId = $this->_request->getParam('id');
            $this->_department = $this->_department->load($entityId);
        }
        return $this->_department;
    }

    public function getLoadedDepartment()
    {
        return $this->_getDepartment();
    }

    public function getListJobUrl(){
        return $this->getUrl('jobs/job');
    }

    protected function _getJobsCollection(){
        if($this->_jobCollection === null && $this->_department->getId()){
            $jobCollection = $this->_job->getCollection()
                ->addFieldToFilter('department_id', $this->_department->getId())
                ->addStatusFilter($this->_job, $this->_department);
            $this->_jobCollection = $jobCollection;
        }
        return $this->_jobCollection;
    }

    public function getLoadedJobsCollection()
    {
        return $this->_getJobsCollection();
    }

    public function getJobUrl($job){
        if(!$job->getId()){
            return '#';
        }

        return $this->getUrl('jobs/job/view', ['id' => $job->getId()]);
    }

    public function getConfigListJobs() {
        return $this->_scopeConfig->getValue(
            self::LIST_JOBS_ENABLED,
            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
        );
    }
}

– Nous y ajoutons une méthode getConfigListJobs qui va récupérer la configuration que l’on a créé
– On lui défini une constante contenant le chemin de la configuration : LIST_JOBS_ENABLED

Maintenant il ne nous reste plus que le template à modifier :
app/code/Maxime/Jobs/view/frontend/templates/jobs/department/view.phtml

Remplacez le avec ce code :

<?php
$department = $this->getLoadedDepartment();

if($this->getConfigListJobs()){
    $jobCollection = $this->getLoadedJobsCollection();
    $iterator = 1;
    $total = $jobCollection->count();
} else {
    $total = 0;
}
?>
<?php if($department->getId()) : ?>
    <div class="department-view-wrapper">
        <div class="description"><?php echo $department->getDescription(); ?></div>
    </div>
    <?php if($total): ?>
        <h2><?php echo __('Jobs for this department'); ?></h2>
        <?php foreach($jobCollection AS $job): ?>
            <ol class="jobs list">
                <li class="item<?php echo ($iterator == 1) ? ' first' : ''; ?><?php echo ($total == $iterator) ? ' last' : ''; ?>">
                    <div class="title">
                        <a href="<?php echo $this->getJobUrl($job); ?>" title="<?php echo $job->getTitle(); ?>">
                            <?php echo $job->getTitle(); ?>
                        </a>
                    </div>
                    <div class="department_name">
                        <?php echo __('Department : '); ?>
                        <a href="<?php echo $this->getDepartmentUrl($job); ?>" title="<?php echo $job->getDepartmentName(); ?>">
                            <?php echo $job->getDepartmentName(); ?>
                        </a>
                    </div>
                    <div class="type"><?php echo $job->getType(); ?></div>
                    <div class="location"><?php echo $job->getLocation(); ?></div>
                    <div class="date"><?php echo $this->formatDate($job->getDate()); ?></div>
                    <div class="description"><?php echo $job->getDescription(); ?></div>
                </li>
            </ol>
            <?php $iterator++; ?>
        <?php endforeach; ?>
    <?php endif; ?>
<?php else : ?>
    <?php echo __('This department does not exist'); ?>
<?php endif; ?>

J’ai mis la condition en amont du template pour ne pas charger la collection de jobs si le paramètre est désactivé.

Maintenant la liste s’affichera ou non selon la configuration sauvegardée !

Dans le prochain article, nous allons voir comment créer une tâche cron 🙂

Continuer la formation
Revenir à la partie précédente
Mettre en place une configuration dans l’admin Magento 2
Share on FacebookTweet about this on TwitterShare on Google+Email this to someone
Taggé sur :        

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous utilisons des cookies afin de nous assurer de vous proposer la meilleure expérience sur ce site.
Ok