Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "cli"

sfPakeTransformTinyint.php

Problem:

Mysql produce TINYINT fields because BOOLEAN is just a synonym for TINYINT. And if you have TINYINT fields with value 0 or 1 (like BOOLEAN fields) in your database and use command symfony propel-build-schema to generate schema, you will have one problem with admin generator, because it will produse TINYINT fields as text form fields with value - 0 or 1, not as checkboxes. Admin generator needs BOOLEAN fields in schema to produse checkboxes.

Solution:

Solution to automate transformation field type tinyint to boolean where field name prefix is "is_".

sfPakeTransformTinyint.php

<?php
pake_desc( 'apply tinyint-boolean transformation to your data model' );
pake_task( 'transform-schema-tinyint', 'project_exists' );
 
function run_transform_schema_tinyint( $task, $args ) 
{
 
    // Check params
    // -- missing params ?
    if ( !count($args) ) {
        throw new Exception( 'You must provide a transformation to apply.' );
    }
 
    // -- schema exists ?
    $schema_filename = sprintf( '%s/schema.xml', sfConfig::get('sf_config_dir') );
    if ( !file_exists($schema_filename) ) {
        throw new Exception( "Missing schema.xml" );
    }
 
    // Backup schema
    pake_copy( $schema_filename, $schema_filename . '.previous', array('override' => true) );
 
     //do hard work - tinyint->boolean
    if ($args[0] == 'do') {
        $handle = fopen($schema_filename, "r");
        $contents = '';
        while (!feof($handle)) {
          $contents .= fread($handle, 8192);
        }
        fclose($handle);
 
        $contents = preg_replace('/(name="is_.*?type=")TINYINT"/i','$1BOOLEAN"',$contents);
 
        $handle = fopen($schema_filename, "w+");
        fwrite($handle, $contents);
        fclose($handle);
    }
     //undo hard work - boolean->tinyint
    if ($args[0] == 'undo') {
        $handle = fopen($schema_filename, "r");
        $contents = '';
        while (!feof($handle)) {
          $contents .= fread($handle, 8192);
        }
        fclose($handle);
 
        $contents = preg_replace('/(name="is_.*?type=")BOOLEAN"/i','$1TINYINT"',$contents);
 
        $handle = fopen($schema_filename, "w+");
        fwrite($handle, $contents);
        fclose($handle);
    }
 
}
 
?>

copy this code and drop it as new file in SF_DATA_DIR/tasks/ use command: symfony transform-schema-tinyint do to change tinyint to boolean, where field name with "is_" prefix, than rebuild your model with propel-build-model, clear cache, and use admin generator with checkboxes.

If something going wrong, do this command to undo changes in your model:

symfony transform-schema-tinyint undo (to change boolean to tinyint, where field name with "is_" prefix)

or you may use schema.xml.previous <- this is your schema before transformation

by Alex Gemini on 2006-08-28, tagged cli  generator  model  pake  task 
(5 comments)

CLI and Symfony with complex arguments

I create a script to use complex arguments while runing script from command line.

It also allow to switch SF_ENVIRONMENT, SF_APP and SF_DEBUG directly from command line.

Just create configBatch.php in your project's config directory and paste this :

<?php
define('SF_ROOT_DIR',    realpath(dirname(__file__).'/..'));
 
$argv = array();
for ($i = 1; $i < $_SERVER["argc"]; $i++) {
    if ($_SERVER["argv"][$i]{0} === '-') {
        // argument
        $value =  (
            isset($_SERVER["argv"][$i+1]) 
            && 
            $_SERVER["argv"][$i+1]{0} !== '-'
            ?
            $_SERVER["argv"][$i+1]
            :
            true
        );
 
        if ($_SERVER["argv"][$i]{1} === '-') {
            // long argument
            $argv[substr($_SERVER["argv"][$i], 2)] = $value;
        }
        else {
            foreach (str_split($_SERVER["argv"][$i]) as $arg) {
                if (ereg('[a-zA-Z0-9]', $arg)) {
                    $last_arg   = $arg;
                    $argv[$arg] = true;
                }
            }
            $argv[$last_arg] = $value;
        }
    }
}
 
define('SF_APP',         (isset($argv['app'])?$argv['app']:'www'));
define('SF_ENVIRONMENT', (isset($argv['env'])?$argv['env']:'prod'));
define('SF_DEBUG',       (isset($argv['debug'])?1:0));
 
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
 

Then, start your batch file with :

<?php
 
require_once(realpath(dirname(__file__).'/..').DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'configBatch.php');
 
// Your script start here
 

Now, you can pass arguments to you script :

php -f /path/to/project/batch/my_batch.php -rf some_value --help --foo bar
 

Here is the generated $argv :

$argv = array (
  'r' => true,
  'f' => 'some_value',
  'help' => true,
  'foo' => 'bar',
);
 

You can also change the SF_ENVIRONMENT with the --env argument, the SF_APP with the --app argument and the debug flag with --debug argumnent

Enjoy

by Romain Cambien on 2007-11-22, tagged argv  batch  cli 

Call the command line via the browser

You can mimick the call of the symfony command line via a PHP script called from the browser. For instance, for the command

$ symfony clear-cache

...create a webclearcache.php file in your myproject/web/ directory (where the index.php is) with the following content:

<?php
 
// as we are in the web/ dir, we need to go up one level to get to the project root
chdir(dirname(__FILE__).DIRECTORY_SEPARATOR.'..');
 
include_once('/lib/symfony/pake/bin/pake.php');
 
$pake = pakeApp::get_instance();
try
{
  $ret = $pake->run('/data/symfony/bin/pakefile.php', 'clear-cache');
}
catch (pakeException $e)
{
  print "<strong>ERROR</strong>: ".$e->getMessage();
}
 
?>

You can now clear the cache by calling:

http://myapp.example.com/webclearcache.php

Note: Beware that by letting web access to administration tools, you can compromise the safety of your website.

by Francois Zaninotto on 2006-05-24, tagged cli  pake 
(3 comments)

Selecting test groups from cli

I find boring to wait to run all the tests while I'm focusing on a single one or few ones. Thus I decided to hack pake simpletest task to accept test group selection.

1st step:

In your Pake tasks folder (eg.: /usr/share/pear/pake/tasks) edit the pakeSimpletestTask.class.php file

public static function call_simpletest($task, $type = &#039;text&#039;, $dirs = array(), $test_file = null)

and add this few lines replacing the single line 48

if (!$test_file) {
    $files = pakeFinder::type(&#039;file&#039;)-&gt;name(&#039;*Test.php&#039;)-&gt;in($test_dirs);
}
else {
    $files = pakeFinder::type(&#039;file&#039;)-&gt;name($test_file)-&gt;in($test_dirs);
}

This way you are making your pake test task able to accept "hints" about which file to load in the test folder.

2nd step:

Open the sfPakeTest.php file in your symfony/tasks folder and do the following: Add

$test_file = null;
if (count($args) &gt; 1)
{
    $test_file = $args[1];
}

at line 14, then change last line into

pakeSimpletestTask::call_simpletest($task, &#039;text&#039;, $dirs_to_test, $test_file);

That's all.

Now you can launch symfony test <app_name> <test_filename> and have this only executed with no loss of time. You can even use wildcards!!! For example: symfont test myportal *ValidatorTest.php It will execute all the tests named with that pattern in your test/myportal folder.

Super confortable testing at last! Test driven programming requires very flexible test groups approach and this could be a small contribution. Hope it helps. Bye!

by Jacopo Romei on 2006-07-10, tagged cli  pake  test  tests 

Call the command line without a pear install

If you have not a PEAR symfony installation, but rather a couple of symlinks in the lib/ and data/ directories of your project, and if you didn't define shortcuts for the symfony command, you'll have to call manually pake (the tool used for the command line interface) and pass it the right pakefile (the configuration file containing the symfony commands).

This can be done that way:

$ cd /home/production/myproject
$ php /path/to/pake.php -f data/symfony/bin/pakefile.php propel-build-model

In systems where both PHP4 and PHP5 are installed, you probably need to use a PHP5 specific command:

$ php5 /usr/local/php5.1.2/lib/php/pake.php -f data/symfony/bin/pakefile.php propel-build-model
by Francois Zaninotto on 2006-05-23, tagged cli  pake 
(1 comment)

simple console options for batch scripts

I was looking for this type of functionality:

'php batch/mybatch.php app=batch env=dev'

The following allows me to use the same batch scripts for different environments and applications. It also keeps batch scripts lean by only requiring one line.

batch/run_me.php:

require_once('lib/batch.php');
 
//
// begin batch scripting here
//

batch/lib/batch.php:

set_time_limit(0);
 
$app = get_app($argv[1]);
$env = get_env($argv[2]);
$debug = get_debug($argv[3]);
 
//
// initialize symfony
//
 
define('SF_ROOT_DIR',         realpath(dirname(__FILE__).'/../..'));
define('SF_APP',              $app);
define('SF_ENVIRONMENT',      $env);
define('SF_DEBUG',            $debug);
 
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
 
sfContext::getInstance();
 
//
// initialize doctrine (just an example)
//
 
$connection = sfDoctrine::connection();
 
//
// parse command line args
//
 
function get_app($argv)
{
  preg_match('@app=(\w+)@', $argv, $match);
 
  return isset($match[1]) ? $match[1] : 'batch';
}
 
function get_env($argv)
{
  preg_match('@env=(\w+)@', $argv, $match);
 
  return isset($match[1]) ? $match[1] : 'dev';
}
 
function get_debug($argv)
{
  preg_match('@(true|false)@', $argv, $match);
 
  return isset($match[1]) ? $match[1] : true;
 
}
by Roger Stanton on 2006-09-25, tagged batch  cli 

Sending email from a batch script

It can be tricky sending email from a batch script (e.g. for cron use), here's how to do it. Start with your usual batch setup:

define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));
define('SF_APP',         'app_name');
define('SF_ENVIRONMENT', 'environment');
define('SF_DEBUG',       true);
 
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
sfContext::getInstance();

You can set attributes directly from the batch script if you wish:

sfContext::getInstance()->getRequest()->setAttribute('key', $value);

Then forward on to another module/action to handle processing and forwarding to mail as usual:

sfContext::getInstance()->getController()->forward('action', 'module');
by James McGlinn on 2006-06-22, tagged batch  cli  email 

bash alias to cleanup

Just add this to your ~/.bashrc

    alias sfcleanup='symfony propel-build-model && symfony propel-build-sql && symfony propel-insert-sql && php batch/load_data.php && symfony cc'

Next time you want to do a cleanup just type sfcleanup at the project dir.

by Roberto Carvajal on 2006-08-24, tagged bash  cli 
(1 comment)

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 
(2 comments)

Tired to type "php symfony" in your terminal ?

Yeah, so am I.

Here's how to create a "sf" command in your terminal that will do exactly the same job than when you use the "php symfony xxx" command.

There's many ways to do it, here's mine, it should works on all unix systems.

In the "/usr/bin" directory, create an "sf" file with this content :

#!/usr/bin/env php
<?php
 
// This file provides the cli "sf" shortcut instead of "php symfony" in syfony projects
 
if (file_exists('config/ProjectConfiguration.class.php'))
{
  require_once('config/ProjectConfiguration.class.php');
  $dir = sfCoreAutoload::getInstance()->getBaseDir();
}
else
{
  die('You must be in a symfony project directory.'."\n");
}
include($dir.'/command/cli.php');
 

Be carefull, don't forget the first line !

Now, open the rights on execution for the file: "sudo chmod +x /usr/bin/sf"

That's it, you're done. Go in a symfony project and try your brand new "sf" command in your terminal.

May the laziness be with you !

[UPDATE]

Pedro Casado has reported in comments a cleaner method that uses the native bash configuration file :

It worked pretty great for me.

[/UPDATE]

by Éric Rogé on 2009-10-27, tagged cli  lazy  terminal 
(6 comments)

myPakeTransformSchemaSfguard.php

or apply transformation on sfGuard tables into your main schema

Problem

When you generate a schema with sf_guard tables from your main database with the following command, the schema contains all the tables included the sf_guard tables (it's normal).

symfony propel-build-schema xml
 

Then after, when you build the model classes, the sfGuardPlugin classes have a wrong name and are in a wrong place (lib/). There is a post on this problem, how to correctly use propel-build-schema after sfGuardPlugin installation?

symfony propel-build-model
 

Solution

To correct the schema, apply the transformation on the XML schema after the schema generation :

symfony transform-schema-sfguard xml
 

The script add in the schema for all sf_guard_* tables, the package and the phpName with the camelcase used by the plugin.

Also you have to switch off the schema in the plugin to don't have twice declaration :

mv ./plugins/sfGuardPlugin/config/schema.yml ./plugins/sfGuardPlugin/config/schema.yml.off
 

The script: myPakeTransformSchemaSfguard.php

pake_desc( 'apply transformation on sfGuard tables into your main schema' );
pake_task( 'transform-schema-sfguard', 'project_exists' );
 
function run_transform_schema_sfguard($task, $args) 
{
  // Check params
  // -- missing params ?
  if ( !count($args) > 1 ) {
    throw new Exception("You must provide a transformation to apply.\nsymfony transform-schema-sfguard\nsymfony transform-schema-sfguard xml");
  }
 
  // -- schema exists ?
  if ($args[0] == 'xml')
  {
    $schema_filename = sprintf( '%s/schema.xml', sfConfig::get('sf_config_dir') );
    if ( !file_exists($schema_filename) ) {
        throw new Exception( "Missing schema.xml" );
    }
  }
  else
  {
    $schema_filename = sprintf( '%s/schema.yml', sfConfig::get('sf_config_dir') );
    if ( !file_exists($schema_filename) ) {
        throw new Exception( "Missing schema.yml (not yet implemented)" );
    } else {
        throw new Exception( "schema.yml not yet implemented" );
    }
  }
 
  // Backup schema
  //pake_copy( $schema_filename, $schema_filename . '.previous', array('override' => true) );
 
 
  if ($args[0] == 'xml')
  {
    $handle = fopen($schema_filename, "r");
 
    // get the entire file in $contents
    $contents = '';
    while (!feof($handle))
    {
      $contents.= fread($handle, 8192);
    }
    fclose($handle);
 
    $num = preg_match_all('/<table(.*)>/i', $contents, $matches);
 
    // each table definition found
    foreach ($matches[0] as $val)
    {
      if (!preg_match('/package|phpName/i', $val) && preg_match('/name="(sf_guard_.+?)"/i', $val, $val_matches)) {
 
        $table_name = $val_matches[1];
 
        //$php_name   = sfInflector::camelize($val_matches[1]);
        $php_name = sfToolkit::pregtr($val_matches[1], array('#/(.?)#e'   => "'::'.strtoupper('\\1')",
                                                             '/(_)(.)/e'  => "strtoupper('\\2')",
                                                             '/(^)(.)/e'  => "strtolower('\\2')"));
 
        $pattern    = '/(<table.*)(name="'.$table_name.'")(.*>)/i';
        $replace    = '$1$2 package="plugins.sfGuardPlugin.lib.model" phpName="'.$php_name.'" $3';
        $contents   = preg_replace($pattern, $replace, $contents, 1, $count);
 
        pake_echo($table_name);
      } 
    }
 
    // write the result
    $handle = fopen($schema_filename, "w+");
    fwrite($handle, $contents);
    fclose($handle);
  }
}
 

Installation

Put the myPakeTransformSchemaSfguard.php script into data/tasks directory

Use

mv ./plugins/sfGuardPlugin/config/schema.yml ./plugins/sfGuardPlugin/config/schema.yml.off
 
symfony propel-build-schema xml
 
symfony transform-schema-sfguard xml
 
symfony propel-build-model
 
by Olivier LOYNET on 2008-04-09, tagged cli  pake  propel  schema  sfguard 

clear the cache without symfony command line interface

Some PHP code to clean the cache very useful when you don't have access to symfony "command line interface" on production server.

file: symfony_cc.php

<?php
function deltree($f)
{
  $sf = realpath($sf);
 
  if (is_dir($f)) {
    foreach(glob($f.'/*') as $sf) {
      if (is_dir($sf) && !is_link($sf)) {
        deltree($sf);
        if (is_writable($sf)) {
          echo 'Delete dir.: '.$sf."\n";
          rmdir($sf);
        }
      } else {
        if (is_writable($sf)) {
          echo 'Delete file: '.$sf."\n";
          unlink($sf);
        }
      }
    }
  } else {
    die('Error: '.$f.' not a directory');
  }
}
 
echo '<pre>';
echo 'Clean symfony cache'."\n";
echo "\n";
deltree('../../cache');
echo '</pre>';
 
by Olivier LOYNET on 2008-03-11, tagged cache  cli 
(1 comment)

Making a specific Pake task quieter

We wanted to use a 'propel-insert-sql' in our acceptance tests suite to clear DB before every test reducing interferences. We all learned here http://www.symfony-project.com/snippets/snippet/16 how to call a Pake task from our PHP code. To get a quiet 'propel-insert-sql' task letting 'test' task be verbose and reporting test results we must add a method to the pakeTask class in pakeTask.class.php file:

public function setVerbose() 
{
  $this-&gt;verbose = false;
}

and edit sfPakePropel.php file to make 'propel-insert-sql' task quiet:

function run_propel_insert_sql($task, $args)
{
  $task-&gt;setVerbose();
  _call_phing($task, &#039;insert-sql&#039;);
}

This way we have a lot quiter acceptance test suite and a clean DB whenever we want.

by Jacopo Romei on 2006-07-31, tagged cli  pake  propel  test