Doctrine: How to define relationships

In this post we will review how to define Doctrine relationships, from one-to-one to many-to-many relationships.

One-to-One

To explain this relationship we do it with an example. We suppose that we have two entities (User and Email); when we define the Email entity we should add a ‘user_id‘ property (which is the foreign key) due to the User entity is the “owner” of the relationship, this means the User has an Email. We always need to identify the “owner” side and add the foreign key to the entity which belongs to the “owner” entity. When we use this relationship, Doctrine uses a hasOne method. Let’s see how to define it with yaml:

1
2
3
4
5
6
7
8
9
Email:
  columns:
    user_id: integer
    address: string(150)
  relations:
    User:
      local: user_id
      foreign: id
      foreignType: one

One-to-Many and Many-to-One

Now, let’s suppose we have the same User entity which can have many phone numbers (for that we have a Phonenumber entity). We should follow the same convention than in the one-to-one relationship and define the foreign key in the Phonenumber entity, which belongs to the User entity. When we define this kind of relationship Doctrine uses the hasOne method for the Phonenumber entity and the hasMany method for the User entity. Let’s see how to define it with yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
User:
  // Some properties definitions here
  relations:
    Phonenumbers:
      type: many
      class: Phonenumber
      local: id
      foreign: user_id

Phonenumber:
  columns:
    user_id: integer
    phonenumber: string(50)
  relations:
    User:
      local: user_id
      foreign: id

Many-to-Many

And last but not least, when we need to define a many-to-many we have the need to add an extra table :-S, called JOIN table. Following with our User entity, let’s suppose we have a new entity called Group, and we know that a User can belong to a many Groups and that a Group can have a lot of Users. In this case, if we remove an User we should not remove the Group, but yes the relationship. When we define this kind of relationship Doctrine uses the hasMany method in both entities. Let’s see how to define it with yaml:

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
User:
  // Some properties definition here
  relations:
    Groups:
      class: Group
      local: user_id
      foreign: group_id
      refClass: UserGroup

Group:
  tableName: groups
  columns:
    name: string(30)
  relations:
    Users:
      class: User
      local: group_id
      foreign: user_id
      refClass: UserGroup

UserGroup:
  columns:
    user_id:
      type: integer
      primary: true
    group_id:
      type: integer
      primary: true

Well, I hope this post will be helpful to understand and know how to define Doctrine relationships.

Ref: Doctrine documentation

 

Different environments in the same front controller

If you are familiar with symfony 1.x you should know that the framework comes with a different front controller for each environment, for instance: frontend.php for production, frontend_dev.php for development and frontend_stage.php for stage environment.

Well, I like much to have just one unique front controller which handle the different environments we have. That is what I do in all my projects, and here is the code snippet to do it:

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
<?php
$domainArrayReversed = array_reverse(explode('.', $_SERVER['HTTP_HOST']));
$subdomain = isset($domainArrayReversed[2]) ? $domainArrayReversed[2] : '';

//This is for switching the environment based on the subdomain
$debug = false;
$app = 'frontend';

switch ($subdomain) {
    case 'local':
    case 'dev':
        $env = 'dev';
        $debug = true;
        break;
    case 'stage':
        $env = 'stage';
        break;
    case 'www':
    default:
        $env = 'prod';
        break;
}

require_once(dirname(__FILE__) . '/../config/ProjectConfiguration.class.php');

$configuration = ProjectConfiguration::getApplicationConfiguration($app, $env, $debug);
$sfContext = sfContext::createInstance($configuration);
$sfContext->dispatch();

So with the above script we will be running the application on DEV mode when we use it local.hasheado.com or dev.hasheado.com.

I hope this script will be helpful for you.

Symfony 1.x: Maintenance mode

Symfony Maintenance mode, when enabled, it disallows access to our Symfony project’s appand replaces it with a placeholder (unavailable) page.

To put in maintenance (disable) our application we should run:

1
user@unix:~$ php symfony project:disable [app] [env]

Once this command finishes Symfony looks for an unavailable.php file and let you choose where you prefer to put it. If we have many apps and we want to have a customized unavailable page foe each, we should put it in

/path/to/my/sfProject/apps/[MyApplicationName]/config/unavailable.php.

But, if we want the same Unavailable page for all our apps we should put it in

/path/to/my/sfProject/config/unavailable.php.

To then enable the app again:

1
user@unix:~$ php symfony project:enable [app] [env]

NOTE: To make this command works we should make sure that the check_lock setting is set to “yes/true”.

Crontab: Scheduling tasks

In this post we will see how to schedule task in unix systems with the use of crontab.

Frequently we need to run processes in the background in out web servers like generate thumbnails, execute mantenance MySQl queries, etc. Unix systems have a great tool named cron. This tool allows us to run processes automatically in regular intervals. Also, we can create backups, synchronize files and a much more. To do all these stuff we have crontab.

Crontab
The crontab command is used in Unix systems to schedule other programs to be executed periodicaly. To see what crontabs are currently running in our system, we can run:

1
user@unix:~$ crontab -l

To edit the crontabs we can run:

1
user@unix:~$ crontab -e

This command will open our editor by default to allow us to edit the crontab. To write our crontabs we can use this format:

1
user@unix:~$ * * * * * php /var/www/hasheado/script.php

Explaining the format

As we can see in the above command there are 5 asterisks. The asterisk represent different date and time parts:

  1. minutes (from 0 to 59)
  2. hour (from 0 to 23)
  3. day of month (from 1 to 31)
  4. month(from 1 to 12)
  5. day of the week (from 0 to 6) (0 = Sunday)

Executing a command every minute

If we use an asterisk in all parts:

1
user@unix:~$ * * * * * php /var/www/hasheado/script.php

This will execute the script /var/www/hasheado/script.php:

  1. every minute
  2. every hour
  3. every day of the month
  4. every month
  5. every day of the week

Well that is, I hope it’s helpful, crontab is so powerful.

Symfony2 final version is not there yet

As Fabian Potencier has posted in the Symfony’s blog, Symfony2 is not ready yet. The core team of Symfony has decided to delay the release of the Symfony2 final version.

The core architecture is now stable, except for a few changes in the naming conventions that will be done in the coming days.

Upgrading from one preview release to the next one is now easier, thanks to the new UPDATE document.

Also, the first beta is not out there because the core team is waiting for the last big modification that will possibly be merged: the form framework refactoring. Entering beta means that all the main features of the framework will be available.

So, looking forward for the beta release at least.

Radio buttons and checkboxes styles with JQuery

Interesting JQuery plugin which allow us to style radio buttons and checkboxes elements.

ezMark is a JQuery plugin which allows us to easily stylize radio buttons and checkboxes. It’s a very little plugin (minified version ~1.5kb) compared with other plugins. Also, it was successfully tested in most of browsers (Firefox, Chrome, Safari, IE 6/7/8).

To customize the default images for radiobutton/checkbox, we just need to change the following background images (checkbox-black.png/radio-black.png) and the CSS (ez-checkbox/ez-radio and ez-checked/ez-selected) with your preferences.

That is, you can see the plugin working here.

Symfony and Doctrine behaviors

This post is about symfony and doctrine behaviors which are useful for daily uses.

These behaviors allow us to speed up the application development and in this post we will find short descriptions about most common behaviors.

Basically, a behavior will give us some relationships, algorithms and other features between our business entities. Those behaviors are deeply configurable (they should be at least), that configurations include: activate/deactivate behavior features, rename some additional schema attributes, etc.
We can use many Doctrine’s behaviors in our projects, such as core behaviors, extension behaviors, symfony’s plugins, or well, we can build our own behaviors.

Core Behaviors

Doctrine already comes with many behaviors (core behaviors), those are:

  • # Versionable – adds a new table to store our diferent versions of the entity to keep our entities versionable.
  • # Timestampable – this probably is the most popular behavior, adds two new columns (created_at and updated_at) to automatically store the dates when the entity is created or updated respectively.
  • # Sluggable – adds a new column (slug) which is unique and could be use by sfDoctrineRoute to refer the entity.
  • # I18n – adds a new table to provide Internationalization (I18n) to our model, this behavior is esential when we develop multi-language apps.
  • # NestedSet – adds a few columns (root_id, lft, rgt and level) to our entity to develop a hierarchy data structure (tree structure).
  • # Searchable – choses the columns of our entity which we want to index and adds a new table, speeding up the search engine development.
  • # Geographical – adds the longitude and latitude columns storing specific geographical coordinates, and provides us a getDistance() method to calculate the distance between 2 geographical entities.
  • # SoftDelete – adds a new deleted_at column which defines if a record has been marked as deleted (and when). It is an useful behavior when we need important consistency data.

Extension Behaviors

Also, we can use the Doctrine exntesions:

  • # Blameable – adds an additional level to audit our entities, it allows us to follow who has created or updated an entity.
  • # EventLoggable – saves a log of every Doctrine’s event (pre/post Delete/Insert/…) used by a record.
  • # Localizable – gives us the functionality to convert measure units (for instance, kilometers to miles).
  • # Locatable – gives us the functionality to use Google Maps to automatically fill our entity with longitude and latitude information from Google.
  • # Sortable – gives us the functionality to sort our entities.
  • # Taggable – adds abilities to tagging, it creates two tables using m:n relationships and provides easy tags administration.

Plugin Behaviors

Finally, there are some symfony’s plugins which gives us more behaviors:

I hope this post is useful.

Symfony: Executing queries after load fixtures

In this post we will see how to use symfony’s events to execute SQL queries after loading fixtures.

Sometimes we have the need to execute some SQL queries after we have loaded our fixtures, for instance, we need to do something specific for our RDBMS (Relational Database Management System) which is not supported by Doctrine nor Propel. Fortunately, symfony 1.4 has an excellent events system which allows us to connect the framework’s core and execute our own code when certain actions take place.

The below code snippet is an example of how we can execute some SQL queries manually after of doctrine:data-load:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class ProjectConfiguration extends sfProjectConfiguration
{
    public function setup()
    {
        // ...
        $this->dispatcher->connect('command.post_command', array(
            $this, 'listenToCommandPostCommandEvent'
        ));
    }

    public function listenToCommandPostCommandEvent(sfEvent $event)
    {
        $invoker = $event->getSubject();
        if($invoker instanceof sfDoctrineDataLoadTask)
        {
            $conn = Doctrine_Manager::connection();
            $conn->exec(// ...);
        }
    }
}

Symfony 1.4 have a lot of events we can use to customize features. You can learn more about these events in the Symfony’s documentation.