Category Archives: symfony

Hooked into Drupal

In my last blog I mentioned how Drupal really does seem to offer more than just the ability to get a simple site up and running quickly.

Framework

When you look at Drupal more closely you realise one key thing: it’s not really a CMS, it’s a framework. Granted, nothing quite like Symfony in terms of its level of sophistication, but a framework nonetheless. Even a fairly modest PHP developer can therefore take what’s there and build on it in quite surprising ways. The vast array of Drupal modules is testament to that.

Hooks

That’s what makes Drupal so alluring as a CMS. It’s founded on a system of hooks: naming conventions which ensure that pieces of code you write will get called in certain pre-defined situations.

The simplest example of a hook is the menu hook. If you build your own module, all you need do is put a function in it called mymodule_menu and whatever code you put in that function will get called each time the core code builds the main site menu.

The real elegance of the system is that almost everything is built from hooks. Even stuff which looks like it’s part of the core code, like user management. Well, that’s actually a module built up using hooks. If you want to build your own slightly different user module, you don’t need to change the existing one. Just copy it, taking out the bits you need, adding in your own bits. Before you know it, you’ve got your own custom user module.

Community

The learning curve can be a little daunting at first, assuming you want to get your hands dirty with some module coding. Luckily, there are loads of excellent books (I can definitely recommend Pro Drupal Development by John VanDyk), web pages, blogs, etc around to help. Just google them, they’re out there! That’s another great strength of Drupal: the community. No matter how stuck you are, how bad things look. Chances are there’s someone out there who’s been in exactly your situation and come out the other end.

OpenSearch

One really useful thing I came across at IWMW 2008 was the ability to put your own site’s search into the browser’s list of search tools. You know, that little google box in Firefox where you can in fact bring down a list of other search engines. That can have your site’s search tool in there too.

This makes use of OpenSearch, a collection of simple XML formats for sharing search results.

Basically achieving your super-cool goal is a very easy three step process. Make a small web-accessible XML file on your web server with the right magic in it, then put a link to that file in your html header, much like you would if you wanted your RSS feed to appear as a button in a browser.

Step 1: work out your own search url

OpenSearch uses a special syntax for the search url, of the form:

http://example.com/search?q={searchTerms}

So for my blog, the search url is http://matthewbull.net/?s={searchTerms}

Step 2: make your xml file

<?xml version=”1.0″ encoding=”UTF-8″?>
<OpenSearchDescription xmlns=”http://a9.com/-/spec/opensearch/1.1/”>
<ShortName>matthewbull</ShortName>
<Description>my blog search</Description>
<Url template=”http://www.matthewbull.net/?s={searchTerms}” type=”text/html” method=”GET” />
<Image height=”16″ width=”16″ type=”image/vnd.microsoft.icon”>http://www.matthewbull.net/favicon.ico</Image> <OutputEncoding>UTF-8</OutputEncoding>
<InputEncoding>UTF-8</InputEncoding>
</OpenSearchDescription>

where the ShortName and Description are up to you, and Url was the url you made in step 1.

Save this as an xml file to your server.

Step 3: tell the browser about your xml file

Now just put a link in your html to tell your browser where your xml file lives:

<link title="matthewbull.net" href="http://matthewbull.net/opensearch.xml"
 type="application/opensearchdescription+xml" rel="search">

And that’s it! Happy searching.

IWMW 2008 – day 2

So, we’re into day 2 of the IWMW 2008 conference at Aberdeen. Day 1 passed with much alcohol, dancing, Aberdonian ‘furry boots’, oh and some web stuff too.

I think the highlight was an excellent opening talk by Derrick McClure from the Centre for Linguistic Research at Aberdeen. It was a novel idea to have an opening talk by a linguist about the Aberdonian dialect (doric). But it worked, and to be honest this talk was more engaging than any of the other web-related talks that followed yesterday. I can’t even really remember any of the other talks, in fact.

Another highlight was a parallel session by Michael Nolan of Edge Hill University. They seem to be doing a lot of good healthy web 2.0 stuff there, and seem to have been given a lot of freedom in what they do. Edge Hill is a very new university, where student recruitment is king, and the website is viewed as a crucial tool in achieving that goal.

Edge Hill are using the symfony framework as a kind of php glue to bind together tools such as wordpress mu for blogging and bbpress for forums. They also developed their own google-style portal with php and jquery.

So now it’s day 2, I’m sitting in a boring talk feeling a little hungover. Oh well, it’s going to be a long day…

symfony 1.1 and 1.2

symfony 1.1 went live just a month or so ago, and in the relatively short history of symfony is somewhat of a revolution. In fact, the shift in a minor version number belies the effort and heartache that seems to have gone into the newer version, and one wonders at the implied major revamp that symfony 2.0 would someday involve. It saw the departure of a key member of the core team, as well as some major changes to the architecture of the framework as outlined in the diagram below.

symfony 1.1 architecture

 

The great thing about the platform is that being decoupled the classes can be used in isolation, so you can use some features of symfony and not have to use the whole system. In other words, you can build your own custom framework which uses just the bits of symfony that you want.

All this is great stuff, and should help symfony establish a place as the leading PHP MVC framework.

symfony 1.2 is released

But no sooner had 1.1 gone live than we heard that 1.2 is not just in development, but is actually imminent. The current release date is October, which is not very far off. According to the symfony blog, the main (and absolute must-have) feature of 1.2 is a completely revised admin generator system. Other features include bundling Doctrine with the framework and supporting it fully in the same way that Propel currently is. I’m sure a lot of people like using Doctrine, but for me Propel is just fine, and the differences in performance (at least where Propel 1.3 is concerned) are moot (see this blog for a good comparison

Worth upgrading to 1.1?

So should I wait for 1.2? I have a couple of live apps running under 1.0. They work just fine as they are, and I see no reason to update those to 1.1 just yet, only to go through the same process again in October. I think I’ll start using 1.1 in a dev environment for getting used to the new architecture, new command line system, etc. Upgrading to Propel 1.3 is also going to be a good idea for the performance gains.

I’m left wondering when symfony 1.3 will be out. Christmas?! Actually, my guess is that now that some of the major architectural changes have been made, things should start to settle down a little. Anyway, it’s great to see such activity in the symfony core development team: evidence that symfony is not just alive and well, but maturing very fast.

symfony’s sfGuard plugin and LDAP

A while ago I needed to hook up symfony’s excellent sfGuard plugin to some LDAP functionality. There are a couple of issues with the plugin and the readme which I think need fixing. In particular, there is no support for checking both LDAP and standard sfGuard passwords. This is absolutely essential (eg an admin user or guest users who aren’t in LDAP), and I’m somewhat amazed that there’s no provision for this. Moreover, the plugin structure generally makes it seemingly impossible (or if it is possible it’s just too horrible to contemplate) to write your own checkPassword() which does do both sorts of checking.

Anyway this post is partly an attempt for me to get my head round something which I’ve either totally misunderstood, or just isn’t well documented.

 

Confusing README

The README file that comes with the plugin is great, but it’s a little confusing for explaining how you might override its own way of checking passwords with something that’s LDAP-based. It’s really very simple to do when written out in plain English:

1. Make a file called myLDAP.class.php in your application’s lib folder. Put this in it:

class myLDAP extends sfGuardSecurityUser
{
}

2. Now put a method inside the class you just created:
public static function checkLDAPPassword($username, $password)
{
// put your preferred LDAP-checking code in here
// should return true or false
}

3. Add this to your application’s app.yml file:

all:
  sf_guard_plugin:
    check_password_callable: [myLDAP, checkLDAPPassword]

where myLDAP is the file called myLDAP.class.php that you created in step 1 above. checkLDAPPassword is the method you made inside myLDAP.class.php that you made in step 2.

And there you have it. Basic LDAP password checking.

 

How does checkPassword() actually work?

The above code is all very well, but what’s really going on?

Well, there are a couple of steps which I managed to work out:

1. sfGuardUserValidator contains a call to $user->checkPassword($password) where $user is a result of sfGuardUserPeer::retrieveByUsername($username)

2. PluginsfGuardUser (extends BasesfGuardUser) has a method called checkPassword() too. This calls the method you listed in your app.yml file (checkLDAPPassword in this case), or does a standard sfGuard password check (checkPasswordByGuard) if you didn’t specify anything:

public function checkPassword($password)
{
if ($callable = sfConfig::get('app_sf_guard_plugin_check_password_callable'))
{
return call_user_func_array($callable, array($this->getUsername(), $password));
}
else
{
return $this->checkPasswordByGuard($password);
}
}

Which it does depends on how you set up your app.yml file (see Step 3 above).

At this point, if you set up your app.yml correctly you’ll be in your custom checkLDAPPassword() method, which will do whatever you want it to do to check LDAP passwords. So long as it returns true or false depending on whether the check was successful or not, you’ll be ok.

Note that sfGuardSecurityUser class also contains a checkPassword() method. This basically does the same thing as the in sfGuardUserValidator, but in a slightly different way, and allows access to checkPassword() in templates and controllers through the $sf_user object. The important thing to realise is that both pieces of code end up calling the same checkPassword() method in PluginsfGuardUser.

 

So how about LDAP and sfGuard checking?

Now the fun begins. The problem is that it’s seemingly impossible to call checkPasswordByGuard() yourself from inside your custom-built checkLDAPPassword() method. Why would you want to do this? Because that way you can do some standard password checking first to see if your user is in fact a sfGuard user and not an LDAP user. Only if that failed would you do LDAP checking (I suppose you could do it the other way round if you wanted.) Even better, you wouldn’t need to alter checkPasswordByGuard().

So why is it impossible to call checkPasswordByGuard() ‘by hand’? As far as I can see, it assumes that you’re not in a static context, and that you have some kind of user object available. But of course, my checkLDAPPassword() is in a static context. It had to be that way because it was called by call_user_func_array() which uses the output of sfConfig::get() as an argument.

Sigh…

If you find a way of doing this, please let me know. Losing the will to live is merely one of the symptoms of battling with this sort of thing. I have a life to live.

All I can suggest to you in the meantime is to modify your copy of PluginsfGuardUser.php to allow both sorts of password checking. That’s what I did and it worked for me. It’s just a pity that you can’t override the checkPasswordByGuard() method in some way without changing the core of the plugin.

mini symfony

I recently read this post by Francois Zaninotto (recently an ex-core symfony developer) about modifying symfony to make it lightweight enough for ajax calls. As he puts it:

That’s when the idea of a “small symfony” comes. Wouldn’t it be great if you could get access to the model layer, the configuration, the autoloading, the user object, the helpers, and keep a MVC separation, without initializing the whole framework?

As symfony stands, it’s sometimes just a tad too bloated for the kinds of really fast responses needed to make ajax applications work. Francois came up with this solution, which is to cut out the call to sfController::dispatch()

But you still get enough to make use of things like the basic MVC design, autoloading, and helpers. I still haven’t tried it myself, but it seems like a really nice idea. Just a shame he’s no longer in the core team…

Zaninotto

Looks like Francois Zaninotto, one of the core symfony developers, has quit the team. He was largely responsible for the documentation, and co-authored the excellent symfony book, published by Apress.

One of the key successes behind symfony was the documentation. The fact that there was human-readable documentation, and not just an API, was a remarkable thing for an open source project. It’s surely to the detriment of the project that he’s no longer a part of it.

Hopefully he’ll continue to play an active role in the community, and might even consider writing documentation independently of the core team. We’ll just have to see what direction symfony head off in over the next couple of years.

symfony admin generator

The symfony admin generator is one of the best features of the framework. With just a couple of commands and a few changes to a config file, you can have something pretty close to a database access interface. There’s a simple built in security module, and sfGuard is fairly simple to understand if you need a more complex security module.

At first it seems like the admin code is pretty much pre-baked, and there’s not much you can do to change the behaviour of the interface, save change the config files. But one of the most useful things to know about the symfony admin generator is that you can do extra things. It’s not well documented, but sticking this method:

protected function updateModuleNameFromRequest()

in your actions.class.php file allows you to add in extra code each time anything is done in that module (substitute ModuleName for your own module).

For example, if you need to clear the cache each time something is done, put it here. If you need to update a set of data in a one-to-many relationship with a class, put it here.

It seems curious that more is not made of this function in the book and documentation, because it’s so useful.

And don’t forget you can also use the standard executeAction() methods, preExecute(), postExecute(), etc. in your module’s action.class.php file, in exactly the way a frontend action would work. This means you can add in any kind of custom action to the admin section of your application.

symfony redirect vs forward

I’ve found the distinction between redirect() and forward() a little tricky to draw. It always seems to sound obvious until you need to use them. I found a nice article here http://firebird84vn.wordpress.com/category/symfony/. To quote:

The choice between a redirect or a forward is sometimes tricky. To choose the best solution, keep in mind that a forward is internal to the application and transparent to the user. As far as the user is concerned, the displayed URL is the same as the one requested. In contrast, a redirect is a message to the user’s browser, involving a new request from it and a change in the final resulting URL.

If the action is called from a submitted form with method="post", you should always do a redirect. The main advantage is that if the user refreshes the resulting page, the form will not be submitted again; in addition, the back button works as expected by displaying the form and not an alert asking the user if he wants to resubmit a POST request.

OK, so basically a submitted form should be redirected by the action (as opposed to doing a forward). In other situations where you’re calling part of your own application, just use a forward(). Maybe I’ve missed something, but this seems pretty straightforward (pun unintended) after all.