Saturday, January 16, 2010

Zend Framework

I've been hearing a lot about Zend Framework over the past year or two, it seemed to have become the de facto standard framework (something else I've been hearing a lot about) and I felt a need to get up to speed on it.

I put up my review of my review of Easy PHP Websites with the Zend Framework. I bought the book a few months back, as it seemed the best of the choices at the time. Quick summary of the review: Okay book, not impressed by Zend Framework, last third of the book is useful and interesting.

I'll talk about not being impressed by the DB part of Zend below, but I feel the main other aspect that bothered me was the way data is given to and then used in views. In the controller I have to write:
$this->view->something=$mymodel->get_something();

Then in the view it is used as:
Our something is <?php echo $this->something;?> today!

All that $this-ing and view-ing makes the code verbose, hiding the real thing I'm trying to say with my code. In particular the view code is ugly - ZF has not helped at all compared to writing plain PHP.

Why do I care? Try getting a designer to edit a view that looks like that. They may be comfortable with HTML but will go pale and faint at the sight of a dollar sign let alone all the surrounding junk. I can tell you from experience they will refuse to even edit a file that contains text that looks like that, let alone type it themselves.

I was also not impressed with how Zend Form does input validation. It seems to be just as much work as doing it in plain PHP. If I add a dependency I want value for money!

Back to databases. I recently wrote about being impressed with Doctrine ORM. Zend DB didn't impress me at all; I already use Pear::DB to abstract away the database, and all Zend adds is having to use PHP instead of SQL to write common queries, while still having to use SQL to write the less common ones.

A web search found I wasn't alone in this opinion, but what was interesting was I found people using Doctrine within Zend Framework, as a replacement for Zend DB.

To quote an article by Ruben Vermeersch: "While Zend_Db isn't a bad technology, it is still quite low-level and close to the underlying database. Using Doctrine, you can manipulate your data like objects, without worrying about the database too much." The article is pro-Zend and pro-Doctrine, and shows how to use the two together. Good clear article.

Here is another example of using Zend and Doctrine together. It is just example code, not a teaching article, but interesting as it also uses ajax (using jquery).

Here is an article comparing Symfony (using Doctrine) with Zend, with a pro-Symfony slant. Also check out the comments, especially the reply by Matthew Weier O'Phinney describing what is coming up in Zend (including how it may have more formal integration with Doctrine at some point, and hopefully auto-admin pages and auto-forms-from-schema).

By the way, the afore-mentioned Ruben Vermeersch article suggests these articles to get up to speed on Zend:
http://framework.zend.com/docs/quickstart
http://akrabat.com/zend-framework-tutorial/

I'd like to stress again that my views of Zend Framework are currently only based on studying it; I'll get back to you once I've tried it out on a full-scale real-world project.

Thursday, January 14, 2010

ASP, Error-Handling and Microsoft's Latest Catchphrase

Microsoft's Latest Catchphrase: It may be crap, but at least it is ready installed crap!

What inspired today's rant? Using ASP, of course. The question I had was to how to handle SQL errors. (This article is more than just rant; I will also tell you how to do a couple of essential tasks that ASP makes hard.)

I've been using ASP for a few months, for one particular sub-project. We wanted to minimize the installed components, and as one sub-system already needed IIS, and the required scripting was fairly simple, we decided to go with that instead of installing WAMP (Windows Apache/MySQL/PHP).

I'm using ADODB COM object for the database connectivity to Microsoft SQL Server. I've used the same COM object from PHP before, and errors get thrown as exceptions. I wrap them in try/catch blocks and everything is good. A bit of searching discovered how it works in ASP/VBScript. First exceptions are thrown just the same. Second, there is no try/catch functionality.

Read those two key facts again, and have a good long think about them.

Some more searching discovered things are not quite that bad, and you can handle errors. The first thing you must do is precede your function with "on error resume next". That tells it to ignore errors. Then immediately after any action that might have had an error you do:

if err.Number <> 0 then
'Handle errors here
end if

See here and here.

By the way, to turn off "resume next" mode, you give the almost mystical "On Error Goto 0". And the other thing you need to know is that resume next mode only affects the current function; if you call another function and that function doesn't explicitly "on error resume next" then any error there will terminate the script. Which I suppose is better than the confusion resulting if the flag was global.

As my next piece of evidence let me show you how to do the equivalent of PHP's "s=file_get_contents(fname);" in ASP (due to the afore-mentioned difficulties in error-reporting it returns a blank string if the file does not exist):

Function file_get_contents(fname)
fname=Server.MapPath(fname)
mode=1 'Read-only
set FSO = server.createobject("Scripting.FileSystemObject")
if(FSO.FileExists(fname))then
set fp= FSO.OpenTextFile( fname, mode)
file_get_contents=fp.ReadAll
fp.Close
set fp= nothing
else
file_get_contents=""
end if
set FSO = nothing
End Function

Oh, what fun! But I try to be fair, and every language has its good and bad points, so I tried to think up all the good features of ASP. After all, I have actually been writing useful, working code in ASP. The bad points flashed into my mind at every turn, but in the end I did manage to find one good point...

It is already installed, if you are already using IIS.

Which brings us back to that catchphrase that Microsoft is hurriedly trade-marking in 120 countries worldwide: It may be crap, but at least it is ready installed crap!

(By the way, speaking of ready-installed crap, did you know IE6 still has 15-20% market share? And IE6+IE7+IE8 together have 67% share? It was news to me - I thought the browser wars were over and everyone used Firefox, or at least Safari!)

Tuesday, January 5, 2010

Portable PDF reader

More and more books, especially tech books, are only available as PDF. Another advantage is I can get the PDF delivered immediately rather than the "2-4 weeks" amazon.jp likes to tell me. But I don't like sitting at my computer to read - I want to be able to sit in an armchair, on the train, in a cafe, etc. to read (see also my moan about php Architect magazine going PDF only)

I've done some searching, and some asking, and I suspect the device I want does not yet exist, but I'm open to suggestions. I don't want the heavy bulk of a notebook. The Kindle (or similar) seem hard-wired for content being sold by Amazon (or whoever), which is no good at all (Update: PDF supported since version 2.3, and content can be uploaded over USB cable; see wikipedia article)

I'm very interested in how easy it is to read a PDF formatted for A4 on an iPhone (or iPod Touch), as that would have lots of other advantages (e.g. portable video player, as well as portable email and web browsing in the case of the iPhone).

UPDATE: list of e-book readers
Apparently the Consumer Electronics Show in Las Vegas this month will see some new e-book readers announced. So, sitting on my hands seems best at the moment.

UPDATE:
Video demo of AjiReader viewing a PDF on the iphone (apparently the app costs $1)

Another video demo showing PDF, DOC, XLS, PPT but the comments seem to be saying you need a jail-broken phone for this?

UPDATE: (8 months later!)
The new Kindle looks good. I decided to stop Waiting For The Next Big Thing, and went ahead and pre-ordered one. It does PDFs, it does Japanese, everyone I've spoken to says e-ink is great; but, above all, at $139 it is now affordable.

I also ordered the case with built-in light; it was 1/3rd of the total cost, so I dithered a lot about that. But while I think the case is over-priced it also looks very cool.

Some people said the 6" screen is still too small to read A4 PDFs in comfort. If I find it unusable for that (my key need) I'm hoping I might be able to resell it at only a small loss. After all, ordering from Japan is a pain.

I'll put up a review in about a month. Watch This Space :-)

Monday, January 4, 2010

Doctrine ORM

I mentioned before, when talking about my Step-By-Step Regex article in php|a magazine, that the same issue (August 2009) had some other interesting articles.

One is about Adminer, an alternative to phpMyAdmin which is designed to be very compact and exists in just one file (so it is easy to upload temporarily to a production server for instance); the article is mainly about how Adminer was written, which was interesting.

But the article - and library - I most want to talk about is Doctrine ORM. The main problem this library is solving is this: when you add a field to your database you have to make the change in at least two places, your PHP script and your database. That sucks. The article describes itself as a tour around Doctrine's more advanced features, but I found I didn't need any other introduction, and it sold the features in a very clear and logical way.

The first thing I liked was you can describe your database schema in any of three ways: SQL, PHP, or the compact YAML files, and utilities are provided to convert between all three. By SQL I mean an existing database, that you could have been creating interactively from phpMyAdmin, or it could be a legacy database that has been around for years and now needs to be connected to a php script.

What only the Yaml and PHP schema formats can specify are what Doctrine calls behaviours. By adding the Timestampable behaviour it will add created_at and updated_at fields to the database and keep them up to date for you. The Sluggable behaviour is for making URLs and is demonstrated in the php|a article, but others that caught my eye are SoftDelete (records just get the deleted_at field set when you delete, rather than physically being removed), and Versionable (each time a record is changed the previous record is saved, and can be reverted to). NestedSet helps build trees, I18n is for holding translations (see below), Searchable does indexing, Geographical can find nearby places.

Incidentally I covered I18n in a previous article and Doctrine is using type 1, but without the language table to store collation. There is no consideration of different collations, and no concept of default language. It is sufficient for most purposes though.

Looking at some behaviours not in the Doctrine core distribution, Taggable looks interesting, allowing you to add blog-style tags. Locatable apparently ties in with Google Maps to get latitude and longitude automatically given an address (it could then be used, for instance, with the Geographical behaviour to automatically find all people within 10km of you based on just their address). EventLoggable logs all actions (select, update, delete, etc.) to a disk file. Blameable records (in the table) who last made any change to a record.

Doctrine's behaviours feature is powerful, portable, the existing ones are customizable (all the above seem to have sensible defaults but also can have their behaviour fine-tuned) and new ones look easy to write.

The third big feature of Doctrine that I like is the way data is retrieved on demand, and how that ties in with table relations (see listing 6 in the php|a article). And if this becomes inefficient you can optimize without having to change much code (listing 7). I'm not a big fan of using PHP to write SQL queries. Generally to do anything interesting you end up dropping down to writing SQL anyway. But I was impressed with the example in the article, and you only need to start explicitly describing joins if you have profiled and found you need to optimize.

(By the way, it goes without saying that Doctrine ORM is database-neutral, not tying you into MySQL or any other database.)

The final cool Doctrine feature is migrations. When you make a change to the schema in either your YAML file or your PHP file you run a script and it will make a migration file. This can then be run to move a database between versions (backwards or forwards). I admit I currently do this with some hand-crafted SQL scripts, which are one way only, and painful. And sometimes I'm not even that organized.

I've not used Doctrine ORM for a real project, but I expect I will try it out very soon.