Code snippets for symfony 1.x

Navigation

How to generate routes (links) from the model or from a task

The symfony routing system is tied to the sfContext resource via the factory handler.

It might an issue if you need to build routes in the cli mode, where sfContext has no instance. Sample: one of your cron jobs sends emails that contain links.

The best way I've found is to provide an access to the routing system linked to the ProjectConfiguration class. Add a static protected "$routing" variable and a static public method "getRouting()" :

class ProjectConfiguration extends sfProjectConfiguration
{
  static protected
    $routing = null # Symfony routing system
    ;
 
 
  /**
   * Returns the routing resource for the active application
   */
  static public function getRouting()
  {
    if (null !== self::$routing)
    {
      return self::$routing;
    }
 
    // If sfContext has an instance, returns the loaded routing resource
    if (sfContext::hasInstance() && sfContext::getInstance()->getRouting())
    {
      self::$routing = sfContext::getInstance()->getRouting();
    }
    else
    {
      // Initialization
      if (!self::hasActive())
      {
        throw new sfException('No sfApplicationConfiguration loaded');
      }
      $appConfig = self::getActive();
      $config = sfFactoryConfigHandler::getConfiguration($appConfig->getConfigPaths('config/factories.yml'));
      $params = array_merge(
        $config['routing']['param'],
        array(
          'load_configuration' => false,
          'logging'            => false,
          'context'            => array(
            'host'      => sfConfig::get('app_host',   'localhost'),
            'prefix'    => sfConfig::get('app_prefix', sfConfig::get('sf_no_script_name') ? '' : '/'.$appConfig->getApplication().'_'.$appConfig->getEnvironment().'.php'),
            'is_secure' => sfConfig::get('app_host',   false),
          ),
        )
      );
      $handler = new sfRoutingConfigHandler();
      $routes = $handler->evaluate($appConfig->getConfigPaths('config/routing.yml'));
      $routeClass = $config['routing']['class'];
      self::$routing = new $routeClass($appConfig->getEventDispatcher(), null, $params);
      self::$routing->setRoutes($routes);
    }
 
    return self::$routing;
  }
}
 

In the method, the 'context' parameter needs further explanations.

In a classic context, symfony is loaded after a web request. Sample: https://www.example.com/frontend_dev.php/products

This request provides data that are reused when sf needs to generate a new dynamic url:

In the cli mode, as Symfony is not loaded by a request, you have to provide these parameters (prefix can be guessed).

In app.yml, add:

all:
  host: www.example.com
  is_secure: false
 

Now, let's see how to generate the link. If your routing.yml file looks like it:

product_show:
  url:     /products/:category_slug/:slug
  class:   sfDoctrineRoute
  options: { model: Product, type: object }
  # ...
 

Then building the link is as simple as:

class Product extends BaseProduct
{
  /**
   * Returns the public url
   */
  public function getUrl()
  {
    return ProjectConfiguration::getRouting()->generate('product', $this, true);
  }
 
 
  /* ... */
}
 

Regards.

by Éric Rogé on 2009-12-11, tagged cli  routing 

Comments on this snippet

gravatar icon
#1 Volker on 2010-01-21 at 02:57

The initialisation line for symfony 1.2.8 should read as following:

// Initialization if (!self::getActive())

There is no method self::hasActive() in symfony 1.2.8, only self::getActive()

gravatar icon
#2 anonymous on 2011-09-23 at 11:28

Spotted a typo in the "context" array definition : ... 'is_secure' => sfConfig::get('app_is_secure', false), // NOT app_host ...

Thanks.