Best Practice for Storing Settings

Every web project faces similar challenges when it comes to deployment and development: how to store settings and how to deploy them. Settings such as database configuration or SMTP server and port or caching and error reporting are different for production and development environments. Let’s say the workflow looks like this:

  • Developers Jane and Joe work on the project on their individual machines.
  • Project is synced to a development server where bosses and beta testers can review the current development state.
  • Finally, the code is deployed to the production server (or more likely, multiple servers).

Each machine (Jane’s, Joe’s, Preview and Production) needs separate configuration.

In it’s worst form, configuration file would look this:

<?php

/**
 * This is a bad example and wrong approach
 */
$config['db']['encoding'] = 'UTF-8'; // We want to force this onto everybody
if ($_SERVER['SERVER_NAME'] == 'joe.dev' || $_SERVER['SERVER_NAME'] == 'jane.dev') {
  $config['db']['host'] = 'localhost';
  $config['smtp']['host'] = 'smtp.test.com';
} elseif ($_SERVER['SERVER_NAME'] == 'preview.server.dev') {
  $config['db']['host'] = 'localhost';
  $config['smtp']['host'] = 'smtp.site.com';
} elseif ($_SERVER['SERVER_NAME'] == 'www.site.com') {
  $config['db']['host'] = 'dbhost';
  $config['smtp']['host'] = 'smtp.site.com';
}

Of course, such approach has many problems: you have to account for every domain, you have to make sure developers use different domain names in order to have different configuration and it becomes hard to maintain after a while.

A better approach would be do create a structure like this:

config/global.php
config/local.php
config/local.php.example
  • global.php would include shared configuration, like database encoding, which is to be forced upon everybody. This file would be committed to source control tool (Subversion, Git, etc.).
  • local.php.example would contain an example setting array which developers could use to realize what options are there and what needs to be set. It would also be in source control, but would never be used except for reference.
  • local.php would be ignored by source control (via .gitignore or svn:ignore) and developers would be expected to create that file locally, and also create it on preview and production servers as well.

You could take this approach a step further and have all .global.php files committed and all .local.php out of source control, so you could have different files for different settings easily:

config/db.global.php
config/session.global.php
config/db.local.php
config/smtp.local.php
...

While this approach looks better than a single ifed file, there are some crucial problems with it:

  • Configuration is not versioned. So, if your production site starts misbehaving due to a wrong configuration setting, you can’t just revert to an older version.
  • Configuration is invisible: developers Joe and Jane have to log into the production servers to examine the configuration of each instance. If Joe needs help from Jane, she doesn’t know what kind of stuff Joe keeps in his local.php
  • If a single configuration item has to be changed on e.g. all production servers, it will be tedious and can’t be done automatically.

This is clearly an anti-pattern, even if very widely used.

The best solution is to have a structure like this:

config/global.php
config/jane.local.php
config/joe.local.php
config/preview.local.php
config/production.local.php
...

In this scenario, all files are stored in version control. The main challenge is to decide which file to use on which machine. There are two approaches here. The first one is to just have a local.php file, unversioned like in the previous scenario, which only contains one directive:

<?php
include('appropriate.local.php');

and change the content of that file per server. Not a terribly bad approach, but there is a better way. Your HTTP server can set an environment variable which will be available to PHP. In Apache, you would set it by adding SetEnv "APP_ENV" "production" or SetEnv "APP_ENV" "jane" in virtual hosts setting or in .htaccess. In lighttpd, you would use ModSetEnv and do something like setenv.add-environment = ("APP_ENV" => "jane")

After you have the environment variable ready, it will be available to PHP and you can use it in local.php like this:


Voila! It takes some setting up, but it is by far the easiest and cleanest solution. Of course, don't go overboard with using environment variables for everything and anything. Use them when they are appropriate: to decide which environment your PHP script is in.

Removing trailing slash using Lighttpd

If you are deploying your PHP website using lighttpd, you may need to be able to remove the ending slash from an url. E.g. http://www.example.com/my-url/
should redirect to: http://www.example.com/my-url

Regardless of which web framework you are using, this is perhaps best done using your web server. There is a plethora of information about Apache out there, but here is a snippet of how to do it using my server of choice, lighttpd:

$HTTP["host"] == "www.example.com" {
        url.redirect-code = 301
        url.redirect = ("^index.php(.+)/$" => "$1")

        server.document-root = "/var/www/public"
        url.rewrite-if-not-file = (
                "^/(.*)$" => "index.php/$1",
        )
}

The gotcha here is that rewrite rule is executed first, and redirect afterwards. This means that you have to take into account index.php (or app.php, or whatever you are rewriting to) when creating your redirect rule.

Decorator Pattern – PHP Way

While the basic premise behind this article is still right, PHP 5.4 introduced Traits, which are suitable for implementing this design pattern. I recommend using them instead.

There is a strong case for using design patterns in PHP applications. They will help you create code that is readable, easy to maintain and flexible to expand upon.

In programming, design patterns are essentially clever ways of solving common problems. By using these standardized and well documented ways of solving problems, other developers will have an easier time reading your code.

Say that you are making a website for a newspaper. This newspaper has, like newspapers usually do, a number of articles displayed on their site. You represent them with as objects of class Article. Each article has certain methods, like getDate(), getAuthor(), getTitle().

Over time though, things may get complicated. Your editor may decide to collect information about all politicians in local elections, and display their biographical information next to the articles realted to that person. At another point, you will need to show information about a football team mentioned in the article.

One way to solve this is to add methods to your class Article, such as getRelatedPolitican() or getFootballTeam(). Overtime, your Articles will grow bigger and bigger: the class will be harder to maintain and objects will have more unnecessary overhead.

Enter decorator pattern. This pattern allows you to extend functionality of objects without modifying their class. The idea is to, when needed, pass a new object to the object which you want to extend. So, instead of implementing getRelatedPolitican() and getFootballTeam() in the Article class, you create two decorators, let’s call them class DecoratorPolitican and class DecoratorTeam and pass them to your Article object for additional functionality.

Let’s see this in action. First of all, I will define a class which represents an article:

decorators[] = 'DecoratorPolitician';
    }

    public function getDate()
    {
        return "11/2/2010";
    }

    public function getAuthor()
    {
        return "Article Author";
    }

    public function getTitle()
    {
        return "Article Title";
    }

    public function __call($method, $args)
    {
        foreach ($this->decorators as $decorator) {
            if (is_callable(array($decorator, $method))) {
                $dec_object = new $decorator($this);
                return call_user_func(array($dec_object, $method));
            }
        }
    }
}

?>

Now, let me create a class for a decorator:

article = $article;
    }

    public function getPoliticianName()
    {
        return $this->getFirstName() . ' ' . $this->getLastName();
    }

    private function getFirstName()
    {
        return "Foo";
    }

    private function getLastName()
    {
        return "Bar";
    }
}

?>

Let’s go step by step through class Article:

public function __construct()
{
    $this->decorators[] = 'DecoratorPolitician';
}

In the class constructor we added a decorator to the array holding all possible decorators for Article objects. These are only strings, and the objects will getcreated on demand.

The class has several public methods, like getAuthor(), getDate() and getTitle() – these will always be used, so it’s smart to put them in the Article class itself.

Now, the interesting bit, which separates this decorator implemention from others on the web and makes it PHP specific:

public function __call($method, $args)
{
    foreach ($this->decorators as $decorator) {
        if (is_callable(array($decorator, $method))) {
            $dec_object = new $decorator($this);
            return call_user_func(array($dec_object, $method));
        }
    }
}

Magic method __call() will be invoked whenever an unaccessible method is called. So, if you create a new object, trying to access its public methods, there will be no change. But if you try to access methods that it doesn’t have, __call() will be invoked. We’ll use this to our advantage: if any of the decorators has the required method, we will invoke it instead.

Class DecoratorPolitician is fairly simple:

public function __construct(Article $article)
{
    $this->article = $article;
}

It takes an object of the type Article as a parameter. This bounds the specific article to it’s decorator. This is very useful in real world scenarios: you’ll need to access properties of the Article object. E.g. to find a related politician, you would need to have article’s ID, category, or some other information.

Method getPoliticianName() is used to actually return the result to Article. All other methods there are for show: if you have some complex computing to do, it will be well isolated within that one decorator.

Pretty neat, isn’t it? Give it a try:

$article = new Article();
echo $article->getTitle() . PHP_EOL;
echo $article->getDate() . PHP_EOL;
echo $article->getPoliticianName() . PHP_EOL;

This will have an output of:

New article created
Article Title
11/2/2010
New decorator created
Foo Bar

1 2