Configuration


1Presentation

The configuration of a project using Temma is done by modifying the temma.php file which is placed in the etc/ directory, and which has several sections.

By default, Temma looks for a file named etc/temma.php, in PHP format (explained below). But you can use other formats for the configuration file:

  • JSON (file etc/temma.json): This format is widely used in IT projects. This is Temma's historic format, and is still recommended if you want to generate your configuration files using a script.
  • YAML (file etc/temma.yaml): This format is increasingly used, notably by other modern frameworks.
  • NEON (file etc/temma.neon): Format used by the Nette framework and the PHPStan static code analysis tool. It is very similar to the YAML format.

We recommend to use the PHP format, as it has the advantage of being cached by OPcache (OPcode's cache, which avoids the need to reread PHP files each time they are accessed), thus speeding up processing. It also enables dynamic configuration generation.

In the etc/ directory, you'll find four files used to illustrate the configuration of a Temma project:

  • temma-mini.php: Minimal file containing basic directives (PHP format).
  • temma-mini.json: Minimal file containing basic directives (JSON format).
  • temma-mini.yaml: Minimal file containing basic directives (YAML format).
  • temma-full.php: File showing all the available options (PHP format).

2Simple temma.php file

Here is a typical example of a minimal etc/temma.php file:

<?php

return [
    // application configuration
    'application' => [
        'dataSources' => [
            'db' => 'mysql://user:passwd@localhost/mybase'
        ],
        'rootController' => 'HomepageController'
    ],
    // definition of log levels
    'loglevels' => 'ERROR',
    // definition of error pages
    'errorPages' => 'error404.html',
    // data imported automatically as template variables
    'autoimport' => [
        'googleId'          => 'azeazeaez',
        'googleAnalyticsId' => 'azeazeazeaze',
    ]
];

We can see:

  • Line 7: The definition of the DSN which allows to connect to the database.
  • Line 9: The name of the root controller, which will be called when someone logs in without specifying a controller.
  • Line 12: Setting the threshold for writing log messages to the log/temma.log file. Here, with the "ERROR" threshold, only the messages with the ERROR and CRIT thresholds will actually be written to the log file.
  • Line 14: Definition of the page to display if an error occurs. The page must be stored in the project's www/ directory.
  • Automatically imported template variables.
    • Line 17: Google ID, available in the templates with {$conf.googleId} and in the controller with $this['conf']['googleId'].
    • Line 18: Google Analytics ID, available in templates with {$conf.googleAnalyticsId} and in the controller with $this['conf']['googleAnalyticsId'].

3Complete temma.php file

Here is another example, which shows all the standard configuration variables:

<?php

return [
    // General application definition variables
    'application' => [
        // data sources
        'dataSources' => [
            // MySQL database connection DSN
            //  (see object \Temma\Datasources\Sql).
            // Optional
            'db' => 'mysqli://user:passwd@localhost/mybase',

            // DSN for connection to the Redis database
            //  (see object \Temma\Datasources\Redis).
            // Optional
            'ndb' => 'redis://localhost:6379/0',

            // DSN for connection to the Memcached cache server
            //  (see object \Temma\Datasources\Memcache).
            // Optional
            'cache' => 'memcache://localhost:11211',
        ],

        // Indicate whether or not we want to use the sessions.
        // Use to deactivate sessions as needed.
        // Optional: "true" by default.
        'enableSessions' => true,

        // Name of the session cookie.
        // Optional: "TemmaSession" by default.
        'sessionName' => 'TemmaSession',

        // Data source to store sessions.
        // Optional: Use the PHP session management
        // mechanism by default
        'sessionSource' => 'ndb',

        // Session duration.
        // Optional: One year by default.
        'sessionDuration' => 31536000,

        // Tell if the session cookie must be sent only on
        // connections secured by HTTPS.
        // Optional: "false" by default.
        'sessionSecure' => false,

        // Domain name associated to the session cookie.
        // Optional: not defined by default.
        'cookieDomain' => null,

        // Default namespace of the controllers
        // Optional: by default the controllers are in
        // the global namespace.
        'defaultNamespace' => '\MyApp\Controllers',

        // Name of the controller used for the site root.
        // Optional. By default uses the controller defined by
        // the 'defaultController' variable.
        'rootController' => 'Homepage',

        // Name of the default controller to use if the requested
        // controller does not exist.
        // Optional. By default, generates a 404 error if you ask
        // for a controller that does not exist.
        'defaultController' => 'NotFound',

        // Name of the controller to always be called,
        // even if the requested one exists.
        // Optional.
        'proxyController' => 'Main',

        // Name of the default view.
        // Optional. \Temma\Views\Smarty by default.
        'defaultView' => '\Temma\Views\Smarty',

        // Name of the object that will be used as
        // a dependency injection component
        // Optional: Uses Temma's dependency injection component
        // by default.
        'loader' => 'MyLoader',

        // Path to the log file.
        // Optional: By default, logs are written into
        // the "log/temma.log" file.
        // Put a false value (null, false, empty string or the
        // number zero) to disable writing to the log file.
        'logFile' => 'log/temma.log',

        // Name of the log management object, or list of object names.
        // Optional: No log manager is enabled by default.
        'logManager' => [ 'ElasticLogManager', 'SentryLogManager' ],
    ],
    // Definition of log levels
    'loglevels' => [
        'Temma/Base' => 'ERROR',
        'Temma/Web'  => 'WARN',
        'myapp'      => 'DEBUG',
        'default'    => 'NOTE',
    ],
    // Definition of log levels for buffered messages
    'bufferingLoglevels' => [
        'Temma/Base' => 'DEBUG',
        'myapp'      => 'DEBUG',
    ],
    // Routing: We indicate the names of virtual controllers,
    // by associating a real controller (or virtual, in cascade),
    // which will handle the requests.
    'routes' => [
        'sitemap.xml'          => 'SitemapController',
        'sitemap.extended.xml' => 'sitemap.xml',
        'robert'               => 'BobController',
    ],
    // Plugin management
    'plugins' => [
        // Plugins executed for all controllers
        // - plugins executed before the controller
        '_pre' => [
            'CheckRequest',
            'UserGrant',
        ],
        // - plugins executed after the controller
        '_post' => [ 'AddCrossLinks' ],
        // Definition of plugins specific to the Article controller
        'Article' => [
            // plugins executed before and after the controller
            '_pre'  => [ 'Something' ],
            '_post' => [ 'SomethingElse' ],
            // plugins specific to the index action
            'index' => [
                '_pre'  => [ 'Aaa' ],
                '_post' => [ 'Bbb' ],
            ],
            // plugin executed before the setData action
            'setData' => [
                '_pre' => [ 'CccPlugin' ]
            ]
        ],
        // Plugin for the BobController controller, but
        // only when called by its route "robert"
        'robert' => [
            '_pre' => [ 'AnotherPlugin' ]
        ],
    ],
    // Definition of error pages
    'errorPages' => [
        '404'     => 'error404.html',
        '500'     => 'error500.html',
        'default' => 'error404.html'
    ],
    // List of inclusion paths, with or without namespace prefix
    'includePaths' => [
        '/opt/some_library/lib',
        '/opt/other_lib',
        '\Acme\Log'      => '/path/to/acme-log/lib',
        '\MyLib\Feature' => '/path/to/vendors/feature',
    },
    // Data imported automatically as template variables
    'autoimport' => [
        'googleId'          => 'azeazeaez',
        'googleAnalyticsId' => 'azeazeazeaze',
    ],
    // Extended configuration
    'x-homepage' => [
        'title'       => 'Site title',
        'description' => 'Site description',
    ],
    // Another extended configuration
    'x-email' => [
        'senderAddress' => 'admin@localhost.localdomain',
        'senderName'    => 'Administrator',
    ]
];

4Configuration sections

4.1application

The main section of the file is the one named application. It is used to define the most important configuration variables of the project.
Here are the different variables it can contain:

  • dataSources: Used to define the DSNs (Database Source Name) for data source connections (MySQL, Redis, Memcached…).
  • enableSessions: This variable must be set to false if you do not want to manage the sessions. This can be useful when you do not want to track user visits, such as for an API.
  • sessionName: Name of the cookie that will contain the session identifier.
  • sessionSource: Name of the data source (in the dataSources associative array) that will contain the session data. This can be a Redis, Memcache or SQL connection (or even File or S3). If this parameter is not set, Temma uses PHP's native session mechanism.
  • sessionDuration: Session duration in seconds.
  • sessionSecure: Boolean telling whether the session cookie should only be sent over connections secured by HTTPS.
  • cookieDomain: Domain name associated with the session cookie. Several possibilities:
    • If the parameter is not set, the current site's level 1 domain (without sub-domains) is used. The browser will send the cookie for the domain and all its sub-domains (and sub-sub-domains, etc.).
      For example, if the current site is www.site.com, the site.com domain will be used. The browser will send the cookie (and the session will therefore be accessible) to the sites site.com, www.site.com, admin.site.com, www.users.site.com, etc.
    • If the parameter is set but empty (empty string, false or null), no domain will be associated with the cookie. The browser will then take the strict value of the current domain (e.g. admin.user.site.com). The cookie will not be sent for parent domains (user.site.com and site.com), nor for child domains (www.admin.user.site.com).
    • If the parameter is set and not empty, this is the value that will be associated with the cookie. In this case, the session will be shared for this domain and all its sub-domains.
  • defaultNamespace: In the event that the controllers' PHP files are not saved in the controlers/ directory, this variable contains the default namespace of the controllers.
    For example, if this variable contains the value \App\Ctrl, and we connect to the URL www.mysite.com/home, Temma will load the \App\Ctrl\Home object.
  • rootController: Name of the controller to run when a connection is made to the site root.
  • defaultController: Name of the controller to execute when a controller that does not exist is requested.
  • proxyController: Name of the controller to execute all the time, even if the requested controller exists.
  • defaultView: Name of the default view, which will be used to generate the output stream (unless another view is explicitly requested in the controller or a plugin).
  • loader: Name of the object that will be used as the dependency injection component.
  • logFile: Path to the log file. Put a false value (null, false, empty string or the number zero) to disable writing to the log file (this can be useful if you want to use only a log manager; see the next directive). Any path not starting with a slash (/) will be relative to the root of the project.
  • logManager: This variable can contain the name of a log management object, or a list of object names. See the log documentation for more details.

4.2DSN (Data Source Name)

To define a connection to a data source, you must write a character string that contains all the parameters.

Several formats are possible:

  • Environment variable
    It is possible to indicate the name of an environment variable.
    env://VAR_NAME
    This variable must be correctly defined, and its content must be a DSN supported by Temma (see the cases below).

  • Relational database
    protocol://user:password@host[:port][/db_name]
    • protocol: Database type, as defined by PDO (mysql, pgsql, cubrid, sybase, mssql, dblib, firebird, ibm, informix, sqlsrv, oci, odbc, 4D)
    • user: User name used to connect to the server
    • password: Password used to connect to the server
    • host: Name of the machine hosting the database server
    • port: Network connection port number (optional, uses the usual port number by default)
    • db_name: Name of the base instance to connect to (optional)
    Examples:
    • mysql://db_user:db_password@localhost/app_db
    • pgsql://db_user:db_password@db_server.mydomain.com:3307/app_db

    It is possible to connect to a MySQL server using a local Unix socket, rather than a network socket: mysql://user:password@localhost/db_name#/path/to/unix/socket
    Compared to a classic MySQL configuration, you must add a hash character (#), followed by the path to the Unix socket file. The host machine name must be localhost. There cannot be a port number.
    Example: mysql://db_user:db_password@localhost/app_db#/var/run/mysqld/mysqld.sock

  • Local relational database (SQLite)
    sqlite:/path/to/file.sq3

  • Non-relational database (Redis)
    redis://host[:port][/db_number]
    • host: Name of the machine hosting the Redis server
    • port: Network connection port number (optional, uses port 6379 by default)
    • db_number: Number of the base to connect to (optional, uses base 0 by default)
    Examples:
    • redis://localhost
    • redis://db_server.mydomain.com:6380/2

    It is possible to connect to a Redis server using a local Unix socket, rather than a network socket:
    redis-sock:///path/to/unix/socket[#base]
    Compared to a classic Redis configuration, you must indicate the path to the Unix socket file, instead of the server name. If a base number is specified, it must be indicated at the end, after a hash character (#); otherwise base 0 is used by default.
    Examples:
    • redis-sock:///var/run/redis/redis-server.sock
    • redis-sock:///var/run/redis/redis-server.sock#2
  • Cache server (Memcached)
    memcache://host[:port]
    • host: Name of the machine hosting the Memcached server
    • port: Network connection port number (optional, uses port 11211 by default)
    Example: memcache://localhost

    It is possible to configure the client to connect to several Memcached servers (the distribution of data on several Memcached servers is managed on the client side). To do this, you must indicate the servers one after the other, separated by a semicolon (;); each server can be accompanied by a specific port number.
    Example: memcache://localhost;serv1:11212;serv2

    It is possible to connect to a Memcached server using a local Unix socket, rather than a network socket:
    memcache:///path/to/unix/socket
    Compared to a classic Memcached configuration, you must indicate the path to the Unix socket file, instead of the server name.
    Example: memcache:///var/run/memcached/memcached.sock

4.3loglevels

The loglevels section is used to define the different log levels. You will find information on its use in the documentation page dedicated to the log.

You can define multiple log "classes", each with a different display threshold. The threshold determines the messages that will appear in the etc/temma.log file. When a code tries to write a log message, the message in question will only appear if its level of criticality is greater than or equal to that of the corresponding threshold.

The different possible threshold values are:

  • DEBUG: debugging message (lowest criticality)
  • INFO: information message (default level for messages whose level is not specified)
  • NOTE: notification; normal but meaningful message (default threshold)
  • WARN: alert message; the application does not work normally but it can continue to work.
  • ERROR: error message; the application is not functioning normally and should stop.
  • CRIT: critical error message; the application risks damaging its environment (filesystem or database).

You can define your own log "classes", depending on your application needs. In addition to that, you can use the following classes:

  • Temma/Base: Logs concerning Temma base objects (database, autoloader, sessions, etc.).
  • Temma/Web: Logs concerning the objects of the framework itself.
  • default: Used to set the default threshold, for all classes that are not defined.

If the loglevels directive does not contain an associative array, but simply a string representing a log threshold, this will be used for all messages, regardless of their specific "class".


4.4bufferingLoglevels

The bufferingLoglevels section is not necessarily required. It is used to modify the behavior of the log.

As seen previously (see loglevels section), a message appears in the log file if its criticality level is greater than or equal to the defined threshold. If not, it is simply discarded.

But sometimes you want a different behavior: that messages which are not written are stored, and if a message does end up being written, all pending messages are written to the log file first.

With the bufferingLoglevels directive, it becomes possible to define − for each "class" of log − the threshold above which unwritten messages are stored for later. It is used in the same way as for loglevels, except that messages related to an unlisted class will not be stored.


4.5routes

Routes are used to define "virtual controllers", serving as aliases for real controllers. This is particularly useful for allowing access to controllers under file names (such as the classic robots.txt and sitemap.xml). This also makes it possible to have the same controller which responds on several different URLs, possibly doing different processing depending on the controller name requested.


4.6plugins

Plugins are used to execute code before and/or after controller execution. You will find detailed information on the dedicated documentation page.

The _pre variable is used to list the plugins that will be executed before the controllers.
The _post variable is used to list the plugins that will be executed after the controllers.

Controllers can be listed by name, specifying specific _pre and _post directives for each. It is also possible to specify plugins for a particular action of a controller.


4.7errorPages

In some cases, your site will need to send an HTTP error code. And if an error occurs in your code itself (due to an incorrect SQL query, for example), the framework will decide to send a 500 error.

It is possible to display a different static HTML page for each type of HTTP error, and to define a default page for all types of errors that are not explicitly configured.

To not define all possible error pages, you can use the "default" key to define the default page.
If you want to use the same page, regardless of the error, you can just provide a string, not an associative array.


4.8includePaths

This section is used to add inclusion paths in which PHP is likely to fetch the objects to include.

Basically, Temma adds the lib/ directory of the project to the include path. So, if you write in your code: include('Toto.php');
The lib/Toto.php file will be loaded.

Or, thanks to the autoloader, if you write: new \Aaa\Bbb();
PHP will load the lib/Aaa/Bbb.php file automatically.

But if you add the following configuration in your etc/temma.php file:

<?php

return [
    'includePaths' => [
        '/path/to/lib1',
        '/path2',
    ]
];

If you write in your code require_once('foo.php');
PHP will try to load successively several paths, until it finds the file. In order, it will try:

  • /path/to/lib1/foo.php
  • /path2/foo.php
  • lib/foo.php

Using the autoloader, if you write new \Aa\Bb(); PHP will try the following paths:

  • /path/to/lib1/Aa/Bb.php
  • /path2/Aa/Bb.php
  • lib/Aa/Bb.php

There may be times when you need to specify specific include paths for certain namespace prefixes. Let's say your etc/temma.php file contains the following configuration:

<?php

return [
    'includePaths' => [
        '\Acme\Log' => '/path/to/acme-log/lib',
        '\Aa\\Bb'   => '/path/to/Bb',
    ]
];

If you write the code new \Acme\Log\Writer();
PHP will try to load the file /path/to/acme-log/lib/Writer.php

On the other hand, if you write new \Aa\Bb\Cc();
PHP will load the file /path/to/Bb/Cc.php

It is possible to specify include paths with and without namespace at the same time:

<?php

return [
    'includePaths' => [
        '/path/to/lib1',
        '/path2',
        '\Acme\Log' => '/path/to/acme-log/lib',
        '\Aa\\Bb'   => '/path/to/Bb',
    ]
];

4.9autoimport

All directives placed in the autoimport section are automatically loaded inside the template variable $conf.

Template variables can be accessed in controllers by writing $this['variable'].
They can also be created (or overwritten) by writing $this['variable'] = $ value;.


5Extended configuration

The configuration file can contain extended configuration sections. Their purpose is to group additional parameterization variables, classifying them by functionality. Thus, a controller or a plugin can easily retrieve the values that interest it, without needing to know all the existing configuration variables.

To retrieve an entire extended configuration section, you have to go through the configuration object which is available directly in controllers:

$this->_config

And via the dependency injection component:

$this->_loader->config

For example, to retrieve the entire x-homepage extended configuration, you must write:

$data = $this->_config->xtra('homepage');

To retrieve the senderName variable from the x-email section:

$data = $this->_config->xtra('email', 'senderName');

It is also possible to specify a default value which will be used if the requested variable does not exist:

$data = $this->_config->xtra('email', 'recipient', 'contact@host.domain');

6Configuration by platform and configuration overload

Rather than having a single etc/temma.php file (or etc/temma.json, etc.), you can use different files depending on the platform on which the site is deployed: local, test, staging, production...

To do this, you need to define an ENVIRONMENT environment variable, whose value is the name of the current platform.

For example, you could have a file etc/temma.test.php and a file etc/temma.prod.php. The former will be used on servers whose ENVIRONMENT environment variable is set to test, and the latter on servers whose variable is set to prod.

Often, only certain parts of the configuration differ from one platform to another. In this case, you can put all the common configuration in the usual etc/temma.php file, and put the platform-specific configurations in the specific files.
The general file is read first, and the platform-specific file overrides it with the values it contains.

Furthermore, the files don't all have to be in the same format. You can have a general file etc/temma.php, and override it in staging with a file etc/temma.staging.json and in production with a file etc/temma.prod.yaml.

Finally, it may be necessary to override the configuration file by adding items to the beginning of a defined list (for example, to add a plugin to the beginning of the list of preplugins). In this case, add the suffix __prepend (starting with two underscores) to the configuration key.
For example:

<?php

return [
    'plugins' => [
        '_pre__prepend' => [
            // this plugin will be the first of the '_pre' list
            'MyFirstPlugin'
        ]
    ]
];