How to make Symfony/Doctrine generate accessors

Please let our ADS show!

This sites offers only FREE software and it's supported by a few advertisement boxes (no intrusive popups).
Please:

  • disable your AdBlocker by adding CoolSoft website to whitelist
  • give the proper cookie consent
  • enable JavaScript for this website

This seconds wait is to let you update your browser configuration...

Ok, I've done the required changes... now show me your content!
!!! Please enable JavaScript !!!

I'm using Symfony for a big project; after a little research I choosed Doctrine as database access layer, since is more configurable (and modern) then Propel.

I use Eclipse 3.4 and PDT as IDE, mostly because of its great Code Assist feature (CA is Intellisense for VisualStudio users...).

Well, after a bit I found that Doctrine class generator misses to generate column accessors (getters and setters) and relies on PHP __get and __set magic accessors.

Suppose you have an user table, Doctrine generates an User class for you and you can access columns of a single record through its properties, like this:

$a = new User(); $a = $user->getUsername(); $user->setUsername('foo');

Since getUsername() and setUsername() are not real properties, Doctrine lets you access them through __get and __set.

Even if this works, IDEs like Eclipse can't help you writing code because they don't know what properties are defined on User class (except the ones of the class it extends, but they are generic and not related to users table).

Searching through Doctrine documentation, it seems that there should be a generateAccessor option of Doctrine builder which should do the trick; you'll quickly find that this option only exists but is not implemented.

Here you are my solution: a patch for Doctrine builder to add missing accessors generator.
Download the attached file and overwrite the existing one here:

/lib/symfony/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Import/Builder.php

NOTE: this patch applies to Doctrine builder included in both Symfony 1.2.2 and Symfony 1.2.4 version.

Feel free to comment my patch...

UPDATE 21/01/2010: starting from Symfony 1.3/1.4, a newer version of Doctrine is bundled. This new version will not still generate accessors but it adds them as @doc comments. This way the code is much lighter and your IDE is happy too (it works  perfectly in Eclipse with PDT).

Category: 

Commenti

Hi,

I'm also stumped as to why they don't have accessors in their code too. Makes it very difficult to gain test coverage using mock objects and it feels really horrible to me writing OOP with property names full of underscores.

I notice in Doctrine 1.1 that, although I can't seem to find the generateAccessors property in the source code any longer, they have a buildAccessors() method that does the same thing as your patch. Perhaps it's now an implicit part of Doctrine?

I'm still on 1.0 and I've actually patched the __call() method in the Record class to deal with accessors but I'll probably download 1.1 and give that a go.

http://trac.doctrine-project.org/browser/branches/1.1/lib/Doctrine/Impor...

While the method buildAccessors() exists, it doesn't appear to be invoked from anywhere though. I'll keep an eye on this.

Cheers,

Chris

Method buildAccessors() existed in version 1.0, and it was not invoked too.
My patch not only calls it, but extends its implementation adding type declaration through PhpDoc, which is great in IDEs like Eclipse.

I'll give a try to 1.1 soon and I hope they extended its implementation and call it.

Thank for this doctrine patch. It work fine with Sf 1.2.8.
Zend studio for eclipse 7 autocomplete model class correctly.
Shame that symfony does not implement natively option generate_accessors.

You're welcome.
I agree about the shame on Doctrine/Symphony :D

How do you use your patch? I mean, Once I replaced the file, how can I make doctrine generate the accessors?

I usually run this from command line:

$ symfony doctrine:build-model

This should overwrite all your model files into /lib/model/doctrine/base/*
Just to be sure, you could rename/move this folder content before running the above command...

A side-effect of the usage of magic accessors, I think, is the missing ability to overwrite setter-methods.
If, for example, You want to verify an email-address, before it's set to the object, You can't do this by overwriting the (not existing) setEmail-method. Usually I would implement:

class Users extends BaseUsers
{
  static protected function validateEmail($emailAddress)
  {
    // some code here ...
  }

  public function setEmail($newEmail)
  {
    if ( Users::validateEmail($newEmail) )
    {
      parent::setEmail($newEmail);
    }
  }
}

But this would lead to a deadlock, as symfony/doctrine will lead parent::setEmail back to the overwritten setter-method.
Maybe someone else stumbled on that and lost some minutes of thinking (and searching) about it ...

maybe you could try to call

parent::_set('email', $newEmail);

 

Nice job! But what about user methods?
For example, I have a class JobTable that extends Doctrine_Table with a bunch of my own methods and would like to have an autocompletion when I type: Doctrine::getTable('Job')-> ...

Is it possible?

Well, method Doctrine::getTable('Job') will return a class of type Doctrine_Table; your IDE can't know that 'Job' (which is a string) means "give me an instance of class JobTable" that extends Doctrine_Table.

A way to help your IDE is to insert a temporary code that you'll remove after you finished writing code:

$j = Doctrine::getTable('Job');
$j = new JobTable(); // you'll comment out this line after
$j->YourMethod1();
$j->YourMethod2();

Another way to "help" your IDE is to declare your class type with PHPDocumentor @var comment:

/* @var $j JobTable */
$j = Doctrine::getTable('Job');

Beware that not all of the IDEs works with this trick, see here for Eclipse-PDT 2.x.

Coolsoft, thank you this is great! phpDoc trick works in Eclipse. However, more often than not I wouldn't like to assign a JobTable object to a variable (like in example above). Is there a way to specify that Doctrine::getTable('Job') method returns JobTable objects? Sort of /* @method Doctrine::getTable('Job') JobTable */

I think it's not possible.

What about defining a short function like this?

/*
 * @return JobTable
 */
function foo() {
    return Doctrine::getTable('Job');
}

Or define your object directly, like

$a = new JobTable();

 An other way for autocompletion when geting a table :

Create an util class :

##############################

abstract class Doctrane{

  /**
  * @return JobTable
  */
  public static fuction getJobTable()
  {
     return Doctrine::getTable('Job');
  }

  // Other Tables ..
}

################################

Jerem, your solution looks very promising though I'm not quite sure where should I define this class? Is it a spelling mistake (DoctrAne) or not?

Aggiungi un commento