Code snippets for symfony 1.x

Navigation

Snippets by user halfer

Redirect cache output depending on module/action

In my current application I found that I often needed to perform a clear-cache to get newly published changes to work on the production site, but in doing this I would clear a lot of valuable data from the template cache.

One solution would have been to turn off cacheing in the appropriate cache.yml file, and then to implement it manually, which would have been fairly easy. However I really like the transparent cacheing feature of symfony, so wrote this extension to sfFileCache to redirect cache output to a safe place, providing that certain criteria are met.

Feedback welcome here.

/**
 * Class to modify location of cache dynamically, thus protecting important files against clear-cache
 *
 * @version 19 Feb 2007
 * 
 * Notes: to configure, place this class in the appropriate lib folder, then in the app settings,
 * enter the following under the all category:
 *
 * all:
 *   safe_cache:
 *     folder:                       altcache
 *     activate:                     [[module1, action1], [module2, action2] ...]
 *
 * Where "altcache" is the name of the alternative cache location, relative to the project root,
 * and the module/action pairs are the actions that the safe cache is to be switched on for.
 *
 * Finally this class needs to be installed in factories.yml:
 *
 * all:
 *   view_cache:
 *     class: SafeFileCache
 *
 * Note that intercepting the constructor was not particularly feasible, as it is called very
 * early in the bootstrapping process, before the context instance is available. This means that
 * getModuleName and getActionName are not be available to test against, leaving us to test the
 * URL, which not be as clean.
 */
class SafeFileCache extends sfFileCache
{
  public function get($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
  {
    $isDiff = $this->isDifferentCache();
    if ($isDiff)
    {
      $save = $this->cacheDir;
      $this->cacheDir = $this->getCachePath();
    }
 
    $result = parent::get($id, $namespace, $doNotTestCacheValidity);
 
    if ($isDiff)
    {
      $this->cacheDir = $save;
    }
 
    return $result;
  }
 
  public function has($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
  {
    $isDiff = $this->isDifferentCache();
    if ($isDiff)
    {
      $save = $this->cacheDir;
      $this->cacheDir = $this->getCachePath();
    }
 
    $result = parent::has($id, $namespace, $doNotTestCacheValidity);
 
    if ($isDiff)
    {
      $this->cacheDir = $save;
    }
 
    return $result;
  }
 
  public function set($id, $namespace = self::DEFAULT_NAMESPACE, $data)
  {
    $isDiff = $this->isDifferentCache();
    if ($isDiff)
    {
      $save = $this->cacheDir;
      $this->cacheDir = $this->getCachePath();
    }
 
    $result = parent::set($id, $namespace, $data);
 
    if ($isDiff)
    {
      $this->cacheDir = $save;
    }
 
    return $result;
  }
 
  public function remove($id, $namespace = self::DEFAULT_NAMESPACE)
  {
    $isDiff = $this->isDifferentCache();
    if ($isDiff)
    {
      $save = $this->cacheDir;
      $this->cacheDir = $this->getCachePath();
    }
 
    $result = parent::remove($id, $namespace);
 
    if ($isDiff)
    {
      $this->cacheDir = $save;
    }
 
    return $result;
  }
 
  private function isDifferentCache()
  {
    $context = sfContext::getInstance();
    $strModule = $context->getModuleName();
    $strAction = $context->getActionName();
 
    $run = false;
    $allowed = sfConfig::get('app_safe_cache_activate');
    if (is_array($allowed))
    {
      foreach($allowed as $allow)
      {
        if (is_array($allow) && (count($allow) == 2))
        {
          list($mod, $act) = $allow;
          if (($mod == $strModule) && ($act == $strAction))
          {
            $run = true;
            break;
          }
        }
      }
    }
 
    return ($run);
  }
 
  private function getCachePath()
  {
    $sysDir = sfConfig::get('sf_root_dir');
    $oldDir = $sysDir . DIRECTORY_SEPARATOR . sfConfig::get('sf_cache_dir_name');
    $newDir = $sysDir . DIRECTORY_SEPARATOR . sfConfig::get('app_safe_cache_folder');
    $cacheDir = $newDir . str_replace($oldDir, '', $this->cacheDir);
 
    return $cacheDir;
  }
}
by halfer on 2007-02-19, tagged cache  clear  filecache  folder 

Custom column selection and use of distinct using Propel Criteria

Here is an example of obtaining a custom set of select columns using Propel Criteria, as opposed to using a custom SQL statement. The use of distinct is also demonstrated.

// Set up empty select
$c = new Criteria();
$c->clearSelectColumns();
 
// Read distinct(owningdepot) from the load table...
$c->addSelectColumn(TmsLoadPeer::OWNINGDEPOT);
$c->addGroupByColumn(TmsLoadPeer::OWNINGDEPOT);
$c->setDistinct();
 
// ...which are IN the provided list
$c->add(TmsLoadPeer::LOAD_ID, $loadIds, Criteria::IN);
$depots = TmsLoadPeer::doSelectRS($c);
 
// Then return an array of depots
$arrDep = array();
foreach ($depots as $depot)
{
  $arrDep[] = $depot[0];
}
by halfer on 2006-08-23, tagged criteria  propel 

Alternative security module

For some applications, the basic security layer offered by symfony is insufficient - often a database describes users organised into groups or hierarchical groups, and a way is needed to translate this into a symfony mechanism. Luckily this is quite easy: a filter can be implemented that redirects if the necessary auth criteria have not been met.

You will need to modify this to match your own objects, but it may be good to get you started. Place it in apps/frontend/lib/myDatabaseSecurityFilter.class.php:

<?php
 
/**
 * Trying something to implement a database security layer
 *
 * HISTORY
 * 24 May 2006 - initial version
 */
class myDatabaseSecurityFilter extends sfBasicSecurityFilter
{
  public function execute($filterChain)
  {
    // A call may be made up of several subcalls, so limit this to just the first one
    if ($this->isFirstCall()) {
      $context = $this->getContext();
      $user = $context->getUser();
      $strUser = $user->getUsername();
      $strModule = $context->getModuleName();
      $strRoute = $strModule . '/' . $context->getActionName();
 
      // Only do security check if the module is security-enabled (which is default, so
      // use 'none' to turn it off
      $strParam = "mod_${strModule}_db_security";
      $boolSec = sfConfig::get($strParam);
 
      if ($boolSec !== 'none') {
 
        // Get the UserMain object for this user
        $objUserMain = $user->getUserMain();
        $objFuncs = $objUserMain->getUserFunctions($strRoute);
 
        // If the above checks did not OK this op, then refuse access
        if (count($objFuncs) < 1)
        {
          $fCtrllr = '';
          if (!sfConfig::get('sf_no_script_name')) $fCtrllr = getenv('SCRIPT_NAME');
          $context->getController()->redirect("$fCtrllr/default/notauth");
        }
      }
    }
 
    $filterChain->execute();
  }
}
 
?>

Basically, this filter looks up a yaml config value on a per-module basis, called mod_<module>_db_security, and if it is set to 'none', then allows the filter to pass through. If it is not, it looks up the database user object (which for convenience I am keeping within my sfUser object) and performs a query called getUserFunctions(), which looks up the current module/action and determines whether this is allowed.

A redirect is called if no explicit authorisation is held, otherwise the module passes control to the next filter.

Then to install it, simply put:

myDbSecurityFilter:
  class: myDatabaseSecurityFilter

in your apps/frontend/config/filters.yml file.

by halfer on 2006-06-20, tagged credentials  owner  security 
(1 comment)

Dump variables/objects to screen

Sometimes a set of circumstances will arise when the programmer is not certain what objects are available to a particular point of a symfony app (the manual is, at the time of writing, not entirely exhaustive).

Simply pop this code in your code temporarily and the output should give you some clues.

$vars = get_defined_vars();
foreach($vars as $key => $val) {
  $t = gettype($$key);
  echo "${key} (${t})<br />";
}
by halfer on 2006-06-02, tagged debug  objects  variables 
(1 comment)