Injecting Closures into your Classes

I wanted to reuse a class of mine, which generated a <ul> with links, only this time I wanted to alter the link text using a custom function (closure) in the constructor.

<?= $this->generateUl($existing_arg1, $existing_arg2, function($args){ //do stuff } ); ?>

Inside the class constructor, I set the following:

public function __construct($existing_arg1, $existing_arg2, Callable $closure = null)
{
    $this->closure = $closure;
}

And here’s the wee catch: You can’t call it like a normal method, $this->closure($args); You need to assign it to a standard variable for whatever reason.

    /** 
     *  @param ESOS_Entity_Org $org
     *  @return string
     */
    private Function generateLinkText(ESOS_Entity_Organisation $org)
    {
        if(!$this->closure)
        {
            // This is my default functionality
            return $org->getName();
        }
        // There are two ways of doing this next bit:
        // $this->closure($args); won't work but $closure($args) will!
        // $closure = $this->closure; 
        // return $closure($org);

                // Here's the better way:
                return call_user_func($this->closure,$org);
    }

Doing this has made me realise just how awesome Callables can be, you could inject in all manner of functionality into a class! Play around with it!

Upgrade your ZF1 classes to PSR-0 Autoload

As a Zend Framework 1 user I loved the simplicity of the class naming convention, being Folder_Subfolder_ClassName. However as you probably know, these class names get really quite long! The latest PHP as you already know uses namespaces and allows for shorter classnames that wont clash with each other. Now I have added an API to my website using the incredible Apigility (http://apigility.org) which was built in Zend Framework 2, I thought it would be nice to upgrade my existing classes to autoload PSR-0 style, so I can eventually migrate easily across.

First thing then, you need composer installed. If you’ve been following my blog, or using any other vendors packages, you’ll already have it in your project.

In ZF1, the library folder was where you would keep your different modules/packages/classes. I have a library called TTB. So in the TTB folder, create an src folder, and another TTB folder in there (this is a quirk of PSR-0, but trust me). In that folder, recreate your classes. Changes aren’t very difficult:

<?php
namespace TTB\Form;
use TTB\Form\Element;

class Contact extends \Zend_Form
{
    //etc
}

The line TTB_Form_Contact extends Zend_Form is shortened by way of the namespace line at the top to just become Contact, and the Zend_Form gets a backslash in front of it as it is in the global namespace. You also specify use  to import any other classes into the namespace. Now we can call Textbox instead of Element\Textbox or TTB\Form\Element\Textbox.

You probably know all this stuff anyway! The point is, to get it autoloading in your project!

So in your index file of your ZF1 project, require once vendor/autoload.php. And in your composer.json, add the following:

"autoload": {
     "psr-0": {
         "TTB" : "application/library/TTB/src/"
     }
 }

Finally, run composer dump-autoload in the terminal from your site root, and this will generate the classmap. You are now ready for PSR-0 compliance! Now you just need to spend all day refactoring! It’ll be worth it when you take your old project to a new framework!  😉

Setup a ZF1 DB Adapter in Zend Framework 2

If you checked my last post, you will have read about how to get all your old ZF1 classes autoloading in your new shiny ZF2 project. However, the DB settings from your application.ini won’t have been set, and so you’ll get a 500 response with  No Db Adapter. Not a problem. We just create the db adapter ourselves and tell Zend_Db that it is the default.

I’ve put this in the ZF2 index.php just before the last line, Zend\Mvc\Application::init($appConfig)->run();

//Set up ZF1 DB
$params = array(
 'host' => '127.0.0.1',
 'username' => 'xxx',
 'password' => 'xxx',
 'dbname' => 'xxx'
);
$adapter = Zend_Db::factory('Pdo_Mysql',$params);
Zend_Db_Table_Abstract::setDefaultAdapter($adapter);

Now your autoloading ZF1 DB classes wont freak out, and should connect no problem!

load ZF1 classes in Zend Framework 2 using composer

I’ve started using Apigility for building my API for my mobile app of my site! It’s incredible, you have to try it!

Anyway, I wanted to be able to load my existing code into ZF2 so I didn’t have to reinvent the wheel.

My API is running on a subdomain in an api sub folder within the main project. In the api folder, I made a folder called library. Then I symlinked my Zend and other folders from my ZF1 project into it (this may not have been necessary, but I didn’t want ../.. relative link type stuff in my composer.json)

:~/www/site/api/library$ ln -s ../../application/library/Zend Zend
:~/www/site/api/library$ ln -s ../../application/library/ZendX ZendX
:~/www/site/api/library$ ln -s ../../application/library/TTB TTB
:~/www/site/api/library$ ln -s ../../application/library/AA AA

Next you need to do is tell composer.json about your libraries.

 "autoload": {
 "psr-0": {
 "AA_": "library/",
 "Zend_": "library/",
 "ZendX_": "library/"
 }
 },
 "include-path": [
 "library"
 ]

Finally get composer generating autoload files. Type in:

~/www/site/api$ composer dump-autoload
Generating autoload files

And thats it! You should now be able to call things like:

$awesome = new Zend_Pdf();
$old_skool = new AA_Old_Skool_Class();

Yay!