Archive for March, 2009

Phrase of the day – 24/03/09 (rekkverk)

Introduction to phrase of the day

I have lived in Norway for a year and a half now, and I really am not using the language enough. Recently I started doing “word of the day” where I’d flick through my small dictionary, find a word I didn’t know and write it on the whiteboard. All day I would glance at it and commit it to memory – thus slowly increasing my vocabluary.

The problems with this approach soon became apparent, progress was slow, I was forgetting some of the words a few days later, and crucially they were not helping me to progress with my grammar, or help me to structure sentences for talking, which is my weakest area at the moment

So “Phrase of the day” is born – somebody (normally a Norwegian colleague) will pick a word, I then (without help) have to make a phrase or sentence to put that word into context. We then discuss the mistakes and I am more likely to remember the word. I hope to bring a new phrase as often as possible, and if you are interested, you can subscribe to an rss feed: just the phrases, or everything I come across whilst learning Norwegain. Since I am learning this from an English perspective, these phrases may be useful to highlight “common pitfalls for English speakers”.

Today’s word: et rekkverk

  • English: a railing
  • Pronunciation: rehk-værk

First attempt:

I går var jeg på besøk
hos Trysil. Jeg lånt 
et snøbredd og var nesten
drept når jeg treffet
et rekkverk med hodet mitt!

Errors/observations:

  • “hos Trysil” should be “i Trysil” – hos is a little bit like chez in French, it means “at” but really means “at the house of” or “at the place of”. When talking about a generic place we use “i” for “in” or “på” for on/at. Unfortunately these can sometimes be confusing, as with English. For example I live in Oslo but at Bjerke. (i Oslo men Bjerke).
  • lånt is past perfect, here we should use lånte which is past participle
  • snøbredd is mis-spelled, and should be snøbrett (was a guess)
  • var should be ble – In English we would say “I was almost killed” but in Norwegian you use “I became almost killed”
  • når should be da – A slip here because I knew this. Når and da can cause confusion for English speakers who would use “when” in both situations. There is a good blog post about this here: http://www.transparent.com/norwegian/2009/02/22/da-da-da/
  • å treffe is an irregular verb – past tense is traff
  • hodet mitt is unnecessary because in this context, it is obvious you are talking about your own head!

So the correct (I think) text:

I går var jeg på besøk
i Trysil. Jeg lånte 
et snøbrett og ble nesten
drept da jeg traff
et rekkverk med hodet!

Translation:

Yesterday I was visiting
Trysil. I borrowed
a snowboard and was almost
killed when I met
a railing with my head!

Customising Symfony forms – be careful with base class inheritence

Background

Recently I was working on a form for updating a couple of very simple values for a single table. When creating such forms, where we only need a subset of the available columns to be editable, we always have the option of either unsetting the fields we don’t need, or overriding the widgetSchema. In this case, I opted for the latter, since I only needed to edit 2 columns out of a possible 10, I didn’t think adding 8 fields to the unset() function was the cleanest way. The following examples contain obfuscated data.

Overriding the widget schema

public function configure()
{
  $this->setWidgets(array(
    'amount'               => new sfWidgetFormInput(),
    'reduced_amount' => new sfWidgetFormInput(),
    ));
 
   //Labels and decorator stuff here
}

My plan was to inherit the validators that already exist in the base class, since they do the job for what I need.

The error

The form worked fine for an insert, but when I came to update an existing record, the error was quite strange:

SQLSTATE[23505]: Unique violation: 7 ERROR: 
  duplicate key value violates unique constraint 
  "body_fee_version_pkey"

The problem it seemed was that my versionable behaviour was not incrementing the version value before attempting to insert a new version record. After a long period of debugging the versionable behaviour, along with some of my other custom behaviours, I was no closer to a solution.

I started to dig into the form classes, working backwords through all the object update methods, save, dosave, etc. Until I finally stumbled across this line:

$this->values = $this->validatorSchema->clean(
   self::deepArrayUnion($this->taintedValues, 
   self::convertFileInformation($this->taintedFiles))
 );

Before this call, everything seemed ok, but after this call, my values array, which at this stage only contained the two fields that had been posted, now suddenly included a value for all the fields in the table. Why? It then occurred to me that the entire validator schema was being processed, not just the fields that are actually posted! This means that all the validators that are required=false will silently return a “clean” value, which is most likely the database default.

So what did this mean? Well, it meant that the validator was “cleaning” all the columns that had not been submitted with the form, including the version column, which was being set to null. When the versionable behaviour kicked in, it read this null value and incremented by 1 for the next version, which then became 1 – a version which of course already existed, causing the error.

The solution

The solution is blindingly simple, we don’t just declare the widget schema, we must also declare the validator schema. Whilst this seems like it makes sense, I feel that it is a shame that I have to essentially copy and paste the necessary validators from the base class. The alternative of course would have been to unset the offending fields, but then we are back to option 1 above, unsetting 8 of 10 fields when it seems cleaner just to declare the 2 fields I actially need.

  $this->setWidgets(array(
    'amount'               => new sfWidgetFormInput(),
    'reduced_amount' => new sfWidgetFormInput(),
    ));
 
// Messages declared here as array since they are the same
 
$this->setValidators(array(
  "amount"  => new sfNumberValidator(
                       array('required' => true), $messages),
  "reduced_amount" => new sfNumberValidator(
                       array(), $messages),
 ));
 
   //Labels and decorator stuff here

Conclusion

I have been working with Symfony for over a year and a half, and with Symfony forms since they were born – and yet I was still caught out by something that seems quite simple, because I assumed it would be ok. There are so many things that could have alerted me to this problem and saved me a lot of time, for example if any of the extra fields had been required=true then at least I would have had some form errors to give me a clue!

I may suggest that the default behaviour should be to only process the validators that match the widgets, or maybe at least for the form to err if extra validators are found that are not used, as I feel that this is a mistake that others could make, and as I mentioned above, it’s a shame that we have to re-declare validators that are already present in the base class.

« Previous Page