Skip to content

Overriding column getters in your Model [Updated]

by Sander Coolen on June 25th, 2010

In my first days as a Symfony newbie I got to work on a relatively small and simple project. My experience with MVC, ORM and Zend Framework helped me in finding my way around Symfony and kept the learning curve quite smooth. However, there were and are some architectural oddities that in my opinion are bugs or at least OO-fallacies, but might as well be there for a reason and I just lack the knowledge to wrap my head around them.

One of the problems I stumbled upon had to do with overriding getter and setter methods in my Model classes.

Lets say I have a class with a name and a display_name property. My model class would now have two getters: getName() and getDisplayName(). What I want to achieve is that getName returns its display-name (if set) or else returns its name. This is what I coded and expected to work:

public function getName()
{
  if (null !== $this->display_name) // or whatever to test for
  {
    return $this->getDisplayName();
  }
  return parent::getName();
}

What actually happened was a fatal error:
Maximum function nesting level of ’100′ reached, aborting!

Somehow the call to its parent gets resolved somewhere back to the subclass. Weird…

Update
What Doctrine does isn’t so bizarre after all: if someone created its own getters then you probably would want your ORM to use them. That’s why they’re there. However, it’s not very nice it completely ignores any subclassing you did.

A quick workaround would be to create a new function. Something like:

public function getDisplayNameOrReallyRealNamePleaseDontCrash()
{
  ...
  return parent::getName();
}

The above would indeed solve my problem, but I still don’t know what the [insert Vuvuzela noise] is going on!

A quick dive into the Doctrine plugin classes learned the following:

  1. My Model base class (parent in this case) doesn’t have an actual getName() method either
  2. There’s a magic __call method that looks for getters and setters and forwards them to a generic get or set method in Doctrine_Record
  3. The generic get in this case, checks to see if the field name it wants to retrieve has custom accessors, which it obviously has, because that’s how we got there in the first place
  4. If it finds one (which it will) it calls it and returns the value.Goto and repeat 1 until my pants drop

Unless rewriting Doctrine, which is no need for, there is no way around this. That is, as far as I know. Another workaround, that is a little bit nicer than the previous one would be something like this:

public function getName()
{
  if (null !== $this->display_name)
  {
    return $this->getDisplayName();
  }
  return parent::_get('name'); // directly shove it up his...
}

One of many foils in my first couple of weeks. For me Symfony is a bit like a baby. Everybody can play with it and there will be shit all over the place, but in the end you get a lot in return…

2 Comments
  1. Well there is a simple way

    Doctrine should be configured

    $manager->setAttribute(Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE, true);

    p.s. this is already configured with symfony so you don’t need to do it unless u r using Doctrine alone

    and your method can be like this

    public function getName()
    {
    return $this->_get(‘name’);
    }

    and for setters

    public function setName()
    {
    return $this->_set(‘name’, $value);
    }

    Doctrine uses _get and _set to handle your calls and actually all of getVar and setVar calls are being redirected to _get(‘var’) and _set(‘var’)

  2. Matt permalink

    Just wanna say thanks, this helped me a lot. Banged my head against this problem (and I *did* try $this->get(‘var’) to workaround that).

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS