Puesto que no se muy bien como justificar una introducción a este post (de hecho tampoco sé si el título es el más adecuado), voy a poneros simplemente en situación.

Tenemos instalado el plugin sfDoctrineGuardPlugin y necesitamos guardar información “extra” sobre nuestros usuarios, por ejemplo, el email y el nombre. En este caso, y de acuerdo con las indicaciones de @jwage, crearíamos una nueva tabla Profile que guarda una relación 1:1 con sfGuardUser, tal que así:

Profile:
  columns:
    sf_guard_user_id: integer(4)
    full_name: string(255)
    email_address: string(255)
  relations:
    User:
      class: sfGuardUser
      local: sf_guard_user_id
      foreign: id
      foreignType: one

Hasta aquí, nada nuevo bajo el sol. Ahora, supongamos que queremos acceder al nombre de un usuario, el código para esto sería:

  $user->Profile->full_name;

Sencillo, ¿no? Pero, puesto que la relación es de 1:1, en el fondo de nuestro corazón nos gustaría que esto,

  $user->full_name;

bastase para obtener ese valor. ¿Cómo lo conseguimos?

Solución rápida y para toda la familia
La forma más rápida y obvia de conseguir lo anterior es también la más sencilla, basta con esto

// lib/model/doctrine/sfDoctrineGuardPlugin/sfGuardUser.class.php
 
  public function getFullName()
  {
    return $this->Profile->full_name;
  }

pero, ¿qué ocurre si también queremos recoger el email?¿y una dirección?¿y el teléfono?¿y …? De acuerdo a este planteamiento tendremos que crear un nuevo getter en el objeto sfGuardUser por cada atributo en el objeto Profile. Por suerte, existe una solución “mejor”.

La solución “mágica”
PHP dispone de algo muy interesante llamado métodos mágicos. La solución que se muestra más abajo está basada en la utilización que hace Doctrine, en su objeto Doctrine_Record, del método mágico __get($fieldName).

// lib/model/sfGuardUser.class.php
class sfGuardUser extends sfDoctrineRecord
{
  public function get($fieldName, $type = true)
  {
    try{
      parent::get($fieldName, $type = true);
    }catch(exception $e){
      $this->Profile->$fieldName;
    }
  }
}

Aunque no entraré a explicar en detalle que es todo lo que ocurre, grosso modo, cada vez que se pide un atributo al objeto sfGuardUser busca entre los suyos propios y en caso de que no lo encuentre, lo intentará buscar entre los del su Profile. En caso de que tampoco los encuentre, saltará una excepción.

Algunas ventajas
Aparte de las ventajas obvias de poder obtener el valor de los atributos del objeto Profile de manera transparente, también podemos utilizar en el admin generator para mostrar estos campos, por ejemplo, en el listado:

  list:
    display: [username, full_name, email]