The definitive guide of Symfony 1.2

19.3. Custom File Structure

Each time the framework uses a path to look for something (from core classes to templates, plug-ins, configurations, and so on), it uses a path variable instead of an actual path. By changing these variables, you can completely alter the directory structure of a symfony project, and adapt to the file organization requirements of any client.

Caution Customizing the directory structure of a symfony project is possible but not necessarily a good idea. One of the strengths of a framework like symfony is that any web developer can look at a project built with it and feel at home, because of the respect for conventions. Make sure you consider this issue before deciding to use your own directory structure.

19.3.1. The Basic File Structure

The path variables are defined in the sfProjectConfiguration and sfApplicationConfiguration classes and stored in the sfConfig object. Listing 19-5 shows a listing of the path variables and the directory they reference.

Listing 19-5 - Default File Structure Variables, defined in sfProjectConfiguration and sfApplicationConfiguration

sf_root_dir           # myproject/
sf_apps_dir           #   apps/
sf_app_dir            #     frontend/
sf_app_config_dir     #       config/
sf_app_i18n_dir       #       i18n/
sf_app_lib_dir        #       lib/
sf_app_module_dir     #       modules/
sf_app_template_dir   #       templates/
sf_cache_dir          #   cache/
sf_app_base_cache_dir #     frontend/
sf_app_cache_dir      #       prod/
sf_template_cache_dir #         templates/
sf_i18n_cache_dir     #         i18n/
sf_config_cache_dir   #         config/
sf_test_cache_dir     #         test/
sf_module_cache_dir   #         modules/
sf_config_dir         #   config/
sf_data_dir           #   data/
sf_doc_dir            #   doc/
sf_lib_dir            #   lib/
sf_log_dir            #   log/
sf_test_dir           #   test/
sf_plugins_dir        #   plugins/
sf_web_dir            #   web/
sf_upload_dir         #     uploads/

Every path to a key directory is determined by a parameter ending with _dir. Always use the path variables instead of real (relative or absolute) file paths, so that you will be able to change them later, if necessary. For instance, when you want to move a file to the uploads/ directory in an application, you should use sfConfig::get('sf_upload_dir') for the path instead of sfConfig::get('sf_root_dir').'/web/uploads/'.

19.3.2. Customizing the File Structure

You will probably need to modify the default project file structure if you develop an application for a client who already has a defined directory structure and who is not willing to change it to comply with the symfony logic. By overriding the sf_XXX_dir variables with sfConfig, you can make symfony work for a totally different directory structure than the default structure. The best place to do this is in the application ProjectConfiguration class for project directories, or XXXConfiguration class for applications directories.

For instance, if you want all applications to share a common directory for the template layouts, add this line to the configure() method of the ProjectConfiguration class to override the sf_app_template_dir settings:

sfConfig::set('sf_app_template_dir', sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR.'templates');

Note Even if you can change your project directory structure by calling sfConfig::set(), it's better to use the dedicated methods defined by the project and application configuration classes if possible as they take care of changing all the related paths. For example, the setCacheDir() method changes the following constants: sf_cache_dir, sf_app_base_cache_dir, sf_app_cache_dir, sf_template_cache_dir, sf_i18n_cache_dir, sf_config_cache_dir, sf_test_cache_dir, and sf_module_cache_dir.

19.3.3. Modifying the Project Web Root

All the paths built in the configuration classes rely on the project root directory, which is determined by the ProjectConfiguration file included in the front controller. Usually, the root directory is one level above the web/ directory, but you can use a different structure. Suppose that your main directory structure is made of two directories, one public and one private, as shown in Listing 19-7. This typically happens when hosting a project on a shared host.

Listing 19-7 - Example of Custom Directory Structure for a Shared Host

symfony/    # Private area
  apps/
  config/
  ...
www/        # Public area
  images/
  css/
  js/
  index.php

In this case, the root directory is the symfony/ directory. So the index.php front controller simply needs to include the config/ProjectConfiguration.class.php file as follows for the application to work:

require_once(dirname(__FILE__).'/../symfony/config/ProjectConfiguration.class.php');

In addition, use the setWebDir() method to change the public area from the usual web/ to www/, as follows:

class ProjectConfiguration extends sfProjectConfiguration
{
  public function configure()
  {
    // ...

    $this->setWebDir($this->getRootDir().'/../www');
  }
}

19.3.4. Linking to Symfony Libraries

The path to the framework files is defined in the ProjectConfiguration class, located in the config/ directory, as you can see in Listing 19-8.

Listing 19-8 - The Path to the Framework Files, in myproject/config/ProjectConfiguration.class.php

<?php

require_once '/path/to/symfony/lib/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();

class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
  }
}

The path is initialized when you call a php symfony generate:project from the command line, and refer to the symfony installation used to build the project. It is used both by the command line and by the MVC architecture.

This means that you can switch to another installation of symfony by changing the path to the framework files.

The path should be absolute, but by using dirname(__FILE__), you can refer to files inside the project structure and preserve independence of the chosen directory for the project installation. For instance, many projects choose to have the symfony lib/ directory appear as a symbolic link in the project lib/vendor/symfony/ directory, as follows:

myproject/
  lib/
    vendor/
      symfony/ => /path/to/symfony/

In this case, the ProjectConfiguration class just needs to define the symfony lib directory as follows:

<?php

require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();

class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
  }
}

The same principle also applies if you choose to include the symfony files as a svn:externals in the project lib/vendor/ directory:

myproject/
  lib/
    vendor/
      svn:externals symfony http://svn.symfony-project.com/branches/1.1

Tip Sometimes, the different servers running an application don't have the same path to the symfony libraries. One way to enable that is to exclude the ProjectConfiguration.class.php file from the synchronization (by adding it to rsync_exclude.txt). Another method is to keep the same paths in the development and production versions of ProjectConfiguration.class.php, but to have these paths point to symbolic links that can vary according to the server.