Symfony 1.0 and 1.1 together! ;-)Announcements about Symfony 1.1 are becoming more frequent and with the creation of the 1.1 branch many users want to try it out and simply play around with 1.1 during the holiday season.

This guide is derived from InstallingMultipleVersionsOfSymfony and assumes you already have Symfony 1.0 installed (via PEAR) and running. Also note that i will use the PEAR directory to store Symfony 1.1 alongside my 1.0 installation, you can however put it wherever you like.

First off, check where your current Symfony installation is located. You could for example look at one of your projects “config/config.php” file – in my case it’s “/usr/lib/php/pear/symfony“, therefore i will be installing Symfony 1.1 one level above into “/usr/lib/php/pear“.

Create a directory for your installation and check out the current 1.1 branch:

sudo mkdir /usr/lib/php/pear/symfony_11
cd /usr/lib/php/pear/symfony_11
sudo svn co http://svn.symfony-project.com/branches/1.1 .

After the checkout is done, the next step is to create a symlink to the “symfony” php executable of the 1.1 checkout. You can find out where your current symfony command is stored with:

whereis symfony

In my case it’s located in “/usr/bin/“, that’s also where i will create the new symlink:

sudo ln -s /usr/lib/php/pear/symfony_11/data/bin/symfony 
/usr/bin/symfony1.1

(Note: It’s important to use absolute paths here)

With this done, you will still have your usual “symfony” command which is linked against your stable PEAR version but also a new “symfony1.1” command which is linked against your subversion checkout.
You can verify it easily by executing each command with the -V parameter.

If everything is working, create a new symfony 1.1 project (as you might already know, Symfony 1.1 features new CLI commands, you can see them by executing the “symfony1.1” command):

mkdir sf11test && cd !$
symfony1.1 generate:project foobar
symfony1.1 generate:app frontend
symfony1.1 generate:module frontend helloworld

Finally, the only thing left to do is to create a Virtual Host, it’s identical to the ones you created for your Symfony 1.0 project except for the path, don’t forget to change it to the location of your symfony 1.1 branch!

<Directory "/usr/lib/php/pear/symfony_11/data/web/sf/"> 
  AllowOverride All 
  Allow from All
</Directory>
<VirtualHost *:80>  
  ServerName sf11test  
  DocumentRoot "/Users/arthur/Webdev/sf11test/web"  
  DirectoryIndex index.php  

  Alias /sf /usr/lib/php/pear/symfony_11/data/web/sf/
  <Directory "/Users/arthur/Webdev/sf11test/web">    
    AllowOverride All    
    Allow from All  
  </Directory>
</VirtualHost>

Have fun!

captchahomepage.gifI just released a new version of the sfReCaptchaPlugin.
It updates the recaptcha-php library to version 1.9 (unfortunately there is no changelog available), fixes a problem in the example module where in some cases an error would’ve been thrown if no text was submitted and updates the documentation.

The most notably change to the recaptcha-php library is that constants are now used instead of globaly declared variables, so that the version included in the plugin doesn’t need to be modified anymore – which is great in terms of maintenance.

To upgrade your existing installation, just execute the following command:

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

Please go to the symfony-wiki page for more information.

WarningIt’s almost half a month ago since PHP 5.2.4 was released and since I really like to update software ;-) I immediately upgraded from 5.2.3 – but the result was rather shocking – all my Symfony projects stopped working because of a Exception thrown by Propel: “Error populating Pages object [wrapped: Unable to convert value at column 13 to timestamp: 0000-00-00 00:00:00]“.

I watched the Symfony forums/mailing lists and the Propel mailing lists, but nothing similar was posted so that i tracked it down on my own and found the issue in Creole (DBAL used by Propel, which is used by Symfony).

The issue lies in the getTimestamp() function (Line 126 in creole/drivers/mysql/MySQLResultSet.php), which basically just converts a date from your database to a unix timestamp.Let’s say that your database field has the default value “0000-00-00 00:00:00” set on a datetime field and the getTimestamp() function tries to parse this default value with strtotime, which worked fine in PHP 5.2.3 and below since this function would return “943905600” (which equals to 1999-11-30, but don’t ask me why…) but was fixed in PHP 5.2.4. The function now returns boolean FALSE which is causing the function to fail and throw an Exception.

It’s okay that strtotime doesn’t accept “0000-00-00 00:00:00” as a date and returns false instead, but since this value is often used as a default for a datetime field in Propel and will break your application(s).Unfortunately Creole is not actively maintained anymore, so don’t expect a fix for this issue, but you can of course fix it yourself like this:

if ($this->fields[$column] == '0000-00-00 00:00:00') {    // If the value is  '0000-00-00 00:00:00', set it back to the value strtotime() returned before PHP 5.2.4    $ts = '943916400';}else {    $ts = strtotime($this->fields[$column]);}

You can try the fix and work with Symfony and PHP 5.2.4, but I will go back to PHP 5.2.3 since i can’t be 100% sure that there is another error somewhere.Please state your opinion in the comments, thanks!

Update: Seth Wilson found another instance of this bug in \pear\symfony\vendor\creole\common\ResultSetCommon.php at line 356:

if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE throw new SQLException("Unable to convert value at column " . $column . " to timestamp: " . $this->fields[$idx]);}

To fix it, just change it to :

if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE  return '943916400';  #throw new SQLException("Unable to convert value at column " . $column . " to timestamp: " . $this->fields[$idx]);}

Thanks Seth!

Update 2: Symfony 1.0.9 fixes this problem, be sure to upgrade!


			

logo1.png

Today we re-launched Tschitschereengreen.com (where i’m currently working) with a new web2.0-like design. I did most of the XHTML/CSS stuff and some code fixes.
There’re still some small bugs, but i hope i can fix them next weekend.

 

Why i’m writing this here? Because the site runs on symfony ;-)

Doktus launched

August 20, 2007

logo.pngI’m currently working in Dresden doing some pretty cool stuff for Tschitschereengreen.
Last Week we launched Doktus – a document sharing plattform developed with Symfony.

We replaced Zend_Search_Lucene with Sphinx, so that search performance got a huge speedup.
Generally speaking Zend_Search_Lucene isn’t bad, i had some nice conversations with Alexander Veremyev (Main Developer of ZSL), but the search still has some serious performance issues with indexing and searching large document sets.
Sphinx on the other hand is simply awesome, you might want to take a look at their website to see all the features. Development is also very active and the upcoming 0.9.8 release looks very promising.

The Flash uploader (which uses SWFUpload Revision 5) was also quite a bit of work, especially with Flash Player behaving different on Windows/Linux/Mac OS X.
For those people that doesn’t like Flash (like myself :-P), there’s a build-in fallback form which still let’s you upload a document.

What’s also pretty cool is all the small AJAX stuff we implemented. We’re using Prototype and script.aculo.us since Symfony already provides very useful helpers for this libraries.
Take for example the categories, the pagination or the sorting of documents, everything is AJAXified ;-)

Development is still ongoing so expect some more cool stuff to come.

guidebook_translate_books_264580_l.jpgI recently translated AndrĂ©ia Bohner’s CLI cheat sheet in german. You can find the JPG and PDF version of the german translation in this post.

Thanks Andréia for creating the cheat sheet in the first place and the kind emails.

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.