Twitter bootstrap + Zend_Form = ♥

Sunday, October 2. 2011
Comments

I dig Twitter's bootstrap library because as a developer, it helps me produce good looking forms without a lot of effort. Especially when administration interfaces are concerned, you I can only go so far — my first constraint is not being a great designer (to confirm, check out this blog) and two: I don't like working with ugly interfaces.

To cut to the chase...

Easybib_Form_Decorator

It's a decorator library for Zend_Form. Among the Twitter Bootstrap style, it also supports simple <div> and <table> styles — all courtesy of the awesome Michael Scholl. The code is MIT licensed: it should suit your budget just fine. ;-)

Installation

(Side-note: We got a PEAR channel.)

$ pear channel-discover easybib.github.com/pear
$ pear install easybib/Easybib_Form_Decorator-alpha

Usage

See the docs folder on github.

Fin

Questions, comments and feedback are always appreciated — pull requests are most welcome.

A roundhouse kick, or the state of PHP

Tuesday, April 12. 2011
Comments

Last week the usual round of PEAR-bashing on Twitter took place, then this morning Marco Tabini asked if PHP (core) was running out of scratches to itch. He also suggests he got this idea from Cal Evan's blog post about Drupal forking PHP.

  • http://blog.tabini.ca/2011/04/is-php-running-out-of-itches-to-scratch/
  • http://blog.calevans.com/2011/04/07/four-reasons-why-drupal-should-fork-php/

[Not submitting to your linkbait.]

Pecl and PHP

So first off — moving libraries from the core to an external repository was done for various reasons. One of them is to not have to maintain more and more in the core — keep it small and lean. Though small is pretty relative in this respect.

Of course doing so, means that people who do not have root on a server cannot install the module in most cases. But I'm inclined to suggest that when a pecl extension is (really) required, there should be nothing holding you back.

And if there is no way, thanks to PHP's extentability there's almost always a PHP-equivalent to any c-extension available.

Drupal and PHP

I know a couple Drupal people myself and most of them consider themselves to be Drupal developers before PHP. Why is that? It's because Drupal found a great way to abstract whatever people annoys about PHP from its developers, thus enabling them to build websites.

Is this a good or bad thing?

Of course it's a good thing because it makes people productive.

It's also a bad thing, because it seems that some (Drupal) people are rather disconnected from upstream [PHP].

Enabling people

Whatever people think about Drupal or any other framework, keep in mind that apparently it's PHP (and not Ruby, Python or pure C) which is more than a good enough enabler because PHP allows people to build a sophisticated content-management-framework like Drupal on top of it.

Drupal is of course no exception here. Despite e.g. the standstill in Ruby-land, in PHP other tools developer over the years who are a defacto standard: take a look at Wordpress or phpBB.

If you'd like to take it down to the framework-level there are projects like Symfony, CodeIgniter, Zend Framework, ezComponents/Zeta and also PEAR.

Fork vs. wat?

I think that forking PHP is a joke and I believe that Cal doesn't know the difference between a fork and a custom package (or a distribution).

A fork usually adds or removes features from the actual code base, but reading Cal's blog post he suggests a custom package. [Woo! Technical details! They get lost along the way!]

The thing is that a lot of people do this already. The people maintain a PHP package for a certain Linux or Unix distribution — Debian/Ubuntu, Gentoo or FreeBSD — there are doing it already. Using these as an example, whatever OS is used, it already runs a customized version PHP; some distributions customize more than others.

No one objects to the Drupal community suggesting ./configure flags or maintaining packages for the various flavours of Linux and Unix, or even Windows.

I would even go as far and say that in order to optimize the stack completely, it wouldn't hurt Drupal if its community recommended flags and extensions for people who run Drupal sites.

I doubt though that anyone will maintain packages for a couple distributions in their spare time and that the majority will not benefit from this effort because they don't run Drupal on their own server. But generally this optimization is enterprisey enough and indeed what I call a business opportunity.

Moving Drupal to ...

So what's "..."? Moving it to Python or Ruby, or maybe Scala? Good luck with that.

While the majority of Drupal developers don't consider themselves to be PHP developers, they still live and benefit off the PHP ecosystem. Think libraries used in modules or used for other areas like testing. Good luck porting those.

Then add PHP's vast adoption among webhosts.

Last but not least

Which brings me to the in my opinion biggest selling point: Doing PHP has another slight advantage over Ruby, Python and the other languages — it's installed on over 90% of the shared webhosts out there.

I invite everyone to google php hosting. It's trivial to find a host for as low as a Dollar per month — you just can't beat that.

Dear Cal, if you call this a business opportunity, I wonder why there's no Dollar Ruby hosting yet. Or Java hosting for a Dollar. But maybe someone is just not seeing this great business opportunity? [Note, Sarcasm.]

PEAR and PHP

What really bothers me about flaming PEAR is that the most vocal people in these flamewars never contributed any code. Open source is different from the Monday morning meetings some people are used to and where they talk people against the wall.

In open source land actual code contributions take the lead.

And while a lot of people complain about PEAR in general, here's something else:

  • thriving download stats of packages
  • PEAR package usage in other projects
  • adoption of the PEAR coding standards and conventions
  • PEAR channels thriving
  • overall installer adoption

Despite being called a mess, PEAR is an enabler for many.

Point taken

PEAR being so many things is confusing!

PEAR packages are not as easy to use as some code you copy-pasted off the Zend devzone or phpclasses. While I agree, that we should try to make it just as easy, it's just not one PEAR's goals right now.

Scratching my own itch

Scratching your own itch, is what code contributions to PEAR are currently all about. Maybe always have been.

Active package maintainers most often contribute to packages they use themselves and they contribute to PEAR's environment to move development forward in areas where its beneficial to them. Call that selfish, but the reality is that most of us contributors actually work in this web industry and we know what we want and therefor we do it.

At the same time PEAR has coding standards and convention which are in place to ensure code is written so its to the benefit of most people.

Maintainership burden

The offiside to this situation is of course that components none of the maintainers have a use for get neglected — but calling this a PEAR-only problem really one-side.

Not even company-driven frameworks like the Zend Framework are prone to this; Zend_GData is/was rather unmaintained for a long time. Or frameworks where the proposal process and architecture are valued above all; I could point how broken ezcFeed is for me. Or general issues I see in projects where decisions are primarily driven by a single person — catch my drift?

This is not meant a pissing contest between frameworks, but I just can't hear it anymore.

Developer-friendly

Is PHP generally developer-friendly?

At the expense of watering the term developer, I'd say yes.

It is extremely easy to get started — embed the following into a .php file:

<?php
echo "Hello World";
?>

There's your PHP. It doesn't require a custom webserver process, root server or anything else. It really doesn't get any easier.

Are PHP frameworks easier than frameworks in [your other favorite language]?

Probably not! Or, hell no!

But that's the barrier of entry to any if not all frameworks on the planet. Some frameworks allow you to write your own blog in 10 steps, but you will soon discover that writing your own blog is not a great indicator for a quality framework.

Indiciators are:

  • maintained code
  • coding standards
  • tests

And if I'm allowed a snarky remark — these are areas Drupal is literally just getting around to.

PHP vs PHP

Destruction breeds creation — but I get the impression that all these fights inside the PHP community don't really make it foster more.

Fighting and trolling may be an art for some and I agree they are entertaining at times, but when it becomes the only way people communicate contribute then let me be clear: it doesn't help.

The PHP community seems to be unaware how thriving PHP is and also its ecosystem. People often mistake stabilization for decline. There's nothing wrong if we don't crank out five new major versions every year.

  • People in the real world are conservative anyway and adoption is slow. [Not a PHP-only problem either, just ask the Ruby folks.]
  • People in the real world don't mind a more stable PHP environment, at the expense of buzzwords and all that crap.

Fin

In hindsight everyone always knew.

I feel like the more vocal people sharing their opinion, are pretty disconnected from the reality. That is dispite them running a magazine or a podcast about the community.

When people resort to flaming others in order to make themselves look smarter or their own project better, then that's just poor judgement on their part. Projects often die off as fast as they came about.

Contributing to PEAR: Taking over packages

Friday, February 18. 2011
Comments

One of the more frequent questions I see on the mailing lists and IRC is, "How do I take over a package?".

Very often people start to use a PEAR package and then at some point encounter either a bug or they miss a certain feature. The package's state however is inactive or flat unmaintained.

Offer help

The first step is to offer your help. And the easiest way to help is to report bugs or open feature requests.

A great bug report or feature request includes:

  1. Accurate problem description.
  2. A proposed solution.
  3. A patch (unified diff, aka diff -up or svn diff)
  4. A PHPUnit test case so this bug stays fixed.

I realize that these are a lot of requirements, but I also said a great bug report and no one said it was easy.

Getting fixes in

Often people persued these first steps and went the whole nine yards. But the bugs are still not fixed, the feature isn't implemented either and no release was pushed out.

How do you move forward now?

  1. Email the maintainer and cc [email protected].
  2. Ping PEAR QA again after reasonable period of time passed (e.g. 1 or 2 weeks tops)

If the package is generally unmaintained or the maintainer did not respond, PEAR QA will be happy to apply patches for you and do a new release. If the maintainer replied, work with them to get the issues fixed and a new release shipped.

Do you want to maintain?

To become the maintainer of any package we need to see your contributions first.

Contributions include:

  • patches for bugs and features
  • tests
  • bug reports
  • (maybe) helping people on the IRC channel

The fastest way to take over an orphaned package is to provide patches to any open issues so the QA team can push out a new release.

Contributing code is not just the preferred way but a hard requirement. It's the only viable way for others to assess your skills.

Another way to maintainership is of course when the current maintainer asked you if you want to contribute more since you showed them an interest through your work.

Find a package

Here's a list of currently unmaintained PEAR packages: http://pear.php.net/qa/packages_orphan.php.

Fin

I hope I summarized the process a little to make it more transparent. In the end it's pretty simple and straight forward to contribute to PEAR — and lots of people will be tankful for your contributions too.

PHP SDK for Amazon Web Services

Wednesday, September 29. 2010
Comments

Yesterday, Jeff Barr announced Amazon's own PHP SDK for their web services — own, because AWS hired CloudFusion's lead developer earlier this year (in March) and I guess after a while they decided it was time to incorporate his open source efforts into the company. The full story is on getcloudfusion.com.

So what?

What's more than just pretty interesting about all of this, is that not only is the AWS PHP SDK hosted on Github (bonus points for sure), but since it implements almost the entire API of all infrastructural services and is backed by the API provider, this library currently presents the most feasible way for PHP developers to work with AWS. And to add to that, the library is fully documented as well.

Having worked myself on various small wrappers for the EC2 and SNS web services, I'm really somewhat glad that I can stop working on them now and continue implementing the web services.

PEAR

Amazon's move is also another victory for PEAR (and of course Pirum) because it brings more acceptance to the distribution of PHP libraries using a PEAR Channel.

The SDK's channel is the following: http://pear.amazonwebservices.com/

Setup

pear channel-discover pear.amazonwebservices.com
pear install aws/sdk

The flipside

There are absolutely no unit tests included anywhere. But since I'm assuming that they exist indeed, I hope they will be open sourced before not too long. Or in case they don't (What's up with that?), that pull requests will be accepted so the community will be able to contribute some.

Debugging Zend_Test

Monday, September 20. 2010
Comments

Sometimes, I have to debug unit tests and usually this is a situation I'm trying to avoid.

If I have to spend too much time debugging a test it's usually a bad test. Which usually means that it's too complex. However, with Zend_Test_PHPUnit_ControllerTestCase, it's often not the actual test, but the framework. This is not just tedious for myself, it's also not the most supportive fact when I ask my developers to write tests.

An example

The unit test fails with something like:

Failed asserting last module used <"error"> was "default".

Translated, this means the following:

  • The obvious: an error occurred.
  • The error was caught by our ErrorController.
  • Things I need to find out:
    • What error actually occurred?
    • Why did it occur?
    • Where did the error occur?

The last three questions are especially tricky and drive me nuts on a regular basis because a unit test should never withhold these things from you. After all, we use these tests to catch bugs to begin with. Why make it harder for the developer fix them?

In my example an error occurred, but debugging Zend_Test also kicks in when things supposedly go according to plan. Follow me to the real life example.

Real life example

I have an Api_IndexController where requests to my API are validated in its preDispatch().

Whenever a request is not validated, I will issue "HTTP/1.1 401 Unauthorized". For the sake of this example, this is exactly what happens.

class ApiController extends Zend_Controller_Action
{
    protected $authorized = false;

    public function preDispatch()
    {
        // authorize the request
        // ...
    }
    public function profileAction()
    {
        if ($this->authorized === false) {
            $this->getResponse()->setRawHeader('HTTP/1.1 401 Unauthorized');
        }
        // ...
    }
}

Here's the relevant test case:

class Api_IndexControllerTest ...

    public function testUnAuthorizedHeader()
    {
        $this->dispatch('/api/profile'); // unauthorized
        $this->assertResponseCode(401);
    }
}

The result:

1) Api_IndexControllerTest::testUnAuthorizedHeader
Failed asserting response code "401"

/project/library/Zend/Test/PHPUnit/Constraint/ResponseHeader.php:230
/project/library/Zend/Test/PHPUnit/ControllerTestCase.php:773
/project/tests/controllers/api/IndexControllerTest.php:58

Not very useful, eh?

Debugging

Before you step through your application with print, echo and an occasional var_dump, here's a much better way of see what went wrong.

I'm using a custom Listener for PHPUnit, which works sort of like an observer. This allows me to see where I made a mistake without hacking around in Zend_Test.

Here is how it works

Discover my PEAR channel:

sudo pear channel-discover till.pearfarm.org

Install:

till@till-laptop:~/ sudo pear install till.pearfarm.org/Lagged_Test_PHPUnit_ControllerTestCase_Listener-alpha
downloading Lagged_Test_PHPUnit_ControllerTestCase_Listener-0.1.0.tgz ...
Starting to download Lagged_Test_PHPUnit_ControllerTestCase_Listener-0.1.0.tgz (2,493 bytes)
....done: 2,493 bytes
install ok: channel://till.pearfarm.org/Lagged_Test_PHPUnit_ControllerTestCase_Listener-0.1.0

If you happen to not like PEAR (What's wrong with you? ;-)), the code is also on github.

Usage

This is my phpunit.xml:

<?xml version="1.0" encoding="utf-8"?>
<phpunit bootstrap="./TestInit.php" colors="true" syntaxCheck="true">
    <testsuites>
    ...
    </testsuites>
    <listeners>
        <listener class="Lagged_Test_PHPUnit_ControllerTestCase_Listener" file="Lagged/Test/PHPUnit/ControllerTestCase/Listener.php" />
    </listeners>
</phpunit>

Output

Whenever I run my test suite and a test fails, it will add something like this to the output of PHPUnit:

PHPUnit 3.4.15 by Sebastian Bergmann.

..Test 'testUnAuthorizedHeader' failed.
RESPONSE

Status Code: 200

Headers:

     Cache-Control - public, max-age=120 (replace: 1)
     Content-Type - application/json (replace: 1)
     X-Ohai - WADDAP (replace: false)

Body:

{"status":"error","msg":"Not authorized"}

F..

Time: 5 seconds, Memory: 20.50Mb

There was 1 failure:

1) Api_IndexControllerTest::testUnAuthorizedHeader
Failed asserting response code "401"

/project/library/Zend/Test/PHPUnit/Constraint/ResponseHeader.php:230
/project/library/Zend/Test/PHPUnit/ControllerTestCase.php:773
/project/tests/controllers/api/IndexControllerTest.php:58

FAILURES!
Tests: 5, Assertions: 12, Failures: 1.

Analyze

Analyzing the output, I realize that my status code was never set. Even though I used a setRawHeader() call to set it. Turns out setRawHeader() is not parsed so the status code in Zend_Controller_Response_Abstract is not updated.

IMHO this is also a bug and a limitation of the framework or Zend_Test.

The quickfix is to do the following in my action:

$this->getResponse()->setHttpResponseCode(401);

Fin

That's all. Quick, but not so dirty. If you noticed, I got away without hacking Zend_Test or PHPUnit.

The listener pattern provides us with very powerful methods to hook into our test suite. If you see the source code it also contains methods for skipped tests, errors, test suite start and end.