After working on the Swedish weather site klart.se for awhile I now work on my own projects again. So I have switched Codeigniter to Zend Framework again.
After a trip to Dublin I finally launched the beginning of a new social tourist Dublin guide. It is exactly the same site as both the Swedish Fuengirola guide as well as the English Fuengirola guide I launched after living there for five months. The functionality is somewhat basic as of yet but every now and then I’ll add something more.
Basing three different sites, even though they are very similar, using two different languages gives me the possibility to try out several parts of Zend Framework. It also requires a good design both in the backend and frontend to keep it maintainable. I thought maybe some people would be interested in a basic overview of the different parts needed to put everything together.
Backend
The sites aren’t really that complicated. On a basic level there is a MySQL database and a database layer using Zend_Db/Zend_Db_Table, there is a Zend Framework MVC architecture using models, controllers, views, layouts with Zend_Layout as well as a few view helpers and some HTML, CSS as well as Javascript. All commonly needed. There is more needed to make it a sitethough.
I want as little configuration per site as possible but I naturally still use Zend_Config_Ini for settings. Zend_Registry is needed to keep the global scope clean and is used to store instantiated objects that need to be available throughtout the website logic.
I have been a bit particular on using ZF as often as possible on these sites. With few exceptions. Thus I also use Zend_Form, Zend_Locale, Zend_Translate, Zend_Cache and more. Zend_Cache is really a no brainer and mainly used to speed up translations. This is extremely easy as Zend_Translate and Zend_Locale both are connected to the cache with one simple method call each. It is not complete but how simple this is to setup is illustrated by the below code.
$configuration = new Zend_Config_Ini(
APPLICATION_PATH .'/config/app.ini',
APPLICATION_ENVIRONMENT
);
$frontendOptions = array(
'lifetime' => $config->cache->lifetime,
'automatic_serialization' => true
);
$backendOptions = array('cache_dir' => $config->cache->dir);
$cache = Zend_Cache::factory(
'Core',
'File',
$frontendOptions,
$backendOptions
);
$conf_locale = $configuration->locale;
$locale = new Zend_Locale($conf_locale);
$locale->setCache($cache);
Zend_Translate::setCache($cache);
$translate = new Zend_Translate(
'array',
APPLICATION_PATH .'/config/translation-' . $conf_locale . '.php',
$conf_locale
);
$translate->setLocale($conf_locale);
Zend_Form have had a few problems in many versions of ZF. In my opinion it is also a bit bloated and limiting to be used all the way. (Even though I like the automatic connection to the translation functionality in Zend_Translate and the validation through Zend_Validate) So I have settled for a simpler way where I use Zend_Form fully for validation (with Zend_Validate) and then give the view access to the form through a Zend_Form subclass to be able to print the fields individually. I think this is easier to handle than all the overloading and coding needed to fully make Zend_Form create forms as I want them. Another good thing with the form classes is that they too are locale aware and are translated automatically by connecting them to Zend_Translate through the simple line Zend_Form::setDefaultTranslator($translate);. The sub classed Form utility class looks like below. The generated elements are translated automatically. Very convenient.
class Custom_Form extends Zend_Form {
/**
* Render a field
* @param string $name The name of the form element
*/
public function _e($name) {
$e = $this->getElement($name);
return ($e) ? $e->render() : "<dt>Error</dt><dd>Missing <$name> field element</dd>";
}
}
Another thing needed for these sites are to keep the urls understandable and thus translated into the language used on the site. For this the routes, or paths, are kept in the translation file as well. The translated paths are then registered to the router through the use of Zend_Controller_Router_Route and Zend_Controller_Router_Route_Regex objects.
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$router->addRoute(
'route_review',
new Zend_Controller_Router_Route(
$translate->translate('route_review'),
array('controller' => 'review', 'action' => 'index')
)
);
For image manipulation I haven’t looked further than ImageMagick. After a bit of tweaking you get very good quality when producing different image sizes.
Search
Last but not least, on the backend that is, there’s the search engine. ZF have an implementation of Lucene through Zend_Search_Lucene (derived from the Apache Lucene project). This is the one time I haven’t gone with ZF as I very much like the open source Sphinx search engine as it is so easy to integrate with MySQL. So Sphinx get to power the search.
This is convenient for several reasons. MySQL is not a great full text search engine, Sphinx give you better weighted results. The main reason though is the performance. Sphinx is very fast in itself but for a site with heavier traffic it is as simple as moving the search backend to it’s own machine to get a performance increase.
Frontend
On the frontend there is as clean html as possible to make it easy to change the design with only CSS as well as manipulate the client side with JQuery. If it wouldn’t be for the Google map the site would actually be pretty useful even without no css style at all.
A good practice I learned just recently (remember I’m mostly a backend developer) is to base all javascript functionality on modules that are instantiated depending on element ids present in the html. This makes it a lot simpler to split the javascript functionality into manageble pieces and also makes it a lot easier to maintain.
There are functionality in the client side javascript used to display error messages and information. This makes it necessary to create one javascript file with translation stirngs for each language. The correct javascript translation file is chosen in the layout (template/view file) depending on the current locale.
The map used is (are there any alternatives) Google Maps API. I chose to completely initiate the map by scanning the actual data displayed on the page. This is possible through clean html markup and also means that if I choose to list ten reviews on a page instead of five nothing need to be changed at all in the frontend. Only a loop limit on the backend.
Conclusion
Well. No conclusion. This was just a very basic walkthrough of most of the different pieces needed to create a fairly simple Zend Framework based website. Mostly it was a walkthrough of the bootstrap… I still hope it is useful or at least interesting.
I know I find it interesting to read about other sites and the architecture and design behind them.
Tags: css, Javascript, jquery, PHP, Web, zend framework
This behaviour has bitten me before. Yesterday I was asked to resolve the issue again. And as my memory is short I was again forced to search the web for a solution. The solution is simple - but also stupid.
The problem is that Internet Explorer does not handle file dowloads without caching over https very well. Or at all. According to knowledge articles on Microsofts website the problem occurs when having one or two of the http headers:
Pragma: no-cache Cache-control: no-cache,max-age=0,must-revalidate
Previously I have have just omitted the http header “Pragma: nocache” for IE but it seems it does not always help.
So, whether you want it or not, the solution to the IE https download cache problem is to tell IE to cache the file.
if ((isset($_SERVER["HTTPS"]) && strtolower($_SERVER["HTTPS"] == "on")) &&
preg_match("/MSIE/", $_SERVER["HTTP_USER_AGENT"])) {
header('Pragma: cache');
} else {
header('Pragma: no-cache');
}
I have been working on some really fun PHP projects with some really cool people the last six months. This has kept me busy both day and night so, naturally, blogging have not been a major priority. After creating a new Spanish photo sharing site fotos.es which took a few months we started on a Swedish project. And now, we are finally launching the best Swedish weather site, klart.se. As weather is what Swedish people talk about whenever they meet, a quality Swedish weather site is needed
Even though all the project members are located in many different locations in both Sweden and Spain most things have gone really well.
After having been in Spain for the last six months it looks like it’s time to move on. In a few weeks we’re probably moving to Kalmar, Sweden. We haven’t lived in those parts since we moved to Dublin in 2000 and even though I really enjoyed my time here in Spain I am a looking forward to moving back home.
Tags: PHP
I hade some time over and updated one of my own projects to Zend Framework 1.8.1. Apart from a change in the auto loader API everything went smooth. But I was a bit annoyed to find out that a simple translation bug still was unfixed. As my project is going live soon I need that bit fixed.
The bug is known and open so I didn’t need to report it. I voted for the issue to be fixed, waited two minutes and still no fix… I thought that was how open source projects worked
Seriously though, I fixed the issue locally and added what I think should be a correct fix in the comments. (Even though I think it is weird that the transfer adapter should even have the remotest connection to translation logic.)
http://framework.zend.com/issues/browse/ZF-6647
Looking at the statistics for Zend Framework issues I think it is time to step back and slow down on implementing new features. The diff between new issues and resolved issues is constantly getting bigger and bigger while the average time to fix an issue is getting longer and longer. This is natural as the project constantly have grown since it’s birth. But as I like working with ZF I’d hate to see it become a big and unruly behemoth that adds more problems than solutions.
Tags: i18n, PHP, zend framework
Last night I spent a couple of hours with Zend Framework and especially Zend_Form. I discovered, and now also reported as ZF-6175, a bug in Zend_Validate_Float when using a locale with a decimal point other than “.”. There are unit tests but none that test Zend_Validate_Float under a different locale.
It is important to know that floats are actually locale aware in PHP. I’m not sure if that have always been the case. The below code will actually output 10,5 as Swedish use “,” as decimal point.
setlocale(LC_ALL, 'sv_SE.UTF-8'); echo 10.5;
The test in Zend_Validate_Float looked like
$locale = localeconv();
$valueFiltered = str_replace($locale['thousands_sep'], '', $valueString);
$valueFiltered = str_replace($locale['decimal_point'], '.', $valueFiltered);
if (strval(floatval($valueFiltered)) != $valueFiltered) {
$this->_error();
return false;
}
Under the Swedish locale mentioned above this will result in a comparison between two strings; “10,5″ and “10.5″.
I have proposed the following solution.
$locale = localeconv();
$valueFiltered = str_replace($locale['thousands_sep'], '', $valueString);
$valueFiltered = str_replace($locale['decimal_point'], '.', $valueFiltered);
list($num, $dec) = explode('.', $valueFiltered);
if (strval(intval($num)) != $num || strval(intval($dec)) != $dec) {
$this->_error();
return false;
}
But I just realized that it can be further simplified.
$locale = localeconv();
$valueFiltered = str_replace($locale['thousands_sep'], '', $valueString);
list($num, $dec) = explode($locale['decimal_point'], $valueFiltered);
if (strval(intval($num)) != $num || strval(intval($dec)) != $dec) {
$this->_error();
return false;
}
Tags: locale, validation, zend framework
There are probably as many solutions to creating SEO friendly urls as there are actual implementations. After real work yesterday I started looking at the rather simple method based on the PHP built in strtr() we use. It’s very simple and apart from some uppercase, lowercase and utf8 juggling the (very shortened) basis is something like below.
$isochars = "\xFC\xFD\xFF"; $asciichars = "uyy"; $urlfriendly = strtr($actual_string, $isochars, $asciichars);
What struck me was that the character þ (FE in hex) was translated into y. As is correct if you look at how y, in different forms, was used as an abbreviation for the, that and so on in old English - or Anglo-Saxon. Often it is now written “Ye” as in the blog post title. (Yes - the “Y” in the title should be pronounced as “th“.
However, it is a bit odd as the Icelandic language still use the letter frequently. The sound value is more or less the equivalent of the English “th” in this or the.
The major value in SEO friendly urls is the readability. Shouldn’t it be more friendly and natural to translate þ into “th” in SEO friendly urls then?
As mentioned earlier I moved with my family from Sweden to Spain for awhile. To complicate things further me and my girlfriend Malin created a new company called Dotvoid AB focusing on web sites and applications based on PHP. (So expect things to change around here in 2009 - though no timeplan or schedule exists). I have also quit working with debt collection software and is now working full time on Spanish consumer web sites for Grupo Inico.
Conferences? Apart from the usual PHP conferences that might or mightn’t (!?) be of interest there’s a score of other events focusing less on technology and more on softer issues. An hour ago I received an email from the Ning group Swedish Startups with lots of interesting conferences. I probably won’t be able to attend many of those. But Future of Web Apps in Dublin really caught my attention. A not too expensive one day event with lots of cool people and companies. Not to mention a good reason to visit the city I lived in almost eight years ago. (At the time I was working as a contractor on a then cool project.)
Tags: conference, Dublin, work
I have been away from blogging awhile. Life has been really busy lately and I have sold my house and moved, with my family, to Fuengirola in Spain. Hopefully now that daily life is again back to normal I’ll blog a bit more. Maybe I’ll talk a bit more about daemons, asynchronous I/O and CodeIgniter as my current contract includes those topics.
Tags: code igniter, fuengirola, PHP, spain
As it is nearing Christmas I started thinking about things I would like to see in the PHP world. I don’t have time to write down a long wishlist but a few things would make me a happier person.
- Faster Eclipse/PDT/Zend IDE
- Builtin, reliable, refactoring support in PDT
- A good (good === simple and extensive) tutorial on using Zend_Test for testing applications built on Zend Framework - cause I’m starting to feel stupid here.
Apart from those three PHP specific wishes I also wish for all the usual stuff; a new mobile (I’ll buy one myself soon), more spare time with my family and friends (I’ll get that soon as well), world peace (tough one unfortunately), new laptop (my currrent - almost new - Dell sucks) and more.
I will get more free time soon. I’m selling the house in southern Sweden and moving with my family to southern Spain where I will work as a contractor for major Spanish consumer sites. Fun PHP work ahead!
Yesterday we had the first OpenCoffee in Karlskrona at the new place Bistro Java. The initiative came from Martin and Christian at Svensk Webbutveckling. Really nice guys even though they seem to prefer strongly typed languages over PHP. We had a good chat about both business and web development in general as well as technology and languages.
Unfortunately we three were the only ones showing up so the event will be repeated next thursday. If you are interested in business, technology, internet and web development - and are nearby - drop in!
Tags: open coffee