Mellow Morning » Symfony http://www.mellowmorning.com Blogging the world of IT and Business Mon, 08 Jun 2009 12:30:43 +0000 http://wordpress.org/?v=2.7 en hourly 1 Django vs Symfony http://www.mellowmorning.com/2008/08/27/django-vs-symfony/ http://www.mellowmorning.com/2008/08/27/django-vs-symfony/#comments Wed, 27 Aug 2008 19:52:00 +0000 tschellenbach http://www.mellowmorning.com/?p=68 As you can see from the posts (one, two) I’ve always been a big Symfony fan. Symfony is really great, but my current favourite is clearly Django. I had to dive deep into python to use it, but it was well worth the effort.

Choosing Django:

Django has a few killer features which make it a better choice for many projects.

High Level Fields

As a starter there’s the usage of high level fields when describing your data model. This is best clarified by an example of a model definition in django:

class Author(models.Model):
   ip = models.IPAddressField()
   email = models.EmailField()
   company = models.ForeignKey(Company)
   picture = models.ImageField(upload_to='images/profile_pics', blank=True)
   homepage = models.URLField(verify_exists=True, blank=True)

Fields are specified by their purpose, such as Email, Url and Image. From this definition all subsequent logic such as form validation and file uploads are handled. The homepage field’s validation will even ping the url to see if it exists.

Read more: Creating Models (django project)

Form Handling

Starting with the knowledge that you have an email field you will often want a nice text input in your form with a regex to check if the email is valid. Django has all these standard use cases worked out for you. The following example clarifies this by using Django’s ModelForm. A model form is basically a normal Form class, with the fields pre-populated as one would expect it based on the given model.

#Form specification
class AuthorForm(ModelForm):
   class Meta:
      model = models.User
      fields = ('ip','email','picture','homepage', 'company')

#Using the form in the view (controller in Symfony terminology)
form = AuthorForm(request.POST, instance=author_instance)
if request.method == 'POST':
  if form.is_valid():
     form.save()
     return HttpResponseRedirect(request.path) 

#In the template (view in Symfony terminology)
{{ uform.first_name.label_tag }}
: {{ uform.first_name }} {{ uform.first_name.errors }}

Django will display a file field for the image field, a text field for the url (with validation), a text input for the email field and a select box for the foreign key relation. Saving the result of the form to the database is as simple as calling save on the instance of the form. Writing custom widgets and field types is straightforward. Currently many localized fields such as a Dutch postal code Field and widgets are available. Symfony has been trying to emulate the Django newforms library. Unfortunately the syntax doesn’t seem very friendly. (Pity php doesn’t have metaclasses)

Read more: Forms (Django book)

Superb ORM

Probably the largest difference is caused by the ORM. In PHP both Propel and Doctrine are nice projects, but simply quite inadequate. The Django ORM is syntax heaven if you are coming from php. A small example:

#Find the first 5 authors which have a relation to a company
#with the name YouTellMe (exact match) and site url that contains youtellme.nl
Author.objects.filter(company__name = 'YouTellMe', company__site__icontains = 'youtellme.nl')[:5]

The possibilities of the standard Django ORM system are quite good. Your queries will be optimized into joins if you call select_related, many to many relations are supported and polymorphic keys are as well. The only part it fails at is query optimization in terms of column based lazy loading and support for complex relations. Fortunately you can fall back to using SQL alchemy, which is Python’s most prestigious ORM layer. SQL alchemy allows you exact query control for performance tuning and many more options you did not know you needed.
However it isn’t (yet, i hope) fully integrated into Django. It would really be great to see a tighter integration with SQL alchemy, but even the Django ORM strongly outperforms Doctrine and Propel.

Read more: DB api.

Python

You could see this both as an advantage or disadvantage. Discussing the differences between Python and PHP is probably best left for a later post. Suffice to say that I found my programming productivity to be substantially higher with Python compared to PHP. The disadvantage is a smaller number of available scripts, developers and hosts. If you are in a position in which you can choose, you really should give python a go. There must be a reason why YouTube and Google do ;)

Read more: Python in 10 Minutes

Speed

When arguing with my colleague about the choice of framework we conducted a speed test between Django and Symfony using Apache bench. At the time I was arguing in favor of Symfony. We compared a lightweight PHP framework, with Symfony and Django. Symfony was stripped down for performance and was only about 30% heavier compared to the lightweight framework. When comparing it to Django however, the results showed that Symfony was only able to handle half the load Django could. Using Python and Django seems to have a substantial effect on your server hardware requirements. (Note that these tests were only intended as an indication for internal usage. We didn’t test enough scenarios to be certain how the outcome would hold up on a live site. )

Symfony Still Rocks

When working with PHP Symfony is still an awesome framework. In many aspects it is even superior to Django. There are quite a few things Django could learn from Symfony:

Generic validation Classes and support for automatic js form validation

When using Symfony your javascript form validation is automatically generated. This is possible because of the usage of generic validation classes. In Django this would be hard to achieve since the validation system is not based on reusable classes.

A debug toolbar


One Symfony feature which I really miss in Django is the debug toolbar. Having an overview of your DB Queries, config settings, logging messages and caching information is very convenient. Especially for debugging a site with caching the caching indicators in Symfony are awesome. These caching indicators simply show which part of the page are taken from cache and which are freshly generated.

DRY templates

Symfony has a simple but very pleasant template tag called a component. A component tag calls a specified view and renders the corresponding template. The typical use case for this tag is sidebar with news items. You will want to show this sidebar on many pages, but you wouldn’t want to have to call that code inside each and every view which needs the sidebar. Doing so would clutter your view and hinder template caching. A nicer approach is to use a component template tag which calls the view responsible for retrieving the news from the database and rendering the sidebar template. This way of allowing the template to invoke code allows for DRY views and templates.

Clear Javascript and CSS management

In Django including a javascript or css file comes down to writing the respective tags in the template. In Symfony these things aren’t left to the template, but are set by the code. This allows for a few neat features. For instance the usage of an ajax utilizing template tag (helper in Symfony) will automatically ensure that prototype.js is loaded on that page. If you would set a textarea to rich, Symfony will automatically figure out you need TinyMCE to achieve the desired effect. Furthermore it allows for a general config file where you specify which assets should be loaded for a certain combination of application and view (in Django terminology). The main benefit of such an approach comes when you combine your css and javascript files and want to optimize the groupings. Here an example of the Symfony config:

// In the view.yml - comparable to settings.py
indexSuccess:
  stylesheets: [mystyle1, mystyle2]
  javascripts: [myscript]

[php]
// In the Action - Controller in Django terminology
$this->getResponse()->addStylesheet('mystyle1');
$this->getResponse()->addStylesheet('mystyle2');
$this->getResponse()->addJavascript('myscript');

// In the Template - The view in Django

Both are great, but Django more so

Having used both Django and Symfony I believe the two frameworks can learn a great deal from each other. Fortunately many people seem to experiment with a wide variety of frameworks (Including at least one delicious developer, version 3 of delicious maybe? ;)). Django in general has some excellent features, which make it a better choice for web development. If you are somehow bound to PHP, Symfony is still a good choice. The Django community is buzzing and active like no other and I look forward to posting on the various features.

If you didn’t try it yet:
django-project.com
djangobook.com

Note: Looking to hire Python and Javascript Coders

YouTellMe.nl is currently looking to hire Python and Javascript programmers in The Netherlands. Drop me an email at thierry [at] youtellme.com if you would like to know more or want to suggest someone for the job openings.

]]>
http://www.mellowmorning.com/2008/08/27/django-vs-symfony/feed/
A new job! - but no Symfony http://www.mellowmorning.com/2008/01/20/a-new-job-but-no-symfony/ http://www.mellowmorning.com/2008/01/20/a-new-job-but-no-symfony/#comments Sun, 20 Jan 2008 22:43:04 +0000 tschellenbach http://www.mellowmorning.com/2008/01/20/a-new-job-but-no-symfony/ Note: We are actively seeking to hire exceptional PHP programmers. More on the job offering at the bottom of this posts.

Zero BubbleAfter one of my posts got featured on Ajaxian many interesting offers hit my mailbox. One of them was actually from a startup right here in Rotterdam called ZeroBubble. I was happily surprised to find an IT startup in Rotterdam. Especially since after talking to them it became clear that they operate at the highest level of technical possibilities and have an absolutely amazing team. Two months ago I happily joined their ranks.

YouTellMe

The project we are working on is called YouTellMe. I don’t want to share too much about it right now, but surely I will have plenty of exciting blog posts coming up in the next months.
Currently we are working with some of the nicest tech on the net. To give some examples: our admin interface is written entirely in ExtJs, the site’s search is powered by Lucene, we use prototype 1.6 for great object extending, for ajax functionality we use yahoo history manager to keep it bookmarkable, the entire site has been optimized according to the Yslow principles and we are doing some interesting things with openSocial. Given all these you can’t help but wonder why we aren’t using Symfony.

Why no Symfony?

Personally I am a huge fan of the Symfony framework. The team at Sensio has done an absolutely amazing job. My opinion on the framework is best described by these blog posts Part1, Part2. However the current project we are working on has some special requirements. First of all the application’s calculations are very harsh on the servers. Combine this with a large amount of AJAX and you have some serious performance issues. The calculation speed has been pretty optimized by a colleague of mine, who wrote a python daemon for the task. Still it is essential to keep the PHP framework’s overhead to a minimum. Prior to my employment at this company it was decided that Symfony would be too slow to handle the task. This is a topic which often nags Symfony.

I am curious how fast Symfony can be. For the YouTellMe site I need a bootstrapped and blazingly fast framework. In the coming weeks I’ll be setting up some tests too see how Symfony compares to our home build framework. As a starters I’ll definitely relieve Symfony from the ORM and fancy routing. From there on I will need to test to see which components are slow and can be removed. The clean and flexible programming in Symfony should make this easy to do.

Our current framework is very lightweight. It even does not do auto loading. I for one have no clue what the speed gain is from not using auto loading and it would also be interesting to test it. The MVC structure is entirely home build, but the rest of the features use Zend.

If there are readers of this blog, which have gone through the process of stripping Symfony, be sure to leave some tips in the comments!

Jobs at ZeroBubble

ZeroBubble is currently recruiting talented PHP programmers in the Rotterdam area. We are located in the Beurs World Trade center. If you are into the latest technology and like to work with great people, software and hardware be sure to email me at thierry [at] zerobubble [dot] nl or my boss at joost [at] zerobubble [dot] nl. As mentioned we work with fun software such as Ext Js, Lucene, Zend, object oriented js with Prototype 1.6, yahoo history, Yslow principles and openSocial.
We are looking for both full and partime PHP programmers. Python, ExtJs, prototype, server admin, subversion and memcached knowledge are all nice extras. As a main quality though, you have to be excited about building a unique and amazing web application.

]]>
http://www.mellowmorning.com/2008/01/20/a-new-job-but-no-symfony/feed/
Pake: propel-build-all-save-mysql http://www.mellowmorning.com/2007/11/11/pake-propel-build-all-save-mysql/ http://www.mellowmorning.com/2007/11/11/pake-propel-build-all-save-mysql/#comments Sun, 11 Nov 2007 23:54:48 +0000 tschellenbach http://www.mellowmorning.com/2007/11/11/pake-propel-build-all-save-mysql/ I tended to use fixtures in order to save my data before propel-build-all commands. In a discussion on syncing development database structure with production, Mike mentioned he uses mysqldumps. This is actually not a bad idea, given that it is faster and less error prone (propel will never bug you). The downside is off course that it only works for mysql.

Here 3 Pake tasks to automate your mysql dumping:

  1. mysql-dump-data
  2. mysql-load-data
  3. propel-build-all-save-mysql

Download all three pake tasks. To install them simply copy the file to myproject/data/tasks/

You will have to edit the file to configure your database settings.

Note that this is only a temporary solution. I personally would be very happy to see Propel making database structure changes.

I didn’t see any manual on creating Pake tasks. Improvements and suggestions are more than welcome.

]]>
http://www.mellowmorning.com/2007/11/11/pake-propel-build-all-save-mysql/feed/
CommentHub.com - Developed with Symfony http://www.mellowmorning.com/2007/11/08/commenthubcom-developed-with-symfony/ http://www.mellowmorning.com/2007/11/08/commenthubcom-developed-with-symfony/#comments Thu, 08 Nov 2007 21:54:02 +0000 tschellenbach http://www.mellowmorning.com/2007/11/08/commenthubcom-developed-with-symfony/ CommentHubCommentHub.com has been developed with Symfony and is currently in Alpha testing. Needless to say it is a great pleasure to use Symfony and new features are being added effortlessly.

CommentHub.com aims to raise the standard in online commenting and make it more social. Commenting has become an important aspect of the internet, however a central system has not been available so far. CommentHub offers a plug and play comment system for your website. Whether it is your blog or any other page, you can add an advanced comment system in a minute. Currently it supports the following features:

  • Fast Ajax commenting
  • Threaded comments
  • Voting on comments
  • Gravatar images
  • Edit capabilities
  • Spam prevention and protection
  • Distinct look for admin comments
  • New comment notification emails for admins
  • Comment RSS Feed
  • Login (to remember email, name and site across websites)

Stronger email integration, personal RSS feeds and social features are all under development. Furthermore the system is already supporting templates. An interface to upload CSS templates will be available soon.

To see the comments in action just scroll down to the bottom of this page. Another example (with more comments) may be found by looking at my previous post.

Currently it is rather bootstrapped and in Alpha testing. To try it out for your website you can register for a webmaster account here (Enter mellow as your invitation code). The product is still under heavy development. Feature request, bug reports and comments are more than welcome.

To have a sneak peak at how easy the implementation actually is, view getting started with CommentHub. Plugins for major blogging systems will soon be available. (If anyone feels like contributing some plugins, it would be greatly appreciated.)

Thanks to Symfony for making the development such a pleasure.

]]>
http://www.mellowmorning.com/2007/11/08/commenthubcom-developed-with-symfony/feed/
Using php to dynamically generate conflict free css http://www.mellowmorning.com/2007/10/29/using-php-to-dynamically-generate-conflict-free-css/ http://www.mellowmorning.com/2007/10/29/using-php-to-dynamically-generate-conflict-free-css/#comments Mon, 29 Oct 2007 15:30:21 +0000 tschellenbach http://www.mellowmorning.com/2007/10/29/using-php-to-dynamically-generate-conflict-free-css/ This little blog has been getting a lot of coverage lately thanks to a write up by Ajaxian. Developing with Symfony is great and always gives you a lot to think and write about.

For my new product I was having a CSS conflict. This tends to happen when you include your own html and css into someone else’s website. For instance if you have a widget as such:

html

<div id="mywidget">
<h1>My hello world widget</h1>
</div>

css

H1 {
color:green;
font-size:20px;
}

The solution to this problem is quite straightforward, you simply specify your css selector as div#mywidget H1. However, what if you want to allow people to customize the looks of your widget. Now you could off course ask them to include the div#mywidget part, but chances are this will give problems.

Since I was already using the great sfCombineFilterPlugin an easy solution was available. (If you didn’t use the sfCombineFilterPlugin yet, go check it out immediately. Also have a look at Yahoo’s Yslow)

The sfCombineFilterPlugin uses php to gzip, minify and cache your css and javascript. Here is how to extend that behavior to include the #mywidget specification. (Assuming you have sfCombineFilter installed)

Step 1: open your .htaccess

Just below the RewriteBase instruction add:
# if we are retrieving javascript or css
RewriteRule ^css/packed/prepend/(.*\.css) /sfCombineFilterPlugin/combine.php?type=css&prepend=1&files=$1
RewriteRule ^css/packed/(.*\.css) /sfCombineFilterPlugin/combine.php?type=css&files=$1
RewriteRule ^js/packed/(.*\.js) /sfCombineFilterPlugin/combine.php?type=javascript&files=$1

Step 2: add this class to the top of web/sfCombineFilter/combine.php

Partly based on CSS parser class.

class prependCss
{

    public static function prependCssString($str) {
        // Remove comments
        $str = preg_replace("//*(.*)?*//Usi", "", $str);

        $parts = explode("}",$str);
        if(count($parts) > 0) {
            foreach($parts as $part) {
                list($keystr,$codestr) = explode("{",$part);
                $keys = explode(",",trim($keystr));
                $newkeys = array();
                if(count($keys) > 0) {
                    foreach($keys as $key) {
                        if(strlen($key) > 0) {
                            $key = (!strstr($key, '#mywidget')) ? '#mywidget'.$key : $key;
                            $newkeys[] = $key;
                        }
                    }
                    $keystr = implode(', ',$newkeys);
                }
                if(!empty($keystr)) //needed for spaces behind last }
                $rules[] = $keystr . " {" . $codestr . "}";
            }
            $prependedCss = implode("n", $rules);
        }
        //
        return $prependedCss;
    }

    public static function prependCssFile($filename) {
        if(file_exists($filename)) {
            return self::prependCssString(file_get_contents($filename));
        } else {
            return false;
        }
    }
}

Step 3: hack around in combine.php

below $minify_js add:
if($_GET['prepend']==1)
$prepend = true;

change the stuff below this comment to:
// Get contents of the files
$contents = '';
reset($elements);
foreach ($files as $path) {
if($prepend && $_GET['type'] == ‘css’) {
$contents .= “\n\n” . prependCss::prependCssFile($path);
} else {
$contents .= “\n\n” . file_get_contents($path);
}
}

And finally just change your urls to css/packed/prepend/yourcss.css (if you are using relative paths in your css you might need to add an ../)

Conclusion

Using this technique your css will load without any problems in third party sites. This comes in very useful when creating widgets or greasemonkey scripts.

]]>
http://www.mellowmorning.com/2007/10/29/using-php-to-dynamically-generate-conflict-free-css/feed/
Introducing a cross site ajax plugin for Prototype http://www.mellowmorning.com/2007/10/25/introducing-a-cross-site-ajax-plugin-for-prototype/ http://www.mellowmorning.com/2007/10/25/introducing-a-cross-site-ajax-plugin-for-prototype/#comments Thu, 25 Oct 2007 20:59:59 +0000 tschellenbach http://www.mellowmorning.com/2007/10/25/introducing-a-cross-site-ajax-plugin-for-prototype/ Update: there have been some improvements to this plugin. Have a look at this post regarding the update. Thanks for the feedback!

After some days of hard labor, I finished my cross site Ajax plugin for the prototype framework 1.5.0. (Download Plugin Here) While working on a new product of mine I realized I needed cross site Ajax, which is not supported in the Prototype framework.

During cross site Ajax requests the standard XmlHttpRequest approach breaks down. The problem is that XmlHttpRequest is bounded by the same site policy. Fortunately the script tag has the freedom to do as it pleases.

Some other libraries such as dojo and jquery do support the script method for doing Ajax. There is even a project on source-forge called COWS, which is dedicated to this purpose. This plugin is an adaptation of the jquery plugin, but modeled to look like an XmlHttpRequest. The credits of the original code go to Ralf S. Engelschall , which amazingly achieved to make it nicely cross browser compatible. This plugin supports FF, IE, Safari, Opera and Konqueror, but has only been properly tested in FF and IE.

Prototype’s structured way of doing Ajax was my main reason to choose the prototype framework. Furthermore it is also included in the great Symfony framework. In Prototype Ajax requests are written like this:

new Ajax.Request('myurl', {
method: 'GET',
crossSite: true,
parameters: Form.serialize(obj),
onLoading: function() {
//things to do at the start
},
onSuccess: function(transport) {
//things to do when everything goes well
},
onFailure: function(transport) {
//things to do when we encounter a failure
}
});

The cross site plugin simply allows you to do Ajax cross site, by specifying crossSite: true (line 3 of the above example). I will now cover some technical aspects of the plugin, but if you just want to start using it simply skip to the plug and play instructions below.

How it works - Technical Aspects

This plugin uses the dynamic script tag technique. This basically means that we insert new <script> tags into the Dom. Since this script tag is not bound to the same site you can send and receive data in the Ajax way. In its most basic form the javascript would be like this:

this.node = document.createElement('SCRIPT');
this.node.type = 'text/javascript';
this.node.src = 'http://www.serversite.com';
var head = document.getElementsByTagName('HEAD')[0];
head.appendChild(this.node);

In order to make it very easy to use with Prototype, or any other library for that matter, I decided to mimic the functions of the XmlHttpRequest. This is easily achieved by implementing the functions open, send and onreadystatechange. Furthermore I needed to specify the variables readyState and status in order to support prototype’s onLoad, onSucces and onFailure.

Detecting the loading of a script element is not that easy. Browsers such as Safari and Konqueror simply give no indication of this at all. One common solution to dealing with this is to use an interval and perform a check. The work at TrainOfThoughts however takes the beautiful approach of inserting a helper script. This exploits the fact that the dynamically added scripts are executed in sequence. This approach makes the plugin nicely cross browser compatible.

Detecting failure is rather cumbersome for the script technique. As far as I know there is no way to read the headers on the incoming file, or to inspect its contents through javascript. This leaves us with the rather blunt approach of setting a global variable using the server output. It works, but it could be prettier.

Plug and Play implementation instructions

Firstly you need to load the plugin javascript file: download cross site ajax plugin for the prototype framework 1.5.0.

Secondly you need to change your regular prototype Ajax request, by ensuring that you instruct it to use the crossSite and GET methods, as such (observe line 2 and 3):

new Ajax.Request(baseurl+'/comment/giveratingjs', {
method: 'GET',
crossSite: true,
parameters: Form.serialize(obj),
onLoading: function() {
//things to do at the start
},
onSuccess: function(transport) {
//things to do when everything goes well
},
onFailure: function(transport) {
//things to do when we encounter a failure
}
});

Thirdly you might need to rewrite some of your javascript code to accommodate the instant execution of the scripts.

Fourthly, if you want to use onFailure for any of your scripts you need to send some javascript instructions back from the server. You need to do this both on success and on failure (since a global variable is used). This is the javascript variable you need to set:

'var _xsajax$transport_status = 200;' Or
'var _xsajax$transport_status = 404;'

Symfony specific tips

Symfony detects if it receives a XmlHttpRequest and automatically turns off your debug bar and layout. Unfortunately it is not so kind to the script technique. So in your action you need to do this manually:

sfConfig::set('sf_web_debug', false);
$this->setLayout(false);

Furthermore your validation files by default only look at POST variables (this one tricked me). To instruct them to look at both, simply mention

methods: [post, get]

at the top of your validation.yml

Since you will probably want to send html to the browser, I would suggest you put this little function (found in the symfony escape helpers) in your toolbox.

public static function esc_js($value) {
return addcslashes($value, "\0..\37\\'\"\177..\377\/");
}

Conclusion

The dynamic script tag technique opens up a wide range of possibilities. Personally I am very glad with the results and would like to thank Ralf S. Engelschall for his superb cbc work. Unfortunately I didn’t include an example this time. You will have to wait for the products’ launch:). Comments and improvements are always appreciated. Enjoy your cross site scripting!

]]>
http://www.mellowmorning.com/2007/10/25/introducing-a-cross-site-ajax-plugin-for-prototype/feed/
Symfony & Gravatars - easy implementation http://www.mellowmorning.com/2007/10/19/symfony-gravatars-easy-implementation/ http://www.mellowmorning.com/2007/10/19/symfony-gravatars-easy-implementation/#comments Fri, 19 Oct 2007 13:01:59 +0000 tschellenbach http://www.mellowmorning.com/2007/10/19/symfony-gravatars-easy-implementation/ Lets start with a small explanation. Gravatars are so called ‘globally recognized avatars’. Basically it is an open directory for avatars. If you didn’t get one yet, feel free to head over to www.gravatar.com.

The implementation of gravatars for your site is already extremely easy. However if you are fortunate enough to be using Symfony, it becomes a real piece of cake. Quite a few people already use gravatars, including the Symfony blog. This number will probably increase quite a bit, given the recent purchase of the company by Automattic.

Gravatars are attached to an email address. Lets assume your program is already setting and getting the email addresses. All you need to get up and running with Gravatars is these simple 3 steps.

1. Extend your setEmail to do setGravatar as well

(somewhere in lib/Comment.php)

function setEmail($input) {

$this->setGravatar(md5($input));

parent::setEmail($input);

}

2. When getting the Gravatar, retrieve the full image code

(somewhere in lib/Comment.php)

function getGravatar() {
$md5email = parent::getGravatar();
$size = 45;
$rating = 'R'; // possible values [ G | PG | R | X ]
$url = ‘<img width=’.$size.’px height=’.$size.’px class=”gravatar” src=”http://www.gravatar.com/avatar.php?gravatar_id=’.$md5email.’&rating=’.$rating.’&size=35″ alt=”gravatar” />’;
return $url;
}

3. In your view template

Simply do: $comment->getGravatar();

DONE!

Have a look at the result:
Gravatar implementation

]]>
http://www.mellowmorning.com/2007/10/19/symfony-gravatars-easy-implementation/feed/
We love FireFox, 76% http://www.mellowmorning.com/2007/10/11/we-love-firefox-76/ http://www.mellowmorning.com/2007/10/11/we-love-firefox-76/#comments Thu, 11 Oct 2007 08:22:44 +0000 tschellenbach http://www.mellowmorning.com/2007/10/11/we-love-firefox-76/ A few days ago I noticed a bug in the Digg-this plugin for my blog. The javascript with this plugin was causing errors with Internet Explorer. The problem must have been around for a week or so, before I noticed it. Now my site doesn’t get too many visitors, but I would have expected someone to complain about it.

Looking in my stats it becomes clear why no-one has. Though only a small and insignificant sample, the traffic at my blog is strongly IE averse. Just have a look at the stats:

Overview of important browsers

Pie Chart of Overview

]]>
http://www.mellowmorning.com/2007/10/11/we-love-firefox-76/feed/
Ajax for unique usernames http://www.mellowmorning.com/2007/10/05/ajax-for-unique-usernames/ http://www.mellowmorning.com/2007/10/05/ajax-for-unique-usernames/#comments Fri, 05 Oct 2007 13:27:50 +0000 tschellenbach http://www.mellowmorning.com/2007/10/05/ajax-for-unique-usernames/ I always enjoy the logical thinking required for programming. For Symfony it is really nice how it all just flows together. I wanted to implement an ajax check for unique usernames. Something similar like how you see it on Twitter. Lets get started:

First create a validator in lib/validators/sfUniqueUserValidator.class.php

<?php
class sfUniqueUserValidator extends sfValidator
{
public function execute (&$value, &$error)
{
//check if the username exists
$c = new Criteria();
$c->add(sfGuardUserPeer::USERNAME, $value);
$user = sfGuardUserPeer::doSelect($c);
if (!empty($user))
{
$error = $this->getParameter('user_error');

return false;
}

return true;
}

public function initialize ($context, $parameters = null)
{
// Initialize parent
parent::initialize($context);

// Set default parameters value
$this->setParameter('user_error', 'This username is taken');

// Set parameters
$this->getParameterHolder()->add($parameters);

return true;
}
}

Then in your view template use:

<?php echo observe_field('rusername', array(
      'update'   => 'userstatus',
      'url'      => 'sfGuardAuth/checkuser',
      'with' => "'id='+$('rusername').value",
  )) ?>

this will monitor an input field called rusername, and submit its value to the sfGuardAuth/checkuser internal url.

And to glue it all together, in the actions:

  public function executeCheckuser()
  {
     $username = $this->getRequestParameter('id');
     $userValidator = new sfUniqueUserValidator();
     $userValidator->initialize($this->getContext());
     $error='none';
     if (!$userValidator->execute($username,$error))
     return $this->renderText($username.' is taken');

     return $this->renderText($username.' is available'); 

  }

Enjoy!

Ps. any tips for posting code in wordpress would be greatly appreciated, for me it does the strangest types of things.

]]>
http://www.mellowmorning.com/2007/10/05/ajax-for-unique-usernames/feed/
Quick Symfony trick - The remote_function workaround http://www.mellowmorning.com/2007/09/30/quick-symfony-trick-the-remote_function-workaround/ http://www.mellowmorning.com/2007/09/30/quick-symfony-trick-the-remote_function-workaround/#comments Sun, 30 Sep 2007 12:15:41 +0000 tschellenbach http://www.mellowmorning.com/2007/09/30/quick-symfony-trick-the-remote_function-workaround/ As mentioned in previous posts, Ajax in Symfony is a very easy experience. However sometimes the pre-made functions don’t provide all the functionality you need.

Unfortunately when you want to update a dynamically assigned part of the page you apparently need to write your javascript manually. In my case I had a list of comments where I wanted to be able to vote them up or down. So i needed the remote_function to update whichever comment the javascript code was called from. The remote_function however always adds nice quotes around what you type. So:

remote_function(array(
'update'  => 'obj',
'url'     => 'comment/giverating',
))

results in this javascript:
new Ajax.Updater('obj', '/frontend_dev.php/comment/giverating', {asynchronous:true, evalScripts:false})
This makes it impossible to refer to an object for the first argument of the Updater method.

How to update a dynamic area:

In javascript you can refer the location from which a function is called by passing the this variable in the function call. So in your function call you write:

link_to_function(__('+'), 'giverating('this)' )

Now in your actual javascript function you simply receive the this object and update it, as such:
function giverating(obj) {
new Ajax.Updater(obj, '".url_for('comment/giverating')."', {asynchronous:true, evalScripts:false})
}
");?>

Note that using the url_for php function to write the javascript ensures that a routing change will not upset the functioning of the javascript.

]]>
http://www.mellowmorning.com/2007/09/30/quick-symfony-trick-the-remote_function-workaround/feed/
Quick Symfony Trick - The power of filters http://www.mellowmorning.com/2007/09/22/quick-symfony-trick-the-power-of-filters/ http://www.mellowmorning.com/2007/09/22/quick-symfony-trick-the-power-of-filters/#comments Sat, 22 Sep 2007 20:09:38 +0000 tschellenbach http://www.mellowmorning.com/2007/09/22/quick-symfony-trick-the-power-of-filters/ After reading the Symfony book it was not clear to me how to deal with servers in the config setting. Say that you are creating a site on your local computer and then want to deploy it to your server. Some variables might be different, like in my case the image directory.

Symfony nicely support setting variables for development environments, but I found no such functionality for different servers. In the meanwhile I’ve created a simple filter setup which deals with the problem very nicely.

First set your config values in the frontend/config/app.yml:

all:
  server: 'local'
  local:
    imagedir: 'http://comments/comment/images/'
  production:
    imagedir: 'http://www.mellowmorning.com/symfony-examples/images/'

Next create a filter in lib/filters/setconfFilter.class.php:

class setconfFilter extends sfFilter
{
  public function execute($filterChain)
  {
    // Execute this filter only once
    if ($this->isFirstCall())
    {
define('SERVER', sfConfig::get('app_server'));
      define('IMAGE_DIR', sfConfig::get('app_'.SERVER.'_imagedir'));
}

// Execute next filter
    $filterChain->execute();
  }
}

Now to tie our little labor together set in frontend/config/filters.yml between security and cache:
setconf: ~
class: setconfFilter

Here you now have your own server dependant config settings, just use IMAGE_DIR in your template and it will refer to the correct location. If you are really lazy and do not want to change your app.yml every time you sync with production, we could automate that in the filter as well. Simple write something like this in the filter to define the SERVER constant:

define('SERVER', ($_SERVER['SERVER_NAME']=='comments')?'local':'production');

and remove the definition of the server from the app.yml.

Read more: About filters
Read more: the Symfony configuration system
PS. Also have a look at some of the great cheatsheets out there, from the Symfony wiki:

Admin generator cheat sheet
Directory structure and CLI
View
View: Partials, Components, Slots and Component Slots
Form Helpers
Javascript and Ajax Helpers

Server Validation
Model
Model: Schema
Lime Unit & Functional Testing
ORM Diagram

]]>
http://www.mellowmorning.com/2007/09/22/quick-symfony-trick-the-power-of-filters/feed/
Ten reasons why Symfony rocks - Part 2 http://www.mellowmorning.com/2007/09/08/ten-reasons-why-symfony-rocks-part-2/ http://www.mellowmorning.com/2007/09/08/ten-reasons-why-symfony-rocks-part-2/#comments Sat, 08 Sep 2007 20:00:28 +0000 tschellenbach http://www.mellowmorning.com/2007/09/08/ten-reasons-why-symfony-rocks-part-2/ If you weren’t convinced by the first 5 reasons why Symfony rocks, you will certainly be today.

Symfony’s closest competitors are probably RoR or rolling your own framework. Using a pre-made framework instead of rolling your own has several advantages:

  • Easy collaboration between coders, because of standardized approach
  • A framework developed by many will include nice features which you wouldn’t bother to implement on your own
  • You can outsource part of your development easily, or if you serve customers they receive a product their own developers can easily work on.
  • Working in a framework not developed by you teaches you the practices of other developers (some of which might be good)

Lets see the final 5 reasons why Symfony rocks. My chosen 10 are just a small subset of the powerful capabilities of Symfony and I will link to all good blog posts covering this topic. (Current Symfony version as of writing is 1.0.7)

1 - Internationalization and Localization (i18n & L10n)

Symfony offers a really fantastic suite of internationalization tools. I suppose the fact that the creators are in France has something to do with it. The simple comment example of the last post actually gives us a nice start to show the possibilities. We will support these nice languages: (English, Dutch, Italian and Romanian - the last two thanks to my girlfriend).

As mentioned Symfony provides a full solution. For the basic translation needs Symfony uses a helper function with two underscores, as such: __(’text which will be translated’). The text which needs to be translated can be exported to an XLIFF format using a plugin (Will be part of Symfony in 1.1.0) . For those wondering the XLIFF format looks like this:

<trans-unit id="5">
<source>Your name</source>
<target>Uw naam</target>
</trans-unit>

A simple config setting deals with the usage of utf-8; Formatting for numbers and dates are available and use the culture automatically. format_date() and format_number() automatically adjust their output depending on the culture.

Best of all the data model supports the concept of I18n tables. This allows you to have translations of items in your database (for instance products) and leave all the logic of dealing with this to Symfony. More advanced translation needs such as sentences, which depending on the database results need to be pluralized are also supported.

Lets look at the possibilities using the simple comment example. Implementing these languages is achieved in a few simple steps:

Firstly Symfony needs to be configured to support translations. This feature is turned off by default for performance reasons. To do this simply uncomment the commented lines in frontend/config/i18n.yml and set the following settings in frontend/config/settings.yml:

standard_helpers: [i18n]
charset: utf-8
i18n: on

Secondly we need to tell Symfony how to change the URLs, which we do in routing.yml. We will use URLs like this symfony-examples/nl/comment. Thirdly we need to actually use the interface translation helper __ on all our text, as such:
__('All Comments:')
I happened to forget the submit button the first time around. This is a rather tedious process and you would usually do this while you create the template and not afterwards.

So now the fun of actually translating. First we create the messages.ro.xml and run the command: symfony i18n extract frontend ro. This command uses the plugin to extract the text, which needs translating. After some translating we now have a nicely internationalized version of the comment example. Go see and click the flags!

Those cute flags were created by famfamfam

Flags by famfamfam

Read More: Internationalization in the Manual

2 - Caching

Caching is essential to the performance of any website. In many situations you can mess everything else up as long as your caching is good.
When reading about frameworks you will likely read that Symfony is somehow slow. Now off course you start to wonder whether this is true given that Yahoo uses it for its bookmark service. My impression is that these tests either use oversimplified ‘hello world’ examples or forget to query the database efficiently. A proper tests of speeds has to my knowledge not yet been conducted. Symfony is in fact lighting fast and offers a wide array of caching tools:

  • Cache of an action (with or without the layout)
  • Cache of a partial, a component, or a component slot
  • Cache of a template fragment
  • (plugin) sfArrayCachePlugin to cache an array
  • (plugin) sfSuperCache Plugin to cache pages fully statically
  • (snippet) Some work on a memcached plugin has already been done, which will be interesting for our developers fortunate enough to need it. (didn’t test this personally)
  • Function result caching with sfFunctionCache
  • sfProcessCache for memory caching with the help of PHP accelerators

In order to make the nice comment example nice and fast we will add some simple caching to it.

in myapplication/mymodule/config/cache.yml:

index:
enabled: on
with_layout: false
lifetime: 3600

This enables the cache, however we do want to clear the cache when someone submits a new comment. This is easily achieved by adding the following to your update action:

$sf_root_cache_dir = sfConfig::get('sf_root_cache_dir');
$cache_dir = $sf_root_cache_dir.'/frontend/*/template/*/all';
sfToolkit::clearGlob($cache_dir.'/*/*/comment.cache');
sfToolkit::clearGlob($cache_dir.'/*/comment.cache');

This looks a bit complicated, but these four lines of code deal with deleting the cache for all languages.

Read more: Caching in Symfony
Read more: Memcached

3 - Development environments

Environments are a great way of running a few different set of configurations next to each other. This comes in extremely handy for development. By default Symfony has two environments: production and development. In the later all the caching is disabled, errors are displayed and the WebDebug toolbar is available.

When I wanted to setup caching these environments came in very handy. Somehow my comment form was not updating as it should. To diagnose the situation I added another environment called test (accessible by frontend_test.php), similar to dev, but with caching enabled. It quickly became clear that the problem originated from caching, client side to be specific.

For every larger application you will need to keep track of these different sets of configurations and Symfony enables this with great ease. To access the various environments simply browse to the corresponding front controller (index.php for production, frontend_dev.php for development, frontend_test.php for testing.)

To set the configuration settings, simply specify the config files as follows (example from standard frontend/config/settings.yml):

all:
.settings:
escaping_strategy: both
escaping_method:   ESC_ENTITIES
standard_helpers:  [i18n, Partial]
charset:           utf-8
i18n:              on
cache:             on

prod:
.settings:
no_script_name:           on

dev:
.settings:
# E_ALL | E_STRICT = 4095
error_reporting:        4095
web_debug:              on
cache:                  off
no_script_name:         off
etag:                   off

test:
.settings:
# E_ALL | E_STRICT & ~E_NOTICE = 2047
error_reporting:        4095
cache:                  on
web_debug:              on
no_script_name:         off
etag:                   on

Read more about: Development Environments

4 - Do not repeat yourself!

All coders live by the rule of not repeating yourself. Symfony tries to make this as easy as possible for you. This is completely integrated into all aspects of Symfony. You can for instance write your own: Propel Behaviors, Filters, Validators and pretty any piece of normal code. This is one of the things which you will really like in Symfony. As a starter and to keep it short I’ll just cover the DRY tools in the view layer.

In Symfony there are four important methods to not repeat yourself in the view layer:

  • Partials
  • Components
  • Slots
  • Component Slots

A partial is a simple piece of repeated template code. Say that you want to have the ability to add comments on multiple parts of your website. Simply stash the template code for adding comments in a partial. Partials are stored in the template directory with a _ (single underscore) before the partial name. When you want to include them simply use:

<?php include_partial('module/partial',array('varinpartial' => $myvar)) ?>

When the code to repeat becomes more complex and also requires some logic we can separate the logic and template code by using a component. Suppose for instance that you created a blog using Symfony and want to display the latest blog posts. The logic part of querying the database goes in a components.class.php file and the template in a partial. This gives you a very convenient way to reuse code. Including goes as follows:

<?php include_component('blog', 'latestposts') ?>

Slots are placeholders. You can define its content anywhere in the view layer. This is great if you for instance want to have a default sidebar in your layout, with the ability to overwrite it in the template.

The really interesting one is the component slot. This combines the power of the configuration file with logic and view separation. It functions very similar to a component, except that logic part to execute is indicated by a config file. As follows:

all:
components:
sidebar: [bar, user]
indexSuccess:
components:
sidebar: []
showSuccess:
components:
sidebar: [bar, options]

This would make the component slot display a user related sidebar by default, but on the index page display no sidebar and on the page displaying the user data display a sidebar with options.

Read more: Symfony’s View Layer

5 - Bridges to other frameworks

A short, but important point. Both the Zend framework and EZ components offer quite some valuable tools. Symfony feautures bridges to both of these, giving you access to two large arrays of tools.

This allows for nice things, such as an instant search engine for your site, using Zend Search Lucene (released just days ago). There is always a lot of discussion regarding the so called best framework, but I believe that eZComponents and Zend are actually pretty complimentary to Symfony.

These 10 points showed some of the power of Symfony. Hope you enjoyed them and will run over straight to The Symfony Documentation. If you like Symfony then Digg this post up and spread the word!

]]>
http://www.mellowmorning.com/2007/09/08/ten-reasons-why-symfony-rocks-part-2/feed/
Updating the Askeet tutorial http://www.mellowmorning.com/2007/09/07/updating-the-askeet-tutorial/ http://www.mellowmorning.com/2007/09/07/updating-the-askeet-tutorial/#comments Fri, 07 Sep 2007 20:15:22 +0000 tschellenbach http://www.mellowmorning.com/2007/09/07/updating-the-askeet-tutorial/ Askeet

Halfer just suggested to update the Askeet tutorial.

When I started out with Symfony this Askeet tutorial made me wonder if Symfony really is the best out there… Should I use RoR or Zend, those were my thoughts. Currently I think I made the right choice by sticking with Symfony. For me it has been a great learning experience and highly productive coding.

An important part of the value of a framework comes with its adoptance. Rewriting the askeet tutorial will go a long way towards achieving that.

Sign me up for a day!

]]>
http://www.mellowmorning.com/2007/09/07/updating-the-askeet-tutorial/feed/
Symfony Camp and the framework’s blazing progress http://www.mellowmorning.com/2007/09/06/symfony-camp-and-the-framework%e2%80%99s-blazing-progress/ http://www.mellowmorning.com/2007/09/06/symfony-camp-and-the-framework%e2%80%99s-blazing-progress/#comments Thu, 06 Sep 2007 06:40:29 +0000 tschellenbach http://www.mellowmorning.com/2007/09/06/symfony-camp-and-the-framework%e2%80%99s-blazing-progress/ Symfony has been producing some amazing music lately. The eagerly awaited version 1.1 progressing rapidly with the delegation of 1.0 development; Plugins are developing at an amazing speed (example, example); Great posts are being written to further enhance one’s understanding of Symfony: such as Understanding Behavior and tomorrow will be the start of the highly anticipated Symfony Camp.

Hope that all the participants will have a great time. With speakers such as

It should certainly be a good event. Congrats to Stefan Koopmanschap and the entire team at Dutch Open Projects for setting up a nice event in The Netherlands. IT is not very progressive in our little country and it is great to see such an event being organized!

Since I am currently on vacation in Romania I will have to miss the great event, but I surely hope everyone will blog and post the slides online!

UPDATE:

Fabien’s Slides 

dustin.whittle

]]>
http://www.mellowmorning.com/2007/09/06/symfony-camp-and-the-framework%e2%80%99s-blazing-progress/feed/
Ten reasons why Symfony rocks - Part 1 http://www.mellowmorning.com/2007/08/18/ten-reasons-why-symfony-rocks-part-1/ http://www.mellowmorning.com/2007/08/18/ten-reasons-why-symfony-rocks-part-1/#comments Sat, 18 Aug 2007 15:57:17 +0000 tschellenbach http://mellowmorning.com/?p=3 In the short attention span of most fellow PHP developer’s, here the first 5 great reasons to use Symfony. (Update: part 2 is here.) This is by no means a full explanation of Symfony, but just enough to get you running over to the documentation to learn more.

Few general highlights first:

  • Enterprise Ready - (used for Yahoo bookmarks)
  • Many Plugins available (eg. authentication, authorization, client side validation, thumbnail, rss)
  • Actively developed
  • Good documentation

1 - Ajax and Javascript

With all the hype surrounding web II.0, any major PHP framework has to add some Javascript and Ajax support. Symfony gives you a few nice building blocks. Small example:

<?php echo form_remote_tag(array(
'url' => 'project/addReply',
'update' => 'replys',
'complete' => visual_effect('highlight', 'replys').
"Element.hide('addReply')",
'position' => 'bottom',
), 'id=addReply style=display:none;') ?>
<?php echo input_hidden_tag('id', $project->getId()) ?>
<?php echo textarea_tag('body') ?><br />
<?php echo submit_tag('submit') ?>
</form>
<?php echo link_to_function('Add a reply', visual_effect('toggle_appear', 'addReply')) ?>

This little snippit gives you an AJAX form, which submits its data to project/addReply (module/action). With a nice visual effect for appearance. Extremely fast to implement and extend. Have a look at my ajax comment form example.

Read More: Ajax in Symfony

2 - Instant admin interface: Advanced crud generation for admin interface

Useful for almost any type of website. Say you have a job listing website, run the command:
symfony propel-init-admin backend listing listings
and there you have your crud admin interface ready. Pretty, friendly, fully featured and without writing a single line of code.

Admin Generator Example

But wait, what if I want to include feature X in the admin interface? Symfony uses a generator.yml configuration file which allows you to set filters and customize your admin interface. Most of the time this will more than fulfill your needs and you will easily create complete and functional backends.

See it happening: Generator Movie

3 - Nice Urls: The Routing System

Symfony uses a frontend controller, in which all requests are managed through a single frontend. This makes creating nice urls simpler than ever.
post:
url: /weblog/:title
param: { module: post, action: permalink }
list_of_posts:
url: /latest_posts
param: { module: post, action: list }

How does that compare to writing htaccess files?
If you for instance would want the url for member profiles on your site to be www.mysite.com/members/member-name you would simply use:
url: /members/:membername
param: { module: users, action: show }

The url indicates how you want the url to look and the param value tells Symfony where the code is located.

Read More: Links and the routing system

4 - Form Handling: Fillin, Validation and Creation

One of the areas where Symfony really shines is the handling of forms. The code for generating forms is clean and easy to understand and learn.

<?php echo select_tag('name', options_for_select(array(
'Steve' => 'Steve',
'Bob' => 'Bob',
'Albert' => 'Albert',
'Ian' => 'Ian',
'Buck' => 'Buck'
), 'Ian')) ?>
=> <select name="name" id="name">
<option value="Steve">Steve</option>
<option value="Bob">Bob</option>
<option value="Albert">Albert</option>
<option value="Ian" selected="selected">Ian</option>
<option value="Buck">Buck</option>
</select>

Furthermore validation and re-filling the form is done in a configuration file. This keeps your code and templates nice and clean. An example:fillin:
enabled: true
fields:
name:
required:
msg: The name field cannot be left blank
sfStringValidator:
min: 2
min_error: This name is too short (2 characters minimum)
max: 100
max_error: This name is too long. (100 characters maximum)

With some simple config lines you can take care of fillin and validation. For the skeptics, off course you can define your own validators. As far as I’ve experienced you can pretty much extend Symfony any way you like, with minimal effort. If you want client side validation as well you can opt to do so by installing one of the many plugins.

Read More: Forms in Symfony

5 - Debugging on Steroids

We all wish our code to run smoothly in the first try. However the only way to achieve this is to never try anything new. If we have to Debug, let it at least be fast. Symfony provides us with a few awesome tools. First one is the developer toolbar.

Developer Toolbar

Showing you: 1. your application variables (useful for multiple development environments) 2. logs and messages (all the steps used for executing the page, perfect for debugging) 3. the number of queries and their sql 4. the size of the page 5. the load time throughout various points of the code.

Exception

If you do something wrong related to Symfony, it gives you a nice explanation of the problem, through it’s custom error display. Installing the famous Xdebug extension further increases the amount of information displayed.

Read More: Application Management Tools

All these little things together make developing with Symfony a joy. More goodness to come up in part two of this post.

(Watch out with installing Symfony though. It will take you anywhere between 30 seconds and two days. Depending on your experience with PEAR. There are some great install guides on the Symfony Wiki.)

Update:
Part 2 has been published: Ten Reasons why Symfony rocks - part 2

]]>
http://www.mellowmorning.com/2007/08/18/ten-reasons-why-symfony-rocks-part-1/feed/