What’s a counter cache? I think that the Ruby on Rails wiki explains this best: “It caches the number of belonging objects on the associated class.
Think about something like a weblog with posts and comments. You may want to display the number of comments each post has. Normally you would execute a query to count them, but with a counter cache the post table would have an extra field which updates every time a new comment is created or deleted. This way you save quite a few SQL queries.

While in symfony it isn’t that simple as in RoR, but it is relatively easy to do. Let’s take a look at the schama.yml first:

 

propel:
  post:
    id:
    title: varchar(255)
    body: longvarchar
    comment_count: integer
    created_at:

  comment:
    id:
    post_id:
    body: longvarchar
    author: varchar(50)
    created_at:

Notice the comment_count field in the post table, which will cache the number of associated comments to each post.
Build the model and open up the lib/model/Comment.php file in your editor. We need to override the save method and make sure that every time a comment is saved, the comment_count field of the associated post is updated:

public function save($con = null) 
{
  if ($this->isNew())
  {
    $this->getPost()->updateCommentCount();
  }
 
  return parent::save();
}

First we check with the isNew method if a comment really is a new comment because the save method is also used to save an modified object, and then we call the updateCommentCount method of the associated post to update the comment count.

Open the lib/model/Post.php file and create the updateCommentCount method:

public function updateCommentCount()
{
  $this->setCommentCount($this->getCommentCount() + 1);
}

And that’s it, now everytime a new comment is created, the comment_count field of the associated post is increased by one. You don’t have to worry about it anymore.

But there is still one thing missing: to decrease the comment_count field of an associated post each time a comment is deleted.

This isn’t a problem because the basics are the same: override the delete method of the Comment model and modify the updateCommentCount method of the Post model (or create increaseCommentCount / decreaseCommentCount methods if you like that more):

Here’s a example:

public function delete($con = null)
{
  $this->getPost()->updateCommentCount(false);
  
  return parent::delete();
}

As you can see i also modified the updateCommentCount method to handle both (in- and decreasing) cases:

public function updateCommentCount($increase = true)
{
  $count = $this->getCommentCount();
  $count = ($increase) ? $count + 1 : $count - 1;
  $this->setCommentCount($count);
  $this->save();
}

If i pass true as a parameter the comment_count field is increased by one and if a pass false it decreases the field by one. (Notice that you have to call the save method when you override the delete method because otherwise it wouldn’t save the updated count. It wasn’t necessary in the save method because the it already returned parent::save)

I also recommend watching this Railscast episode about counter cache, its not PHP but you get the clue.

All comments are appreciated.

The first update for the sfReCaptchaPlugin is available, which updates the ReCaptcha php-library from version 1.6 to 1.8.

While there doesn’t seem to be a changelog around, i found the bugs at the mailinglist (here and here):

There was a problem with a variable which holds the url for the SSL authentication server, it was named $recaptcha_api_ssl_server instead of $recaptcha_api_secure_server.
Both, version 1.7 and 1.8 were adressed to fix this problem.

If you have version 1.0.0 of the plugin installed, you can update it by executing this command in your projects root directory:

symfony plugin-upgrade http://plugins.symfony-project.com/sfReCaptchaPlugin

 

checkbox_abs.pngIt’s common knowledge to never trust any user input and to validate everything. But is this also true for checkboxes? Shouldn’t Propel handle this properly?

Well, it depends on whether you want to have just zeros and ones in your database field or don’t care – because Propel will write every numeric value in the database and not just zeros and ones.

Test

To check this, i used a small example to test if Propel really does save every value of the checkbox in the database:
I created a test module which had a template with a really simple form and just a checkbox:

 

<?php echo form_tag('boolean/index') ?>
  <?php echo checkbox_tag('value'); ?>
  <?php echo submit_tag('submit'); ?>
</form>

To save the value in the database (Note: The field was specified as a “boolean” in the schema.yml) , a simple action was required:

$checkbox = new Valuetest();
$checkbox->setValue($this->getRequestParameter('value'));
$checkbox->save();

With this, the application saved the value of the checkbox (ideally zero or one) in the “boolean” database field (which Propel translates to unsigned integer(11)).

This is where the real test began. What would’ve happend if the user transformed the checkbox field into a input field? (check out the Webdeveloper firefox extension, it’s really useful for this kind of tests)

Since the database field was of the integer type it wouldn’t save values like “abc” and instead just saved a zero.
But it turned out that Propel would’ve saved every other numeric value that will fit in the unsigned integer(11) field (This is a range from -2147483648 to 2147483647).

Here are a few examples which i entered in the datasbase and what Propel returned on a $foobar->getValue():

The value 0 returned false
The value -9123 returned true
The value 1 returned true
The value 9123 returned true

Conclusion

Your application will not be in danger if you don’t validate a checkbox field, since Propel will only return true or false for a field that is specified as boolean in the schema.yml.
But your database can be messy and have all kind of numeric values saved in it.

If you’re like me and just want to have zeroes or ones in your boolean database field, the best thing is to validate the checkbox field using a simple custom validator like this simple sfCheckboxValidator i wrote.

Please state your opinion on this topic in the comments, thanks!

webned_logo.jpgLast weekend we launched webnedvizhimost.com/.ru, a real estate portal for Russia and Ukraine – developed with symfony.

One of the interesting parts is the i18n of the website, you can switch between English and Russian (on the top right). Thanks to the XLIFF support in symfony, managing translations has been very easy.

But there’s one feature that, for me, has made a _really_ huge difference – to sync the local directory with the server directory via rsync.
It has made deploying updates so much easier and faster. Honestly, even when writing this blog post i noticed a validation error on the frontpage, 10 seconds and a “symfony sync production go” later this was fixed.

But there’s more to come. There will be a shop which lets you buy more object and yellow page entries. You’ll also be able to buy “top objects days” which basically give you the possibility to make your object a top object for a specific timeframe.

Stay tuned.

plugins.pngTo uninstall a plugin you normally use the “symfony plugin-uninstall” command but not everyone knows that, and just deleting the directory from the plugins directory is a often mistake.

After deleting the directory PEAR still thinks that the plugin is installed (try executing “symfony plugin-list“).

Installing the plugin again to uninstall it properly won’t work either. It will skip the package and say that it is aleady installed.

>> pear      Skipping package "symfony/sfThumbnailPlugin", already
>> pear      installed as version 1.3.0
>> pear      No valid packages found

But there is an easy fix for this problem:

Each plugin stores a .reg file in the PEAR registry, this registry is hidden in the plugins directory – you just need to delete the file from the registry.
For example, if you have accidentally deleted the sfThumbnailPlugin directory, just remove the registry file too:

rm plugins/.registry/.channel.pear.symfony-project.com/sfthumbnailplugin.reg

PEAR will not think that the plugin is installed anymore (check with “symfony plugin-list“).

reCAPTCHAI just released a plugin for symfony which integrates the reCAPTCHA php library in symfony.

What’s reCAPTCHA” you ask? Check out this three sites:

Lately reCAPTCHA has been very popular (it even made it to the Digg frontpage and Slashdot).

High time for a reCAPTCHA plugin for symfony. You can read all the installation and usage instructions over at the symfony wiki.

Comments and critiques are always appreciated!

I just released sfSocialBookmarkingPlugin which lets you add this little icons in order to submit your site to a social bookmarking service like del.icio.us.

All the instructions are in the wiki-page, however i still have problems with the images. It seems that PEAR doesnt link them properly so that you have to copy them into web/images by hand.

Here’s a little screenshot if you absolutely can’t image what i’m talking about:

sfSocialBookmarkingPlugin

Might be useful if you have a blog (e.g. the sfSimpleBlogPlugin).
Also, feel free to add services that aren’t in the Plugin yet and don’t forget to commit a patch. Thanks!