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 :
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.
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 :
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 :
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 :
Le storeviewcode est à remplacer par le code du store view en BO :
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 :
Il peut y avoir plusieurs lignes si le champ est sauvegardé sur différentes portées (scopes) : Default, website, store view.
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 :
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 🙂