Viewing entries tagged
zf2

Distributing a ZF2 Module through GitHub, Packagist & Composer

I was in an interesting situation where I wanted to build a custom ACL management panel for BjyAuthorize, and figured it was something I'd probably reuse time and again.  Seems to make sense as a vendor module in my ZF2 project, and it is something I would probably want to maintain independently of a particular project's scope.  If this thing is well built, it'll be standalone...amirite!

If you haven't yet used composer, it hauls a ton of ass (its website is a pretty dry read though...).  Part of my day's pleasure is running 'php composer.phar selfupdate' and 'php composer.phar update' while I take the first few sips of coffee to see what updates while I caffeinate.   Who else was working last night!

It's a pretty straight thing to configure; you'll find the tell-tale composer.json in the ZF2 Default Skeleton App if you started there (highly recommended).  My current big project's composer looks like:

{
"name": "zendframework/skeleton-application",
"description": "Skeleton Application for ZF2",
"license": "BSD-3-Clause",
"keywords": [
"framework",
"zf2"
],
"homepage": "http://framework.zend.com/",
"minimum-stability" : "dev",
"require": {
"php" : ">=5.3.3",
"zendframework/zendframework" : "2.1.5",
"doctrine/doctrine-orm-module" : "0.7.*",
"aws/aws-sdk-php-zf2" : "dev-master",
"zf-commons/zfc-twig" : "dev-master",
"zf-commons/zfc-base" : "0.1.*",
"zf-commons/zfc-user" : "0.1.*",
"zf-commons/zfc-user-doctrine-orm" : "0.1.*",
"bjyoungblood/BjyAuthorize" : "dev-master",
"zendframework/zend-developer-tools": "dev-master",
"saeven/circlical-acl-admin": "*"
}
}

That last line down there, the saeven/circlical-acl-admin -- is the package we want to create (these blog articles are strange that way aren't they, we write them as a recap of what we've done, but in future tense for readability).

 

First Step - GitHub

You can create a repo to distribute your source to Packagist in different ways (Git/Svn/Hg); subscribing to Occam's Razon, GitHub is a pretty convenient means to get this done.  If you're working under the scrutiny of some IS nerds with badges, or are working on top-secret stuff, you'll use a different source repo for Packagist (you probably won't even use Packagist, you'll use Satis - blog post for another day). 

Sign up for a free account at GitHub if you don't have one, and create a repository (it's that book-looking icon at top right). 

 

Create a new repo button on GitHub

Create a new repo button on GitHub

Be a good sport, and name the repo after the ZF2 module name it'll be housing, give it a quick description, and optional, initialize it with a ZendFramework .gitignore.

 

Once this is done, leave the tab open -- we'll need it later, but, you are theoretically done here.  The confirmation page at GitHub gives you the command line syntax to commit and push code; but you are using a GitHub ready IDE -- right?

 

Second Step - Module Layout & Config

Here's where we configure the Module you're offering the world, and the composer config nested within it.  For this article's sake, we'll give it a basic route, and rig things to be PSR-0 compliant. 

Fire up your IDE, create a new project with this folder structure. 

Project layout (in PhpStorm w/Darcula theme)

Project layout (in PhpStorm w/Darcula theme)

If you're not familiar with ZF2 module layouts, it does matter.  You'll notice, contrary to the skeleton app (at least at present day), there's a Module.php in the base folder and  in the src/ModuleName/ folder.  This is that PSR-0 compliant effort we were talking about.  

The code in the base-folder Module.php looks like so:

/Module.php

<?php
/**
* This file is placed here for compatibility with ZendFramework 2's ModuleManager.
* It allows usage of this module even without composer.
*/
require_once __DIR__ . '/src/CirclicalACLAdmin/Module.php';

We notice that it defers to the Module.php tucked in the src folder, which naked, like so:

src/CirclicalACLAdmin/Module.php

<?php
/**
* Circlical ACL Admin Module for BjyAuthorize Module
*
* @link TBD for the Circlical ACL Admin canonical source repository
* @link https://github.com/bjyoungblood/BjyAuthorize for the BjyAuthorize canonical source repository
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace CirclicalACLAdmin;

use Zend\EventManager\EventInterface;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\ControllerPluginProviderInterface;
use Zend\ModuleManager\Feature\ViewHelperProviderInterface;
use Zend\Mvc\ApplicationInterface;

/**
* Circlical ACL Admin Interface for BJYAuthorize
*
* @author Alexandre Lemaire <alemaire@circlical.com>
*/
class Module implements
AutoloaderProviderInterface,
BootstrapListenerInterface,
ConfigProviderInterface,
ControllerPluginProviderInterface,
ViewHelperProviderInterface
{
/**
* {@inheritDoc}
*/
public function onBootstrap(EventInterface $event)
{
/* @var $app \Zend\Mvc\ApplicationInterface */
$app = $event->getTarget();
}

/**
* {@inheritDoc}
*/
public function getViewHelperConfig()
{
return array(
'factories' => array(

),
);
}

/**
* {@inheritDoc}
*/
public function getControllerPluginConfig()
{
return array(
'factories' => array(

),
);
}

/**
* {@inheritDoc}
*/
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/../../src/' . __NAMESPACE__,
),
),
);
}

/**
* {@inheritDoc}
*/
public function getConfig()
{
return include __DIR__ . '/../../config/module.config.php';
}
}

Bare-bones, it should be enough to get you started with most of the common connection points.  The standard getConfig() is there, referencing config/module.config.php.  We're going to pimp ours out a bit though, I have a two fundamental requirements of my module:

  1. Capture a basic route of: acl-admin to show an index page
  2. Be guarded by BjyAuthorize itself

Reverse engineering a bit, I'll put the following in my config and reverse engineer the details into my Module.php.

config/module.config.php

<?php


return array(


'bjyauthorize' => array(

// Guard listeners to be attached to the application event manager
'guards' => array(
'BjyAuthorize\Guard\Controller' => array(
array('controller' => 'CirclicalACLAdmin\Controller\Index', 'roles' => array( 'user' ) ),
),
),

),


'controllers' => array(
'invokables' => array(
'CirclicalACLAdmin\Controller\Index' => 'CirclicalACLAdmin\Controller\IndexController'
),
),


'service_manager' => array(

'factories' => array(

),

'initializers' => array(

),
),


'view_manager' => array(
'template_map' => array(
'circlical-acl-admin/index' => __DIR__ . '/../view/circlical-acl-admin/index.phtml',
),
),


'router' => array(

'routes' => array(

'circlical-acl-admin' => array(

'type' => 'Literal',
'priority' => 1000,
'options' => array(
'route' => '/acl-admin',
'defaults' => array(
'controller' => 'CirclicalACLAdmin',
'action' => 'index',
),
),
'may_terminate' => true,

),
),
),
);

I added a bare-bones view and controller in there, you can get them in the full source archive at the end (plain old ZF2, no rocket science there).  Roll your own, or skip down and cheat (and the come back here) and let's look at the composer specification that we need to create in the Module's base folder, composer.json (don't confuse with the composer.json that is put in your project base to pull files.  This one is more of a push manifest).

{
"name": "saeven/circlical-acl-admin",
"description": "Admin moderation panel for bjyoungblood/bjy-authorize",
"type": "library",
"license": "BSD-3-Clause",
"homepage": "https://github.com/Saeven/CirclicalACLAdmin",
"keywords": [
"zf2",
"acl",
"zfc-user",
"bjyauthorize",
"circlical"
],
"authors": [
{
"name": "Alexandre Lemaire",
"email": "alemaire@circlical.com",
"homepage": "http://circlical.com/",
"role": "Developer"
}
],
"minimum-stability": "dev",
"require": {
"php": ">=5.3.3",
"bjyoungblood/BjyAuthorize": "~1.3"
},
"require-dev": {
"phpunit/phpunit": "~3.7",
"doctrine/common": ">=2.3,<2.5-dev"
},
"suggests": {
"zf-commons/zfc-user-doctrine-orm": "If you want to use BjyAuthorize with Doctrine ORM"
},
"autoload": {
"psr-0": {
"CirclicalACLAdmin\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "0.1-dev"
}
}
}

Super straight forward, I'll spare your eyeballs the play-by-play; but there are some important details we'll carry into the subsequent steps: 

  1. module name, saeven/circlical-acl-admin.  This is what'll appear in Packagist.
  2. homepage, so that people can read about your work when they discover it through Packagist
  3. keywords, these appear as tag-bubbles in the Packagist display
  4. authors, be proud
  5. autoload.psr-0 - put your Module name here, note the escaped backslash \\ 
  6. require - put the packagist packages that your package requires here

Save that in the base. 

Here's the full source. 

If you're using PhpStorm, pushing to GitHub is really simple.   You can otherwise do it from the command line too -- get your code into GitHub.

 

Third Step - Code Ready, Push to Packagist

Your code in GitHub, head to https://packagist.org/, log in, and head to the Submit Package area. Punch in your GitHub repo URL, click "Check" and follow the steps.  

Screen Shot 2013-06-24 at 9.44.04 PM.png

Do connect your Packagist repo to GitHub, so that pushes to your repo make their way to packagist as well.  Steps are on-screen when you complete your Packagist submission.

Grand Finale

If you completed all the steps, you should be able to simply add your Packagist package name to your application project's (not the one we rigged here, another) composer.json and run 'php composer.phar update' to see your source download and rig itself with all the right autoloaders.  It'll even trap whatever route you configured if you did like me above.  Now how cool is that!

Or, save now, and do it tomorrow over coffee ;)

If you want me to clarify any of the steps above, drop a comment and it's my pleasure to expand on any specific section!