Remarques :

Le guide technique, ci-dessous, a été réalisé sous les versions de :
  • Sweelix : 3.1.0
  • Yii : 1.1.16
  • Php : 5.4

Les entités (node, content, tag, group, template) décrites ci-dessous héritent de l'ActiveRecord de Yii. On supposera que vous savez les manipuler. Si ce n'est pas le cas, veuillez-vous reporter à la documentation de Yii relative aux ActiveRecord.

Premier pas avec Sweelix

A la différence de Yii où l'on définit nos besoins pour construire une base de données, dans Sweelix on définit nos besoins afin de créer les nodes et contents du site.
Vous verrez ci-dessous comment créer un template et y associer son contrôleur.

Créer un template

La première étape consiste à insérer en base de données une entrée dans la table templates. On y définit le titre du template (le nom du gabarit affiché dans le back office), la définition du template (le nom du fichier) et le type du template (si c'est un template de type node ou content).
Une fois inséré, il faut coder le template. Les templates se situent dans le répertoire templates à la racine de votre projet. Si c'est la première fois que vous suivez ce tutoriel, créez le.
Un template est un fichier contenant un array qui contient un sous ensemble d'array ayant la structure suivante.

return [
    'propriete1' => [
        //définition des règles de validation de la propriété
        'model' => [
            'rules' => [
                ['yii\validators\StringValidator', 'max' => 100],       //règle de validation de la propriété
                ['required'],                                           //règle de validation de la propriété
            ],
        ],
        //représentation de l'élément dans le B.O
        'element' => [
            'labelOptions' => ['label' => 'titre de la propriété'],     //label affiché
            'type' => 'text',                                           //type CHtml de l'élément
            'class' => 'classic',                                       //classe par défaut
            'layout' => "{label}<br/>{element}<br/>
",     //structure du label et du champ dans le B.O
        ],
    ],
    'propriete2' => [
        ...
];

Dans un premier temps, il faut définir les règles de validations. Elles respectent les règles éditées par Yii à ceci près que chaque règle est définie dans un array unique.
Dans un second temps, il est possible de définir l'apparence dans le back office à l'aide des propriétés suivantes: labelOptions, type, class et layout.

LabelOptions (array)

Il définit les options CHtml du label qui sera affiché dans le back office.

Type (string)

Le type de l'élément CHtml :

  • text
  • dropdonwlist
  • radiolist
  • checkbox
  • textarea
  • asyncfile (permet de générer un champ d'upload)

Class (string)

Elles peuvent être chaînées :

  • classic
  • small
  • medium
  • long
  • wysiwygimage
  • wysiwyg (utilisée conjointement avec le type textarea permet de générer un champ textarea doté d'un wysiwyg)

Layout (string)

Il définit l'apparence de l'élément (label + champ) dans le back office en autorisant l'utilisation de CHtml.

Remarque : À un node ou content est associé un template.

Associer un contrôleur

Après avoir créé le template, il faut lui associer son contrôleur. Par défaut, il reprend le même nom que le fichier template et l'action par défaut est l'action Index.
Il est possible de les définir dans la table templates.
A la création d'un contrôleur, il faut déclarer la classe du contrôleur de Yii. En étendant le contrôleur de base de Yii avec celui de Sweelix, il devient possible de récupérer automatiquement les entités en cours grâce aux méthodes et propriétés suivantes :

//on étend le contrôleur Yii par défaut avec celui de Sweelix
use sweelix\yii2\ext\web\Controller;

Pour la suite de la documentation, on supposera que cette opération a été faite.

Récupérer un élément

Ci-dessous sont les propriétés et méthodes définies dans le contrôleur de Sweelix.

Propriétés Description
nodeId Retourne une string contenant l'id du node en cours
contentId Retourne une string contenant l'id du content en cours
tagId Retourne une string contenant l'id du tag en cours
groupId Retourne une string contenant l'id du group en cours

 

Méthodes Description
getNode() Retourne l'objet node en cours
getContent() Retourne l'objet content en cours
getTag() Retourne l'objet tag en cours
getGroup() Retourne l'objet group en cours

Exemples :

Les exemples ci-dessous sont valables pour les entités de Sweelix suivantes : node, content, tag, group.
Depuis un contrôleur :

//import de l'entité node
use sweelix\yii2\ext\db\entities\Node;

$node = node::findOne(1);                       //retourne un objet node

//utilisation de la méthode $this->getnode()
$node = $this->getNode();                       //retourne un objet node

//utilisation de la propriété $this->nodeId
$node = node::findOne($this->nodeId);           //retourne un objet node
Remarque : Ces méthodes sont lazy loadées, l'objet ne sera instancié que lors de l'appel à la fonction. C'est pourquoi si l'entité en cours est différente de la propriété ou de la méthode appelée, elles retourneront NULL.

Gestion des URL

Surcharger la configuration de Yii

Depuis le fichier de configuration web.php :

//app/config/web.php
...
'components' => [
    'urlManager' => [
        'class' => 'sweelix\yii2\ext\web\CmsUrlRule',
    ],
],
...

Faire un lien vers un node|content du CMS

Tout node ou content est accessible via une URL de la façon suivante :

//controllers/SingleArticleController.php

namespace app/controllers;

use sweelix\yii2\ext\web\Controller;

class SingleArticleController extends Controller
{
    public function actionIndex()
    {
        $node = $this->getNode();
        if ($node !== null) {
            return $this->render('index', [
                'node' => $node,
            ]);
        }
    }
}

Dans une vue :

<?php 
//views/single-article/index.php

echo CHtml::link($node->nodeTitle, $node->getUrl());

Uploader un fichier

Les templates utilisent PlUpload pour la gestion des images.
Il faut déclarer de la façon suivante l'upload :

return [
    'uploader' => [
        'model' => [
            'rules' => [
                ['yii\validators\FileValidator', 'extensions'=>'jpg, gif, png', 'maxFiles'=>1, 'maxSize'=>4*1024*1024],
            ],
            'targetPathAlias' => 'webroot.resources.contents.{contentId}',
            'targetUrl' => 'resources/contents/{contentId}',
        ],
        'element' => [
            'labelOptions' =>  ['label' => 'titre de mon champ'],
            'type'  => 'asyncfile',
            'config' => [
                'maxFileSize' => '4mb',
                'multiSelection' => false,          //true pour autoriser le multiupload
                'urlPreview' =>  [
                    'asyncPreview',
                    'targetPathAlias' => 'webroot.resources.contents.{contentId}',
                    'width' => 100,
                    'height' => 100,
                ],
            ],
            'layout' => "{label}<br/>{element}<br/>
",
            'class' => 'wysiwygimage',
        ],
    ],
];

ActiveQueryBuilder

ActiveQueryBuilder est une classe qui permet d'effectuer des requêtes plus complexes pour les éléments de Sweelix. Il est à Sweelix ce que QueryBuilder est à Yii.
A l'aide d'ActiveQueryBuilder il est possible de :

  • lister des éléments
  • construire une requête
  • modifier une requête

Il faut l'instancier avec l'entité de Sweelix que l'on souhaite requêter. Les entités valables sont :

  • author
  • content
  • group
  • language
  • meta
  • node
  • tag
  • template
//import du composant ActiveQueryBuilder
use sweelix\yii2\ext\db\ActiveQueryBuilder;
//import de la classe Node
use sweelix\yii2\ext\db\entities\Node;

$node = Node::findOne(1);
$activeQueryBuilder = new ActiveQueryBuilder('content');

Pour construire une requête, on dispose de la méthode filterBy :

$activeQueryBuilder->filterBy('nodeId', $node->nodeId);

A celle-ci s'ajoute la méthode published qui permet de filtrer l'élément en fonction de s'il est publié :

  • node : de son statut online
  • content : de son statut online et dans le cas où elle serait définie, de sa date de publication valide (contentStartDate < NOW() < contentEndDate)
$activeQueryBuilder->published();

Pour ordonner une liste d'éléments, il faut utiliser orderBy :

$activeQueryBuilder->orderBy('contentOrder');

Pour finir, on récupère le résultat comme on le ferait avec une query de Yii. La requête complète donne :

//import du composant ActiveQueryBuilder
use sweelix\yii2\ext\db\ActiveQueryBuilder;
//import de la classe Node
use sweelix\yii2\ext\db\entities\Node;

$node = Node::findOne(1);
$activeQueryBuilder = new ActiveQueryBuilder('content');
$activeQueryBuilder->filterBy('nodeId', $node->nodeId);
$activeQueryBuilder->published();
$activeQueryBuilder->orderBy('contentOrder');
$contents = $activeQueryBuilder->getQuery()->all();

Pour allez plus loin

Créer une requête plus complexe

Supposons qu'en plus de vouloir récupérer tous les contents d'un node, on veuille les filtrer avec les éléments d'une autre table shops.

//import du composant ActiveQueryBuilder
use sweelix\yii2\ext\db\ActiveQueryBuilder;
//import de la classe Node
use sweelix\yii2\ext\db\entities\Node;

$node = Node::findOne(1);
$activeQueryBuilder = new ActiveQueryBuilder('content');
$activeQueryBuilder->filterBy('nodId', $node->nodId);
$activeQueryBuilder->published();
$activeQueryBuilder->orderBy('contentOrder');
$activeQuery = $activeQueryBuilder->getQuery();
$activeQuery->leftJoin('shops s', 's.nodeId = :nodeId', [':nodeId' => $node->nodeId]);
$activeQuery->andWhere('contentStartDate < NOW()');
$contents = $activeQuery->all();

Créer un objet ActiveDataProvider

//import du composant ActiveDataProvider
use yii\data\ActiveDataProvider;
//import du composant ActiveQueryBuilder
use sweelix\yii2\ext\db\ActiveQueryBuilder;
//import de la classe Node
use sweelix\yii2\ext\db\entities\Node;

$node = Node::findOne(1);
$activeQueryBuilder = new ActiveQueryBuilder('content');
$activeQueryBuilder->filterBy('nodeId', $node->nodeId);
$activeQueryBuilder->published();
$activeQueryBuilder->orderBy('contentOrder');
$activeDataProvider = new ActiveDataProvider([
    'query' => $activeQueryBuilder->getQuery(),         //récupère la requête
    'pagination' => [
        'pageSize' => 20,
    ]
]);

Récupérer les descendants/enfants d'un node

Sweelix utilise la représentation intervallaire. Pour savoir si un node a des descendants, il faut trouver toutes les entités comprises entre son nodeLeftId et son nodeRightId.

//import du composant ActiveQueryBuilder
use sweelix\yii2\ext\db\ActiveQueryBuilder;

//on récupère l'entité en cours de type node
$node = $this->getNode();
//instanciation de la classe en lui passant comme argument l'entité qu'on veut requêter
$activeQueryBuilder = new ActiveQueryBuilder('node');
$activeQueryBuilder->filterBy('nodeLeftId', $node->nodeLeftId, '<');
$activeQueryBuilder->filterBy('nodeRightId', $node->nodeRightId, '>');
$nodes = $activeQueryBuilder->getQuery()->all();                   //retourne un array d'objets node


//instanciation de la classe en lui passant comme argument l'entité que l'on veut requêter
$activeQueryBuilder = new ActiveQueryBuilder('content');
$activeQueryBuilder->filterBy('nodeId', $node->nodeId, '=');
$contents = $activeQueryBuilder->getQuery()->all();                   //retourne un array d'objets content

Récupérer les parents d'une entité

Rappel : L'entité node peut avoir une infinité d'enfants alors que group ne peut en avoir qu'un seul.

Récupérer tous les parents d'une entité

Sur le principe de la représentation intervallaire on doit rechercher l'entité dont la propriété nodeLeftId est plus petite que le nodeLeftId de l'entité courante, et dont la propriété nodeRightId est plus grande que le nodeRightId de l'entité courante.

//import du composant ActiveQueryBuilder
use sweelix\yii2\ext\db\ActiveQueryBuilder;

$node = $this->getNode();
$activeQueryBuilder = new ActiveQueryBuilder('node');
$activeQueryBuilder->filterBy('nodeLeftId', $node->nodeLeftId, '<');
$activeQueryBuilder->filterBy('nodeRightId', $node->nodeRightId, '>');
$nodes = $activeQueryBuilder->getQuery()->all();            //retourne un array d'objets node

Récupérer le parent direct d'une entité

Un content ne peut exister qu'en tant qu'enfant d'un node, sa propriété statique nodeId ne peut donc être NULL.
Pour récupérer le parent d'un content :

//import de l'entité node
use sweelix\yii2\ext\db\entities
ode;
$content = $this->getContent();
$node = node::findOne($content->nodeId);                  //retourne un objet node

Il est possible d'ajouter un filtre supplémentaire sur le nodeLevel pour affiner la requête :

//instanciation de la classe en lui passant comme argument l'entité qu'on veut requêter
$activeQueryBuilder = new ActiveQueryBuilder('node');
$activeQueryBuilder->filterBy('nodeLeftId', $node->nodeLeftId, '<');
$activeQueryBuilder->filterBy('nodeRightId', $node->nodeRightId, '>');
//ajout du filtre par nodeLevel
$activeQueryBuilder->filterBy('nodeLevel', $node->nodeLevel-1, '=');
$node = $activeQueryBuilder->getQuery()->one();                   //retourne un objet node

Récupérer un node|content qui a un tag

Sweelix possède une table de liaison pour récupérer un node ou un content qui a un tag.

//import de l'entité nodeTag
use sweelix\yii2\ext\db\entities
odeTag;

$nodes = nodeTag::find()->where(['tagId' => $this->tagId])->all();                //retourne un array d'objet node

//import de l'entité contentTag
use sweelix\yii2\ext\db\entities\contentTag;

$contents = contentTag::find()->where(['tagId' => $this->tagId])->all();          //retourne un array d'objet content

Récupérer le group d'un tag

//import de l'entité Group
use sweelix\yii2\ext\db\entities\Group;

$tag = $this->getTag();

Une fois le tag récupéré, il est possible de récupérer le group de deux façons :

$tag = $tag->group;                                 //retourne un objet Group
$group = Group::findOne(tag->tagId);                //retourne un objet Group

Savoir si un node|content a un tag

//import des entités
use sweelix\yii2\ext\db\entities
ode;
use sweelix\yii2\ext\db\entities\content;

$node = node::findOne(1);
$node->hasTag($this->tagId);            //retourne un TRUE ou FALSE

$content = content::findOne(1);
$content->hasTag($this->groupId);        //retourne un TRUE ou FALSE

Savoir si un node|content a un group

//import des entités
use sweelix\yii2\ext\db\entities
ode;
use sweelix\yii2\ext\db\entities\content;

$node = node::findOne(1);
$node->hasGroup($this->groupId);           //retourne un TRUE ou FALSE

$content = content::findOne(1);
$content->hasGroup($this->groupId);        //retourne un TRUE ou FALSE

Migrations

Utiliser la commande PrepareMigration

Lancez l'invité de commande et se mettre à la racine du projet :

$ > cd myProject/

S'assurez que le répertoire export existe sinon le créer. Il doit être accessible en écriture :

$ > mkdir -m 644 ./export

Tapez la ligne de commande suivante :

$ > protected/yii preparemigration
  > Fichier généré

La commande génère un fichier mXXXXXX_XXXXXX_importCms.php, où X correspond au timestamp de la création du fichier au format yymmdd_hhmmss.
Cette migration est créée dans le répertoire export. Pour jouer la migration de ce fichier, il faut le déplacer dans le répertoire migrations.

$ > mv export/m150310_170641_importCms.php protected/migrations/
  > protected/yii 'migrate'
  > Yii Migration Tool v1.0 (based on Yii v1.1.14)

    Total 1 new migration to be applied:
        m150310_170641_importCms

    Apply the above migration? (yes|no) [no]:

Personnaliser le WYSIWYG

La première chose à faire est de configurer quel WYSIWYG sera utilisé.
Les éditeurs disponibles sont CKEditor et CLEditor.

Dans la configuration de l'application Yii, il faut placer dans le fichier web.php :

//config/web.php
'sweeft' => [
    'id' => 'sweeft',
    'class' => 'sweelix\yii2\admin\core\Module',     //
    'editor' => 'ckeditor',                          //Editeur utilisé
    'modules' => [
        'dashboard' => [
            'class' => 'sweelix\yii2\admin\dashboard\Module',
        ],
        'structure' => [
            'class' => 'sweelix\yii2\admin\structure\Module',
        ],
        'cloud' => [
            'class' => 'sweelix\yii2\admin\cloud\Module',
        ],
        'users' => [
            'class' => 'sweelix\yii2\admin\users\Module',
        ],
    ],
],

Ajout du champs texte dans le template

Pour permettre l'affichage d'un éditeur dans le back office de Sweelix, la configuration de l'attribut dans le template doit être précisée.
Voir la création d'un template.

//templates/article.php
return [
    'content' => [
        'model' => [
            'label' => 'content',
            'rules' => [
                ['safe'],
            ],
        ],
        'element' => [
            'labelOptions' =>  ['label' => 'Contenu'],
            'type' => 'textarea',                             //type du champ (ici un textarea)
            'class' => 'wysiwyg',                             //Ajout de la classe wysiwyg
        ],
    ],
];

Le menu de l'éditeur comporte des actions par défaut, elles suffisent dans la plupart des cas.

Les éditeurs peuvent tout de même être personalisés. Cette personnalisation est en fonction de l'éditeur utilisé.

Configuration du menu de CKEditor :

Afin de personnaliser l'éditeur, il faut ajouter le paramètre data-wysiwyg dans l'attribut configuré dans le template.

return [
    'content' => [
        'model' => [
            'label' => 'content',
            'rules' => [
                ['safe'],
            ],
        ],
        'element' => [
            'labelOptions' =>  ['label' => 'Contenu'],
            'type' => 'textarea',
            'class' => 'wysiwyg',

            'data-wysiwyg' => \CJSON::encode([
                'width' => '600',

                'toolbar' => [
                    ['name' => 'document', 'groups' => ['mode', 'document', 'doctools'], 'items' => array('Source', '-',/* 'Save', 'NewPage', 'Preview',*/ 'Print', '-', 'Templates']],
                    ['name' => 'clipboard', 'groups' => ['clipboard', 'undo'], 'items' => array('Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo']],
                    ['name' => 'forms', 'groups' => ['Title'), 'items' => ['title']],
                    '/',
                    ['name' => 'basicstyles', 'groups' => ['basicstyles', 'cleanup'), 'items' => array('Bold', 'Italic', 'Underline', 'Strike', '-', 'Format']],
                    ['name' => 'paragraph', 'groups' => ['list', 'indent', 'blocks', 'align'), 'items' => array('NumberedList', 'BulletedList',  '-', 'JustifyLeft', 'JustifyCenter']],
                    ['name' => 'links', 'items' => ['Link', 'Unlink', 'Anchor']],
                    ['name' => 'insert', 'items' => ['Inlineimage', 'Iframe', 'Table', 'HorizontalRule',/* 'Smiley',*/ 'SpecialChar',
                    '/',

                ],
            ])
        ],
    ],
];

Pour avoir plus d'options, voici le lien vers la configuration CKEditor

Configuration du menu CLEditor :

Comme pour la configuration du CKEditor, le CLEditor a besoin du paramètre data-wysiwyg pour y indiquer les actions du menu de l'éditeur.

return [
    'content' => [
        'model' => [
            'label' => 'content',
            'rules' => [
                ['safe'],
            ],
        ],
        'element' => [
            'labelOptions' =>  ['label' => 'Contenu'],
            'type' => 'textarea',
            'class' => 'wysiwyg',

            'data-wysiwyg' => \CJSON::encode([
                'controls' => 'bold italic underline strikethrough | highlight removeformat | inlineimage | bullets numbering | undo redo | link unlink | cut copy paste pastetext | print source'
            ]);
        ],
    ],
];

Pour avoir plus d'options, voici le lien vers la configuration CLEditor

Création d'un template HTML

La création d'un template CHtml permet de personnaliser le template dans le back office de Sweelix.

Pré-requis

Le fichier du template CHtml est lié au fichier PHP qui définit le template.
Les attributs ajoutés dans le fichier PHP sont accessibles dans le fichier CHtml.

Pour commencer, il faut créer un template au format PHP.
Voir la création d'un template

Créer un nouveau fichier

Une fois, le template PHP créé, nous allons créer un nouveau fichier portant le même nom que le template, mais ayant l'extension .tpl.php.

Dans notre exemple :
Le fichier du template PHP est : product.php
Le fichier du template CHtml sera : product.tpl.php

Les deux fichiers sont placés dans le même répertoire.

Contenus du template CHtml

Ce fichier se comporte comme une vue dans le framework Yii.
On peut utiliser les composants de Yii, de Sweelix ou créer ses propres composants.

Dans cet exemple, nous allons utiliser le composant Yii CHtml.

Dans le fichier, la variable qui porte le modèle de données se nomme $model.

Avec cette variable, nous avons accès à tous les attributs de l'élément Sweelix (un node, un content, un group ou un tag) pour lequel le template a été créé, ainsi que, les attributs ajoutés dans le fichier PHP qui définit le template.

<div>
    <?php echo CHtml::activeLabel($model, 'newsDate', ['label' => 'Date (mm/jj/aaaa)']); ?>
    <br/>
    <?php echo CHtml::activeTextField($model, 'newsDate', ['class' => 'classic calendar', 'id' => 'newsDate']); ?>
</div>
<div>
    <h3>Visuel de l'article</h3>
    <?php echo CHtml::activeLabel($model, 'picture', ['label' => 'Image']); ?>
    <br/>
    <?php echo CHtml::activeAsyncFileUpload($model, 'picture', ['content' => 'Parcourir...', 'config' => $config]); ?>
</div>
<div>
    <h3>Contenu de l'article</h3>
    <?php echo CHtml::activeLabel($model, 'presentation', ['label' => 'presentation']); ?>
    <br/>
    <?php echo CHtml::activeTextArea($model, 'presentation', ['class' => 'wysiwyg', 'style' => 'width:100%', 'data-wysiwyg' => Enum::getCkEditorConfig()]); ?>
</div>