ZnetDK 4 Mobile

Code Snippets

Code snippets for extending the capabilities of your ZnetDK for Mobile Starter App

Displaying meetings with FullCalendar

DESCRIPTION Integrating the popular Javascript Calendar FullCalendar into the Starter Web Application.

PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Only four steps are required:
  • Step 1: Coding the view in charge of displaying the calendar,
  • Step 2: Coding the controller that supplies the events to display on the calendar,
  • Step 3: Loading the CSS and JS scripts of FullCalendar from CDN hosting,
  • Step 4: Adding a new item to the App's navigation menu.

DEMONSTRATION See live demo....

Step 1 - Coding the view meetings.php

The view meetings.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

  • <div id="my-calendar"/> is the HTML container of the calendar.
  • The extra style applied to the fc-toolbar-title class is for optimization purpose on mobile small screens.
  • The calOptions JS variable defines the FullCalendar standard options applied to the calendar (see JS Calendar documentation).
  • The fetchEvents() JS function requests through the AJAX API the meetings to display on the calendar.
  • The jQuery event handler on ZnetDK for Mobile afterviewdisplay events instantiates the calendar when the view is displayed for the first time.
  • The App's header is hidden automatically when the view content is scrolled by calling the znetdkMobile.header.events.handleHideHeaderOnScroll(true) method.

View meetings.php

<div id="my-calendar" class="w3-stretch w3-margin-top"></div>
<style>
#my-calendar .fc-toolbar-title {
    font-size: 18px;
}
</style>
<script>
console.log('meetings.php');
var myCalendar = null,
    calOptions = {
        initialView: 'timeGridWeek',
        weekends: false,
        slotMinTime: '06:00:00',
        slotMaxTime: '22:00:00',
        height: 'auto',
        stickyHeaderDates: true,
        events: fetchEvents
    };

function fetchEvents(fetchInfo, successCallback) {
    znetdkMobile.ajax.request({
        controller: 'meetingctrl',
        action: 'fetch',
        data: {start:fetchInfo.startStr, end:fetchInfo.endStr},
        callback: function (response) {
            successCallback(response);
            // Footer position is adjusted
            znetdkMobile.footer.adjustPosition();
        }
    });
}

/* Once the view is displayed ... */
$('body').on('afterviewdisplay', function (event, viewId) {
    if (viewId === 'meetings') {
        if (myCalendar === null) { // Calendar is not yet instantiated
            myCalendar = new FullCalendar.Calendar($('#my-calendar').get(0), calOptions);
            myCalendar.render();
            // The footer position is adjusted
            znetdkMobile.footer.adjustPosition();
        } else { // Calendar already exists as object
            // The events are refreshed
            myCalendar.refetchEvents();
        }
        znetdkMobile.header.events.handleHideHeaderOnScroll(true);
    } else {
        znetdkMobile.header.events.handleHideHeaderOnScroll(false);
    }
});

</script>

Step 2 - Coding the controller meetingctrl.php

The controller meetingctrl.php must be installed into the INSTALL_DIR/applications/default/app/controller/ folder.

  • The action_fetch() method is called by the meetings.php view through the AJAX API (see the fetchEvents() JS function in the view).
  • The start and end POST parameters sent in the AJAX requests indicate the begin and end date of the week to display on the calendar.
  • Two meeting events are returned by the controller's action in JSON format (the PHP array is automatically tansformed in JSON by the ZnetDK \Response object).

Controller meetingctrl.php

<?php
namespace app\controller;

class 
MeetingCtrl extends \AppController {
    static protected function 
action_fetch() {
        
$request = new \Request();
        
$start = new \DateTime($request->start);
        
$end = new \DateTime($request->end);
        
$events = [];
        
$events[] = [
            
'title' => 'All Day Event',
            
'start' => $start->format('Y-m-d'),
            
'end' => $end->format('Y-m-d')
        ];
        
$events[] = [
            
'title' => 'Meeting',
            
'start' => $start->format('Y-m-d') . ' 10:00',
            
'end' => $start->format('Y-m-d') . ' 12:00'
        
];

        
$response = new \Response();
        
$response->setResponse($events);
        return 
$response;
    }
}

Step 3 - Loading the CSS and JS FullCalendar scripts

The FullCalendar CSS and JavaScript libraries are automatically loaded by specifying into the config.php of the Web App, the matching url on the CDN hosting (see Settings | App extra CSS and JS libraries).

The config.php script is located into the INSTALL_DIR/applications/default/app/ folder.

The two lines below can be inserted anywhere in the config.php script.

Script config.php

define('CFG_APP_JS', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.5.0/main.min.js');
define('CFG_APPLICATION_CSS', 'https://cdn.jsdelivr.net/npm/fullcalendar@5.5.0/main.min.css');

Step 4 - Adding a "Meetings" item to the navigation menu

Finally, to give users access to the meetings.php calendar view, a menu item definition is added into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, 'meetings', 'My meetings', 'fa-calendar');
    
    // ... Here, other menu items...
    
}

Displaying a bar chart with ChartJS

DESCRIPTION Integrating ChartJS into the Starter Web Application and display of bar chart.

PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Only four steps are required:
  • Step 1: Coding the view in charge of displaying the bar chart,
  • Step 2: Coding the controller that supplies data to the bar chart,
  • Step 3: Loading the JS script of ChartJS from CDN hosting,
  • Step 4: Adding a new item to the App's navigation menu.

DEMONSTRATION See live demo....

Step 1 - Coding the view mybarchart.php

The view mybarchart.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

  • <canvas id="my-bar-chart"/> is the HTML container of the bar chart.
  • The loadChartData() JS function requests through the AJAX API the data of the bar chart.
  • The showChart() JS function instantiates the bar chart on first call and updates its data if it is already instantiated (see ChartJS documentation).
  • The jQuery event handler on ZnetDK for Mobile afterviewdisplay events is triggered each time the view mybarchart.php is displayed.

View mybarchart.php

<div class="w3-padding-64">
    <canvas id="my-bar-chart" width="400" height="400"></canvas>
</div>
<script>
console.log('mybarchart.php');
var ctx = document.getElementById('my-bar-chart').getContext('2d'),
    myChart = null;

/* Once the view is displayed ... */
$('body').on('afterviewdisplay', function (event, viewId) {
    if (viewId === 'mybarchart') {
        loadChartData();
    }
});

function loadChartData() {
    znetdkMobile.ajax.request({
        controller: 'barchartctrl',
        action: 'data',
        callback: function (response) {
            showChart(response);
            // Footer position is adjusted
            znetdkMobile.footer.adjustPosition();
        }
    });
}

function showChart(chartData) {
    if (myChart === null) { // First display
        myChart = new Chart(ctx, {
            type: 'bar',
            data: chartData,
            options: {
                scales: {
                    yAxes: [{
                        ticks: {
                            beginAtZero: true
                        }
                    }]
                }
            }
        });
    } else {
        myChart.data = chartData;
        myChart.update();
    }
}
</script>

Step 2 - Coding the controller barchartctrl.php

The controller barchartctrl.php must be installed into the INSTALL_DIR/applications/default/app/controller/ folder.

  • The action_data() method is called by the mybarchart.php view through the AJAX API (see the loadChartData() JS function in the view).
  • Data to display by the chart data are returned by the controller's action in JSON format (the PHP array is automatically tansformed in JSON by the ZnetDK \Response object).

Controller barchartctrl.php

<?php
namespace app\controller;

class 
BarChartCtrl extends \AppController {
    static protected function 
action_data() {
        
$data = [
            
labels => ["January","February","March","April","May","June","July"],
            
datasets => [[
                
label => 'My Dataset',
                
data => [65,59,80,81,56,55,40],
                
fill => false,
                
backgroundColor => ["rgba(255, 99, 132, 0.2)""rgba(255, 159, 64, 0.2)",
                    
"rgba(255, 205, 86, 0.2)""rgba(75, 192, 192, 0.2)",
                    
"rgba(54, 162, 235, 0.2)","rgba(153, 102, 255, 0.2)",
                    
"rgba(201, 203, 207, 0.2)"],
                
borderColor => ["rgb(255, 99, 132)""rgb(255, 159, 64)""rgb(255, 205, 86)",
                    
"rgb(75, 192, 192)","rgb(54, 162, 235)",
                    
"rgb(153, 102, 255)","rgb(201, 203, 207)"],
                
borderWidth => 1
            
]]
        ];
        
$response = new \Response();
        
$response->setResponse($data);
        return 
$response;
    }
}

Step 3 - Loading the ChartJS library

The ChartJS library is automatically loaded by specifying into the config.php of the Web App, the matching url on the CDN hosting (see Settings | App extra CSS and JS libraries).

The config.php script is located into the INSTALL_DIR/applications/default/app/ folder.

The line below can be inserted anywhere in the config.php script.

Script config.php

define('CFG_APP_JS', 'https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js');

Step 4 - Adding "My bar chart" item to the navigation menu

Finally, to give users access to the mybarchart.php bar chart view, a menu item definition is added into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, 'mybarchart', 'My bar chart', 'fa-bar-chart');
    
    // ... Here, other menu items...
    
}

Reading barcodes with QuaggaJS

DESCRIPTION Decoding EAN-13 barcode with QuaggaJS and the Starter Web Application.

PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Only three steps are required:
  • Step 1: Coding the view in charge of decoding barcodes,
  • Step 2: Loading the JS script of QuaggaJS from CDN hosting,
  • Step 3: Adding a new item to the App's navigation menu.

DEMONSTRATION See live demo....

Step 1 - Coding the view mybarcodeview.php

The view mybarcodeview.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

  • <form id="barcode-form"/> is the HTML form that embeds the Start and Stop buttons of the camera and that displays the barcode number once decoded.
  • <div id="live-camera"/> is the HTML container of the camera stream.
  • By clicking on the Start button, the Quagga.init() function initializes the Quagga library for the configuration set through the liveStreamConfig variable and then requests for camera access. Next, if no error is detected, the video-stream is started by a call to the startScan() JS function (that finally calls Quagga.start()).
  • By clicking on the Stop button, the camera is disconnected through a call to the stopScan() JS function (in turn by a call to Quagga.stop()).
  • The Quagga.onProcessed() method registers a callback function that draws frames around possible barcodes on the video-stream.
  • Finally, the Quagga.onDetected() method registers the function called once a barcode has been decoded. The barcode number is displayed in the Decoded barcode field and the camera-stream is stopped.

View mybarcodeview.php

<form id="barcode-form" class="w3-padding-16">
    <label>Decoded barcode</label><br>
    <input class="w3-input w3-border" type="search" placeholder="Click on Start for scanning a barcode..." readonly><br>
    <button class="start w3-btn w3-green" type="button"><i class="fa fa-play"></i> Start</button>
    <button class="stop w3-btn w3-red w3-hide" type="button"><i class="fa fa-stop"></i> Stop</button>
</form>
<div id="live-camera" class="w3-hide">
</div>
<style>
    #live-camera {
        position: relative;
        width: 100%;
        height: auto;
        overflow: hidden;
        text-align: center;}
    #live-camera > canvas,
    #live-camera > video {
        max-width: 100%;
        width: 100%;
    }
    #live-camera > canvas.drawing,
    #live-camera > canvas.drawingBuffer {
        position: absolute;
        left: 0; top: 0;
    }
</style>
<script>
    console.log('mybarcodeview.php');
    var liveStreamConfig = {
        inputStream: {
            type: "LiveStream",
            target: '#live-camera',
            constraints: {
                width: {min: 640},
                height: {min: 480},
                aspectRatio: {min: 1, max: 100},
                facingMode: "environment" // or "user" for the front camera
            }
        },
        locator: {
            patchSize: "medium",
            halfSample: true
        },
        numOfWorkers: (navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4),
        decoder: {
            "readers": [
                {"format": "ean_reader", "config": {}}
            ]
        },
        locate: true
    };
    // The fallback to the file API requires a different inputStream option.
    // The rest is the same
    var fileConfig = $.extend(
            {},
            liveStreamConfig,
            {
                inputStream: {
                    size: 800
                }
            }
    );
    // Start the live stream scanner when the start button is clicked on
    $('#barcode-form button.start').on('click', function () {
        Quagga.init(
                liveStreamConfig,
                function (err) {
                    if (err) {
                        znetdkMobile.messages.add('error', err.name, err.message);
                        stopScan();
                        return;
                    }
                    startScan();
                }
        );
    });
    
    $('#barcode-form button.stop').on('click', function () {
        stopScan();
    });

    // Make sure, QuaggaJS draws frames an lines around possible
    // barcodes on the live stream
    Quagga.onProcessed(function (result) {
        var drawingCtx = Quagga.canvas.ctx.overlay,
                drawingCanvas = Quagga.canvas.dom.overlay;

        if (result) {
            if (result.boxes) {
                drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")),
                    parseInt(drawingCanvas.getAttribute("height")));
                result.boxes.filter(function (box) {
                    return box !== result.box;
                }).forEach(function (box) {
                    Quagga.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: "green", lineWidth: 2});
                });
            }

            if (result.box) {
                Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: "#00F", lineWidth: 2});
            }

            if (result.codeResult && result.codeResult.code) {
                Quagga.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3});
            }
        }
    });

    // Once a barcode had been read successfully, stop quagga
    Quagga.onDetected(function (result) {
        if (result.codeResult.code) {
            $('#barcode-form input').val(result.codeResult.code);
            $('#barcode-form input').addClass('w3-pale-green');
            stopScan();
            znetdkMobile.messages.add('info', 'Information', 'Barcode decoded successfully.');
        }
    });
    
    function startScan() {
        $('#barcode-form input').removeClass('w3-pale-green');
        $('#barcode-form input').val('');
        Quagga.start();
        $('#live-camera').removeClass('w3-hide');
        $('#barcode-form button.start').addClass('w3-hide');
        $('#barcode-form button.stop').removeClass('w3-hide');
        znetdkMobile.messages.showSnackbar('Scan in progress...');
    }
    
    function stopScan() {
        Quagga.stop();
        $('#live-camera').addClass('w3-hide');
        $('#barcode-form button.stop').addClass('w3-hide');
        $('#barcode-form button.start').removeClass('w3-hide');
        znetdkMobile.messages.showSnackbar('Scan terminated.');
    }
    
</script>

Step 2 - Loading the QuaggaJS library

The QuaggaJS library is automatically loaded by specifying into the config.php of the Web App, the matching url on the CDN hosting (see Settings | App extra CSS and JS libraries).

The config.php script is located into the INSTALL_DIR/applications/default/app/ folder.

The line below can be inserted anywhere in the config.php script.

Script config.php

define('CFG_APP_JS', 'https://cdnjs.cloudflare.com/ajax/libs/quagga/0.12.1/quagga.min.js');

Step 3 - Adding "EAN-13 barcode" item to the navigation menu

Finally, to give users access to the mybarcodeview.php bar chart view, a menu item definition is added into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, 'mybarcodeview', 'EAN-13 barcode', 'fa-barcode');
    
    // ... Here, other menu items...
    
}

Adding an Autocomplete field to a form

DESCRIPTION Example of the Starter application showing a form with an autocomplete field to select a country.

PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Only three steps are required:
  • Step 1: Coding the view in charge of displaying the form with the autocomplete field,
  • Step 2: Coding the controller that supplies data to the autocomplete field,
  • Step 3: Adding a new item to the App's navigation menu.

DEMONSTRATION See live demo....

Step 1 - Coding the view autocompleteview.php

The view autocompleteview.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

  • <input id="my-autocomplete"> is the HTML input element used as autocomplete field.
  • znetdkMobile.autocomplete.make() is the JS method that changes the input element to an autocomplete field and connect it to the remote PHP controller's action developed in next step 2.
  • onSelect() is a JS function called when a country is selected in the autocomplete field.
    This function displays a snackbar message indicating the name of the selected country.
  • onRender() is a JS function called before displaying a suggestion of country in the autocomplete field.
    This function customizes the display of the suggestion by showing the country code in bold on the left and the country label on the right in italics.

View autocompleteview.php

<form id="barcode-form" class="w3-padding-16">
    <label>Country</label><br>
    <input id="my-autocomplete" class="w3-input w3-border" type="search" placeholder="Type a country name..."><br>
</form>
<script>
    console.log('autocompleteview.php');
    znetdkMobile.autocomplete.make('#my-autocomplete', {
        controller: 'autocompletectrl',
        action: 'suggestions'
    }, onSelect, onRender);

    function onSelect(item) {
        znetdkMobile.messages.showSnackbar('Country <b>' + item.label + '</b> selected');
    }
    function onRender(item) {
        return '<b>' + item.value + '</b> - <i>' + item.label + '</i>';
    }
</script>

Step 2 - Coding the controller autocompletectrl.php

The controller autocompletectrl.php must be installed into the INSTALL_DIR/applications/default/app/controller/ folder.

  • The AutocompleteCtrl::action_suggestions() method is the controller's action called by the autocompleteview.php to get the suggestions matching the letters entered in the autocomplete field.
  • The countries are read in JSON format from the http://country.io/names.json URL and are converted in PHP array.
  • The letters entered in the autocomplete field are passed to the controller's action through the query POST parameter and read through a ZnetDK \Request object.
  • The suggestions of countries matching the letters entered in the autocomplete field are returned to the view in JSON format through the ZnetDK \Response object.

Controller autocompletectrl.php

<?php
namespace app\controller;

class 
AutocompleteCtrl extends \AppController {
    static protected function 
action_suggestions() {
        
$response = new \Response();
        
$countriesAsJson file_get_contents("http://country.io/names.json");
        if (
$countriesAsJson === FALSE) {
            
$response->setCriticalError(NULL'Unable to read the countries');
            return 
$response;
        }
        
$allCountries json_decode($countriesAsJsonTRUE);
        
$request = new \Request();
        
$suggestions = [];
        if (
is_array($allCountries)) {
            foreach(
$allCountries as $key => $label) {
                if (
stripos($label$request->query) !== FALSE) {
                    
$suggestions[] = ['label' => $label'value' => $key];
                }
            }
        }
        
$response->setResponse($suggestions);
        return 
$response;
    }
}

Step 3 - Adding "Autocomplete" item to the navigation menu

Finally, to give users access to the autocompleteview.php view, a menu item definition is added into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, 'autocompleteview', 'Autocomplete', 'fa-keyboard-o');
    
    // ... Here, other menu items...
    
}

Editing HTML content with CKEditor

DESCRIPTION Here is an example of application that shows how to edit HTML content with the popular Javascript Editor CKEditor in version 5.

PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Five steps are required:
  • Step 1: Coding the view used to edit HTML content in Back Office,
  • Step 2: Coding the controller that stores and supplies the HTML content,
  • Step 3: Coding the view that displays the HTML content in Front Office,
  • Step 4: Loading the CKEditor JS library from CDN hosting,
  • Step 5: Adding a new item to the App's navigation menu.

DEMONSTRATION See live demo....

Step 1 - Coding the view backoffice.php

The view backoffice.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.
It embeds the editor used to edit HTML content.

  • The HTML element used as editor is a textarea field named my_content.
  • This editor is declared within a ZnetDK form that allows both to store (see data-zdk-submit attribute) and load (see data-zdk-load attribute) the data typed in the textarea field.
  • The form data is loaded via a call to the JS znetdkMobile.form.load() API method.
  • After the data is loaded into the textarea element, the CKEditor component is instantiated by calling the ClassicEditor.create() API method.
  • The position of the app footer is adjusted whenever text is changed in the HTML editor with the help of the znetdkMobile.footer.adjustPosition() API method.
  • By clicking on the Show content button, the view named frontoffice is displayed using the znetdkMobile.content.displayView() API method.

View backoffice.php

<div class="w3-content w3-margin-top">
    <form id="my-content-form" data-zdk-load="backofficectrl:get" data-zdk-submit="backofficectrl:save">
        <textarea name="my_content"></textarea>
        <button class="w3-button w3-green w3-margin-top" type="submit"><i class="fa fa-save"></i> Save</button>
        <button class="w3-button w3-theme-action w3-margin-top show" type="button"><i class="fa fa-eye"></i> Show content</button>
    </form>
</div>
<script>
console.log('backoffice.php');
// The ZnetDK form is instantiated and form content loaded
var myForm = znetdkMobile.form.make('#my-content-form');
myForm.load(null, function(){
    // CKEditor is instantiated
    var ckeditor = document.querySelector('#my-content-form textarea[name=my_content]');
    ClassicEditor.create(ckeditor, {
        toolbar: ['heading', 'bold', 'italic', 'undo', 'redo']    
    }).then( newEditor => {
        newEditor.model.document.on('change:data', () => {
            // App's footer is adjusted
            znetdkMobile.footer.adjustPosition();
        });
    })
    .catch( error => {
        console.error( error );
    });    
});
// On click events of the Show content button
$('#my-content-form button.show').on('click', function(){
    znetdkMobile.content.displayView('frontoffice');
});
</script>

Step 2 - Coding the controller backofficectrl.php

The controller backofficectrl.php must be installed into the INSTALL_DIR/applications/default/app/controller/ folder.

  • The action_get() method is called by both the backoffice and frontoffice views. It returns the text in HTML format typed in the editor.
    The data is read from the user's session if it exists through the \UserSession::getCustomValue() method. Otherwise, a default text is returned.
    In a real world application, the data would instead be read from a database via the \DAO API.
  • The action_submit method is called by backoffice view to store in session the formated text typed in the HTML editor.
    The data is stored in the user's session by calling the \UserSession::setCustomValue() method.
    As said before, a better solution would be to store the HTML text in a database via the \DAO API.

Controller backofficectrl.php

<?php
namespace app\controller;

class 
BackOfficeCtrl extends \AppController {

    static private 
$allowedTags '<strong><i><br><p><h2><h3><h4>';
    static private 
$contentSessionKey 'z4mdemo-editor-content';

    static protected function 
action_get() {
        
$response = new \Response();
        
$myContent '<p>Type here <strong>the content</strong> to publish in <em>Front office</em>...</p>';
        
$contentInSession = \UserSession::getCustomValue(self::$contentSessionKey);
        if (!
is_null($contentInSession)) {
            
$myContent strip_tags(html_entity_decode($contentInSession), self::$allowedTags);
        }
        
$response->my_content $myContent;
        return 
$response;
    }

    static protected function 
action_save() {
        
$request = new \Request();
        \
UserSession::setCustomValue(self::$contentSessionKeyhtmlentities($_REQUEST['my_content']));
        
$response = new \Response();
        
$response->setSuccessMessage(NULL'Content saved');
        return 
$response;
    }

}

Step 3 - Coding the view frontoffice.php

The view frontoffice.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

View frontoffice.php

<?php $contentObj = \app\controller\BackOfficeCtrl::doAction('get'); ?>
<div class="zdk-viewreload"><?php echo $contentObj->my_content; ?></div>
<script>
znetdkMobile.action.addCustomButton('editcontent', 'fa-pencil', 'w3-blue');
znetdkMobile.action.registerView('frontoffice', {
    editcontent: {
        isVisible: true,
        callback: function () {
            znetdkMobile.content.displayView('backoffice');
        }
    }
});
</script>

Step 4 - Loading the CKEditor JS library

The CKEditor library is automatically loaded by specifying into the config.php of the Web App, the matching url on the CDN hosting (see Settings | App extra CSS and JS libraries).

The config.php script is located into the INSTALL_DIR/applications/default/app/ folder.

The line below can be inserted anywhere in the config.php script.

Script config.php

define('CFG_APP_JS', 'https://cdn.ckeditor.com/ckeditor5/25.0.0/classic/ckeditor.js');

Step 5 - Adding "Edit content" and "Show content" items to the navigation menu

Finally, to give users access to the backoffice.php and frontoffice.php views, the menu's items are declared into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, 'backoffice', 'Edit content', 'fa-code');
    \MenuManager::addMenuItem(NULL, 'frontoffice', 'Show content', 'fa-eye');
    
    // ... Here, other menu items...
    
}

Server-side form data validation

DESCRIPTION This application shows how to validate on the server-side the data entered in an input form using the Data Validation API.
For illustration purposes, all the fields in the input form are defined with type="text" and without the required attribute for the mandatory fields.

PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Only four steps are required:
  • Step 1: Coding the view that displays the input form,
  • Step 2: Coding the controller that processes the form data,
  • Step 3: Coding the validator in charge of checking the data entered by the user,
  • Step 4: Adding a new item to the App's navigation menu.

DEMONSTRATION See live demo....

Step 1 - Coding the view dataformview.php

The view dataformview.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

  • The input form id="my-data-form" is declared with the data-zdk-submit attribute to specify the controller and the action to call on form submit.
  • All the input fields are declared voluntarily with the type="text" attribute, even for the fields used to input the minimal and maximal numeric values because we want the data to be validated on the server-side.
    Obviously, in a real world input form, the two numeric fields would be preferably declared with the type="number" attribute.
  • A red asterisk is added to the Title label via the zdk-required ZnetDK CSS class.
    On the other hand, no required attribute is voluntarily defined for the corresponding input field name="title" as we want to check in PHP on the server-side, that a value is indeed entered.
  • Finally, to connect the input form to the remote PHP controller action specified via the the data-zdk-submit attribute, the ZnetDK method znetdkMobile.form.make() is called in JavaScript.
    So, when the submit button is clicked, the data entered in the form are sent in AJAX through POST parameters to the app\controller\FormValidCtrl::action_submit() PHP method described in next chapter.

View dataformview.php

<form id="my-data-form" class="w3-padding-16" data-zdk-submit="formvalidctrl:submit">
    <label class="zdk-required"><b>Title</b></label><br>
    <input class="w3-input w3-border" type="text" name="title" placeholder="This field is mandatory"><br>
    <label><b>Min. number</b></label><br>
    <input class="w3-input w3-border" type="text" name="min_number" placeholder="Must be the lower value"><br>
    <label><b>Max. number</b></label><br>
    <input class="w3-input w3-border" type="text" name="max_number" placeholder="Must be the higher value"><br>
    <label><b>Other value</b></label><br>
    <input class="w3-input w3-border" type="text" name="other" placeholder="This field is optional"><br>
    <button class="w3-button w3-block w3-green w3-section w3-padding" type="submit"><i class="fa fa-check"></i> Submit</button>
</form>
<script>
    console.log('dataformview.php');
    znetdkMobile.form.make('#my-data-form');
</script>

Step 2 - Coding the controller formvalidctrl.php

The controller formvalidctrl.php must be installed into the INSTALL_DIR/applications/default/app/controller/ folder.

  • The custom app\controller\FormValidCtrl class is derived from the \AppController ZnetDK class to be identified as an application controller.
  • The action_submit() method, a controller's action, is called on submit of the input form.
    The form data is validated with the help of the \app\validator\FormValidator() custom Validator class described in next chapter.
  • If data validation failed, an error message is returned in the response of the HTTP request by calling the \Response::setFailedMessage() method.
  • Otherwise if data validation succeeded, then a success message is returned by calling the \Response::setSuccessMessage() method.

Controller formvalidctrl.php

<?php
namespace app\controller;

class 
FormValidCtrl extends \AppController {
    static protected function 
action_submit() {
        
$response = new \Response();
        
$validator = new \app\validator\FormValidator();
        
$validator->setCheckingMissingValues();
        if (!
$validator->validate()) {
            
$response->setFailedMessage(NULL$validator->getErrorMessage(),
                
$validator->getErrorVariable());
            return 
$response;
        }
        
$response->setSuccessMessage(NULL'Form data checked.');
        return 
$response;
    }
}

Step 3 - Coding the validator formvalidator.php

The validator formvalidator.php must be installed into the INSTALL_DIR/applications/default/app/validator/ folder.

  • The FormValidator custom class is derived from the \Validator ZnetDK class, specialized in data validation.
  • The initVariables() must be implemented to indicate as an array, the names of the the POST parameters whose values the validator must check.
  • The three other methods declared in the class with their name prefixed by check_ are responsible for validating the value of a particular input field.
    For example, the check_title() method checks the value of the input field named title.
  • If the entry field value passed in parameter of the method through the $value variable is correct, then the method returns TRUE.
    Otherwise, if the value is incorrect, the error message to be displayed to the end user is set by calling the Validator::setErrorMessage() method and the value FALSE is returned.
  • As shown in the check_max_number() method, the value of the input field named min_number is read by calling the Validator::getValue() method.

Validator formvalidator.php

<?php
namespace app\validator;

class 
FormValidator extends \Validator {
    protected function 
initVariables() {
        return array(
'title','min_number','max_number');
    }
    protected function 
check_title($value) {
        if (
strlen($value) === 0) {
            
$this->setErrorMessage('Title is missing.');
            return 
FALSE;
        }
        return 
TRUE;
    }
    protected function 
check_min_number($value) {
        if (
strlen($value) > && !is_numeric($value)) {
            
$this->setErrorMessage('Min. number is not a number.');
            return 
FALSE;
        }
        return 
TRUE;
    }
    protected function 
check_max_number($value) {
        if (
strlen($value) > && !is_numeric($value)) {
            
$this->setErrorMessage('Max. number is not a number.');
            return 
FALSE;
        }
        if (
strlen($value) > && $this->getValue('min_number') >= $value) {
            
$this->setErrorMessage('Max. number is not higher than the min. number');
            return 
FALSE;
        }
        return 
TRUE;
    }
}

Step 4 - Adding "Data form" item to the navigation menu

Finally, to give users access to the dataformview.php view, the menu's item named Data form is declared into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, 'dataformview', 'Data form', 'fa-check-circle-o');
    
    // ... Here, other menu items...
    
}

Displaying Dashboard boxes

DESCRIPTION This Web App illustrates the display of statistics boxes like the ones we can find on popular dashboard templates.

The statistics displayed on the boxes are retrieved from a remote PHP controller action.
They are refreshed both by using an AJAX request (Refresh button) and by reloading the entire view.

Finally, the amounts are displayed in euros by applying the French locale installed on the web hosting.


PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Only four steps are required:
  • Step 1: Coding the view in charge of displaying the statistics boxes,
  • Step 2: Coding the controller that supplies the data to display on the boxes,
  • Step 3: Setting the locale to French in order to format the amounts in currency,
  • Step 4: Loading two extra style sheets to beautify the display of the statistics boxes,
  • Step 5: Adding a new item to the App's navigation menu.

DEMONSTRATION See live demo....

Step 1 - Coding the view statboxes.php

The view statboxes.php must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

  • In order to retrieve the statistics to display in the view, the code starts by calling directly in PHP on the server-side, the get action implemented in the \app\controller\StatCtrl controller (see implementation in Step 2), via the doAction() method.
  • Next, the statistics returned by the get action are inserted in the corresponding <h3> tags when the view is converted to HTML on the server-side, before being downloaded.
  • In order to force the view to be reloaded each time the corresponding menu item is clicked, the zdk-viewreload CSS class is added to any HTML element of the view, in this case to the div.statboxes element.
  • The responsiveness of the statistics boxes is ensured by the w3-row-padding and w3-quarter W3.CSS classes.
  • Extra Flat UI colors (w3-flat-alizarin, w3-flat-belize-hole, ...) are used to color the statistics boxes. Theses colors are declared by loading the w3-colors-flat.css library (see step 4).
  • Finally, an event handler is implemented within the <script> tag in response to the clicks on the Update button, to request in AJAX the last statistics and display them in the view, thus avoiding fully reloading the view.
    The znetdkMobile.ajax.request() is the method used to invoke remotely the same controller action than the one initially called on the server-side, to fill the view with the statistics.
    Once the statistics updated in the DOM, a snackbar message is displayed by calling the znetdkMobile.messages.showSnackbar() method.

View statboxes.php

<?php
$response = \app\controller\StatCtrl::doAction('get');
?>
<div class="statboxes zdk-viewreload w3-row-padding w3-margin-top w3-stretch">
    <div class="w3-quarter w3-margin-bottom">
        <div class="w3-container w3-flat-alizarin w3-padding-16">
            <div class="w3-left"><i class="fa fa-tasks w3-xxxlarge"></i></div>
            <div class="w3-right">
                <h3 class="tasks"><?php echo $response->tasks; ?></h3>
            </div>
            <div class="w3-clear"></div>
            <h4>Tasks</h4>
        </div>
    </div>
    <div class="w3-quarter w3-margin-bottom">
        <div class="w3-container w3-flat-belize-hole w3-padding-16">
            <div class="w3-left"><i class="fa fa-bank w3-xxxlarge"></i></div>
            <div class="w3-right">
                <h3 class="balance"><?php echo $response->balance; ?></h3>
            </div>
            <div class="w3-clear"></div>
            <h4>Balance</h4>
        </div>
    </div>
    <div class="w3-quarter w3-margin-bottom">
        <div class="w3-container w3-flat-emerald w3-padding-16">
            <div class="w3-left"><i class="fa fa-credit-card w3-xxxlarge"></i></div>
            <div class="w3-right">
                <h3 class="expenses"><?php echo $response->expenses; ?></h3>
            </div>
            <div class="w3-clear"></div>
            <h4>Expenses</h4>
        </div>
    </div>
    <div class="w3-quarter w3-margin-bottom">
        <div class="w3-container w3-flat-carrot w3-text-white w3-padding-16">
            <div class="w3-left"><i class="fa fa-handshake-o w3-xxxlarge"></i></div>
            <div class="w3-right">
                <h3 class="sales-orders"><?php echo $response->salesOrders; ?></h3>
            </div>
            <div class="w3-clear"></div>
            <h4>Sales orders</h4>
        </div>
    </div>
</div>
<button id="btn-refresh-stats" class="w3-button w3-theme-action"><i class="fa fa-refresh"></i> Update</button>
<script>
    $('#btn-refresh-stats').on('click', function(){
        znetdkMobile.ajax.request({
            controller: 'statctrl',
            action: 'get',
            callback: function (response) {
                $('.statboxes h3.tasks').text(response.tasks);
                $('.statboxes h3.balance').text(response.balance);
                $('.statboxes h3.expenses').text(response.expenses);
                $('.statboxes h3.sales-orders').text(response.salesOrders);
                znetdkMobile.messages.showSnackbar('Statistics refreshed.');
            }
        });
    });
</script>

This view requires extra styles that are coded in a dedicated style sheet named statboxes.css, placed into the INSTALL_DIR/applications/default/public/css/ folder and finally loaded in the main page of the application via the declaration made in Step 4.

Style sheet statboxes.css

.statboxes .fa {
    color: rgba(255,255,255,.6);
}
.statboxes h4 {
    border-left: 6px solid;
    margin-left: -16px;
    padding-left: 12px;
    color: rgba(255,255,255,.6);
}

Step 2 - Coding the controller statctrl.php

The controller statctrl.php must be installed into the INSTALL_DIR/applications/default/app/controller/ folder.

  • The get action (method named action_get() in the class derived from \AppController) is called by the statboxes.php view to obtain the statistics to display.
  • The \Convert::toMoney() method is called to convert the float values to currency amounts according to the locale configured for the application.

Controller statctrl.php

<?php
namespace app\controller;
class 
StatCtrl extends \AppController {
    static protected function 
action_get() {
        
$response = new \Response();
        
$response->tasks rand(0,99).'%';
        
$response->balance = \Convert::toMoney(rand(0,9999)+(rand(0,99)/100));
        
$response->expenses = \Convert::toMoney(rand(0,9999)+(rand(0,99)/100));
        
$response->salesOrders rand(0,200);
        return 
$response;
    }
}

Step 3 - Setting the locale to French

To set the locale to French (in my case named fr_FR.utf8), just edit the INSTALL_DIR/applications/default/app/lang/locale.php script and declare the LC_LOCALE_ALL PHP constant as shown below.

Script locale.php

define('LC_LOCALE_ALL', serialize(array('fr_FR.utf8')));

Step 4 - Loading two extra CSS libraries

Two extra style sheets are loaded in the main page of the application by declaring the CFG_APPLICATION_CSS parameter into the config.php script located into the INSTALL_DIR/applications/default/app/ folder.

The line below can be inserted anywhere in the config.php script.

Script config.php

define('CFG_APPLICATION_CSS', serialize([
    'https://www.w3schools.com/lib/w3-colors-flat.css',
    'applications/default/public/css/statboxes.css'
]));

Step 5 - Adding "Dashboard" item to the navigation menu

Finally, to give users access to the statboxes.php view, the menu's item named Dashboard is declared into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, 'statboxes', 'Dashboard', 'fa-dashboard');
    
    // ... Here, other menu items...
    
}

Multilingual Application

DESCRIPTION

Here is an example of a Web application whose display is translated into English, Spanish and Portuguese.

The source code can be adapted to translate the application into languages other than those offered.


PREREQUISITE The ZnetDK for Mobile Starter Application is installed and configured (go to the Get Started page and follow the given procedure).

STEPS Only 6 steps are required:
  • Step 1: Coding of the display language selection screen,
  • Step 2: Coding a multilingual data form,
  • Step 3: Displaying a multilingual content,
  • Step 4: Translating labels into three languages,
  • Step 5: Adding new items to the App's navigation menu,
  • Step 6: Configuring multilingual display.

DEMONSTRATION See live demo....

Step 1 - Coding the view lang.php

The view lang.php allows to select another language than the one currently set to display the application (English by default, see CFG_DEFAULT_LANGUAGE parameter).
This view must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

  • The labels displayed for each button are defined via a PHP constant (for example MYLOCALE_BUTTON_LANG_ENGLISH) that contains the button text translated into the current display language. The PHP constants in charge of translating the labels of the application are defined in step 4.
  • When a button is clicked, the application is reloaded (via the locale.assign() JavaScript method) with the addition of the lang parameter of type GET to the URL and whose value corresponds to the code of the selected language (for example pt if Portuguese was clicked).
    The URL of the Web App is obtained by a call to the znetdkMobile.ajax.getParamsFromAjaxURL() method.

View lang.php

<div id="myapp-select-lang" class="w3-panel w3-stretch">
    <p>
        <button lang="en" class="w3-button w3-block w3-theme-d3">
            <i class="fa fa-fw fa-lg"></i>
            <b><?php echo MYLOCALE_BUTTON_LANG_ENGLISH; ?></b>
        </button>
    </p>
    <p>
        <button lang="es" class="w3-button w3-block w3-theme-d3">
            <i class="fa fa-fw fa-lg"></i>
            <b><?php echo MYLOCALE_BUTTON_LANG_SPANISH; ?></b>
        </button>
    </p>
    <p>
        <button lang="pt" class="w3-button w3-block w3-theme-d3">
            <i class="fa fa-fw fa-lg"></i>
            <b><?php echo MYLOCALE_BUTTON_LANG_PORTUGUESE; ?></b>
        </button>
    </p>
</div>
<script>
    console.log('View "lang.php"');
    /* Current display language is checked */
    var currentLang = $('html').attr('lang'),
        selectedButton = $('#myapp-select-lang button[lang=' + currentLang + ']');
    selectedButton.prop('disabled', true);
    selectedButton.find('i.fa').addClass('fa-check');

    /* Click event of a button */
    $('#myapp-select-lang button').on('click', function(){
        var newLang = $(this).attr('lang'),
            url = znetdkMobile.ajax.getParamsFromAjaxURL().url;
        znetdkMobile.browser.events.detachBeforeUnload();
        location.assign(url + '?lang=' + newLang);
    });
</script>

Step 2 - Coding the view form.php

The view form.php illustrates the display of the same data form in several languages thanks to the PHP constants defined in step 4.
This view must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

View form.php

<form class="w3-panel w3-stretch">
    <label><b><?php echo MYLOCALE_FORM_LABEL_MY_VALUE; ?></b></label>
    <input class="w3-input w3-border" placeholder="<?php echo MYLOCALE_FORM_PLACEHOLDER_MY_VALUE; ?>">
    <button class="w3-button w3-block w3-section w3-green"
        type="button" onclick="znetdkMobile.messages.showSnackbar('<?php echo MYLOCALE_FORM_BUTTON_SUBMIT; ?>')">
        <i class="fa fa-check fa-lg"> </i><?php echo MYLOCALE_FORM_BUTTON_SUBMIT; ?>
    </button>
</form>

Step 3 - Coding the views content_[LANG].php

Here are the three views content_en.php, content_es.php and content_pt.php which display the same text translated in the three languages supported by the application.
These views illustrate another way to translate a view in several languages.
They must be installed into the INSTALL_DIR/applications/default/app/view/ folder.

View content_en.php

<h2>Content</h2>
<p>Example of text content translated into the application display language.</p>

View content_es.php

<h2>Contenido</h2>
<p>Ejemplo de contenido de texto traducido al idioma de visualización de la aplicación.</p>

View content_pt.php

<h2>Contente</h2>
<p>Exemplo de conteúdo de texto traduzido para o idioma de exibição do aplicativo.</p>

Step 4 - Translating the labels in locale_[LANG].php

The three scripts locale_en.php, locale_en.php and locale_en.php are created from the INSTALL_DIR/applications/default/app/lang/locale.php script supplied with the Starter Application.
Each script contains the definition of PHP constants which translate the labels of the application into a specific language.
These scripts must be installed into the INSTALL_DIR/applications/default/app/lang/ folder.

View locale_en.php

<?php
/**
* ZnetDK, Starter Web Application for rapid & easy development
* See official website http://www.znetdk.fr
* ------------------------------------------------------------
* Custom english labels of your application
* YOU CAN FREELY CUSTOMIZE THE CONTENT OF THIS FILE
*/

/* General labels */
define('LC_PAGE_TITLE''ZnetDK 4 Mobile');

/* Heading labels */
define('LC_HEAD_TITLE''Starter App');

/* Heading images */
//define('LC_HEAD_IMG_LOGO', ZNETDK_APP_URI.'images/logo.png');

/* Footer labels */
define('LC_FOOTER_LEFT''Version 1.0');
define('LC_FOOTER_CENTER''Developed with ZnetDK');
define('LC_FOOTER_RIGHT''&copy; 2021');

/* Custom labels */
define('MYLOCALE_MENU_HOME''Home');
define('MYLOCALE_MENU_LANG''Language');
define('MYLOCALE_MENU_FORM''Form');
define('MYLOCALE_MENU_CONTENT''Content');

define('MYLOCALE_BUTTON_LANG_ENGLISH''English');
define('MYLOCALE_BUTTON_LANG_SPANISH''Spanish');
define('MYLOCALE_BUTTON_LANG_PORTUGUESE''Portuguese');

define('MYLOCALE_FORM_LABEL_MY_VALUE''My value');
define('MYLOCALE_FORM_PLACEHOLDER_MY_VALUE''Enter a value...');
define('MYLOCALE_FORM_BUTTON_SUBMIT''Submit');

View locale_es.php

<?php
/**
* ZnetDK, Starter Web Application for rapid & easy development
* See official website http://www.znetdk.fr
* ------------------------------------------------------------
* Custom english labels of your application
* YOU CAN FREELY CUSTOMIZE THE CONTENT OF THIS FILE
*/

/* General labels */
define('LC_PAGE_TITLE''ZnetDK 4 Mobile');

/* Heading labels */
define('LC_HEAD_TITLE''Aplicación de inicio');

/* Heading images */
//define('LC_HEAD_IMG_LOGO', ZNETDK_APP_URI.'images/logo.png');

/* Footer labels */
define('LC_FOOTER_LEFT''Versión 1.0');
define('LC_FOOTER_CENTER''Desarrollado with ZnetDK');
define('LC_FOOTER_RIGHT''&copy; 2021');

/* Custom labels */
define('MYLOCALE_MENU_HOME''Página de inicio');
define('MYLOCALE_MENU_LANG''Idioma');
define('MYLOCALE_MENU_FORM''Formulario');
define('MYLOCALE_MENU_CONTENT''Contenido');

define('MYLOCALE_BUTTON_LANG_ENGLISH''Inglés');
define('MYLOCALE_BUTTON_LANG_SPANISH''Español');
define('MYLOCALE_BUTTON_LANG_PORTUGUESE''Portugués');

define('MYLOCALE_FORM_LABEL_MY_VALUE''Mi valor');
define('MYLOCALE_FORM_PLACEHOLDER_MY_VALUE''Ingrese un valor...');
define('MYLOCALE_FORM_BUTTON_SUBMIT''Enviar');

View locale_pt.php

<?php
/**
* ZnetDK, Starter Web Application for rapid & easy development
* See official website http://www.znetdk.fr
* ------------------------------------------------------------
* Custom english labels of your application
* YOU CAN FREELY CUSTOMIZE THE CONTENT OF THIS FILE
*/

/* General labels */
define('LC_PAGE_TITLE''ZnetDK 4 Mobile');

/* Heading labels */
define('LC_HEAD_TITLE''Aplicativo inicial');

/* Heading images */
//define('LC_HEAD_IMG_LOGO', ZNETDK_APP_URI.'images/logo.png');

/* Footer labels */
define('LC_FOOTER_LEFT''Versão 1.0');
define('LC_FOOTER_CENTER''Desenvolvido with ZnetDK');
define('LC_FOOTER_RIGHT''&copy; 2021');

/* Custom labels */
define('MYLOCALE_MENU_HOME''Pagina inicial');
define('MYLOCALE_MENU_LANG''Língua');
define('MYLOCALE_MENU_FORM''Forma');
define('MYLOCALE_MENU_CONTENT''Contente');

define('MYLOCALE_BUTTON_LANG_ENGLISH''Inglês');
define('MYLOCALE_BUTTON_LANG_SPANISH''Espanhol');
define('MYLOCALE_BUTTON_LANG_PORTUGUESE''Português');

define('MYLOCALE_FORM_LABEL_MY_VALUE''Meu valor');
define('MYLOCALE_FORM_PLACEHOLDER_MY_VALUE''Insira um valor...');
define('MYLOCALE_FORM_BUTTON_SUBMIT''Enviar');

Step 5 - Link the views to the navigation menu

Finally, to give users access to the views of the application, menu items are declared into the menu.php script of the Web App (see Get Started | New menu items for more information).

The menu.php script is located into the INSTALL_DIR/applications/default/app/ folder.

Script menu.php

static public function initAppMenuItems() {
    
    // ... Here, some menu items...
    
    \MenuManager::addMenuItem(NULL, '_home', MYLOCALE_MENU_HOME, 'fa-home');
    \MenuManager::addMenuItem('_home', 'lang', MYLOCALE_MENU_LANG, 'fa-language');
    \MenuManager::addMenuItem('_home', 'form', MYLOCALE_MENU_FORM, 'fa-keyboard-o');
    \MenuManager::addMenuItem('_home', 'content', MYLOCALE_MENU_CONTENT, 'fa-newspaper-o');
    
    // ... Here, other menu items...
    
}

Step 6 - Activate multilingual display in config.php

Multilingual display is enabled by declaring the CFG_MULTI_LANG_ENABLED parameter into the config.php script located into the INSTALL_DIR/applications/default/app/ folder.

The line below can be inserted anywhere in the config.php script.

Script config.php

define('CFG_MULTI_LANG_ENABLED', TRUE);