Code snippets for symfony 1.x

Navigation

Popular Tags

action admin ajax batch cache cli criteria css culture custom database date debug doctrine email filter form forms generator helper i18n javascript model navigation object pager pagination pake propel query routing session sql symfony template test user validation validator view widget
This is a public source code repository where you can find, rate and comment code snippets published by others, or store you owns and categorize them with tags for easy retrieval.

Latest snippets

Form widget to allow using the values of a column as labels for the optgroup HTML element

Form widget for symfony 1.4 extending sfWidgetFormDoctrineChoice or sfWidgetFormPropelChoice. The new feature is the possibility to indicate a column which values will be used to group all the fields with that column value within optgroup HTML elements.

You can get the code in this link.

by cram1010 on 2012-07-04, tagged optgroup  sfwidgetformdoctrinechoice  sfwidgetformpropelchoice  widget 

Forward in filters

The regular use of forward is causing double content rendering and it took me a while to find the proper solution so here it is:

<?php
 
class SiteFilter extends sfFilter
{
 
  public function execute($filterChain)
  {
    $context = $this->getContext();
 
    if($this->isFirstCall()){
      if(true){ // put some condition in here
        $context->getController()->forward('module', 'action');
        throw new sfStopException(); // the solution
      }
    }
 
    $filterChain->execute();
  }
}
 

As you can see sfStopException() is the key.

by rozwell on 2012-06-08, tagged content  double  filter  filters  forward  rendering 

[Symfony2] Extract the current namespace, bundle, controller and action name

Sometimes, you may have to know, at the controller level what are these informations, it can be easily achieved with the following regexp: (inside a controller action function)

$matches    = array();
$controller = $this->getRequest()->attributes->get('_controller');
preg_match('/(.*)\\\Bundle\\\(.*)\\\Controller\\\(.*)Controller::(.*)Action/', $controller, $matches);
 
$request = $this->getRequest();
$request->attributes->set('namespace',  $matches[1]);
$request->attributes->set('bundle',     $matches[2]);
$request->attributes->set('controller', $matches[3]);
$request->attributes->set('action',     $matches[4]);
 

These informations are now available in the action attributes:

For example:

echo 'namespace: '. $request->attributes->get('namespace'). PHP_EOL;
echo 'bundle: '. $request->attributes->get('bundle'). PHP_EOL;
echo 'controller: '. $request->attributes->get('controller'). PHP_EOL;
echo 'action: '. $request->attributes->get('action'). PHP_EOL;
 

Will output:

namespace: COil
bundle: ToolsBundle
controller: Home
action: index
 

See you. COil

PS: This can be useful in a preExecute() like function.

PS2: The namespace here is the parent directory where is stored the bundle.

by Loïc Vernet on 2012-03-17, tagged action  controller  preexecute  symfony2 

translate messages with html tags

Example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/committees/xliff/documents/xliff.dtd">
<xliff version="1.0">
    <file original="global" source-language="en" datatype="plaintext" date="2009-08-12T12:32:00Z">
        <header/>
        <body>
            ...
            <trans-unit>
                <source>from %from_date%&lt;br /&gt;to %to_date%</source>
                <target>de %from_date%&lt;br /&gt;até %to_date%</target>
            </trans-unit>
        </body>
    </file>
</xliff>
 

Use '&lt;' and '&gt;' to replace '<' and '>'. respectively.

by Raphael Araújo on 2012-01-26, tagged i18n  translate  xml 

Support for Multiple Themes / Styles in Symfony

This will allow you to use multiple themes for symfony, each with it's own templates and stylesheets.

Download

Grab the code at GitHub: https://github.com/acetous/Symfony-Themed

New Directory for Templates

The templates have to be stored in sf_root_dir/themes/application/themename/module. A theme named default has to be present. Layouts have to be placed in sf_root_dir/themes/themename/application.

Example:

Stylesheets

Create stylesheets for your theme. You'll need to create one for each application.

Example:

Please include this stylesheets in your themes root directory. They need to be copied into the /web/css folder.

Only Change What You Need

All themes (except default) will load the default-templates if a custom one is not found. This way you just need to create the template files you want to alter.

Apart from that the default-stylesheet will be included if a custom one cannot be found.

Installation

Setup a Theme

Just run the ./symfony themed:setup task to setup all themes or ./symfony themed:setup name to setup a specific theme.

by acetous on 2011-07-09, tagged style  template  theme  view 
(3 comments)

Collate in propel sort

$c->addAscendingOrderByColumn( 'NAME COLLATE utf8_bin' );

quite obvious

by karol _ on 2011-06-13, tagged criteria  orderby  propel  sort 

Conditional object actions for the admin generator Explained

ReUse of: Conditional object actions for the admin generator By Georg Sorst

The list view of the admin generator currently always displays all defined object actions for each object. There is no way to display an object action for an object only if some condition on this object itself is met.

In order to extend the admin generator with this functionality only a small enhancement is required. You can either apply this change per module or create a new admin generator theme as described in the Symfony book.

The templates/_list_td_actions.php has to be extended to look roughly like this, depending on whether you already have your own modifications in there.

I use sf v1.4.11, for make this enhancement...

First, you should find the partial _list_td_actions.php found in

lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/data/generator/sfDoctrineModule/admin/template/templates/_list_td_actions.php 
 

And modify the original code like this:

<td>
    <?php if ($this->configuration->getValue('list.object_actions')): ?> 
    <ul class="sf_admin_td_actions">
    <?php foreach ($this->configuration->getValue('list.object_actions') as $name => $params): ?>
        <?php if ( isset( $params['condition'] ) ): ?>
            [?php if ( <?php echo ( isset( $params['condition']['invert'] ) && $params['condition']['invert'] ? '!' : '') . '$' . $this->getSingularName( ) . '->' . $params['condition']['function'] ?>( <?php echo ( isset( $params['condition']['params'] ) ? $params['condition']['params'] : '' ) ?> ) ): ?] 
        <?php endif; ?>
 
        <?php if ('_delete' == $name): ?>
            <?php echo $this->addCredentialCondition('[?php echo $helper->linkToDelete($'.$this->getSingularName().', '.$this->asPhp($params).') ?]', $params) ?>
        <?php elseif ('_edit' == $name): ?>
            <?php echo $this->addCredentialCondition('[?php echo $helper->linkToEdit($'.$this->getSingularName().', '.$this->asPhp($params).') ?]', $params) ?>
        <?php elseif ('_show' == $name): ?>
            <?php echo $this->addCredentialCondition('[?php echo $helper->linkToShow($'.$this->getSingularName().', '.$this->asPhp($params).') ?]', $params) ?>
        <?php else: ?>
            <li class="sf_admin_action_<?php echo $params['class_suffix'] ?>">
                <?php echo $this->addCredentialCondition($this->getLinkToAction($name, $params, true), $params) ?>
            </li>
        <?php endif; ?>
 
        <?php if ( isset( $params['condition'] ) ): ?>
            [?php endif; ?]
        <?php endif; ?>
    <?php endforeach; ?>
    </ul>
    <?php endif; ?>
</td>
 

Second, in the generator.yml you should add aditional lines like

actionName:
            label:          actionLabel
            action:         executeAction
            #Now the enhancement =D
            condition:
              # function is the name of function in the model::functionName and must return boolean
              function:     functionName 
              # params are the params to send to functionName
              params:       "$model->getDbField(), $sf_user, 'test'"
              # invert is used if you need invert the result of functionName
              invert:       false
 

Third and final step, go to

lib/model/doctrine/model.class.php
 

and create the functionName like:

/**
* $param1 is $model->getDbField()
* $param2 is $sf_user
* $param3 is 'test'
*/
public function functionName($param1, $param2, $param3){
        //code personal
        return boolean;
    }
 

Final, important!

php symfony cache:clear 
 

Well that's all, sorry for my bad English =S Thanks Georg Sorst and Google Translator

by Krikor Krikorian on 2011-05-26, tagged actions  admin  condition  conditional  generator  object 

Doctrine_Hydrator_XmlDriver

Remember to register your hydrator first.

public function executeIndex(sfWebRequest $request)
  {
    $manager = Doctrine_Manager::getInstance();
    $manager->registerHydrator('xml', 'Doctrine_Hydrator_XmlDriver');
}
 

See http://www.doctrine-project.org/documentation/manual/1_2/en/data-hydrators

<?php
 
class Doctrine_Hydrator_XmlDriver extends Doctrine_Hydrator_ArrayDriver
{
    public function hydrateResultSet($stmt)
    {
        $array = parent::hydrateResultSet($stmt);
        return $this->arrayToXml($array);
    }
 
    /**
     * <pre>Converts an Doctrine array graph of the form:
     * .array
     * .  0 =>
     * .    array
     * .      'id' => '1'
     * .      'PersonaDomicilio' =>
     * .        array
     * .          0 =>
     * .            array
     * .              'id' => '1'
     * To a XML representation.
     * @param array $array
     * @return DOMDocument <pre> The XML with following structure:
     * . &lt;result&gt;
     * .   &lt;rootTable_Collection&gt;
     * .     &lt;rootTable&gt;
     * .       &lt;id&gt;&lt;/id&gt;
     * .       &lt;field1&gt;&lt;/field1&gt;
     * .       &lt;relatedTable_Collection&gt;
     * .         &lt;relatedTable&gt;
     * .         &lt;/relatedTable&gt;
     * .         &lt;relatedTable&gt;
     * .        &lt;/relatedTable&gt;
     * .         ::
     * .       &lt;/relatedTable_Collection&gt;
     * .     &lt;/rootTable&gt;
     * .     &lt;rootTable&gt;
     * .       ::
     * .     &lt;/rootTable&gt;
     * .     ::
     * .   &lt;/rootTable_Collection&gt;
     * . &lt;result&gt;
     * </pre>
     */
    public function arrayToXml(array $array) {
        $result = new DOMDocument();
        $rootNode = $result->createElement('result');
        $result->appendChild($rootNode);
        $iterator = new RecursiveIteratorIterator(
            new RecursiveArrayIterator($array),
            RecursiveIteratorIterator::SELF_FIRST
        );
        $prevLvl = 0;
        $component[$prevLvl] = $this->_queryComponents[$this->_rootAlias]['table']
            ->getComponentName();
        $obj = $result->createElement($component[$prevLvl] . '_Collection');
        $rootNode->appendChild($obj);
        foreach ($iterator as $k => $val) {
            $depth = $iterator->getDepth();
            if ($depth < $prevLvl) {
                for ($i = 0; $i < ($prevLvl - $depth); $i++) {
                    $obj = $obj->parentNode;
                }
            }
            if (! is_array($val)) {
                $son = $result->createElement($k, $val);
                $obj->appendChild($son);
            } else {
                if (is_numeric($k)) {
                    $son = $result->createElement($component[$depth]);
                } else {
                    $component[$depth + 1] = $k;
                    $son = $result->createElement($k . '_Collection');
                }
                $obj->appendChild($son);
                !empty($val) && $obj = $son;
            }
            $prevLvl = $depth;
        }
        return $result;
    }
}
 
by juan Manuel Fernandez on 2011-04-25, tagged doctrine  hydrator  orm 

Generate admin generator module cache from anywhere

Sometimes you'd like to use partial from auto-generated module, like list partial, to keep list presentation unified.

But, before using partial, you add to be sure that cache has been generated or your application will be broken.

This little method (you can place in your tools.class.php) check that cache exists, and if not, generate it.

public static function generateAdminGeneratorModuleCache($module, $configuration)
{
  if(!($configuration instanceof sfApplicationConfiguration)) {
    throw new sfConfigurationException('You must provide a valid application configuration object');
  }
  if(!file_exists(sfConfig::get('sf_app_module_dir').DIRECTORY_SEPARATOR.$module)) {
    throw new sfConfigurationException('The module specified does not exists for this application');
  }
  if(!file_exists(sfConfig::get('sf_app_module_dir').DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'generator.yml')) {
    throw new sfConfigurationException('This module does not seems to be a valid admin generator module');
  }
  if(!file_exists(sfConfig::get('sf_module_cache_dir').DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.'actions'.DIRECTORY_SEPARATOR.'actions.class.php')) {
    // Init generator manager
    $generator_manager = new sfGeneratorManager($configuration);
    $config = sfYaml::load(sfConfig::get('sf_app_module_dir').DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'generator.yml');
    $config['generator']['param']['moduleName'] = $module;
    $generator_manager->generate($config['generator']['class'], $config['generator']['param']);
  }
}
 

Now you can call it from any actions with

myTools::generateAdminGeneratorModuleCache('my_module',$this->getContext()->getConfiguration());
 
by netounet on 2011-03-15, tagged cache  generator 

Validator for latitude / longitude

<?php
/**
 * This validator accepts either a four-member array such as
 * array( 'deg' => 12, 'min' => 34, 'sec' => 56, 'dir' => 'N' )
 * or a numeric value such as 12.3456
 */
class ynValidatorLatLong extends sfValidatorBase
{
  protected function configure($options = array(), $messages = array())
  {
    parent::configure( $options, $messages );
 
    $this->addRequiredOption('axis');  // 'latitude' || 'longitude'
 
    $this->addMessage('invalid_axis', 'The selected axis is invalid.');
  }
 
  protected function doClean( $value )
  {
    $max = 0;
 
    switch ( $this->getOption('axis') ) {
      case 'latitude':
        $max = 90;
        break;
 
      case 'longitude':
        $max = 180;
        break;
 
      default:
        throw new sfValidatorError($this, 'invalid_axis');
    }
 
    if ( is_array( $value ) ) {
      $value = $this->arrayToInt( $value );
    }
 
    if ( ! is_numeric( $value ) ) {
      throw new sfValidatorError($this, 'invalid');
    }
 
    if ( abs( $value ) > $max ) {
      throw new sfValidatorError($this, 'invalid');
    }
 
    return $value;
  }
 
  protected function arrayToInt( array $value )
  {
    if ( count( $value ) != 4 ) {
      throw new sfValidatorError($this, 'invalid');
    }
 
    if (
      ! isset( $value['deg'] )
      || ! isset( $value['min'] )
      || ! isset( $value['sec'] )
      || ! isset( $value['dir'] )
    ) {
      throw new sfValidatorError($this, 'invalid');
    }
 
    if ( preg_match( '/\D/', $value['deg'].$value['min'].$value['sec'] ) ) {
      // non-integer component
      throw new sfValidatorError($this, 'invalid');
    }
 
    $multiplier = 1;
 
    switch ( strtolower( $value['dir'] ) ) {
      case 'n':
        $axis = 'latitude';
        break;
 
      case 's':
        $axis = 'latitude';
        $multiplier = -1;
        break;
 
      case 'e':
        $axis = 'longitude';
        break;
 
      case 'w':
        $axis = 'longitude';
        $multiplier = -1;
        break;
 
      default:
        throw new sfValidatorError($this, 'invalid');
    }
 
    if ( $axis != $this->getOption('axis') ) {
      throw new sfValidatorError($this, 'invalid');
    }
 
    return ( $value['deg'] + $value['min']/60 + $value['sec']/60/60 ) * $multiplier;
  }
}
 
/*
 * UNIT TEST
 */
 
<?php
require_once dirname(__FILE__).'/../../bootstrap/unit.php';
 
$t = new lime_test();
 
$lat_validator = new ynValidatorLatLong( array( 'axis' => 'latitude' ) );
$lon_validator = new ynValidatorLatLong( array( 'axis' => 'longitude' ) );
 
$lat_good = array(
  array( 'deg' => 50, 'min' => 12, 'sec' => 14, 'dir' => 'N' ),
  array( 'deg' => 50, 'min' => 12, 'sec' => 14, 'dir' => 'S' ),
  50.456789,
  50,
  -50.456789,
  -50
);
 
$lat_bad = array(
  'three members' => array( 'deg' => 50, 'min' => 12, 'sec' => 14 ),
  'invalid n/s 1' => array( 'deg' => 50, 'min' => 12, 'sec' => 14, 'dir' => 'F' ),
  'invalid n/s 2' => array( 'deg' => 50, 'min' => 12, 'sec' => 14, 'dir' => 'E' ),
  'non-integer member' => array( 'deg' => 50, 'min' => 12, 'sec' => 14.2, 'dir' => 'N' ),
  'out of range' => array( 'deg' => 100, 'min' => 12, 'sec' => 14, 'dir' => 'N' ),
);
 
$lon_good = array(
  array( 'deg' => 150, 'min' => 12, 'sec' => 14, 'dir' => 'E' ),
  array( 'deg' => 150, 'min' => 12, 'sec' => 14, 'dir' => 'W' ),
  50.456789,
  50,
  -50.456789,
  -50
);
 
$lon_bad = array(
  'three members' => array( 'deg' => 150, 'min' => 12, 'sec' => 14 ),
  'invalid e/w 1' => array( 'deg' => 150, 'min' => 12, 'sec' => 14, 'dir' => 'F' ),
  'invalid e/w 2' => array( 'deg' => 150, 'min' => 12, 'sec' => 14, 'dir' => 'N' ),
  'non-integer member' => array( 'deg' => 150, 'min' => 12, 'sec' => 14.2, 'dir' => 'E' ),
  'out of range' => array( 'deg' => 200, 'min' => 12, 'sec' => 14, 'dir' => 'E' ),
);
 
foreach ( $lat_good as $value ) {
  try {
    $clean = $lat_validator->clean( $value );
    $t->ok( is_numeric( $clean ), 'is numeric' );
 
    if ( is_array( $value ) ) {
      switch( $value['dir'] ) {
        case 'E':
          $multiplier = 1;
          break;
        case 'W':
          $multiplier = -1;
          break;
      }
 
      $t->ok( abs($clean) >= $value['deg'] && abs($clean) <= $value['deg']+1, "value $clean makes sense" );
      $t->ok( $clean * $multipler >= 0, 'direction correct' );
    }
    else {
      $t->is( $value, $clean, 'value makes sense' );
    }
  }
  catch( sfValidatorError $e ) {
    $t->fail( $e->getMessage() );
  }
}
 
foreach ( $lat_bad as $message => $value ) {
  try {
    $lat_validator->clean( $value );
    $t->fail( $message );
  }
  catch( sfValidatorError $e ) {
    $t->pass( $message );
  }
}
 
foreach ( $lon_good as $value ) {
  try {
    $clean = $lon_validator->clean( $value );
    $t->ok( is_numeric( $clean ), 'is numeric' );
 
    if ( is_array( $value ) ) {
      switch( $value['dir'] ) {
        case 'E':
          $multiplier = 1;
          break;
        case 'W':
          $multiplier = -1;
          break;
      }
 
      $t->ok( abs($clean) >= $value['deg'] && abs($clean) <= $value['deg']+1, "value $clean makes sense" );
      $t->ok( $clean * $multipler >= 0, 'direction correct' );
    }
    else {
      $t->is( $value, $clean, 'value makes sense' );
    }
  }
  catch( sfValidatorError $e ) {
    $t->fail( $e->getMessage() );
  }
}
 
foreach ( $lon_bad as $message => $value ) {
  try {
    $lon_validator->clean( $value );
    $t->fail( $message );
  }
  catch( sfValidatorError $e ) {
    $t->pass( $message );
  }
}
 
by yitznewton on 2011-02-27, tagged coordinates  form  latitude  longitude  validator