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

PHP & Symfony & Web Development tschellenbach 11 Oct 2007 5 Comments

How the Rubicon Project is innovating Google’s online advertising business

Update: In the comments the founder of the Rubicon Project indicated that they will not be working directly with advertisers. My misperception was based on the TechCrunch write-up. The article below is based on the assumption that they would approach both sides of the problem. Since this is not the case, take this into account when reading the post.

Rubicon

The Rubicon Project is by far the most promising, exciting and revolutionizing startup of the moment. Their business has the potential to completely change the entire web-advertising industry.
They are trying to become an intermediary (of intermediaries) by offering:

  • Publishers: automated ad revenue optimization between networks
  • Advertisers: a central point to setup online advertising (wrong)

They display it in a graphical way in their beta overview video.

Rubicon Industry Value Chain Position

The Changing Industry

An intermediary like Rubicon profoundly changes the competitive landscape for ad networks such as Google Adsense.

Currently startups in the ad network business face a so called chicken and egg problem. Even if you have a technically great product, you will still need advertisers to get publishers and vice-versa. The advertising and sales efforts required in this industry are substantial and present a major obstacle for new companies to enter the market.

Now imagine a new market where Rubicon is the intermediary. Any new advertising network could instantly get its product of the ground by joining Rubicon. No longer are millions in capital needed for sales and promotion. When a startup is able to outperform the market incumbents, in terms of matching advertisements with visitors, it has its road to success paved. Not only does this benefit those startups, it also gives Rubicon’s clients access to the best performing advertising solutions.

Google was the first to get the match between ads and viewers somewhat right. Eager to be next in line seems to be the currently hyped Facebook, with its personalized advertising. My impression is that the current solutions are tremendously under-performing. When an intermediary, be it Rubicon, establishes a position for themselves, innovation in online advertising will boom.

An intermediary like Rubicon changes the balance between required core competences for ad networks. The focus moves from sales&marketing to clever algorithms, extensive data and intelligent models to match the advertisements with the viewers. The market’s changes effectively open up this 27 billion industry to a far larger array of entrepreneurs.

Google’s Perspective

Rubicon effectively lowers the barriers to entry into this Google Adsense dominated market. In the new market situation it will be harder for Google to stay ahead of its competition. This fact makes you wonder, will Google move to the Rubicon position or remain where it is. Or in other words, will it defend its sales competence or its ability to match visitors with advertisements?

If Rubicon succeeds we will soon have some very interesting entrepreneurial possibilities ahead. I certainly wish them the best of luck. Given the experience and progress of the founding team, I think they have a good shot.

@Frank, Good luck starting your sixth company!

Recommended Readings:

Techcrunch coverage of Rubicon

Rubicon about page

Blog of Frank Addante (I subscribed to it, great readings)

http://www.founderblog.com/2007/10/what-is-rubicon-project-part-ii-solving.html

http://www.founderblog.com/2007/10/what-is-rubicon-project.html

Rubicon beta overview video

Business & Web Development tschellenbach 08 Oct 2007 4 Comments

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.

PHP & Symfony & Web Development tschellenbach 05 Oct 2007 8 Comments

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.

PHP & Symfony & Web Development tschellenbach 30 Sep 2007 No Comments

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

PHP & Symfony & Web Development tschellenbach 22 Sep 2007 8 Comments

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!

PHP & Symfony & Web Development tschellenbach 08 Sep 2007 15 Comments

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!

PHP & Symfony & Web Development tschellenbach 07 Sep 2007 No Comments

« Previous PageNext Page »