Modules

Edit this on Github

Here you'll find everything needed to start developing your first module, from structure to update routine & packaging.

What is a module ?

Modules are the core of SiberianCMS, they run frontend, backend, features & even more.

A module can be a single front page with new features or settings, or a complete feature for SiberianCMS to be used in your Mobile apps and managed in your App editor.

Here you can find a module skeleton to start with Siberian module Skeleton, Job

Modules are installed in the app/local/modules folder, for more information about the inheritance see this page module/core-inheritance

Structure

Folder structure

ModuleName
├─ Controller
│  └─ Default.php   /** If you need to override the default controller Classes */
├─ controllers
│  ├─ Backoffice
│  │  └─ ModuleNameController.php
│  └─ Mobile
│     └─ ModuleNameController.php
├─ features
│  └─ [...] // Core feature related files
├─ Form
├─ Model
├─ View
├─ resources
│  ├─ db
│  │  ├─ data
│  │  └─ schema
│  ├─ media 
│  │  └─ library
│  ├─ translations
│  │  ├─ default
│  │  │  └─ mymodule.po
│  │  ├─ en
│  │  └─ [...]
│  └─ design
└─ package.json

Basics

package.json

The package.json is used by the Installer to know the requirements, and routines to run during the installation/update process

{
  "name": "ModuleName",
  "description": "Module description",
  "type": "module",
  "version": "1.0",
  "dependencies": {
    "system": {
      "type": "SAE",
      "version": "4.16.0"
    },
    "modules": {
      "OtherModule": "2.1.0"
    }
  }
}

resources/db/schema

We use resources/db/schema/table_name.php to describe the table schema; below an example of a basic table.

This file(s) reflects your database at it's latest version, each time you update your module, the local schema is compared against this file and updating

Note: the schema only add fields if they are new or missing, fields are never removed.

<?php
/**
 * Schema definition for "table_name"
 */
$schemas = (!isset($schemas)) ? [] : $schemas;
$schemas["table_name"] = [
    "mytable_id" => [
        "type" => "int(11) unsigned",
        "auto_increment" => true,
        "primary" => true,
    ],
    "admin_id" => [
        "type" => "int(11) unsigned",
        "is_null" => true,
        "foreign_key" => [
            "table" => "admin",
            "column" => "admin_id",
            "name" => "FK_MY_MODULE_ADMIN_ID_ADMIN_AMIN_ID", // Must be unique!
            "on_update" => "CASCADE",
            "on_delete" => "CASCADE",
        ],   
    ],
    "name" => [
        "type" => "varchar(50)",
        "default" => "default_value",
        "index" => true,
    ],
    "created_at" => [
        "type" => "datetime",
    ],
    "updated_at" => [
        "type" => "datetime",
    ],
];

List of available options

Key Type Usage, values, comment
type String int(11) unsigned, varchar(50), datetime, etc ...
auto_increment Boolean
primary Boolean
is_null Boolean
default mixed
foreign_key Array() See the Foreign key options below
index Array() See the Index options below

Foreign Key options

Key Type Usage, values, comment
table String Referenced table
column String Referenced column in table
name String Foreign key name (ex: FK_TABLENAME_KEYNAME_REFTABLENAME_REFKEYNAME)
on_update String NO ACTION, SET NULL, CASCADE, RESTRICT
on_delete String NO ACTION, SET NULL, CASCADE, RESTRICT

Index options

Key Type Usage, values, comment
key_name String Index name, use the same on multiple columns for composite indexes
index_type String BTREE, HASH
is_null Boolean
is_unique Boolean

resources/db/data

This folder is used to insert default values when installing, or updating a Module.

Every php file in this folder will be executed when installing and/or updating the module, they should reflect the required data as the latest version.

Protected names are install.php & %VERSION%.php where %VERSION% is a semver string, you must NEVER use them.

Best practice:

features/modulename/feature.json

This file is the key for every In app features

{
    "name": "ModuleName",
    "code": "modulename",
    "version": "1.0.0",
    "category": "contact",
    "model": "ModuleName_Model_MainClass",
    "desktop_uri": "modulename/application/",
    "routes": [
        {
            "root": true,
            "state": "modulename-home",
            "controller": "ModuleNameHome",
            "url": "modulename/mobile_home/index/value_id/:value_id",
            "template": "l1/home.html",
            "cache": false
        },
        {
            "state": "modulename-view",
            "controller": "ModuleNameView",
            "url": "modulename/mobile_view/index/value_id/:value_id/item_id/:item_id",
            "template": "l1/view.html",
            "cache": false
        }
    ],
    "layouts": [
        1
    ],
    "icons": [
        "icons/modulename1-flat.png",
        "icons/modulename2-flat.png",
        "icons/modulename3-flat.png"
    ],
    "files": [
        "js/services/modulename.js",
        "js/factory/modulename.js",
        "js/controllers/modulename.js",
        "scss/modulename.scss"
    ],
    "compile": true,
    "use_account": true,
    "only_once": true,
    "load_on_start": false,
    "on_start_factory": null
}

List of options

Key Type Usage, values, comment
name String Your feature name
code String This code is unique to your Feature, Module
category String social, media, contact, monetization, customization, integration, events, misc
version String Not used here see package.json for the version
model String Default model class used in the editor
desktop_uri String Default controller class uri used in the editor
compile Boolean Leave true by default
use_account Boolean If the feature requires user to login set true
only_once Boolean Whether an app may have this feature only once, or more
load_on_start Boolean If the feature must be loaded right after the Application starts
on_start_factory String When load_on_start is set to true, Factory.onStart function will be executed, where Factory is the factory class name

Translations

Since version 4.16.5, siberian uses .po files, which are Gettext source files.

First create a new file named mymodule.po then place this file in the translations/default folder

If you want to ship your module with translations, place files in directories named with the locale code, example: english will be in translations/en/mymodule.po

Below as an example the contact.po file.

Be sure to not use existing filename which are located in SIBERIANCMS_ROOT/languages/base otherwise your translations won't work.

msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2019-03-28T15:24:21+01:00\n"
"PO-Revision-Date: 2019-03-28T15:24:21+01:00\n"
"Language: \n"

msgctxt "contact"
msgid "Cover image"
msgstr "Illustration"

msgctxt "contact"
msgid "Name"
msgstr "Nom"

#, mobile
msgctxt "contact"
msgid "Facebook"
msgstr "Facebook"

#, mobile
msgctxt "contact"
msgid "Twitter"
msgstr "Twitter"

#, mobile
msgctxt "contact"
msgid "Website"
msgstr "Site web"

msgctxt "contact"
msgid "String to translate"
msgstr "Phrase à traduire"

msgctxt "contact"
msgid "Hello, I'm %s"
msgstr "Bonjour je suis %s"

List of options

Key Type Usage, values, comment
#, mobile String Add this line if the string is translated inside the Mobile app
msgctxt String This is you context key, generally it's the module code
msgid String The original string, used as a key
msgstr String In default folder, msgstr = msgid, in translation files, msgstr is the translated sentence

How to translate

Inside editor & backoffice

<?php

// Simple translation
echo p__("context_key", "String to translate");

// Will render [en]"String to translate" , [fr]"Phrase à traduire", as per the .po file below

// sprintf translation
$userName = "John";
echo p__("context_key", "Hello, I'm %s", $userName);

// Will render [en]"Hello, I'm John", [fr]"Bonjour je suis John", as per the .po file below


Inside mobile apps, note key & context are swapped compared to the php function

// From the controllers, include $translate factory
$translate.instant("Hello, I'm %s", "context_key");
// From any template
<div class="item">
    {{ "Hello, I'm %s" | translate:"context_key" }}
</div>

Design

Everything you need to organize, style & interact with your Feature is located in the design folder

ModuleName
├─ [...]
├─ resources
│  └─ design
│     ├─ desktop
│     │  └─ flat
│     │     ├─ css
│     │     │  └─ modulename.css
│     │     ├─ js
│     │     │  └─ modulename.js
│     │     ├─ images
│     │     │  └─ customization
│     │     │     └─ layout
│     │     │        └─ modulename
│     │     │           ├─ layout-1.png
│     │     │           └─ layout-2.png
│     │     ├─ layout
│     │     │  └─ modulename.xml
│     │     └─ template
│     │        ├─ company
│     │        │  └─ [...]
│     │        └─ modulename
│     │           ├─ index.phtml
│     │           └─ application
│     │              ├─ edit.css
│     │              ├─ edit.js
│     │              └─ edit.phtml
│     └─ email
│        ├─ layout
│        └─ template
└─ [...]

modulename.xml example

This is the minimum required information in the default layout.xml, the file should be named as the module itself, lower-cased so job.xml in our case.

<?xml version="1.0" encoding="UTF-8"?>
<layout>
    <modulename_application_modulename_edit>
        <views>
            <content class="application_view_customization_features_edit_tabbareditor" 
                     template="application/customization/features/edit/tabbar_editor.phtml" />
            <content_editor class="core_view_default" 
                            template="job/application/edit.phtml" />
        </views>
    </modulename_application_modulename_edit>
</layout>

The section content is the default for the feature editor tab, you should not need to change it.

The section content_editor should point to the feature editor template

here: the short path modulename/application/edit.phtml referring to ModuleName/resources/design/template/modulename/application/edit.phtml

Cache

While developing a module you will have to manually rebuild what we call design cache

You can do so with the Siberian cli by running ./cli cache:design sae (replace sae with your edition, sae|mae|pe)

Note: when installing and/or updating a module with the regular zip package, the cache is automatically cleared for the users.

Background images

Editor side

In the file edit.phtml which handles the Editor UI for your module, you must add a background section like below.

<div class="background-images-import">
    <?php echo $this->importBackground($option_value); ?>
</div>

<script type="text/javascript">
$(document).ready(function () {
    // Bind form, only if the current form is not binded from a parent (this could bind it twice)
    bindForms('.background-images-import');
});
</script>

This is as easy as the code below, as everything is linked to the feature, and cropped/saved automatically for you.

Application / Ionic

Then to be sure your background images inside your Application pages, you must ensure all views & lists your and uses the new directive sb-page-background

<ion-view sb-page-background>
    <ion-content>
        {{ "My Awesome Content!" |translate:"module_name" }}
    </ion-content>
</ion-view>

As the old directive sb-background-image is deprecated/empty it will not affect anymore your features.

Package

When you are done with your module, it's time to pack !

zip everything at the root of your module and you're done !

ModuleName.zip
├─ Controller
├─ controllers
│  └─[...]
├─ features
├─ Model
├─ View
├─ resources
│  └─[...]
└─ package.json

Disable a Module

While in production modules can't be uninstalled, but can be disabled in Backoffice > Settings > Advanced > Modules