Getting Started

If you are just now getting started with Doctrine, check this previous blog post for how to get started with a new symfony + Doctrine project.

Installing sfDoctrineGuardPlugin

The sfDoctrineGuardPlugin has not been packaged for symfony 1.2 yet so you will need to install via svn like the following:

$ cd /path/to/symfony1.2project
$ svn co http://svn.symfony-project.com/plugins/sfDoctrineGuardPlugin/trunk plugins/sfDoctrineGuardPlugin

Now that the plugin is in your plugins folder you need to tell symfony to enable it. Edit config/ProjectConfiguration.class.php and enable the sfDoctrineGuardPlugin.

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

Be sure to clear your cache after doing the previous steps.

$ ./symfony cc

Enable Modules

sfDoctrineGuardPlugin comes with three modules by default, so in order to use these we will need to enable them in our apps/backend/config/settings.yml. Open it up and modify the enabled_modules setting like the following:

all:
  .settings:
    enabled_modules:        [default, sfGuardUser, sfGuardGroup, sfGuardPermission]

Schema and Data Fixtures

First we need to add some new models to our schema that have relationships defined to the sfGuardUser model included in the sfDoctrineGuardPlugin. So, create a config/doctrine/schema.yml and place the below YAML inside.

In this example we're going to add a Profile model and relate it to sfGuardUser to include some additional information. By default the sfGuardUser schema only includes the information required for the authentication process, nothing more and nothing less. So, in order to capture additional information it is common practice to create a Profile model and relate it to sfGuardUser.

Profile:
  columns:
    sf_guard_user_id: integer(4)
    first_name: string(255)
    middle_name: string(255)
    last_name: string(255)
    email_address: string(255)
  relations:
    User:
      class: sfGuardUser
      foreignType: one
 

Now you will see we defined a one-to-one relationship between Profile and sfGuardUser. By adding that schema, the following is now possible.

$user = new sfGuardUser();
$user->Profile->first_name = 'Jonathan';
 

And you can also access the relationship from the opposite end as Doctrine automatically makes relationships bi-directional.

$profile = Doctrine_Query::create()
  ->from('Profile p')
  ->innerJoin('p.User u')
  ->where('p.id = ?', 1)
  ->fetchOne();
$user = $profile->User;
 

Now that we have our schema defined, we need to define some simple data fixtures to test against. Edit data/fixtures/data.yml and place the following YAML inside.

sfGuardUser:
  jwage:
    username:       jwage
    password:       changeme
    is_super_admin: true
    Profile:
      first_name: Jonathan
      middle_name: Hurley
      last_name: Wage
      email_address: jonwage@gmail.com
 

Now that we have our schema and data fixtures defined, we need to build everything. You can do so by running the following command:

$ ./symfony doctrine:build-all-reload

Well that was pretty easy! Now lets just do a little inspecting and make sure that all is well and the data is loaded properly. Run the following DQL query to inspect the data.

$ ./symfony doctrine:dql "FROM sfGuardUser u, u.Profile p"
>> doctrine  executing dql query
DQL: FROM sfGuardUser u, u.Profile p
found 1 results
-
  id: '1'
  username: jwage
  algorithm: sha1
  salt: 9509acc86d1201e5d8314c2421339896
  password: a9119b7ca39bbb842fed640ed93c121990a37dbf
  is_active: true
  is_super_admin: true
  last_login: null
  created_at: '2008-11-12 13:40:42'
  updated_at: '2008-11-12 13:40:42'
  Profile:
    id: '1'
    sf_guard_user_id: '1'
    first_name: Jonathan
    middle_name: Hurley
    last_name: Wage
    email_address: jonwage@gmail.com

You can even do the opposite to get the Profile objects with the User record joined.

$ ./symfony doctrine:dql "FROM Profile p, p.User u"
>> doctrine  executing dql query
DQL: FROM Profile p, p.User u
found 1 results
-
  id: '1'
  sf_guard_user_id: '1'
  first_name: Jonathan
  middle_name: Hurley
  last_name: Wage
  email_address: jonwage@gmail.com
  User:
    id: '1'
    username: jwage
    algorithm: sha1
    salt: 9509acc86d1201e5d8314c2421339896
    password: a9119b7ca39bbb842fed640ed93c121990a37dbf
    is_active: true
    is_super_admin: true
    last_login: null
    created_at: '2008-11-12 13:40:42'
    updated_at: '2008-11-12 13:40:42'

Now we are ready to take a look at the enabled modules and check out the functionality they provide. Open http://yourhost/backend_dev.php/sf_guard_user and you should see the sfGuardUser module in action like the following:

sfDoctrineGuardPlugin Users

The Customizing

Now we finally get to the fun part. We added a Profile model and related it to sfGuardUser but how do we make that editable when editing sfGuardUser records via the admin generator? This is pretty simple. We need to tweak a few pieces of code to make this possible.

First, lets update our sfGuardUserAdminForm to embed the ProfileForm. To do this we need to copy a file from the plugin to our project so we can customize the form.

$ cp plugins/sfDoctrineGuardPlugin/lib/form/doctrine/sfGuardUserAdminForm.class.php lib/form/doctrine/

Now open lib/form/doctrine/sfGuardUserAdminForm.class.php and override the configure() method to customize it and embed the ProfileForm.

public function configure()
{
  parent::configure();
 
  $profileForm = new ProfileForm($this->object->Profile);
  unset($profileForm['id'], $profileForm['sf_guard_user_id']);
  $this->embedForm('Profile', $profileForm);
}
 

The last thing we need to make this all work is to customize the generator.yml that comes with the plugin. To do this we need to override some of the plugin.

$ mkdir apps/backend/modules/sfGuardUser
$ mkdir apps/backend/modules/sfGuardUser/config
$ touch apps/backend/modules/sfGuardUser/config/generator.yml

Now we need to open apps/backend/modules/config/generator.yml in our editor and tweak it a bit to include the embedded form we named Profile in the previous step.

generator:
  class: sfDoctrineGenerator
  param:
    config:
      form:
        class: sfGuardUserAdminForm
        display:
          "NONE":                   [username, password, password_again, Profile]
          "Permissions and groups": [is_active, is_super_admin, groups_list, permissions_list]
 

Notice all we added was the Profile to the list of things to display in the form.

Final Product

sfDoctrineGuardPlugin Edit User

Now when you add and edit users you have the ability to enter the Profile information directly inside of the user form.