Installing Symfony2 on Ubuntu 11.04 (Natty Narwhal)

Introduction

This article will walk you through what you need to do to start developing in Symfony2. The guide starts from a fresh install of Ubuntu 11.04 (Natty Narwhal), and ends with passing the Symfony2 "check.php" script with a perfect score. I realize that these exact step-by-step instructions may not work for everybody. They're intended mainly to help me keep track of what to do for future installs; but if they can help anybody else, then that's just icing on the cake :) And one last thing before we get started, this isn't just the bare bones install, I threw in a few other config options for PHP that I use frequently enough.

SVN resolve all conflicts

Recently, I was working on a project where I was developing on my own branch of an SVN repository. It had actually been a while since I merged my branch with the main development branch, so I knew there would be conflicts. But during the "merge" command I thought I resolved all conflicts.

After trying to commit my changes, however, I kept getting errors like:
"svn: Aborting commit: file-XXX remains in conflict"

This can easily be resolved by doing an
svn resolve --accept working file-name

but in my situation, I'm using a framework that has a TON of files it uses. I started running that command and then trying the commit, only to find another file had a conflict. The reason for my conflict was because my branch was missing some files that was in the development branch that I no longer needed. This is why I used "working" in the resolve command above, because I wanted to use my working copy as the base for resolving conflicts.

after running the command quite a few times, I decided to look for a better way to resolve all conflicts, and found out that this worked for me (run in the root of the branch directory):
svn resolve --accept working -R .

Symfony Doctrine data-load not importing all fixture files

I ran into a strange issue with symfony 1.4.x. I added 7 new models to my config/schema.yml file, and then I created 7 corresponding fixtures files for each of the new models.

So far, so good. I try to then import all the fixtures into the database by running a
./symfony doctrine:build --all --and-load --no-confirmation

but when I look in the database, only 2 of the 7 models have any data in them! So I get a little more specific with the data import command. All my new fixture files for the new models start with "cl" so I type
./symfony doctrine:data-load data/fixtures/cl*

and the output of that command shows it proccessed each of the 7 files, but alas, the database only has content from 2 of the models!

So now I manually run the data-load command on each of the new fixture files seperately, ... and Lo and Behold, it works, all the data is there! But I don't have to have to do this each time I recreate the application!

I did some more digging, and found the solution! more like I found the problem!

Normally in a fixtures file, you start by specifying the model
ExampleModel:

Then you indent one level and specify an instance name. This can be any valid varible name, like:
SampleEntry_1:

I usually append a number after the name, because we're normally dealing with more than one entry.

Well, if you're dealing with different models, each fixture file can use the set format of instance names. e.g., I can use the same
SampleEntry_1:
in another fixtures file for a different model, because symfony/doctrine can tell it's a different model.

Well, the reason why I didn't work in my sitation, even though I had these as 7 different models, is because I am using doctrine's Table Inheritance so each of these 7 models actually use the same database table/base model.

So my solution was just to make sure each fixture file used a different convention for the instance lables.

LimeSurvey 1.91 RC4 released!

About a month ago I posted about a minor addition I made to LimeSurvey, the open source web survey tool. My patch makes it possible to use the {SGQ} Identifier inside the question text, so you can include custom question javascript and have the whole survey export in a portable way (since the question is referenced by this SGQ identifier, instead of a hard coded ID).

Well now this update is available in an actual public version of LimeSurvey (v1.91 RC4)! This was my first coding contribution to the open source community, so even though it's a small change, it feels pretty good.

the SGQ identifier was only one of the few updates made from 1.91 RC3, check out the full list by clicking "Read More" below...

Symfony forms - Checkboxes working the opposite way!

So I was making a simple form submission page by first creating a custom form class in ./lib/forms/customForm.class.php and in there I specified that a form element named "active" should be of type sfWidgetFormInputCheckbox(). Great, so I display the form on the page, and it renders fine. Now I make it part of a basic New/Edit functionality. The New model form page uses the same custom form class as the Edit model form page.

But the weird thing is, whenever I would edit the model object with the form, the Active checkbox behavior would be the opposite of what I expected! If I would check Active and click submit, it would save the form as inactive. And if I would mark it as inactive and submitted, it would save it as Active!

So I found the solution easily enough, by looking in another custom form module that used a checkbox :)

The solution is to update the customForm.class.php definition. Previous, I had set my "active" form element to be validated with a sfValidatorPass(), this would make is so when the checkbox was UNchecked, it would return a "1" (I assume to mean that it returned a successful (i.e. True/1) use of sfValidatorPass), and if the box was checked, it would return the text "on".

So I set removed the Pass validator, and set it now to sfValidatorBoolean(array('required'=>false)) and it worked like a charm, now it returns "1" if it's checked, and null if it's not.

Hope that saves somebody some time :)

ORM Designer, a Workbench for MVC projects

In my last post, I wrote about the many benefits from using an ORM and DAL with Symfony and other MVC frameworks. Not only does the ORM/DAL let seamlessly utilize different database backends without changing your code, it also allows you to work with data in the more natural, object oriented way, and use time saving behaviors like SoftDelete and Sluggable.

Another major difference between using direct DB manipulation and an ORM is how the model or schema is defined. Normally for say MySQL you would have to write out an SQL definition of a table, and the associated queries for creating relations between tables. This is where MySQL Workbench came in handy, because you could do this in a visual manner quite easily. With the Doctrine ORM, this definition is created in a Schema file. The schema file can either be a PHP file that acts as a class definition, or you can create it in the more convenient (and easily readable) YAML format.

While designing and beginning to develop my Symfony project's model using MySQL workbench, I quickly noticed there was a lot of information that was not captured in the visual MySQL schema, but that did exist in the Doctrine Schema file.

This is where ORM Designer comes in! ORM Designer is like MySQL Workbench, but for PHP ORM's instead. It let's you keep track of, and design for models using the feature-rich abilities that come with the best PHP ORMs. For instance, in our Doctrine schema we use a convenient feature called Table Inheritance that lets you define a base class, and essentially have sub-classes that inherit from the base. There are three different types of table inheritance definitions in Doctrine 1.2, and the one we used actually only utilizes one master table for all sub classes (but takes care of model separation at the ORM level). In the visual representation of the schema in MySQL workbench, this relationship is not clear at all, as only one table is shown. But ORM Designer not only let's you see the relationship as it is, but provides an easy way to define the relationship as well. You can also see/store other meta information in your visual model as well, such as model behaviors, and long comments/descriptions (which come in very handy when you're returning to a project after some time away!)

Another core feature of ORM Designer is that it let's you import and export schemas. That is, you can design your schema completely in ORM Designer, then export it to the format you want to use in your project (in my case, a doctrine 1.2 schema file for Symfony). If you already have your schema mostly created, you can also import the file so you can manipulate it visually in ORM Designer.

ORM Designer currently works with some of the best and most popular PHP ORM's and Frameworks. These include Doctrine 1.2 and Doctrine 2, Propel, CakePHP, and Symfony. Inventic, the creator of ORM Designer, is also constantly adding features to the app, and they are currently working on a version 2 which is tentatively scheduled for release at the end of 2011. But there's no way I'm going to wait that long to start using this software! I went through the 14-day free trail, and now I'm going to buy a license for the full version, since €99 Euro (about $135 USD) is a reasonable price for this application, considering the productivity I will get in return.

ORM/DAL in MVC projects

I'm sure many web developers are familiar with MySQL's WorkBench product. It let's you visually design your database by placing table entities on a stage, and specifying relationships between tables. This is very convenient especially in the design phase of a project.

For my latest project, I started using the nacent MVC PHP Framework known as Symfony. The latest production version of Symfony, 1.4.x, is quite stable, and has good documentation and a solid developer base. While still being very well integrated with databases, Symfony and other modern MVC frameworks don't deal directly with a database. Instead, it uses what's called an ORM, or Object-Relational Mapping software, and a DAL or Database Abstraction Layer.

The DAL is of the least concern to me as a web developer because it provides and important but transparent role. Basically it allows the ORM to communicate with many different types of databases, be they MySQL, PostgreSQL, SQL lite, MsSQL, Oracle, etc, etc.

What is very important to me is the ORM. There are many ORM's out there, and two of the biggest ones in PHP (and also which integrate nicely into Symfony) are Doctrine, and Propel. I've been using Doctrine 1.2 for our project here, although we may move to version 2, as it has been release in stable form and offers some significant improvements.

Another big advantage, besides database agnostic, is that an ORM is no longer table-centric, but model-centric. It is much easier to work with data in an object-oriented way. Instead of doing something like
SELECT * FROM PERSON
you can basically say
$guest = Doctrine_Core::getTable('Person')->createQuery()->execute();
and then you will be able to say something like "print $guest->getName()"

This model/OO way of doing things is even more useful when you start incorporating associations, such as one Person can have many PhoneNumbers.

Another great thing about Doctrine and other ORM's, is that you are not as limited to the particular flavor or capabilities of the database solution that you are using. Because Doctrine operates at a higher level than the DB, it can keep track of certain things independent of the DB, which let's you do some really nifty things, like what Doctrine calls "Behaviors".

One example of a behavior is the SoftDelete feature. By specifying that a model has SoftDelete, whenever you "Delete" a record of that model, it will not actually remove them from the table, but instead simply mark a "delete_at" flag. When you later on retrieve records from that model, it will Not include this delete entry. This is all done without the programmer having to add any additional functionality!

recursive svn add while still ignoring files

when working with svn and a symfony project, you don't want to put certain files (namely logs and the cache) under version control, so you can to do a "svn pe svn:ignore dir_name" to ignore a specific directory.

But what happens when later on you add a whole like to new files, all throughout your directory structure, and you'd like to add them all in one fell swoop, instead of doing an "svn add filename1" one at a time.

I first tried doing
svn add * --force
from the main project directory, but this added files that I already ignored with the svn:ignore property.

So the solution I found was to do
svn add . --force
again, from the root of the project dir. The * above is expanded by the shell, and then passed to the svn command, while in the bottom command, we're only passing the svn command the current directory, so it will handle which files need to be force added (and ignores the proper files/dirs)

Symfony 1.4 -> how to filter results with sfWidgetFormDoctrineChoice

Let's say you have a form based on a model that has a one to many relationship with another model. Using the standard blog example, our "Blog Entry" model can only have one "Category" assigned to it. But each Category can belong to more than one Blog Entry.

So if we want to make a form to create a new Blog Entry, we can create a custom form, and use the sfWidgetFormDoctrineChoice class for the Category field. But what if we don't want to display *all* the categories on the drop down selection list? Simple, we can pass in the "table_method" to the constructor list and tell it to only display results that this custom table method returns.

So for example, we can say:
'category' => new sfWidgetFormDoctrineChoice(array('model'=>'BlogCategory','table_method'=>'getActive',)),

In this case, the "getActive" method is a custom method we can create in the models table class that's located in:
./lib/model/doctrine/BlogCategoryTable.class.php

and in here we can make it return whatever we like for instance:
public function getActive()
{
$query = Doctrine_Core::getTable('BlogCategory')
->createQuery('q')
->where('q.active = ?', '1')
->orderBy('name ASC');
$result = $query->execute();
return $result;
}

There you have it, now the Form will only give us the option to select categories that are "active"

LimeSurvey SGQ patch added

Yippie, my patch has officially been added to the LimeSurvey project! It's in build 9755 which is upstream and will be release for download hopefully soon.
I updated some of the docs on the LimeSurvey page already:
Dynamically reference the SGQ identifier