Category Archives: Symfony

Symfony related.

Force MySQL timezone on RDS in a Symfony1 project

If you need to force a specific MySQL timezone for your symfony1 project you should edit ProjectConfiguration.class.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ProjectConfiguration extends sfProjectConfiguration
{
    ...
    public function configureDoctrineConnection(Doctrine_Connection $connection)
    {
        $mysql_timezone = sfConfig::get('app_mysql_timezone', 'SYSTEM');
        try
        {
            $connection->exec('SET time_zone = "' . $mysql_timezone . '"');
        } catch (Exception $e)
        {
            /* I'm here because if an invalid timezone
             * is given I'm silently (and cowardly),
             * ignoring it and using MySQL's default
             * timezone instead */

        }
    }
    ...
}
up and down arrow

Symfony 1.4 embed ordered Doctrine relations

Imagine a scenario where a “Product has N ordered Photos”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Product:
  columns
:
    name
:              { type: string(128), notnull: true }
 
Photo
:
  columns
:
    url
:         { type: string(255) }
    product_id
:  { type: integer }
    position
:    { type: integer }
  relations
:
    Product
:
      local
:           product_id
      foreign
:         id
      foreignAlias
:    Photos
      onDelete
:        CASCADE

In the ProductForm you can embed the related Photos with:

1
2
3
4
5
6
7
class ProductForm extends BaseProductForm
{
    public function configure()
    {
        $this->embedRelation('Photos')
    }
}

Problem: The related Photos will be displayed ordered by their id

Solution: Specify the relation between Product and Photos on the schema.yml file and provide a orderBy attribute:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Product:
  columns
:
    name
:              { type: string(128), notnull: true }
  relations
:
    Photos
:
      type
:     many
      class
:    Photo
      local
:    id
      foreign
:  product_id
      orderBy
:  position ASC   # this is the magic part!
      onDelete
: CASCADE
 
Photo
:
  columns
:
    url
:         { type: string(255) }
    product_id
:  { type: integer }
    position
:    { type: integer }
  relations
:
    Product
:
      local
:           product_id
      foreign
:         id
      foreignAlias
:    Photos
      onDelete
:        CASCADE

Example adapted from: http://devblog.lexik.fr/symfony/tips-symfony-1-31-4-orderby-des-relations-1026

Using the Zend framework with Symfony 1.4

In order to integrate Zend with your Symfony 1.4 project, follow these steps:

Step 1. Add the SplClassLoader class to your project (e.g., in /lib/autoload).

Step 2. Require the SplClassLoader and sfCoreAutoload.class.php (located in Symfony’s lib/autoload directory) in your projectConfiguration.class.php:

1
2
3
4
5
<?php
class projectConfiguration extends sfApplicationConfiguration{
       require_once dirname(__FILE__).'/usr/share/symfony/1.4.20/lib/autoload/sfCoreAutoload.class.php';
       require_once dirname(__FILE__).'/../lib/autoload/SplClassLoader.php';
       //...

Step 3. Then, copy the Zend framework to your project (e.g., to /lib/vendor/Zend) and add the following in your projectConfiguration.class.php:

1
2
3
4
5
6
7
8
9
10
<?php
class projectConfiguration extends sfApplicationConfiguration {
      //...
      public function configure(){
            //...
            sfCoreAutoload::register();
            $classLoader = new SplClassLoader('Zend', dirname(__FILE__).'/../../../lib/vendor');
            $classLoader->register();
      }
      //...

And it’s done! Now you can use namespaces to add Zend’s features to your Symfony project:

1
2
3
4
5
6
7
<?php
use Zend\Validator;
class myActions extends sfActions
{
  public function executeValidate(sfWebRequest $request){
    $validator = new EmailAddress();
    //...

Symfony1.4 and Doctrine1.2 setting and getting child elements in execution time

Question

I’m using Symfony1.4 and Doctrine1.2 to create children objects and print them in execution time. The problem is that I always get the children objects from the first query.

I have the following schema:

1
2
3
4
5
6
7
8
Parent:
  id
  name

Child:
  id
  parent_id
  name

My operations:

  1. Initially I have one Parent (with id=1), and no Child
  2. I grab a Parent (id=1) and store that object on $parent
  3. List it’s Child objects
  4. Result: none OK: as expected
  5. Create a new Child and set it’s parent to 1
  6. List $parent‘s Child objects
  7. Result: none OOPS: I expected the new Child from 5.!

Code:

1
2
3
4
5
6
$parent = Doctrine_Query::create()->from('Parent p')->where('p.id = ?', 1)->limit(1)->fetchOne(); /* from 2. */
print_r($parent->getChild()->toArray()); /* from 3. */
$child = new Child();
$child->setParentId($parent->getId());
$child->save(); /* from 4. */
print_r($parent->getChild()->toArray()); /* from 6. */

Note, from Doctrine’s comments:

1
2
3
4
5
6
7
8
9
10
11
/**
* refresh
* refresh internal data from the database
*
* @param bool $deep                        If true, fetch also current relations. Caution: this deletes
*                                          any aggregated values you may have queried beforee
*
* @throws Doctrine_Record_Exception        When the refresh operation fails (when the database row
*                                          this record represents does not exist anymore)
* @return boolean
*/

I’ve already tried re-grabbing the $parent before the last line, but the result is the same.

Own Answer

I found a work-around for this issue:

1
2
3
4
5
6
7
$parent = Doctrine_Query::create()->from('Parent p')->where('p.id = ?', 1)->limit(1)->fetchOne();
print_r($parent->getChild()->toArray());
$child = new Child();
$child->setParentId($parent->getId());
$child->save();
$parent->refresh(true); /* see note! */
print_r($parent->getChild()->toArray());

http://stackoverflow.com/questions/18859509/symfony1-4-and-doctrine1-2-setting-and-getting-child-elements-in-execution-time

Como evitar “The “default” context does not exist.” quando se corre tasks do doctrine em symfony 1.4

O erro acontece devido ao uso do sfContext::getInstance() no código.

Temos duas formas de possível correcção:

Ou se edita a task em questão e se coloca

1
sfContext::createInstance($this->configuration)

para criar um context.

Ou se cria o contexto no código:

1
2
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'doctrine', false);
$context = sfContext::createInstance($configuration);
optimization-icon

Doctrine 1.2 (Symfony 1.4) performance tips & tricks

Sure Doctrine is awesome, but sometimes (every time?), it is also a memory killer. Hopefully there are some handy tricks that can be used on several occasions. Here are some Doctrine 1.2 performance tips & tricks I’ve collected over the time working with Symfony 1.4. Hope they’re useful to you guys!

If you know more performance tips, please leave them in the comments.

 

 

Tip #1

Create a task environment to run tasks and disable the profiler on databases.yml:

1
2
3
4
task:
  doctrine
:
    param
:
      profiler
: false

 

Tip #2

Enable Doctrine’s auto free query objects

1
Doctrine_Manager::connection()->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true);

 

Tip #3

Free Doctrine objects when they are no longer needed

1
2
$doctrine_object->free(true);
$doctrine_object = null;

 

Tip #4

Force Doctrine connection clear after performing needed Doctrine operations

1
2
3
4
5
6
7
Doctrine_Manager::connection()->connect();

// code code ...
$doctrine_object = Doctrine_Query::create()->from('Modal a')->limit(1)->fetchOne();
// code code...

Doctrine_Manager::connection()->clear();

 

Tip #5

Hydrate array when Model objects are not needed.

1
$doctrine_object = Doctrine_Query::create()->from('Modal a')->limit(1)->execute(array(), Doctrine_Core::HYDRATE_ARRAY);

 

Tip #6

Enable APC caching on Doctrine queries.

1
2
Doctrine_Manager::connection()->setAttribute(Doctrine::ATTR_QUERY_CACHE, new Doctrine_Cache_Apc(array('prefix' => 'fancyapcprefix_')));
Doctrine_Manager::connection()->setAttribute(Doctrine_Core::ATTR_RESULT_CACHE, new Doctrine_Cache_Apc(array('prefix' => 'fancyapcprefix_')));

 

Tip #7

Perform bulk inserts instead of one-by-one inserts.

1
2
3
4
5
6
7
8
9
10
11
$record1 = new Model()
$record1->setName('Example #1');
$record2 = new Model()
$record2->setName('Example #2');

$col = new Doctrine_Collection('Model');
$col->add($record1);
$col->add($record2);
$col->add($record3);
$col->add($recordN);
$col->save();

from this post

 

You can read more on Doctrine 1.2 performance here, here, here and here.

sfDoctrineGuardPlugin is evil (on delete cascade)

It happened once, a while ago and it happened again… We’ve deleted a user on the sf_guard_user table and ALL records from ALL tables with that user’s ID (on created_by / updated_by field), got dropped!

Some wise guy thought it made sense to delete all user’s related entries when you delete the user :S

Heres how to change that weird behaviour. On all your schema models, change the old “Signable: ~”, to:

1
2
3
4
5
6
ActAs:
  Signable:
    created:
      onDelete: set null
    updated:
      onDelete: set null

Nginx Symfony 1.4 Configuration

We’ve been trying out nginx server for symfony 1.4 applications, the configuration can be a little bit tricky though… Here’s a working example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server {
  listen 80;
 
  server_name yourdomain.com www.yourdomain.com;

  root /var/www/yourdomain.com/httpdocs/web;

  access_log /var/www/yourdomain.com/logs/access_log main;
  error_log /var/www/yourdomain.com/logs/error_log;

  index index.php;

  location / {
    try_files $uri $uri/ /index.php$uri?$args;
  }
 
  location ~ "^(.+\.php)($|/)" {
        fastcgi_split_path_info ^(.+\.php)(.*)$;
 
        fastcgi_param PHP_VALUE "error_log=/var/www/yourdomain.com/logs/error_log";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_pass   127.0.0.1:9000;
        include        fastcgi_params;
    }

}

Form choice filter auto sort by name

The following snippet will auto-sort all sfWidgetFormDoctrineChoice elements on symfony filters.

On BaseFormFilterDoctrine.class.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
abstract class BaseFormFilterDoctrine extends sfFormFilterDoctrine
{

    public function setup()
    {
        $guesses = array('name', 'title', 'description', 'subject', 'keywords', 'id');

        foreach ($this->getWidgetSchema()->getFields() as $f)
        {
            if ($f instanceof sfWidgetFormDoctrineChoice)
            {
                $model = $f->getOption('model');
                $table = Doctrine::getTable($model);
                $order_by = null;
                foreach ($guesses as $descriptionColumn)
                {
                    if ($table->hasColumn($descriptionColumn))
                    {
                        $order_by = $descriptionColumn;
                        break;
                    }
                }
               
                if (isset($order_by) && $order_by)
                {
                    $f->setOption('order_by', array($order_by, 'asc'));
                }
            }
           
        }

    }

}