Liens inter-applications avec Symfony 1.1

24 juillet 2008 par Olivier Mansour

Un important travail réalisé pour la sortie de Symfony 1.1 a été le retrait du pattern singleton du framework. On peut maintenant instancier plusieurs objet sfContext par exemple. Cela permet notamment de faire des liens inter-application a peu près proprement. Voici l’avancée de mon travail sur la question :

fichier lib/helper/crossAppLinkHelper.php

<?php
/**
 * @author Olivier Mansour
 */
 
/**
 * return an url for a given symfony application and an internal url
 * work with symfony 1.1
 * freely inspired from sfWebControlleur code
 *
 * @author Olivier Mansour
 * 
 * @param string $appname
 * @param string $url
 * @param boolean $absolute
 * @param string $env
 * @param boolean $debug
 * @return string
 */
function cross_app_url_for($appname, $url, $absolute = 'false', $env = null, $debug = 'false')
{
 
  if (sfConfig::get('sf_no_script_name'))
  {
  // wont work
  throw new sfException(__FUNCTION__.' : the cross app link helper will not work with sf_no_script_name to true');
  }
 
  // get the environment
  if (is_null($env))
  {
    $env = sfContext::getInstance()->getConfiguration()->getEnvironment();
  }
 
  // context creation
  if (!sfContext::hasInstance($appname))
  {
    $c = ProjectConfiguration::getApplicationConfiguration($appname, $env, $debug);
    sfContext::createInstance($c, $appname);
  }
 
  list($route_name, $parameters) = sfContext::getInstance($appname)->getController()->convertUrlStringToParameters($url);
  $request = sfContext::getInstance($appname)->getRequest();
 
  $url_root = $request->getRelativeUrlRoot();
  if ($absolute)
  {
    $url_root = 'http'.($request->isSecure() ? 's' : '').'://'.$request->getHost().$url_root;
  }
 
  //scriptname
  $scriptname = '';
  if (($env != 'prod') and ($env))
  {
  	$env_suf = '_'.$env;
  } 
  else
  {
   $env_suf = '';
  }
  if (!file_exists(sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.$appname.$env_suf.'.php'))
  {
  	//test with index ?
  	if (file_exists(sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'index'.$env_suf.'.php'))
  	  $scriptname = 'index'.$env_suf.'.php';
  	else
      throw new sfException(__FUNCTION__.' : can\'t find a script name for appname : '.$appname.' and env : '.$env); 	 
  }
  else
  {
  	$scriptname = $appname.$env_suf.'.php';
  }
 
 
  $fragment = '';
  // strip fragment
  if (false !== ($pos = strpos($url, '#')))
  {
    $fragment = substr($url, $pos + 1);
    $url = substr($url, 0, $pos);
  }
 
  // generate url
  list($route_name, $parameters) = sfContext::getInstance($appname)->getController()->convertUrlStringToParameters($url);
 
  if (sfConfig::get('sf_url_format') == 'PATH')
  {
    // use PATH format
    $divider = '/';
    $equals  = '/';
    $querydiv = '/';
  }
  else
  {
    // use GET format
    $divider = ini_get('arg_separator.output');
    $equals  = '=';
    $querydiv = '?';
  }
  $web_url = $url_root.$querydiv.$scriptname.sfContext::getInstance($appname)->getRouting()->generate($route_name, $parameters, $querydiv, $divider, $equals);
 
  if ($fragment)
  {
    $web_url .= '#'.$fragment;
  }
 
  return $web_url;
}

Pour l’utiliser (par exemple, depuis une application nommée back) :

<?php echo cross_app_url_for('front' , '/module/action?id=5&tmp=ok#raoul'); ?>

Je ne l’ai pas beaucoup testé et a vrai dire je ne sais pas si on peut faire plus efficace. Le point particulier qui m’a poussé à écrire autant de code est que, si il est facile d’extraire les routes pour un contexte donnée, la méthode genUrl de sfWebController utilise un objet sfRequest pour obtenir l’url du contrôleur (back_dev.php par exemple) ce qui est bloquant dans mon cas.

Si vous avez des retours n’hésitez pas.

Vous pouvez télécharger le code cité plus haut : crossAppLinkHelper.php.zip

Pour soutenir ce site, n'hésitez pas à cliquer sur un de ces liens :

  1. Par nautilebleu le 25 juillet 2008 | Répondre

    http://fr.pastebin.ca/1082529

    Ce n’est pas un retour mais voici ma solution, pas très différente apparemment.
    Je ne gère dans ce helper que la génération du lien. Il faut donc faire:

    link_to(’text’, cross_app_link_to(’app’, ‘route’, array(
    ‘arg1′ => ‘value1′,
    ‘arg2′ => ‘value2′,
    )))

    Je ne gère pas non plus les fragments.

    A noter que certains paramètres de config (tels que ceux du sfPropelActAsNestedSetBehaviorPlugin disparaissent lorsque l’on switche le contexte, d’où le stockage de ces paramètres au début du helper.

  2. Par Tonio le 4 août 2008 | Répondre

    Hello,

    J’essaie de me servir de cette fonction. Si je génère une URL dans une action, aucun soucis. Par contre si je m’en sers dans layout.php, je perds mes feuilles de style (pas de d’appel dans le html généré). C’est possiblement un bug, ou j’ai encore codé avec les pieds ? :)

    Merci,

    Tonio

  3. Par Olivier Mansour le 11 août 2008 | Répondre

    Oui, en théorie cela devrait bien fonctionner. Pas de raison à mon avis que cela génère le bug que tu décris. Ou bien, c’est un bug de Symfony ?!

  4. Par Oncle Tom le 26 août 2008 | Répondre

    À noter que j’ai aussi découvert `sfContext::switchTo(’controller_env’)` qui effectue une bascule totale du contexte vers cet environnement (config, utilisateurs & cie).

    Je l’ai utilisé dans le cas de liens “preview” du back vers le front sans avoir à me casser la tête.

    Très pratique je trouve.

Commentaires

RSS des commentaires pour ce post