Introduction

Temma in 3 minutes

Temma is a Model-View-Controller (MVC for short), designed to facilitate and accelerate website development.

The framework takes care of incoming requests, saving you from re-developing the lowest layers of your applications over and over again, leaving you to focus on the “business code”, the most important part.

Its philosophy: simple conventions rather than configuration.

  • No routes to declare: by default, the URL /articles/show/2 calls the show(2) method of the Articles controller.
  • No SQL queries to write for simple cases: the framework builds the object that accesses the matching table by itself.
  • No view to wire up: the template associated with the action is automatically interpreted; for APIs, the JSON view is enabled in one line.

The rest of this page demonstrates it on a complete example.


0With an AI agent

If you develop with a coding agent (Claude Code, Codex, Copilot…), you have nothing to install by hand. Just give it this sentence:

Create a website using Temma (temma.net/go)

The agent reads temma.net/go, an executable installation guide: it checks the prerequisites, creates the project, configures the database and the web server, then starts the site. From there it has Temma's AI skills, installed in the project, to write code that follows the framework conventions.

The rest of this page is still worth reading: it explains how Temma works, and therefore what the agent will have produced.


1Basic principles

Temma facilitates the development of sites made up of URLs such as:

http://www.site.com/controller/action/p1/p2/p3

URLs are split into 3 parts:

  • The name of the controller, an object that will be instantiated upon receipt of the request.
  • The name of the action, a method of this object that will be called.
  • A variable number of parameters that this method will be able to use.

The following code will then be executed:

Controller::action(p1, p2, p3)

By default, the framework will generate a page by interpreting the templates/controller/action.tpl template file

On the model side, Temma can automatically create a DAO (Data Access Object): an object that reads and writes the table named after the controller, with no SQL to write. For complex queries, you take back control by writing your own DAO.

Obviously, it is possible to modify the default behaviors. A controller can choose to read data received in POST instead of − or in addition to − those received on the URL or as GET parameters. An action can define a specific template to use, or even define a completely different type of view (which will generate JSON or XML instead of HTML, for example).

The execution flow page details everything Temma does between the moment it receives the request and the moment it sends the response.


2Development example

For this example, we'll create a very simple website with two pages:

  • /articles/list: displays the list of articles.
  • /articles/show/2: displays the article whose identifier is 2.

You can read this example without installing anything.

Four files are involved, shown in bold below. The configuration file already exists after installation, and we are going to fill it in; the three others are the ones we are going to write:

my_project/
    controllers/
        Articles.php
    etc/
        temma.php
    templates/
        articles/
            list.tpl
            show.tpl

Note the templates/articles/ directory: its name is that of the controller, and the name of each template inside it is that of an action. This is the naming convention mentioned above.


2.1Configuration

The first thing to do is to create the project configuration file. This is the etc/temma.php file.

Refer to the configuration documentation for the different options.

Temma installation provides sample files, but here is the content of the one we'll be using:

<?php

return [
    'application' => [
        'dataSources' => [
            // database configuration
            'db' => 'mysql://user:passwd@localhost/mybase'
        ],
        // root controller configuration
        'rootController' => 'Articles'
    ],
    // log writing threshold
    'loglevels' => 'WARN',
    // automatically imported template variables
    'autoimport' => [
        'siteName' => 'Demo site'
    ]
];
  • Line 7: Configuration of the connection to the database. The source is named db, which is the name the DAO will look for by default.
  • Line 10: The rootController directive is used to define the root controller of the site, that is to say the one that will respond when we connect to the address http://www.my-site.com/.
  • Line 13: We define the minimum level of errors that will be recorded in the log/temma.log file.
  • Line 16: We define a template variable containing the name of the site. Auto-imported variables are grouped under the conf variable, so this one will be read in templates by writing {$conf.siteName}.

2.2Database

First of all, we will create a table in the database. You need to run the following query on your database:

CREATE TABLE articles (
    id     INT UNSIGNED AUTO_INCREMENT,
    title  TINYTEXT,
    text   MEDIUMTEXT,
    author TINYTEXT,
    PRIMARY KEY (id)
);

Two naming details matter here, because Temma will rely on them to automatically create the DAO that connects to this table (as we will see in the next section):

  • The table is named articles, like the controller we are about to write.
  • Its primary key is named id.

These are Temma's two default conventions. They can be changed (see the generic DAO documentation), but sticking to them means having nothing to configure.

And we can add data to it:

INSERT INTO articles (title, text, author)
VALUES ('First article',  'Text of the first article',  'John'),
       ('Second article', 'Text of the second article', 'Bob'),
       ('Third article',  'Text of the third article',  'John');

2.3Controller

We will write our first controller. A controller is an object that receives connections and manages them to send data back.
Controllers have actions, and each action can be assigned parameters.

Our controller will be called Articles. Rather than writing it in one go, let's start with the strict minimum: what it takes to display the list of articles.

In the controllers/ directory of your project, create a file named Articles.php.

One line deserves attention before reading the code: $_temmaAutoDao. By declaring this attribute, we ask Temma to automatically create the DAO that will be used to access the data. It will be configured to use the articles table, based on the controller name. It will be available in the controller's $this->_dao attribute, so the controller can query the database without writing any SQL.

<?php

/** Articles management controller. */
class Articles extends \Temma\Web\Controller {
    /** Tell the framework to automatically create the DAO. */
    protected $_temmaAutoDao = true;

    /** Action that displays the list of articles. */
    public function list() {
        // retrieving the list of items from the database
        $articles = $this->_dao->search();

        // the list is made available for the template
        $this['articles'] = $articles;
    }
}
  • Line 4: Controllers must inherit from the \Temma\Web\Controller object.
  • Line 6: The DAO is requested. Temma creates it before the action is executed.
  • Line 9: The list action, which responds to the URL http://www.my-site.com/articles/list
  • Line 11: The search() method of the DAO returns every row of the table, as a list of associative arrays whose keys are the column names:
    [
        ['id' => 1, 'title' => 'First article',  'text' => '...', 'author' => 'John'],
        ['id' => 2, 'title' => 'Second article', 'text' => '...', 'author' => 'Bob'],
        ['id' => 3, 'title' => 'Third article',  'text' => '...', 'author' => 'John'],
    ]
    This is the structure we will find again in the template.
  • Line 14: We copy the value of the $articles variable into the articles template variable. The used template will (implicitly) be the templates/articles/list.tpl file.

That is enough to make the list page work. Here is now the complete controller: we have added the show() action, which displays a single article, and the __invoke() root action, whose only role is to receive connections on the root of the site and to redirect them to the list of articles.

<?php

/** Articles management controller. */
class Articles extends \Temma\Web\Controller {
    /** Tell the framework to automatically create the DAO. */
    protected $_temmaAutoDao = true;

    /** Root action (no explicit action). */
    public function __invoke() {
        // redirection to the list of articles
        $this->_redirect('/articles/list');
    }

    /** Action that displays the list of articles. */
    public function list() {
        // retrieving the list of items from the database
        $articles = $this->_dao->search();

        // the list is made available for the template
        $this['articles'] = $articles;
    }

    /**
     * Action that displays the full content of an article.
     * @param  int  $id  Article's identifier.
     */
    public function show(int $id) {
        // retrieval of article content from the database
        $article = $this->_dao->get($id);

        // we check if the requested item exists or not
        if (!$article) {
            // it does not exist, redirect to the list
            $this->_redirect('/articles/list');
        } else {
            // it exists, data are sent to the template
            $this['article'] = $article;
        }
    }
}
  • Line 9: The root action is executed when no action is specifically requested. As this controller has been defined as the root controller (rootController in the etc/temma.php file), this is therefore the action that will be called when accessing the site root.
    • This action responds to the following two URLs:
      http://www.my-site.com/
      http://www.my-site.com/articles
    • Line 11: The Internet user is redirected to the page which displays the list of articles.
  • Line 27: The show action, which displays the content of an article whose identifier is provided as a parameter on the URL. The $id parameter of the method receives the value read on the URL, converted to an integer.
    • This action responds to the URL: http://www.my-site.com/articles/show/2
    • Line 29: The get() method of the DAO retrieves a single row from its identifier, and returns it as an associative array (or an empty value if it doesn't exist).
    • Line 34: If the article does not exist, we redirect to the list of articles.
    • Line 37: If the article exists, we save it as a template variable. The used template will (implicitly) be the templates/articles/show.tpl file.

2.4Templates

Temma uses the Smarty template engine, which is very popular and has a very easy to understand syntax.

For the page that displays the list of articles, we will create the file templates/articles/list.tpl:

<html>
<head>
    <title>{$conf.siteName}</title>
</head>
<body>
    <ul>
        {* loop on the list of articles *}
        {foreach $articles as $article}

            {* add a link to the article *}
            <li>
                <a href="/articles/show/{$article.id}">
                    {$article.title}
                </a>
            </li>

        {/foreach}
    </ul>
</body>
</html>
  • Line 3: The name of the site is placed in the <title> tag. It comes from the autoimport directive of the configuration file. It is escaped, to convert any special characters into HTML entities.
  • Line 8: Loop through the items in the article list, the one the controller stored in the articles template variable.
  • Lines 11 to 15: Creation of the link to the page of an article. Each $article is one of the associative arrays returned by the DAO, so its columns are read by writing {$article.id} and {$article.title}. The title of the article is automatically escaped, to convert special characters to HTML entities.

For the page that displays an article, we will create the file templates/articles/show.tpl:

<html>
<head>
    <title>{$conf.siteName}</title>
</head>
<body>
    {* display the article's title *}
    <h1>{$article.title}</h1>

    {* display the article's author *}
    <h2>by {$article.author}</h2>

    <p>
        {* display the article's content *}
        {$article.text|raw}
    </p>
</body>
</html>
  • Line 3: The site name is placed in the <title> tag, and its special characters are automatically escaped.
  • Line 7: The title of the article is placed in an H1 tag, and its special characters are automatically escaped.
  • Line 10: The author's name is placed in an H2 tag, and its special characters are automatically escaped.
  • Line 14: The text of the article is placed in a paragraph (P tag), and we explicitly request that its contents not be escaped (it is already HTML).

2.5Summary

Here is what the browser displays:

www.my-site.com/articles/list
  • First article
  • Second article
  • Third article
www.my-site.com/articles/show/1
First article
by John
Text of the first article

And here is the chain Temma went through to produce the page of an article:

  1. The Internet user requests /articles/show/2.
  2. Temma instantiates the Articles controller and creates its DAO, configured for the articles table.
  3. Temma calls the show(2) action, which queries the table through $this->_dao and stores the result in a template variable.
  4. Temma interprets the templates/articles/show.tpl template with that variable, and sends the resulting HTML back.

You wrote neither an SQL query, nor routing code, nor any glue between the layers: only the three files of the example.

One last thing: a single line is enough to turn this controller into an API returning JSON, thanks to views. Temma can even do content negotiation: the same controller can then send HTML or JSON, depending on what the client requests.


3Further reading