Symfony __toString() generation

I’ve recently had to look at Symfony, and, while OK, it’s made me realize how much I like Grails.  :)

For example, in Symfony, you generate Model classes based on a schema file.  You then generate Form objects for the Models, then tie them together in ‘CRUD’ screens.  All of this is generatable pretty easily, once you know how to do this.  This has changed (and been a bit more complicated since the 1.0 release I used last year).

Anyway, if there are relations (an Author has a Book, for example). the generated forms will complain that the generated Models need a __toString() method to be used in the Form/View.  In grails, this is the case, but every domain (corresponding to a Symfony ‘model’) has an implicit toString() method already generated, which return the string “<domain>:<id>”.  For most production work, you’ll want to override it with whatever you need the string to read, but for prototyping, it’s fine.

In Symfony’s case, I have to explicitly go add a toString() method before I can do anything else.  So, I found the object builder in the symfony core and added this to the addClassClose() method (line 351)

$script .= ”
public function __toString() {
return \”".$this->getTable()->getPhpName().” : \”.\$this->id;

The file I added this to is: /usr/share/php/symfony/plugins/sfPropelPlugin/lib/propel/builder/SfObjectBuilder.php

IMO something like this should be in the symfony core.  Does anyone else agree?  Or is this something already in the works for 1.2?

I'm currently working on a book for web freelancers, covering everything you need to know to get started or just get better. Want to stay updated? Sign up for my mailing list to get updates when the book is ready to be released!

Web Developer Freelancing Handbook

Share and Enjoy:
  • DZone
  • Facebook
  • Reddit
  • StumbleUpon
  • Digg
  • Simpy
  • Technorati

{ 14 comments to read ... please submit one more! }

  1. C’mon, not even symfony devs are that stupid. You must’ve missed a step or something?

    Who would would rely on a function, w/o using if function_exists() and not generate it, and not supply an implementation in the base class?

  2. From my own experience with symfony I know that the default lack of __toString() method for generated model classes can indeed be quite irritating.

    Some sort of default implementation would be a nice addition, but I would take a different approach. As model is defined in schema.yml it would be really easy to just add a property to a table field e.g.

    name : { type: varchar(20), toString: true }

    You could even go further and just use common field names like ‘name’, ‘title’ etc. as the default properties returned by the __toString() method.

  3. Personally i will vote for Krzychu’s approach,

  4. eehh.
    you can override the toString function in you model classes. And it’s there you should overwrite them also.

  5. There’s no ‘toString’ method to ‘override’ which is the crux of my issue. Generated code expects a model to have a toString() method, but the generation procedure doesn’t create one.

  6. Yeah,
    Agree with you on that one. I am a Symfony developer, and yes that does suck. In saying this, you dont always want a __toString method for all your objects. So I can see why it wasnt generated out of the box, but you would think they would make that an option.

    In saying all this but – Symfony is awesome at many other things such as pagination, form validation, search (va sfLucine) and many others.

    Im hooked! /

  7. @Mark: I hope we are not stupid, but nonetheless, thanks for the kind words ;)

    The __toString() method is a PHP magic method. And there is no default implementation in PHP either (hmm, must be because the PHP guys are stupid).

    When you use the form framework, it uses the __toString() method by default to display a representation of the object (for example to display a select box for a foreign key). Even if it would be convenient to have a default implementation, you would still have to override the default implementation for production. So, better to do it now than later, no?

    But more importantly, without default implementation, symfony/PHP is able to give you a nice error message telling you exactly what to do: create a __toString() method. If there was a default implementation for the __toString() method, you would not have the error message but then, you would also have no clue as to how to override the default behavior.

    I think that most of the time, it is better to be explicit rather than implicit.

    But I’m really open to the discussion.

  8. I don’t think it’s in the works already, but feel free to create a ticket in the symfony trac instance. It is a great feature.

  9. @fabien:

    Howdy. Thanks for the reply. I do understand the notion that you’d generally want to override it, but still would have to say that having a default avoids an error message, however nice it may be. Also, the __toString() doesn’t seem to be used in all of the CRUD screens – the ‘list’ page, for example, just uses relation numeric IDs. Having it used consistently across all the generated pages would be useful as well. I generally don’t want to keep the default CSS either, nor the generated HTML for production, but Symfony is still providing something without throwing errors in those cases.

    Mark’s comment aside, I’d meant this as a constructive issue, but don’t know enough about 1.2 to know if it was going to be in there or not. And from what I’m seeing here, some others find this behaviour at least an annoyance. I made the comparison to Grails, which by default does what I made my above code do: “
    : “. Yes, most often you want to change that for production, but for the initial prototyping, it’s nicer to just have it done, saving time and avoiding errors.

    While I’m at it, I’ll make another suggestion (relating to Grails) :) Model-schema generation directly from classes. With Grails, I can have models defined as classes directly, and the system will generate the relations and DB schema and ORM magic automatically, by inferring things from the code. This lets me write classes and run. Very handy. Is it perfect? Certainly not, but it’s the fastest way I’ve yet seen to test out ideas. Again, this isn’t a complaint against Symfony specifically, because no PHP frameworks yet do this (tho is going to give it a try I think!)

    I mentioned this on IRC earlier – I’ve been doing PHP for 12 years, but I find I’m still often able to be more productive in Grails than with any PHP framework. Some of this may just be the language itself – Groovy is expressive in ways that PHP can’t be.

    In any event, thanks for the comment/reply, and perhaps some of these ideas can be taken in to consideration for future Symfony iterations.

  10. I think a standard __toString() method should be automatically created in any class that has a ‘name’ or ‘title’ field. One could also add a config param, so that the developer could specify the fields that would trigger this behavior. This would be a useful addition to the framework, and would facilitate rapid prototyping. The doc in Symfony seems good – I’d think that just documenting this – as well – would handle the concern that Fabien mentioned as to user confusion.

  11. I went in and set this up, and made an additional change so the automatically generated list would pick it up as well, without further intervention.

  12. @mgkimsal – you actually can input your whole schema from classes, you just have to do it in Doctrine (the ORM layer). Relatioships, collections, behaviours, etc, you can do it all in the class defs. Then generate the sql, schema.yml, then the database, forms, etc.

{ 2 Pingbacks/Trackbacks }

  1. » A week of symfony #86 (18-&gt;24 august 2008)
  1. Blackfin Software » Automating __toString in Symfony

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">