PHP’s function naming and argument order

Geplaatst in PHP, Webdevelopment Reeds 3 reacties

Just got back from PHPVikinger, a unconference, traveling around the world, organised by Derick Rethans. This year’s conference was held in Leuven, and since that is only a 30 minute drive from where I live I had to attend ofcourse.

For the summary of the event itself I’m happy to point you to Jeroen’s blog but I’d like to talk about something Stefan Koopmanschap brought up during Scott’s and Derick’s session on the PDM.

During the Q&A Stefan asked why the developers of PHP didn’t grab the opportunity to clean up the seemingly random and sometimes messed up functionnaming and argument ordering in some of PHP’s internal functions. Stefan by far isn’t the first one to bring this issue up, there are dozens of people reporting and asking this on the mailinglist and even filing bugs for it (with questionable degrees of success) but he did make a very valid point by stating that the release of PHP6 is the moment of choice to introduce these kind of changes in the core functionality of the language.

Function Naming

So what is this all about? Well really, as much as I love PHP, in several area’s it’s a mess. Especially in function naming.
Take the isset() function for example. Why is the is_null() function written with an underscore, these functions seem to me like they belong together since they both inspect a variable and return true or false if the state of the variable is as the function requested. Well then why is is_null written with an underscore and isset not? Doesn’t really make sense unless you want to confuse people.

Another example is the htmlentities() function, this function encodes some characters in a string with their entity value, the function that does the exact opposite is called html_entity_decode(). Again one is written with underscores, the other without. And again without an obvious reason.

Other examples are all the string functions, there are a dozen function that start with str_ and alot more of them that just start with str.

Argument order

Another issue is argument order. There are several functions that seem rather random in the way they order arguments. Especially function that required needle/haystack arguments.

String functions, like strstr() for example, accept $haystack as a first argument and $needle as a second while array function like array_search accept them in the reverse order. It just seems counter intuitive to me.

PHP 6

What disturbs me the most was the reply Scott and Derick gave Stefan at the conference, their reply simply was that it won’t be fixed because otherwise a lot of developers would be upset about the changes and lacking backwards compatibility.

Well they have a valid point there … if you’d consider fixing it in a minor version upgrade like from PHP 5.2 to 5.3. But if we are talking upgrading from PHP 5 to PHP 6 I’m absolutely sure the majority of PHP developers wouldn’t mind giving up backwards compatibility in exchange for fixing these issues. Over time the amount of functions in PHP really isn’t going to decrease so I’d prefer to have it fixed before it really runs out of control. But who am I?

I hope that with this blogpost I’ve inspired some people to think about this subject too and maybe undertake some action and write about it on their blog or twitter it since this isn’t something that is going to change unless us, PHP users, are asking for it and making the PHP core developers aware of these issues and that fixing them is important to us.


Dojo Dijits in Zend_Layout

Geplaatst in PHP, Webdevelopment, Zend Framework Reeds 8 reacties

A quick tip on using the Dojo implementation in Zend Framework.

Yesterday I was trying to put a borderContainer on my application. Following the code samples in the manual I had it set up pretty fast in my View, but since all pages should utilize this it seemed normal to me that I would integrate this in my Zend_Layout instead of each View separately.

Thus I moved all the code to my Zend_Layout and tada … no more Dojo, it just stopped working. The code below is the (simplified) code of my Zend_Layout at that time.

< ?php
$this->headTitle()->setSeparator(' :: ');
$this->headTitle()->append('Skyrocket Admin');

echo $this->doctype() ?>
<HTML xmlns="http://www.w3.org/1999/xhtml">
<head>
	< ?= $this->headTitle() ?>
	< ?= $this->headLink() ?>
	< ?= $this->headStyle() ?>
	< ?= $this->headScript() ?>
	< ? $this->dojo()->setLocalPath('/admin/scripts/dojo/dojo.js')
	                ->addStyleSheetModule('dijit.themes.tundra');?>
	< ?= $this->dojo() ?>
</head>
<body class="tundra">

< ?
// Load the Dojo helpers
$this->addHelperPath('Zend/Dojo/View/Helper/', 'Zend_Dojo_View_Helper');

// The page layout is a borderContainer, the views
// get rendered in the Center pane
$this->borderContainer()->captureStart('masterLayout',
                                       array('design' => 'headline'),
									   array('style' => 'width: 100%; height: 100%'));

	$this->contentPane()->captureStart('leftPane',
	                                   array('region' => 'left', 'splitter' => true),
									   array('style' => 'width: 200px'));
		?>
		<ul id="navigation" style="margin: 0">
			<li><a href="/admin/pages">Pages</a></li>
			<li><a href="/admin/auth/logout">Logout</a></li>
		</ul>
		< ?
	echo $this->contentPane()->captureEnd('leftPane');

	$this->contentPane()->captureStart('contentPane',
	                                   array('region' => 'center'));
		echo $this->layout()->content;

	echo $this->contentPane()->captureEnd('contentPane');

echo $this->borderContainer()->captureEnd('masterLayout');

?>
</body>
</html>

Back then it was almost 2AM so I didn’t feel like going after the solution. I dropped a post on Zfforums.com and went to sleep. Today on the other hand I felt like digging through the classes that are responsible for creating the dijits and it didn’t took too long to realize what was wrong.

The problem lies in the order of execution, the Zend_Dojo_View_Helper_Dojo class is responsible for outputting the javascript code that converts your basic html elements into Dijits. But in the code sample above I was outputting the dojo() helper before I was actually creating Dijits. Thus the HTML elements got created but the javascript code to convert them into Dijits is never outputted.

The solution is to simply move all your dijit creation code to the top of the page or to move the output of the dojo helper to the bottom. My advice is using the first option, simply because if you output it at the bottom you get to see the un dijitized html for a brief moment which is not nice.

Here is the working code for the borderContainer Layout in a Zend_Layout

< ?php
$this->addHelperPath('Zend/Dojo/View/Helper/', 'Zend_Dojo_View_Helper');
$this->dojo()->setLocalPath('/admin/scripts/dojo/dojo.js')
		     ->addStyleSheetModule('dijit.themes.tundra');

$this->borderContainer()->captureStart('masterLayout',
                                       array('design' => 'headline'),
									   array('style' => 'width: 100%; height: 100%'));

	$this->contentPane()->captureStart('leftPane',
									   array('region' => 'left', 'splitter' => true),
									   array('style' => 'width: 200px'));

		if (Zend_Auth::getInstance()->hasIdentity()):?>
		<ul id="navigation" style="margin: 0">
			<li><a href="/admin/pages">Pages</a></li>
			<li><a href="/admin/auth/logout">Logout</a></li>
		</ul>
		< ?
		endif;

	echo $this->contentPane()->captureEnd('leftPane');

	$this->contentPane()->captureStart('contentPane',
									   array('region' => 'center'),
									   array());

		echo $this->layout()->content;

	echo $this->contentPane()->captureEnd('contentPane');

$data = $this->borderContainer()->captureEnd('masterLayout');

$this->headLink()->appendStylesheet($this->autover('/admin/css/style.css'));

$this->headTitle()->setSeparator(' :: ');
$this->headTitle()->append('Skyrocket Admin');

echo $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	< ?= $this->headTitle() ?>
	< ?= $this->headLink() ?>
	< ?= $this->headStyle() ?>
	< ?= $this->headScript() ?>
	< ?= $this->dojo() ?>
</head>
<body class="tundra">

	< ?= $data ?>

</body>
</html>

I hope this helps at least some of you out, and if there are any questions or remarks i’d be glad to hear them!


Admin CMS routes in Zend Framework

Geplaatst in PHP, Webdevelopment, Zend Framework Reeds 10 reacties

For some time now I’ve been pondering on how to implement a CMS in the websites I build using Zend Framework, there are several options available around the internet. Here I’m going to explain how I solved this issue and why this is my preferred way of working.

No custom routing for me sir

One of the solutions I found involved creating a separate module for each part of your website that requires administration (eg: news, blog, products, …). Then you can easily access the admin for each module. For example to access the news admin you would point your browser to domain.com/news/admin.

At this point this solution has one drawback and that is the URL structure, while for some people this doesn’t really pose a problem, I always like to have the part that identifies the CMS as first part of my URL. domain.com/admin/news instead of domain.com/news/admin. You could however solve this by creating some routes, but I still didn’t feel happy about this solution.

While this might be a good solution when you are building a CMS with plug-and-play modules where all code is contained in one module, this solution wasn’t really what I was looking for. I would rather have all my CMS code close together, preferable in a separate environment from my front-end website.

Modules

The solution I found most suited and flexible to use was creating a separate module for both the front-end and the back-end. This allows you to separate your business code from the CMS from your front-end while still being able to use common models for data access and manipulation.

The automatically registered Zend_Controller_Router_Route_Module route takes care of routing the request to the appropriate module or to the default module if no module has been specified.

My directory layout looks something like this.

Admin module directory Layout

You are ofcourse free to use whatever layout works for you, the most important part is that you have at least a frontend and admin module.
You’ll also notice i’ve split up the public directory to separate the public assets for the admin and frontend modules, keeps everything nice and tidy.

Next up is configuring the Front Controller to use modules which is quite easy.

$frontController = Zend_Controller_Front::getInstance();
$frontController->addModuleDirectory(APP_PATH.'/modules');
$frontController->setDefaultModule('frontend');

In the code above we tell the Front Controller where to find the modules and which module to use when none has been specified in the request or when none is found. Pretty basic and it works!
Just put all your CMS specific controllers in the admin module, and all front-end controllers in the frontend module.

But wouldn’t it be nice if we could also separate our Zend_Layout’s, so we have a separate layout for our front-end and admin area’s and the files for these are contained in the respective module directories? This is where Controller plugins come in handy.

/**
 * Controller plugin that sets the correct paths to the Zend_Layout and
 * Zend_Controller_Plugin_errorHandler instances
 *
 * @package    Skyrocket_Plugin
 * @copyright  Copyright (c) 2005-2008 Skyrocket Concepts (http://www.skyrocket.be)
 */
class Skyrocket_Plugin_Adminsetup extends Zend_Controller_Plugin_Abstract
{
	public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
	{
		// Set the layout directory for the loaded module
		$layoutPath = APP_PATH . '/modules/' . $request->getModuleName() . '/layouts/scripts/';
		Zend_Layout::getMvcInstance()->setLayoutPath($layoutPath);

		// Configure the error plugin to use the loaded module
		// so we can use module-specific error handling
		$frontController = Zend_Controller_Front::getInstance();
		$errorPlugin     = $frontController->getPlugin('Zend_Controller_Plugin_ErrorHandler');
		$errorPlugin->setErrorHandlerModule($request->getModuleName());
	}

}

Create a class file like the one above and register the plugin instance with the Front Controller like this:

$frontController->registerPlugin(new Skyrocket_Plugin_Adminsetup());

The Adminsetup plugin intercepts the request before the Front Controller dispatches and modifies the Zend_Layout path to the current module’s Layout directory. It also registers a separate error handler for the admin module in case you want to handle your errors separately from your front-end errors.

What if I still want to use modules for my front-end?

I can hear some of you asking: But what if i’m building a huge website, with a huge amount of business logic? This is what modules really were made for but you are forcing me to use only one module for all my front-end controllers? Does this mean that I should stuff all the code for my forum in one gigantic controller in my frontend module?

No, not really, you still are free to use modules as you please. Feel free to create a forum module with a TopicController, ForumController, PostController and a CategoryController. These modules still work as expected and are accessible via domain.com/forum/topic

Conclusion

See, no funky routing configuration, no numerous admin controllers spead out over dozens of modules, all your admin controllers and layouts are nicely contained within one admin module and you are still able to separate all your code in individual modules or all into one frontend module. The choice is yours.

That’s it for now folks, any remarks, questions or do you think you are using a better method, feel free to comment.


PHP Professionals in Belgium

Geplaatst in PHP Reeds 2 reacties

It’s becoming more and more obvious that finding a skilled and professional PHP developer in Belgium is extremely hard. Either they all have jobs that they don’t wanna quit or there just aren’t any, but we at Inventis web architects are looking for a skilled PHP developer. Response has been minimal i’m afraid so if you live in Belgium and have serious PHP powers, drop Jan an email or check the job posting on our site.

And according to this thread on Kevin’s blog we aren’t the only ones looking for new team members.


The hell that is mod_rewrite infinity!

Geplaatst in PHP, Webdevelopment Nog geen reacties

Apache’s Mod_rewrite module has always been a difficult part of webdevelopment for me, wether it is because of it’s extensive use of regular expressions (which I finally master after several years of staring at regex tutorials) or the lack of response you get when something goes wrong. At work we use mod_rewrite on almost each project thus having a stable and solid base of rules to start from is a must.

Recently we decided it was time to implement something new with mod_rewrite i’ve been thinking about for a long time. Rewritten URLs with unlimited parameters by Ruben K. This allows me to rewrite a long and complex request URL into as many $_GET variables I need by using a simple PHP function. I’m not going to discuss the details here since thats something the tutorial by Ruben K. already does but let me tell you one thing … Ruben forgot something.

On a recent project I noticed that the debugger instance I was running in index.php got called several times while I only requested the page once. Strange no? The cause was quickly found … mod_rewrite! Finding the solutions took me weeks …

This rule is suggested by Rubens tutorial

RewriteRule ^(.*)\.html$ index.php?string=$1

The problem here is that ANYTHING gets rewritten to index.php … including broken images and other includes that should normally trigger a 404. Well “just fix your broken images” you’d say and yes you are right, but there are 2 problems with that. We can’t count on our client inserting only valid image links in our CMS. And second, firefox and other browsers have a habit of requesting favicon.ico several times during the loading of a page and guess what … if you don’t have a favicon it gets rewritten to index.php too!

I don’t need to tell you that this results in serious overload. I tried the modrewrite.com and sitepoint.com forums but nobody could give me a solid solutions until I found it myself. With a simple rewrite condition we are going to check if the url requested is a file that is not found and if so we rewrite to an error page. The final .htaccess looks like this, with the newly added rule in bold:

RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} -f [OR]
RewriteCond %{SCRIPT_FILENAME} -d
RewriteRule .* - [L]
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.+)\.[a-zA-Z0-9]{3,}$ /error.php [L]

RewriteRule ^(.*)$ /index.php?string=$1 [L]

This fixed alot of problems we previously had with several sites and never knew where to look … mod_rewrite was to blame.