Installation et création d’un module Orchard – Partie 2

250px-Orchard_logo_1.svg

Cet article fait suite au précédent post qui avait pour but de vous initier au CMS Orchard. Vous pouvez le trouver ici

1. Architecture et déclaration du Module/Feature (widget)

1.1. Qu’est-ce qu’un module

Un module est un projet ASP.NET MVC pouvant être généré via un template (Code Generation) et :

  • Doit être dans le répertoire Modules d’Orchard pour être détecté – « Convention over configuration »
  • Peut contenir plusieurs widgets et/ou services communs à plusieurs modules
  • Peut être activé/désactivé via Admin ou CLI
  • Notion de dépendance entre modules – activation automatique des dépendances
  • Gestion de montée en version – Migrations

 

1.2. Création d’un nouveau module

Tout d’abord il faut savoir qu’Orchard intègre un terminal qui permet de gérer facilement les paramètres du CMS… [source]

Le terminal est situé ici : ~\MyOrchard\src\Orchard.Web\bin\Orchard.exe

Orchard_1.2

1.2.1.   Activer le module CodeGeneration

orchard> feature enable Orchard.CodeGeneration
Enabling features Orchard.CodeGeneration
Code Generation was enabled

 

1.2.2.   Créer son module

orchard> codegen module MyWidget /IncludeInSolution:false
Creating Module MyWidget
Module MyWidget created successfully

 

  • Répertoire MyWidget contenant le projet web du nouveau module ajouté dans MyOrchard\Modules

 

warning [/IncludeInSolution:false] => Ne pas inclure le projet « MyWidget » dans la solution car cette dernière comporte 77 projetsLa solution « Orchard » une fois compilée, ne nécessite plus de l'être à nouveau.

1.2.3.   Module manifest

Le fichier Module.txt est utilisé par Orchard pour détecter le module et permet d’activer des dépendances lors de l’activation. [source]

Name: MyWidget
AntiForgery: enabled
Author: Bertrand LOUVIER
Website: http://www.netapsys.fr
Version: 1.0
OrchardVersion: 1.0
Description: Description for the module
Features:
MyWidget:
Description: Description for feature MyWidget.
 Orchard_1.2.3

Dans le Dashboard d’Orchard vous devriez maintenant trouver votre module :

Orchard_1.2.3-2

 

2. Un peu d’administration Orchard

2.1. Content Definition

Dans la partie Content Definition du DashBoard vous devriez trouver :

Orchard_2.1

 

2.2. Création d’une page

2.2.1.   Création d’un nouveau content

Orchard_2.2.1

Ici vous verrez donc la page de garde d’Orchard présente à la racine du site. Vous pouvez donc créer un nouveau « Content ».

2 options :

  • Save : sauvegarde la page mais elle reste inaccessible
  • Publish now : Sauvegarde + Publication de la page. La page est disponible à l’adresse par défaut à savoir [@racine]/le_nom_de_la_page ; ou bien une adresse personnalisée dans l’option « permalink » (=> rien ne sert de mettre des majuscules, Orchard fera une passe pour tout remettre en minuscule)

Orchard_2.2.1-2

 

2.3. Les layers

Une couche (layer) est un groupe de widgets (avec leur configuration spécifique, qui comprend leur positionnement, zone, nom et ordre) qui est activé par une règle spécifique.

Par exemple, la couche TheHomePage est activée par une règle qui sélectionne spécifiquement la page d'accueil. La couche par défaut est toujours active, peu importe quelle page est affichée. La couche authentifiée est active uniquement lorsque les utilisateurs sont identifiés.

Lorsque plus d'une couche est active sur une page donnée, tous les widgets de toutes ces couches sont affichés au même moment. Orchard les ordonne entre eux en fonction de leur position.

Ajout d’un layer [Add a new Layer…]

Orchard_2.3

  • Options

Orchard_2.3-2

  • Les règles de base
Layer Rule Description
Default true Always displayed on every page.
Authenticated authenticated Displayed if the user is authenticated
Anonymous not authenticated Displayed if the user is anonymous.
Disabled false Not displayed. This layer is provided as way to save the configuration of widgets that are not currently displayed.
TheHomepage url("~/") Displayed on the home page.
MyWidgetDemo url("~/mywidgetdemo" Displayed the page we’ve just created.

[source]

 

2.4. Ajout de notre page dans un menu

Dans le menu navigation, ajoutez un « custom link »

Orchard_2.4

warning N’oubliez pas de cliquer sur « Save All » pour finir.

 

Orchard_2.4-2

 

2.5. Résultat

Affichage (vide pour le moment) de la page créée :

Orchard_2.5

 

3. Désinstallation du Module Widget

 

Une désinstallation complète implique de supprimer les éléments en base de données. En voici la procédure :

  • Lancez orchard.exe  > package uninstall Orchard.Module.MyModuleName
  • Puis ouvrez SQL Server Management Studio et supprimez les éléments associés à votre module de la façon suivante  :
SELECT * FROM MyOrchard_Orchard_Framework_ContentTypeRecord WHERE Name LIKE '%modulename%'
SELECT * FROM MyOrchard_Settings_ContentTypeDefinitionRecord WHERE Name LIKE '%modulename%'
SELECT * FROM MyOrchard_Settings_ContentPartDefinitionRecord WHERE Name LIKE '%modulename%'
SELECT * FROM MyOrchard_Settings_ShellFeatureRecord WHERE Name LIKE '%modulename%'
SELECT * FROM MyOrchard_Settings_ShellFeatureStateRecord WHERE Name LIKE '%modulename%'
SELECT * FROM MyOrchard_Orchard_Framework_DataMigrationRecord WHERE DataMigrationClass LIKE '%modulename%'

Supprimez les lignes correspondantes à votre module et tout sera comme neuf !

 

4. Injection de dépendance dans Orchard

Orchard utilise Autofac en interne comme DI Container

Il suffit d’implémenter l’interface Orchard.IDependency pour que la classe soit injectable dans une autre classe via son constructeur.

  • Il existe d’autres interfaces plus spécifiques

Voir la partie suivante

Une bonne pratique est de créer des classes sous le principe du SRP (Single Responsibility Principle)

  • Les classes ont chacune un but précis qui peut être réutilisable dans d’autres classes via injection

Si plusieurs classes implémentent une même interface (par exemple Iinjectable), vous pouvez injecter IEnumerable<IInjectable> (where IInjectable : IDependency) dans le constructeur pour récupérer toutes les instances en même temps.

 

4.1. Injection avancée

[source]

“The standard way of creating injectable dependencies in Orchard is to create an interface that derives from IDependency or one of its derived interfaces and then to implement that interface. On the consuming side, you can take a parameter of the interface type in your constructor. The application framework will discover all dependencies and will take care of instantiating and injecting instances as needed.

There are three different possible scopes for dependencies, and choosing one is done by deriving from the right interface:

–      Request: a dependency instance is created for each new HTTP request and is destroyed once the request has been processed. Use this by deriving your interface from IDependency. The object should be reasonably cheap to create.

–      Object: a new instance is created every single time an object takes a dependency on the interface. Instances are never shared. Use this by deriving from ITransientDependency. The objects must be extremely cheap to create.

–      Shell: only one instance is created per shell/tenant. Use this by deriving from ISingletonDependency. Only use this for objects that must maintain a common state for the lifetime of the shell.”

4.2. Création d’une dépendance

SOURCE :

namespace MyWidget.Services
{
    public class TextBuilder : ITextBuilder
    {
        public string Build(string data)
        {
            return "Here is the data you just sent me: " + data;
        }
    }
}

SOURCE :

using Orchard;

namespace MyWidget.Services
{
    public interface ITextBuilder : IDependency
    {
        string Build(string data);
    }
}

 

On déclare qu’une instance implémentant l’interface ITextBuilder peut être injectée dans le constructeur d’une autre classe.

4.3. Modification du controller

SOURCE :

using System.Web.Mvc;
using MyWidget.Services;

namespace MyWidget.Controllers
{
    public class WidgetController : Controller
    {
        private readonly ITextBuilder textBuilder;

        public WidgetController(ITextBuilder textBuilder)
        {
            this.textBuilder = textBuilder;
        }

        public ActionResult GetData(string data)
        {
            return Json(this.textBuilder.Build(data), JsonRequestBehavior.AllowGet);
        }
    }
}

Le contrôleur est dépendant d’une abstraction (interface ITextBuilder) et non d’une classe concrète: c’est le paterne d’injection de dépendances.

  • On peut ainsi remplacer l’implémentation de TextBuilder dès lors que la nouvelle classe implémente ITextBuilder.
  • Cette paterne facilite grandement l’écriture des tests unitaires.

 

4.4. Refactoring de la vue du widget

Pour l’instant la vue contient un élément html script, contenant du javascript, qui sera dupliqué dans le DOM lors du rendu de plusieurs instances de notre widget sur un layer.

  • Le mieux serait de bouger le JavaScript dans son propre fichier et de l’inclure à notre vue de la même façon que jQuery.
  • Orchard utilise la notion de Module Resource Manifest pour définir des ressources utilisables dans notre modules ou par d’autres modules (qui serait alors notre module en dépendance dans le module manifest).

 

4.5. Création du fichier JavaScript widget.js

SOURCE :

$(document).ready(function () {
    $('.MyWidget button').click(function () {
        var $widget = $(this).parent();
        var widgetId = $widget.attr('id');
        var controllerUrl = $widget.data('controller-url');

        var ajaxRequest = $.ajax({
            type: "get",
            dataType: "json",
            data: { data: $('#' + widgetId + ' input').val() },
            cache: false,
            url: controllerUrl
        });

        ajaxRequest.done(function (data, textStatus, jqXHR) {
            $('#' + widgetId + ' label').text(data);
        });
        ajaxRequest.fail(function (jqXHR, textStatus, errorThrown) {
            alert("Try again insert coins! Error:" + errorThrown);
        });
    });
});

 

On modifie légèrement le javascript pour que le setup du click handler se fasse sur une classe css au lieu d’un id.

On récupère le widget id via l’attribut id.

On récupère le controller url via un attribut data (standard html 5).

La convention est de le placer dans le répertoire Scripts du module.

 

4.6. Widget.css

SOURCE :

.MyWidget label{
	color: red;
}

 

On ajoute un peu de style au label.

  • La convention est de le placer dans le répertoire Styles du module

 

4.7. Création du ModuleRessouceManifest.cs

SOURCE :

using Orchard.UI.Resources;

namespace MyWidget
{
    public class ModuleResourceManifest : IResourceManifestProvider
    {
        public const string WidgetAlias = "MyWidget.Widget";

        public void BuildManifests(ResourceManifestBuilder builder)
        {
            var manifest = builder.Add();

            manifest.DefineScript(WidgetAlias).SetUrl("widget.min.js", "widget.js");

            manifest.DefineStyle(WidgetAlias).SetUrl("widget.min.css", "widget.css");
        }
    }
}

On définit un alias pour les fichiers javascript et CSS associés au widget.

On peut voir que widget.js est dépendant de jQuery (un alias défini dans le module resource manifest de  Orchard.jQuery).

  • La convention est de le placer à la racine du module.

 

4.8. Modification de la vue

SOURCE :

@using MyWidget
@{
    Script.Require(ModuleResourceManifest.WidgetAlias).AtHead();
    Style.Require(ModuleResourceManifest.WidgetAlias).AtHead();
}

<div id="@Model.Id"
     class="oc_new_module_widget"
     data-controller-url="@Url.Action("GetData", "Widget", new { area = "MyWidget" })">

    <input type="text" value="@T("Entrer une valeur")" />
    <button>@T("Envoyer la valeur")</button>
    <label>@T("Texte qui va être remplacé au click")</label>

</div>

On utilise les helpers d’Orchard (Script et Style) pour ajouter les scripts associés à l’alias « WidgetAlias » ainsi que leurs dépendances dans la DOM.

  • Puisque une dépendance à jQuery est définie pour l’alias dans le resource manifest, le fichier javascript de jquery sera ajouté au header du DOM avant l’ajout du fichier widget.js
  • « .AtHead() » spécifie que les fichier javascripts ou CSS doivent être ajoutés au header du DOM.

On ajoute une classe CSS« oc_new_module_widget » pour facilement retrouver tous les widgets dans le DOM

  • Utile pour faire un setup commun à tous les widgets du même type

On ajoute un attribut data (html 5 standard) pour stocker l’url vers le controller

 

4.9. TEST

RECOMPILEZ et rechargez le Pools d’applications

Orchard_4.9

5. Petit +

5.1. Minification des fichiers JavaScript

Installez l’extension Visual Studio Web Essentials [source]

 

5.2. Liens utiles

Orchard site
Orchard doc
Forums
Tutorials
Vidéos de présentation

Orchard Youtube channel(notamment Conférences 2013/2014)

.NET

Laisser un commentaire

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

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.