Skip to content

jonocode – a developer's blog

I moved! –>

Here is something to watch out for. If you define global behaviors in your schema, and then define table-level behaviors, the global behavior will be removed (unless you declare it again on the table level).

Here is a quick example:

actAs: [Timestampable]

      fields: [name]
    name: string(255)
    user_id: integer(4)
      foreignType: many
      type: one
      local: user_id
      foreign: id

For a short while I couldn’t figure out why the created_at and updated_at fields weren’t showing up in the Program table. Then I realized that it was removed at the table level, and I had to add it in again.

The official documentation does not mention this:

Hopefully this will save you 15 minutes of scratching your head.

Here is more information on Symfony 1.2 and doctrine:

This post assumes you have some experience with Symfony 1.0.

At my work I needed to create several different versions of the same site. This mainly entailed changing background images to get a slightly different look and feel, and changing the content category, depending on a request parameter.

For this tutorial, I will use the company I work for as an example. Momentum IT Group has two distinct divisions: ELearning and Web. So let’s say I wanted to make slight design changes depending on which division I’m looking at.

We’ll start where all things Symfony begin: with the routes. Open up apps/frontend/config/routing.yml and enter the following:

  url:               /:division/:slug
  param:          { module: cms, action: display }
  requirements: { division: elearning|web }

I leave the cms module for you to implement. The display action would take a unique slug as a key to look up the page content from the database for display.

In this route, the division is required to be either elearning or web, and these two options will be used to display a different background design (and possibly select from a different content category in your cms module).

The next step is to implement the switch which determines which background to apply, if any. You can always write this code in your cms module, but you may have other modules other than the cms module which need to change design elements depending on which division the user is viewing. To handle this situation, you can create a filter.

A filter is applied once for each request. Start by opening apps/frontend/config/filters.yml and adding a new filter class:

rendering:    ~
web_debug: ~
security:     ~

# generally, you will want to insert your own filters here
  class:       cssFilter

cache:       ~
common:    ~
flash:         ~
execution:  ~

Create the filter class in apps/frontend/lib/cssFilter.class.php:


class cssFilter extends sfFilter
  public function execute($filterChain)
    if ( $this->isFirstCall())
      $response = $this->getContext()->getResponse();
      switch ( sfContext::getInstance()->getRequest()->getParameter('division') ) 
        case 'elearning':
          $response->addStylesheet('elearning', 'last');
        case 'web':
          $response->addStylesheet('web', 'last');

Make sure you place two new CSS files in your web/css directory.

For this example, they are elearning.css and web.css. They will be the last css files in your HTML header and will override your main.css where needed. So, you might override a background image like so:


body {
  background: url(../images/background.jpg) no-repeat top left;


body {
  background-image: url(../images/elearning.jpg);

Now if you direct your browser to [your_site]/elearning/[page_slug], you will have taken advantage of CSS cascading and Symfony filters to present a slightly different design depending on the context.

Tags: , , ,

This post has moved to:

Please update your links.

With a query in its own function, you can write calling functions that:

a). Retrieve a collection for that type of query.

b). Retrieve one result for that type of query.

c). Extend that type of query with more conditions.

d). Pass the query to other objects that take a query as a parameter (eg. sfPager).

e). Distribute processing to the appropriate ORM classes.

For example, you have a database of classes and students.

If you need to get a classes’ students, you make a request to the classroom->getStudents() query function.

The classroom->getStudents() function adds its criteria (eg. = #), and then passes that criteria to the StudentTable->getStudents() query function.

In short, you reduce repetition.  You enhance maintainability.  Because each query has a single responsibility.

More info:

Tags: ,

These are Robert C. Martin’s five rules for writing clean test code.  They form the acronym F.I.R.S.T.

Your tests should be fast so that you will run them frequently.  If they run slowly, you won’t want to run them as often.  If some tests must be slow, try to partition them out so you can run the fast tests more often.

Each test should run independently.  An error in one test should not cause tests after it to fail.

They should run anywhere, anytime.  Variables external to the system should not affect their outcome.

There are only two possible outcomes.  The test passed, or the test failed.  No in-between.  Judging whether or not a test passed should not be a matter of opinion.

Unit tests should be written just before the production code that makes them pass.  This helps you write code that is testable.

Robert C. Martin, Clean Code — A Handbook of Agile Software Craftmanship

Law 1:
You may not write production code until you have written a failing unit test.

Law 2:
You may not write more of a unit test than is sufficient to fail, and not compiling is failing.

Law 3:
You may not write more production code than is sufficient to pass the currently failing test.

Do you hold up to this?

Professionalism and Test-Driven Development, Robert C. Martin, Object Mentor, IEEE Software, May/June 2007 (Vol. 24, No. 3) pp. 32–36

Tags: ,