Latest Articles

A short status update about Zend Framework 3

Tuesday, April 1, 2014 2 comments

As many of you surely know, the development of the next major version of Zend Framework pretty much came to a hold as the Zend team was and is still occupied with apigility. The maintenance of Zend Framework 2 is also coming along pretty slowly right now, although it's not completely stalled.

For those following the discussions in our development IRC channel more frequently, you probably saw that some of us are actually working on refactoring many components for Zend Framework 3, some a little more (like the completely rewritten Dash Router), and some with just minor BC breaks like the service manager, the event manager and everything around forms.

There was quite a bit of discussions on IRC, the mailing list and on GitHub about how we could speed up the development of ZF3, so we could get a release out in a proper time. We not only came to a final decision, but also developed a plan to reduce the number of future BC breaks permanently. So what does this look like? Well, this is actully a plan with multiple steps.

First we are going to define all component layers via interfaces within Zend Framework itself. We won't ship any concrete implementations with it, but only make our MVC layer consume and work with those interfaces. The next step is developing reference implementations as separate projects, although still maintained by Zend. This way we are still able to ship a complete application framework, while making it easier to completely swap out specific components. The reference implementations will hook into the system as normal modules, so that they can also supply application configuration on their own.

So what is the timeframe for all this you may ask? As I wrote earlier, we don't want to fall behind too much, so we planned to finalize all the interfaces until the end of this month. We then will write bridges to older ZF2 components where required, so that they can already be used in the new architecture. In cases where we already have new implementations in place, like the router, service mager and such, we will alter those to follow the defined interfaces.

Another plus side on this new approach is that we can directly target PHP 5.5 on components here it makes sense to use new features, while other components can still be PHP 5.4. For those components which make use of PHP 5.5 features, we will parallely maintain PHP 5.4 compliant versions, which will automatically be selected by composer if the user is running an older PHP version.

If everything goes as planned, we should have a beta release of Zend Framework 3 out by May 16th, and a release candidate around June 1st. Proposals for all interfaces will be posted throughout this month, so make sure to watch the mailing list and join the discussion and bring in your ideas!

About {@inheritDoc} and other useless documentation

Monday, October 28, 2013 3 comments

I've seen and followed many different documentation rules in my life. Everytime when I was taught something new for code documentation and it made any sense to me, I tend to addopt these pretty quickly. When looking back, some of the rules certainly made sense, especially when our poor IDEs weren't as good with resolving documentation as they are now. What I want to teach you with this article is, how to reduce redundant documentation and keep it as short as possible, without loosing any documentation from auto completion or API docs.

First, let's talk about the @return annotation. It became pretty popular in PHP to write "@return void" when the method will not return anything. Techncially though, it is actually returning "null". But writing "@return null" isn't actually helping much either. Since you are really not returning anything, it is perfectly fine to ommit the @return annotation completely. Any IDE or API-doc generator will interpret this as the classical "@return void".

So, let us start with a very simple interface to demonstrate all following usecases:
interface ToasterInterface
{
    /**
     * Toast a bread.
     *
     * This method will toast a bread for a given amount of seconds.
     *
     * @param Bread $bread
     * @param int   $time
     */
    public function toast(Bread $bread, $time);
}
When generating API-docs from this with phpDocumentor, it will look like this:
Toast a bread.

This method will toast a bread for a given amount of seconds.

    access: public

void toast (Bread $bread, int $time)

    Bread $bread
    int $time
There's nothing really special about this you haven't seen before. Now there are quite a few ways people take to document the method in an implementation. I won't list all here to keep the article short, so let's just get to the point. If your method doesn't do anything special over the already documented interface, just leave the doc-block out. Every API-doc generator will take everything from the parent, which is in this case the short description, long description and all annotations. Now let's say that you want to change something, e.g. you throw exceptions in your implementation. In that case, you'd only include the @throws annotation in your doc block:
class AwesomeToaster implements ToasterInterface
{
    /**
     * @throws RuntimeException
     */
    public function toast(Bread $bread, $time) {}
}
In case you want to override the short description, you can so so easily:
class AwesomeToaster implements ToasterInterface
{
    /**
     * Toast a white-bread.
     */
    public function toast(Bread $bread, $time) {}
}
Let's come to the {@inheritDoc} inline annotation. First I have to clearify that you cannot override the long description without having a short description first. The {@inheritDoc} annotation is there to include the parent's long description, so you can actually use that one and extending it with your own documentation. In your case, this could look like this:
class AwesomeToaster implements ToasterInterface
{
    /**
     * Toast a white-bread.
     *
     * {@inheritDoc} It only accepts white-bread thought.
     */
    public function toast(Bread $bread, $time) {}
}
There you go. We have the original description and on top of that our implementation-specific one. This would output like this:
Toast a white-bread.

This method will toast a bread for a given amount of seconds.
It only accepts white-bread thought.

    access: public

void toast (Bread $bread, int $time)

    Bread $bread
    int $time
A last thing about overriding @param keywords. This is possible, but will make no sense most of the time, since a parent pretty much describes what the method should be able to take. In some cases you may want to widen the allowed range of values though. If that's the case, you only have to put the @param annotation for that single argument in your doc-block, and not repeat any of the other annotations.

I hope that this helps a few people to reduce the insaneness of way too much redundant and copy-pasted inline documentation and gives you a bit more time to actually produce awesome code.

Update
I changed the Toast to Bread, based on Geeh's comment.

Zend Framework 2 Routing and Reverse Proxies

Friday, October 11, 2013 1 comment

I came about a pretty interesting routing scenario in #zftalk.dev which was not quite easy to solve, so I thought about writing a blog post about that. A user was using an HTTP reverse proxy with the following configuration:
ProxyPass /application/ http://www.example.com/
ProxyPassReverse /application/ http://www.example.com/
As it turned out, reverse proxies will not pass any path information via headers, so this is not detectable at all. What's even worse is, that the matching works as expected, but the assembling will not have the path from the proxy included. This means that assembled URLs cannot be matched. Setting the base path to /myapplication/newpath/ doesn't work either, as matching will fail in that case then. The solution to the problem is a little bit dirty, but it should work in 99% of all cases. What you must basically do is allowing the router to do the matching with the detected base path, and afterwards set it to the proxy's path, so assembled URLs look correct. The problem with this approach is, that this only works with a single reverse proxy. As soon as you have more (for whatever reason), this will not work anymore. This is, as I wrote, because the reverse proxy does not pass any path information to the target server.

So after coming up with this idea, Peter Hough, who asked the question, worked out the code for this and supplied me the code for demonstration. The entire code is compressed into a single re-usable module, so everyone who needs it can just use it:
class Module
{
    /**
     * @param \Zend\Mvc\MvcEvent $e
     */
    public function onBootstrap(MvcEvent $e) {
        $eventManager = $e->getApplication()->getEventManager();

        // Trigger after matched route & before authorization modules.
        $eventManager->attach(
            MvcEvent::EVENT_ROUTE,
            array($this, 'setBaseUrl'),
            -100
        );

        // Trigger before 404s are rendered.
        $eventManager->attach(
            MvcEvent::EVENT_RENDER,
            array($this, 'setBaseUrl'),
            -1000
        );
    }

    /**
     * Triggered after route matching to set the base URL for assembling with ProxyPass.
     * 
     * @param \Zend\Mvc\MvcEvent $e
     */
    public function setBaseUrl(MvcEvent $e) {
        $request = $e->getRequest();
        $baseUrl = $request->getServer('APPLICATION_BASEURL');

        if (!empty($baseUrl) && $request->getServer('HTTP_X_FORWARDED_FOR', false)) {
            $router = $e->getApplication()->getServiceManager()->get('Router');
            $router->setBaseUrl($baseUrl);
            $request->setBaseUrl($baseUrl);
        }
    }
}
To enable the replacement, you have to set an environment variable named APPLICATION_BASEURL. If that one is not set or it is not a proxy request (accessing the application directly), nothing will happen. Setting the base URL is pretty simple.

Apache:
SetEnv APPLICATION_BASEURL "/application/"
nginx:
fastcgi_param APPLICATION_BASEURL /application/;
Again, thanks to Peter Hough providing the code.

QR-Code generation in PHP, now with bacon flavor

Monday, April 1, 2013 0 comments

First of, this is not an April Fool's joke. I actually planed to make one this year, but eventually gave up. Anyway, as some of you who follow me on Twitter may know, I worked on a modern QR-Code library, known as BaconQrCode, the past few weeks. Eventually it is now fully working and the public API can be considered stable.

As a base for my implementation I had choosen the ZXing library library. After writing the first unit tests though I noted that their implementation of the Reed-Solomon codec performed rather bad in PHP, so I exchanged it with the much faster implementation by Phil Karn. As the rest of the library performed quite well and seemed much more logical, I choosed to stay with it instead of a different implementation like qrencode, which formed the base for PHP QR Code.

So far my complete implementation works, at least according to the unit tests and some personal testing. I'd like to encourage you to try it out and give me your feedback. I have implemented three different renderers so far, namely Bitmap (PNG), SVG and EPS. There is still a little bit of work to be done for me, like finishing the code-documentation, adding a few more unit tests and doing a few more PHP-specific optimizations, but all that work won't influence the public API anymore.

So, what are you waiting for? As always, you can find the library in the Bacon repository on GitHub or include it in your application via Packagist. If you are interested in more cool stuff, check out the website of of Bacon.

Oh and before I forget it. I may also add QR-Code decoding in the future. This would really be a feature you won't find in any other QR-Code library for PHP ;)

Sequel of the Internet Explorer hell

Saturday, December 15, 2012 1 comment

Many of you may remember the "good old days", when Windows XP came out which would let Joe Average be stuck with Internet Explorer 6 for a while, while finally giving him IE7, on which he'd be stuck for all eternity though, unless he'd upgrade to another browser like Firefox or Chrome. Surely, Joe Average may not know about these or be happy with this browser, which was very bad for us web developers. Eventually, the IE6 and IE7 were falling, and (depending on your business) we were able to drop support for those legacy browsers.

Everything seemed to be fine for the moment, until the prefix hell begun. But so far we were able to survive it, until recently browser vendors started to drop vendor prefixes on many key features (even IE9 came with a few unprefixed CSS3 features). Microsoft is also doing well with IE10, by implementing all those new CSS3 features without prefixes at all, following a recommendation from the CSS working group.

So, this basically sounds very exciting, but since we don't live in a perfect world, there's always some bad player; In this case it's Webkit. So far, less of the mostly used CSS3 features are available unprefixed in current, near future or farther future versions of Webkit, like background gradients, transitions and so on. But okay, we can live with this for now, it's just a single additional prefix, right?

Wrong! Do you remember the first paragraph, were I was talking about people with old operation systems and stock browsers? Well, the same thing is now repeating in the mobile world. For instance, the majority of Android users is stuck on Gingerbread (Android 2.3), which comes with a (relatively) very outdated stock browser, which even requires you to use an even older prefix with a different syntax for gradients. This forces us again to use a third version, which works completely different from the official and the newer webkit implementation.

Again, people could upgrade to a different browser (Firefox, Opera, …), but most simply don't care, because the browser works for them. What's the solution you may ask? Well, in my opinion, Google should handle the browser as any other app in the system and upgrade the Webkit base as often as they upgrade their desktop browser. Those are just my two cents, and I know that this action wouldn't change anything about the status quo, but could avoid the same problem in the future.