Download and Install

Upgrade

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


Install symfony 1.2

About this Release

symfony training
Be trained by symfony experts
Aug 20: London (Getting Started with Symfony2 - English)
Aug 20: London (Web Development with Symfony2 - English)
Aug 21: Köln (Getting Started with Symfony2 - Deutsch)
Aug 21: Köln (Web Development with Symfony2 - Deutsch)
Aug 22: London (Mastering Symfony2 - English)
and more...

Content

How to upgrade?

Upgrade to 1.2 final

Propel

Request

Validators

Forms

Widgets

Response

Prototype and Scriptaculous

Assets from built-in plugins

Browser

Tests

Testers

Links

Actions

Components

sfParameterHolder

Tasks

URL helpers

Image helper

View

Configuration

Plugin configuration

I18N

Exception Templates

This page refers to the 1.2 symfony release. You can switch to:

Upgrading Projects from 1.1 to 1.2

This document describes the changes made in symfony 1.2 and what need to be done to upgrade your symfony 1.1 projects.

If you want more detailed information on what has been changed/added in symfony 1.2, you can read the What's new? tutorial.

symfony 1.2 is compatible with PHP 5.2.4 or later. It might also work with PHP 5.2.0 to 5.2.3 but there is no guarantee.

How to upgrade?

To upgrade a project:

The remaining sections explain the main changes made in symfony 1.2 that need some kind of upgrade (automatic or not).

Upgrade to 1.2 final

If you have upgraded your 1.1 project before 1.2 final, you need to check the following things:

Propel

Propel has been upgraded to version 1.3, which replaces support for Creole with PDO.

Due to the removal of Creole, the following classes are removed:

class name equivalent
sfCreoleDatabase sfPropelDatabase
sfDebugConnection DebugPDO
sfMessageSource_Creole sfMessageSource_PDO
sfCreoleSessionStorage sfPDOSessionStorage

The propel:build-db task has been removed as this functionality is not yet provided by Propel 1.3.

The first step to upgrading is changing from Creole to PDO syntax in the database configuration from the project databases.yml file.

Locate the following:

all:
  propel:
    class:      sfPropelDatabase
    param:
      dsn:      mysql://username:password@localhost/example

Replace with the following:

dev:
  propel:
    param:
      classname: DebugPDO
 
test:
  propel:
    param:
      classname:  DebugPDO
 
all:
  propel:
    class: sfPropelDatabase
    param:
      dsn:        mysql:dbname=example;host=localhost
      username:   username
      password:   password
      encoding:   utf8
      persistent: true
      pooling:    true
      classname:  PropelPDO

Next, you must also upgrade the propel.ini with the PDO format DSN and updated configuration options.

Locate the following:

propel.database            = mysql
propel.database.createUrl  = mysql://username:password@localhost/
propel.database.url        = mysql://username:password@localhost/example

Replace with the following:

propel.database            = mysql
propel.database.driver     = mysql
propel.database.url        = mysql:dbname=example;host=localhost
propel.database.user       = username
propel.database.password   = password
propel.database.encoding   = utf8

Since the underlying api has changed quite a bit, you need to rebuild the object model:

$ php symfony propel:build-model

In most cases, this will be all that is required. If you have customized object model classes, you may need to manually upgrade for the changes in API from Creole to PDO. The upgrade task will attempt to change method signatures to match the Persistent interface, by adding type hinting for PropelPDO in ->save($con = null) and ->delete($con = null).

Change instances of:

public function save($con = null)
public function delete($con = null)

To add PropelPDO type hint:

public function save(PropelPDO $con = null)
public function delete(PropelPDO $con = null)

The transaction api has change slightly: ->begin has been renamed ->beginTransaction() and ->rollback() has been renamed ->rollBack(). Here are the differences:

Creole:

$con->begin();
try {
  /* db logic */
  $con->commit();
} catch (SQLException $sqle) {
  $con->rollback();
  throw $sqle;
}

PDO:

$con->beginTransaction();
try {
  /* db logic */
  $con->commit();
} catch (PDOException $sqle) {
  $con->rollBack();
  throw $sqle;
}

The ::doSelectRS method has been renamed to ::doSelectStmt. Here are the differences:

Creole:

// example of how to manually hydrate objects
$rs = AuthorPeer::doSelectRS(new Criteria());
while($rs->next()) {
  $a = new Author();
  $a->hydrate($rs);
}
 
// example of how to create array of single column
$rs = AuthorPeer::doSelectRS(new Criteria());
$names = array();
while($rs->next()) {
  $names[] = $rs->getString(2);
}
 
$con = Propel::getConnection(SomeTablePeer::DATABASE_NAME);
$stmt = $con->prepareStatement("SELECT * FROM some_table WHERE name = ?");
$stmt->setString(1, $name);
$rs = $stmt->executeQuery();
while($rs->next()) {
   print "Name: " . $rs->getString("name") . "\n";
}

PDO:

// example of how to manually hydrate objects
$stmt = AuthorPeer::doSelectStmt(new Criteria());
while($row = $stmt->fetch(PDO::FETCH_NUM)) {
  $a = new Author();
  $a->hydrate($row);
}
 
// example of how to create array of single column
$stmt = AuthorPeer::doSelectStmt(new Criteria());
$names = array();
while($res = $stmt->fetchColumn(1)) {
  $names[] = $res;
}
 
$con = Propel::getConnection(SomeTablePeer::DATABASE_NAME);
$stmt = $con->prepare("SELECT * FROM some_table WHERE name = ?");
$stmt->bindValue(1, $name);
$stmt->execute();
while($row = $stmt->fetch()) { 
   print "Name: " . $row['name'] . "\n";
}

The Clob and Lob classes from Creole are not used anymore. It means you need to change your code when using these objects:

// Propel 1.1
$object->getClobColumn()->getContents();
 
// Propel 1.2
$object->getClobColumn();

See http://propel.phpdb.org/trac/wiki/Users/Documentation/1.3/Upgrading for more details on upgrading.

All the Propel library have been moved from lib/propel to lib. The upgrade task upgrades the propel.ini file to reflect these changes.

Request

The path_info_array, path_info_key, and relative_url_root settings have been moved from settings.yml to factories.yml (in the param section of the request factory configuration).

This change removes the dependency between sfRequest and sfConfig.

These three request options are now passed to the request constructor as a fourth argument. The formats are also passed as an option, instead of being passed as an attribute.

The request method constants from sfRequest values have changed from integers to strings and the sfRequest::NONE method has been removed:

Constant Old value New value
GET 2 GET
POST 4 POST
PUT 5 PUT
DELETE 6 DELETE
HEAD 7 HEAD
NONE 1 -

The getMethod() and getMethodName() methods now returns the same value, so getMethodName() is deprecated.

The sfAction::getMethodNames() and the corresponding code in sfValidationExecutionFilter from sfCompat10Plugin have been removed. This method was deprecated in 1.1 and was not really useable in 1.0.

Validators

The sfValidatorSchemaCompare constant values have been changed. No change to your code need to be done, but now, you can use nice shortcuts. The following two examples are equivalent:

// symfony 1.1 and 1.2
$v = new sfValidatorSchemaCompare('left', sfValidatorSchemaCompare::EQUAL, 'right');
 
// symfony 1.2 only
$v = new sfValidatorSchemaCompare('left', '==', 'right');

The sfValidatorI18nChoiceCountry and sfValidatorI18nChoiceLanguage validators had a required culture option in symfony 1.1. As the culture is not used in those validators, the culture option is now deprecated. It is still there to maintain backward compatibility but you don't need to provide it anymore.

Forms

In symfony 1.1, the BaseFormPropel was generated in the wrong place (under the lib/form/base/ directory). You need to move it to the lib/form/ directory.

Widgets

The new sfWidgetFormChoice widgets are now used by default by the Propel generated forms instead of sfWidgetFormSelect. To take advantage of this more powerful widgets, you will need to rebuilt your forms:

$ php symfony propel:build-forms

Response

There is a new setting for the response factory: send_http_headers. This setting is true by default, except for the test environment where the headers must not be sent by PHP (the same goal was achieved by using the sf_test setting in symfony 1.1).

This change removes the dependency between sfResponse and sfConfig.

The getStylesheets() and getJavascripts() methods can now return all the stylesheets and javascripts ordered by position if you pass sfWebResponse::ALL as their first argument:

$response = new sfWebResponse(new sfEventDispatcher());
$response->addStylesheet('foo.css');
$response->addStylesheet('bar.css', 'first');
 
var_export($response->getStylesheets());
 
// outputs
array(
  'bar.css' => array(),
  'foo.css' => array(),
)

The sfWebResponse::ALL is also now the default value for the position argument. In symfony 1.1, as the default value is the empty string, the methods only return the files registered for the default position by default, which is not very intuitive.

In symfony 1.1, you was able to get all the files by passing the 'ALL' string as the position, and this behavior is still available by passing sfWebResponse::RAW:

var_export($response->getStylesheets(sfWebResponse::RAW));
 
// outputs
array(
  'first' =>
    array(
      'bar.css' => array (),
    ),
  '' =>
    array(
    'foo.css' => array(),
    ),
  'last' => array(),
)

All the positions (first, '', and last) are now also available as constants:

sfWebResponse::FIRST  === 'first'
sfWebResponse::MIDDLE === ''
sfWebResponse::LAST   === 'last'

The removeStylesheet() and removeJavascript() methods now only take one argument, the file to remove from the response. It will remove the file in all the available positions. In symfony 1.1, they take the position as a second argument.

Prototype and Scriptaculous

symfony continues to decouple its bundled software. In 1.2 the bundled Prototype and Scriptaculous libraries and helpers (JavascriptHelper) have been moved to a core-plugin. Core plugins behave like any plugin but are shipped with symfony. This will make the JavaScript and CSS files of the new sfProtoculousPlugin (the more or less unofficial name of the often featured duo) behave like real plugin assets. They will be now in web/sfProtoculousPlugin rather than in web/sf (as it has been in 1.0 and 1.1). The prototype_web_dir setting will also now point to the new directory.

In addition some very basic javascript helpers that are reusable by any JS framework, have been extracted to a JavascriptBaseHelper which stays in core.

As a new addition, javascript_tag() now can behave as slot(). This allows such usage

<?php javascript_tag() ?>
alert('All is good')
<?php end_javascript_tag() ?>

Assets from built-in plugins

Some built-in plugins come with some stylesheet and JavaScript files. To make them accessible to your project, you need to run the plugin:publish-assets task:

$ php symfony plugin:publish-assets

The project:upgrade1.2 task do this for you.

Browser

The sfBrowser and sfTestBrowser classes have been refactored in four classes:

The idea behind the refactor is that the sfTestFunctional class is a test class, not a browser. So, it takes a browser and a test object as its arguments:

$testBrowser = new sfTestBrowser('localhost');
 
$tester = new sfTestFunctional(new sfBrowser('localhost'), new lime_test());

The sfTestFunctional class acts as a proxy for the browser class which means that all methods from the browser are accessible directly from the functional tester object.

This refactor must not introduce backward incompatibility with symfony 1.1.

The browser classes now add the HTTP_REFERER header for each request.

Tests

Testers

The sfTestFunctionalBase class now delegates the actual tests to sfTester classes. symfony 1.2 has several built-in tester classes:

All the old methods from the test browser have been moved to one of the tester class:

method name tester class new method name
isRequestParameter sfTesterRequest isParameter
isRequestFormat sfTesterRequest isFormat
isStatusCode sfTesterResponse isStatusCode
responseContains sfTesterResponse contains
isResponseHeader sfTesterResponse isHeader
checkResponseElement sfTesterResponse checkElement
isUserCulture sfTesterUser isCulture
isCached sfTesterViewCache isCached
isUriCached sfTesterViewCache isUriCached

The tester classes also comes with new test methods:

tester class new method name
sfTesterRequest hasCookie
sfTesterRequest isCookie
sfTesterRequest isMethod
sfTesterUser isAuthenticated
sfTesterUser hasCredential
sfTesterUser isAttribute
sfTesterUser isFlash

Even if the old methods are deprecated, they do not send any warning and will not be removed to maintain backward compatibility with symfony 1.0 and 1.1.

Links

When you simulate a click on a button or on a link, you give the name to the click() method. But you don't have the possibility to differentiate two different links or buttons with the same name.

As of symfony 1.2, the click() method takes a third argument to pass some options.

You can pass a position option to change the link you want to click on:

$b->
  click('/', array(), array('position' => 1))->
  // ...
;

By default, symfony clicks on the first link it finds in the page.

You can also pass a method option to change the method of the link or the form you are clicking on:

$b->
  click('/delete', array(), array('method' => 'delete'))->
  // ...
;

This is very useful when a link is converted to a dynamic form generated with JavaScript.

Actions

By default, when you use the redirectIf() or redirectUnless() methods in your actions, symfony automatically changes the response HTTP status code to 302.

These two methods now have an additional optional argument to change this default status code:

$this->redirectIf($condition, '@homepage', 301);
$this->redirectUnless($condition, '@homepage', 301);

The redirect() method already have this feature.

Components

If you have the output escaper enabled, there was a bug in symfony 1.0 and 1.1. When you passed some variables from an action to a component, these were escaped in the component. So, in some circumstances, you had to unescaped them:

public function executeInAComponent($request)
{
  $this->foo = $this->foo->getRawValue();
}

As of symfony 1.2, this has been fixed and all variables are now unescaped by default in a component method.

For the above example, you will need to remove the getRawValue() step as the framework does this automatically for you.

sfParameterHolder

The has() method of sfParameterHolder has been changed to be more semantically correct.

It now returns true even if the value is null:

$ph = new sfParameterHolder();
$ph->set('foo', 'bar');
$ph->set('bar', null);
 
$ph->has('foo') === true;
$ph->has('bar') === true; // returns false under symfony 1.0 or 1.1

The sfParameterHolder::has() method is used by the hasParameter() and hasAttribute() methods available for a large number of core classes.

Tasks

The Propel tasks relying on Phing now output a clear error message if the embed Phing task fails.

Some CLI tasks takes an application name as an argument because they need to connect to the database. We need an application because the configuration can be customized on an application basis and all the symfony configuration system is based on the application level.

For these tasks, this argument has been removed in favor of an optional "application" option. If you don't provide the "application" option, symfony will take the database configuration from the project databases.yml file.

The following task signatures have been changed accordingly:

This is possible because sfDatabaseManager now takes a project configuration or an application configuration. For the curious one, this works because sfDatabaseConfigHandler now returns a static or a dynamic configuration based on an array of configuration files (see the execute() and evaluate() methods).

The propel:insert-sql task removes all the data from the database. As it destroys information, it now asks the user to confirm the execution of the task. The same goes for the propel:build-all and propel:build-all-load tasks, as they call the propel:insert-sql task.

If you want to use these tasks in a batch and want to avoid the confirmation question, pass the no-confirmation option:

$ php symfony propel:insert-sql --no-confirmation

Before symfony 1.2, the propel:insert-sql task was the only task to read its database configuration information from propel.ini. As of symfony 1.2, it reads its information from databases.yml. So, if you use several different connections in your model, the task will take those into account. Thanks to this new feature, you can now use the --connection option if you want to only load SQL statements for a given connection:

$ php symfony propel:insert-sql --connection=propel

You can also use the --env and the --application options to select a specific configuration to use:

$ php symfony propel:insert-sql --env=prod --application=frontend

The propel:generate-crud has been renamed to propel:generate-module. The old task name is still available as an alias.

The non-atomic-actions option of propel:generate-module has been removed and some new options have been added:

To ease the debugging, the propel:build-model, propel:build-all, and propel:build-all-load tasks do not remove the generated XML schemas anymore if you pass the --trace option.

URL helpers

The old post option of link_to is still valid but deprecated:

// is deprecated
<?php echo link_to('@some_route', array('post' => true)) ?>
 
// and equivalent to
<?php echo link_to('@some_route', array('method' => 'post')) ?>

Using link_to() for non-symfony links is no longer possible in favour of the new functionality. In fact, link_to() was never intended for cases like this:

// does no longer work
<?php echo link_to('Link', '#', array('onclick' => "alert('js')"); ?>
 
// use this instead
<a href="#" onclick="alert('js')">Link</a>

The url_for() and link_to() helpers support new signatures. Instead of an internal URI, they can now also take the route name and an array of parameters:

echo url_for('@article', array('id' => 1));
echo link_to('Link to article', '@article', array('id' => 1));

The old behavior still works without changing anything to your code.

Image helper

In symfony 1.0 and 1.1 the image_tag helper would generate the alt attribute of the img-tag from the filename. This now only happens if sf_compat_10 is on. The new behaviour eases finding of unset alt attributes using a (x)html validator. As a bonus, there is now a alt_title option that will set alt and title attribute to the same value, which is useful for cross browser tooltips.

View

You can override sfViewCacheManager::generateCacheKey() by defining a sf_cache_namespace_callable setting. As of symfony 1.2, the callable is now called with an additional argument, the view cache manager instance.

Configuration

Before symfony 1.2, all the plugins installed under the plugins directory, and all built-in plugins were automatically loaded.

As of symfony 1.2, you need to enable the plugins you want to use in your projects. You can do this in your ProjectConfiguration class. Here is how to enable the Doctrine plugin and disable the Propel one:

public function setup()
{
  $this->enablePlugins('sfDoctrinePlugin');
  $this->disablePlugins('sfPropelPlugin');
}

You can add several plugins in one call by passing an array of plugin names:

public function setup()
{
  $this->enablePlugins(array('sfDoctrinePlugin', 'sfGuardPlugin'));
}

You can also change the order in which plugins are loaded by using the setPlugins method:

public function setup()
{
  $this->setPlugins(array('sfDoctrinePlugin', 'sfCompat10Plugin'));
}

The orm setting is deprecated in settings.yml as it is now automatically set when the ORM plugin is loaded.

The compat_10 setting is also deprecated in settings.yml as it is now automatically set when the sfCompat10Plugin is loaded.

So, to enable the 1.0 compatibility plugin, you need to enable it in your configuration:

public function setup()
{
  $this->enablePlugins('sfCompat10Plugin');
}

By default, symfony only enables the Propel plugin.

You can also enable all installed plugins:

public function setup()
{
  $this->enableAllPluginsExcept('sfDoctrinePlugin');
}

The previous example allows you to enable all plugins except the Doctrine one. If you upgrade from 1.0 or 1.1, this line will make symfony behave like in symfony 1.0 and 1.1.

The sfLoader class is deprecated as the getHelperDirs() and loadHelpers() methods are now part of the sfApplicationConfiguration class. The sfLoader methods now generate a deprecated log message and then call the new methods from the current active configuration.

Plugin configuration

Plugins now have the option of providing a plugin configuration class. These plugin configuration classes setup autoloading for the plugin, and are instantiated in sfProjectConfiguration. This means symfony 1.2 tasks no longer require an application argument for plugin classes to be used. This allows plugins to connect to command.* events, something that was not previously possible.

I18N

Internally, the sfCultureInfo class is now only used as a singleton. Even if it is still possible to bypass the getInstance() method and instantiate a new object directly, it is deprecated. By using the singleton, the performance are better as we only instantiate one culture info object per request and it also means that you can now override some culture information globally in your configuration classes.

The sfCultureInfo::getCountries(), sfCultureInfo::getCurrencies(), and sfCultureInfo::getLanguages() methods now take an optional argument which allows to restrict the return value:

// will only return the FR and ES countries in english
$countries = sfCultureInfo::getInstance('en')->getCountries(array('FR', 'ES'));

The sfCultureInfo::getCurrencies() method now returns an array of currency names. In previous symfony versions, it returned an array with the symbol and the name. To get the old behavior, just pass true as the second argument:

$currencies = sfCultureInfo::getInstance('en')->getCurrencies(null, true);

To get the translation of a single country, language, or currency, you can now use the getCountry(), getCurrency(), and getLanguage() methods from the sfCultureInfo class.

Exception Templates

symfony now respects the current request format when rendering any uncaught exceptions. You can customize each format's output by adding a template to your project or application config/error directory.

For example, an uncaught exception during an XML request could render config/error/exception.xml.php when your application is in debug mode, or config/error/error.xml.php when your application is not in debug mode.

If you had customized the 500 error template in your project, you will need to manually move it to the new directory:

Questions & Feedback

If you find a typo or an error, please register and open a ticket.

If you need support or have a technical question, please post to the official user mailing-list.