File Structure

All you need to run EMPS is a single index.php file, a local/temp_c folder for compiled Smarty templates (make it writable by the server), and a local/local.php config file for your project. A sample of the config file can be found here: sample_local.php. A sample of the index.php file can be found nearby: sample_index.php. Although the index.php can be used as is, the local.php file needs some editing before it could be used.

It is preferable that the index.php file and the local folder (along with the local.php file) are located in the htdocs subfolder of your project folder. There could be some things that you would want to keep in your project but outside of direct reach though the web server - those could be kept in folders other than htdocs.

The htdocs folder where the index.php file is located has to be the DocumentRoot folder of the web app that you are creating. An example of a hidden (not directly accessible through the HTTP server) folder would be the vendor folder for composer components. Or a folder to keep a nodejs app that renders your custom CSS from a SASS source.

A typical EMPS web app project folder would look like this:

{root}
  - htdocs/
    - local/
      - temp_c/ (chmod 0777)
    - index.php
  - vendor/
  - composer.json

Direct by HTTP(S)

Any non-PHP files that you put in the htdocs folder are immediately accessible by the web server for direct delivery to the end user. For example, if you want to put some images or some CSS or JS files, you can do that by putting them to appropriate subfolders in the htdocs folder (don't litter in the htdocs folder directly, though you can).

Here is how a project's htdocs folder would look with some asset files in it:

htdocs
  - css/
    - design.css
  - i/
    - logo.svg
    - background.jpg
  - local/
    ... (appropriate files)
  favicon.png
  index.php

So, in this example, the /css/design.css, /i/logo.svg and /favicon.png files are all accessible directly through an HTTP(s) request to your web server, e.g. https://my-webapp.here/i/logo.svg. Such files are delivered directly by nginx or apache without running any PHP code.

Extensions to EMPS File Structure

The files that constitute the source code of your web app are extensions to the folder and file structure of the base EMPS app. Those can be either new files, or files that replace the default EMPS files.

This is best understood using an example. If you create a file named ./htdocs/templates/site/headscripts.nn.htm it will serve as a source of HTML/Smarty template for this line of code in a core EMPS Smarty template:

templates/page/headscripts.nn.htm (follow this link to see actual EMPS6 source code)

This templates/page/headscripts.nn.htm file is part of EMPS6/6.X, it's the default insert that is added to the HTML code of the page inside the <head></head> tags. After mentioning all the standard scripts and CSS files that it has to include, it transfers control to your project's templates/site/headscripts.nn.htm template that can add its own scripts and CSS files.

By default, the templates/site/headscripts.nn.htm file does not exist in EMPS, so if you don't create it in your project, EMPS will get an empty string when it will try to include the {{include file="db:site/headscripts"}} template. But, there will be some HTML code if you define that file in your project and add some code to it.

All the static files are also treated as an extension on top of the default EMPS folder structure. For example, the EMPS file structure contains this JS file:

/js/emps.js (GitHub link)

But, if you add your own ./htdocs/js/emps.js file to your project, you can replace that file with your own version.

The procedure is as follows:

  • A static file is first looked up in the app htdocs folder including the appropriate subfolders (e.g. if the request is /css/design.css the server will first look for ./htdocs/css/design.css).
  • (optional step) If the file is not found in the app folder, and your app is in turn an extension to another EMPS app, the file is looked for in the parent app's folder.
  • If the file is not found, it is looked up in the EMPS6/6.5 (or EMPS6/6.0 depending on the version you are using) folder.
  • If the file is still not found, it is looked up in the EMPS6/6.X (common shared) folder.
  • Then, if it is not found anywhere, an HTTP/404 response is given to the client.

Automatic URL Parsing & Routing

The primary routing procedure is the following:

  • The URL (the part after the hostname and before the ? or #) is split into parts by the slash symbol /. So, /manage-orders/1/-/info/ becomes ['', 'manage-orders', '1', '-', 'info']. The first empty string is thrown away and what's left is ['manage-orders', '1', '-', 'info'].
  • The values are then assigned to EMPS variables. The following variables get extracted from a URL:

define('EMPS_URL_VARS', 'pp,key,start,ss,sd,sk,sm,sx,sy');
  • In our example, /manage-orders/1/-/info/ becomes $pp = 'manage-orders', $key = '1', $start = '' (hypen - means "empty value"), $ss = 'info'. Those are actual global PHP variables, can be accessed from anywhere in subsequent PHP code. They also can be restored if you change their value and can be used to produce internal link URLs.
  • The module router only needs the $pp variable. If the value contains hypens, it replaces hypens with slashes and uses that as the local folder path, e.g. manage-orders becomes htdocs/modules/manage/orders.
  • By default, EMPS expects to see at least an HTML template file or a PHP file in that module folder (or both files). It assumes that the PHP script file name is the same as the name of the last folder (in this case, orders) with a .php extension. So, it looks for htdocs/modules/manage/orders/orders.php and require_once loads that PHP script.
  • If the PHP script does not exist, or if it doesn't execute $emps->no_smarty = false, EMPS assumes that it needs to display the default Smarty template for that page. It assumes that the file name of the template is the same as the name of the folder, but with a .nn.htm extension. You can actually have multiple templates for many languages, like .en.htm or .ru.htm or .it.htm. That depends on the default language setting of the current website. But the default file is in this case - htdocs/modules/manage/orders/orders.nn.htm. That file then gets displayed inside the Smarty template of the website (between header and footer).

Code in Modules and Referencing Include Files

Following our previous example of opening the manage-orders URL, we now have the orders.php controller or procedure file and the orders.nn.htm view file.

The PHP script can do some work and assign some Smarty variables like $smarty->assign('order', $order) and then the template will display {{$order.client_name}} or {{$order.price|money}}.

But rarely the controller or the view file can contain all the code that is needed to render this page. Sometimes they need to include some source code from another PHP file or Smarty template.

Including Files Into the Controller

  • The controller file can require_once or include any PHP files from wherever you prefer, it can also reference autoloaded composer classes. But for referencing source files in this particular EMPS project (or default EMPS files, which are in the same virtual combined file structure, as you have learner earlier, see above) there is a special procedure to follow:

  • Use the $emps->page_file_name() function to find the exact path to an EMPS file or a file in your modules folder.

  • Refer to the file using its 'virtual' name. E.g., if you want to reference a PHP class file that is contained in the ./htdocs/modules/orders/orders.class.php file, use the this virtual name: _orders,orders.class, i.e.

    require_once $emps->page_file_name('_order,orders.class', 'controller');
  • The _ symbol specifies that the lookup function should try to find that file in the modules folder of your app (then the modules folder of the parent app, then the EMPS base apps, following the procedure explained above).

  • The string before comma , specifies the path to the subfolder in modules, in this case orders means ./htdocs/modules/orders/. If there was no comma, the virtual filename parser would assume that it needed to include the file with the same name as the folder and with the extension fitting the requested file type (view, controller, or inc). Controller files get the .php extension, view files are first looked up with the .{$lang}.htm (e.g. .en.htm) extension, and if not found - with the .nn.htm extension.

  • The string after the comma ,, if present, specifies that the name of the include file is not the same as the name of the folder. With view and controller types, you should omit the file extension, hence orders.class to get the orders.class.php file. With the inc type, you should specify the full name of the include file.

  • More on Internal References →

Including Templates Into the View

  • Any view file can {{include file="..."}} any Smarty template (HTML) inserts from other parts of the module, from other modules, other parts of HTML or even from settings (meta).
  • The virtual names of include files follow the same principles, in fact, the same $emps->page_file_name() function is used to look for the actual file (however, in this case, the view type is used).
  • One important difference: the include file names in Smarty templates should start with a prefix. The most common prefix is db:. When you use this prefix, the template is first looked up in the Settings (/admin-set/ page of your app), those are essentially meta variables or options. If no such setting is found, and if the virtual file name starts with a _, then the contents is looked up using the $emps->page_file_name() function with view type (see above).
  • If the virtual file name does not start with a _, the file is looked up in the templates folder. If it is not found there, it is looked up in the common modules folder.
  • A few quick examples:
    1. You can define a setting named inc/phone and set its value to +1 800 XXX-XX-XX. Then, in a template, you can reference it as {{include file="db:inc/phone"}}.
    2. You can have a snippet of Smarty/HTML code representing a block containing, say, product information. E.g. you have a file named ./htdocs/modules/orders/itemblock.nn.htm. You can have it referenced from the products page by {{include file="db:_orders,itemblock"}}.
    3. You have a Smarty/HTML template in ./htdocs/templates/site/navbar.nn.htm that contains some navbar code. You can reference it by {{include file="db:site/navbar"}}.
    4. If you need to load some HTML code into your PHP program by applying a Smarty/HTML template, you can do it this way: $invoice_html = $smarty->fetch("db:_orders/print,invoice");
  • More on Internal References →

The page: Prefix for Smarty Templates

Another option to include Smarty/HTML code into your view is to create a content item (a page) in /admin-content/ of your app. For example, you created a content item identified by the URI _disclaimer and used the TinyMCE editor to create some HTML text (you can use Smarty templates there as well). This HTML code can be referenced this way:

{{include file="page:_disclaimer"}}.

Vue.js and Other JS Specifics, In-Browser Includes

  • The Vue.js interaction works a bit differently, with a few extra steps, but following the same principles. There, the Smarty template contains the code that is required to load and initialize a Vue.js app or a mix-in. The Smarty templates contain Vue.js templates (which makes an interesting and very helpful combination of features sometimes). And then the Vue.js app sends requests to the orders.php script (or any other script for that matter) that return JSON data (no Smarty templates and no HTML). They do it by calling $emps->json_ok($data); exit; or $emps->json_error('No such order!'); exit;. Note that the exit prevents any further processing and displaying of the HTML code.
  • The mjs component loader. Sometimes there are also .css and .js and .vue (in EMPS, .vue files contain only the plain HTML code of the template) files. In order to load any one of them from JS or from the template <script> tags, use the following URL template: /mjs/{$module_pp}/{$filename}, where {$module_pp} is the value of the $pp variable in the URL of this module (in our case it will be manage-orders), and {$filename} is the actual file name. For example, if we also need to load the JS script for this module from this JS file - htdocs/modules/manage-orders/orders.js we can open this external URL: /mjs/manage-orders/orders.js. The file name can be any name, it doesn't have to match the folder name here. So it can be like /mjs/manage-orders/extra.css.