whitewashing.de

Application Lifecycle Management and Deployment with PEAR and PHAR (revisited) *UPDATE*

10. January 2010

Some weeks ago I posted an article on using PEAR and PHAR for application lifecycle management and deployment. Since then I have gotten some feedback through comments, but also discussed the topic with collegues. I have also optimized the approach quite considerably and even made an open-source project out of parts of it and I want to share all that is new with you. First of all, yes the presented solution was somewhat complex, partly because it is still a proposed idea and definately up for optimizations. However I am still very convinced of my approach, something I should discuss in more detail.

The only other two languages I have ever programmed something in with more than 50 lines of code are Java and C#. In both languages you can explicitly import different dependencies like libraries and frameworks by adding them to your application, i.e. in java you would add for example Spring as an MVC Web layer, Hibernate as an ORM and several other things to your project and directly bundle them in your executable. This is very easy to configure and maintain in IDEs like Netbeans or Eclipse (C# has the same with allowing you to attach DDLs of libraries to your project). It also makes for a much more straightforward deployment.

In the PHP world this siutation was quite different (up to PHP 5.3) for several reasons:

  • You could not package a library into a single distributable file.
  • The PEAR installer as the only tool for updating and managing dependencies of your application by default installs into a system/global directory. This means dependencies your application uses are located in a completly different location than your application code.
  • You can't manage multiple versions of the same package with PEAR in this system directory, making it very hard to control servers with different applications.
  • The global directory with your application dependencies is most often not under version control, which makes deployment of applications with PEAR dependencies somewhat difficult.

There are some solutions to this problems:

  • Don't use PEAR, but put all dependencies in your version control system.
  • Don't use PEAR, and bundle dependencies to your code in the build/deployment process.
  • Use PEAR like in the article described, on a per project basis.

The solutions that don't use PEAR suffer from the disadvantage that you need to keep track of all the library and framework dependencies yourself and upgrade them yourself. This might not be such a huge problem from a first glance, but in my opinion many PHP applications and projects suffer from using either no framework/library or just exactly one. There is no real cherry-picking going on the PHP world, for example I would really like to use Zend Framework for the general application layout, but still use Doctrine for the Modelling and HTML Purifier for the Output Escaping. Certain tasks might then only be solvable with the help of eZ Components, all of which are then to some extend dependencies of my application. With PEARHUB and PEARFARM on the horizon (Read Padraic on this topic) even more PHP code will be distributed using PEAR channels in the near future. My immutable DateTime code for example makes for a great little open source library that could be distribued via PEAR, aswell as Yadif - a dependency injection container I am using extensivly.

Question: Are you really going to manage all these dependencies correctly manually? Is everything up to date all the time, and upgradeable with ease?

The PEAR driven solution then begins to look very desirable in this light, however it has a considerable disadvantage: The PEAR installer itself works on a system-wide/user-centric basis, making it impossible to manage dependencies of several applications using only one linux user. My little Pearanha to the rescue: I have taken the PEAR installer code (which is distributed with all PHP installations across all systems) and put a new CLI tool on top of it. Its a very simple code-generator that allows to generate a re-configured PEAR installer script which only manages a single application in a given directory. This approach is also used by the symfony plugin mechanism, which internally uses the PEAR installer (did you know?).

Lets revisit my blog application example from my previous PEAR post, first install from Github and make the "pearanha" file executable and put it in your PATH (A PEAR Server Channel will follow any time soon).

Now we need to have an existing application directory somewhere, for example /var/www/blog and then we can put Pearanha on top of it with:

benny@desktop: pearanha generate-project 

You then need to specifiy the project base dir and then the project style (for example Zend Framework or Manual) which prompts your for the directory that should be used for as the vendor/library directory that PEAR will install all the code in. You will also be prompted for a binary/scripts directory which will then hold a new PHP file for you, the file my_phpiranha.

Pro Argument: Switching to Pearanha can be done at any point in your application lifecycle. Just define an additional vendor directory for all the dependencies to go in and generate the applications pear installer and you are good to go.

The generated script is your new application specific PEAR installer and you can begin to install all the required dependencies of your application:

benny@desktop:~$ cd /var/www/blog
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover pear.zfcampus.org
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install zfcampus/zf-alpha
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover htmlpurifier.org
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install hp/HTMLPurifier
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover pear.phpdoctrine.org
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install pear.phpdoctrine.org/DoctrineORM-2.0.0
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha channel-discover components.ez.no
benny@desktop:/var/www/blog$ ./vendor/pear/my_pearanha install ezc/ezcGraph

All this stuff is now located in /var/www/blog/vendor. Again you can use PEARs complete upgrade, remove and install functionality for your application, now without the hazzle of having to create a linux user for each project you want to manage this way, which in my opinion is a considerable simplification. The complete application (including its dependencies) can then be put under version control and be readily packaged as a single executable PHAR file by your build process.

As a side node, I did try Pyrus instead of PEAR for the same discussed purpose, however most of the current PEAR channels don't validate against Pyrus strict standards for the package.xml file. In the future this might change and a Pyrus based application installer will then be integrated into Pearanha.

UPDATE: I renamed PHPiranha to Pearanha as its more appropriate. Also after apinsteins comment on "pear config-create" I rewrote the generate-project parts to use the config-create functionality internally, which allowed me to throw away half of the self-written code. Thanks!

:: Category: PHP, Comments (8)

Comments (8)

Great! Already thought about something like this, as you pointed out the global installation of PEAR is quite unsatisfying for running several different applications under the same user name. I will definitely try it out. User: frank kleine - Date: 2010/01/11 00:19
this is win! User: fqqdk - Date: 2010/01/11 00:29
For people with php 5.3 you can use pyrus the new PEAR installer to control a specific registry by simply passing the directory name before the command:
pyrus /var/www/blog/vendor install pear/PackageName

All pyrus controlled registries are directory specific. More info here: http://pear.php.net/manual/en/pyrus.differences.frompear.php#pyrus.differences.frompear.configuration User: brett - Date: 2010/01/11 01:10
I have been doing serious automated deployment with PHP for a while now, and although I can't quite tell what phpirhana does, it seems like you might be missing one of PEAR's best features!

pear config-create

I use it on a per-project basis like so:
pear config-create externals conf/.pearrc

Then I have code that on deploy programmatically installs all packages I need, like so:
pear -c conf/.pearrc install A B C D

Then I use ini_set('include_path', '.:/path/to/externals/pear') in my web application.

Tha't all there is to it! With this setup you get per-application dependencies entirely managed via PEAR.

If phpirhana does something different, I'd like to understand the additional advantages (if any) of your system.

Oh and btw I am part of the pearfarm team, so thanks for mentioning us and please do release your libs on pearfarm!

Looking forward to hearing from you,
Alan User: apinstein - Date: 2010/01/11 03:07
@apinstein, actually it does the same, seems i havent read the manual of the pear installer good enough ;-) PHPiranha is no real magic though, its mostly the PEAR code with 2-3 adjustments to set the different config paths, i.e. its something like a wrapper around having to call "pear -c /path/to/config". Maybe i should rewrite it in this regard though :-)

@brett, pyrus is really great and I would have used it for this purpose if not most of the current public channels throw errors in combination with pyrus :-) User: beberlei - Date: 2010/01/11 09:20
@beberlei ok cool!

It is a problem that once you install "locally" it's annoying to run the "local" executables.

A simple executable wrapper that would rig your pear conf and include_path would be nice.

localize pear install X == pear -c conf/.pearrc install X
localize phing blah == phing -d include_path='XXX'

Something like that... User: apinstein - Date: 2010/01/13 17:23
The topic of deployment in PHP is woefully underrepresented. I'm glad your pushing this topic to a new level. Great work! User: samhennessy - Date: 2010/01/20 20:50
@beberlei This is a pretty cool approach.

We developed an in-house solution, a couple of months ago, not unlike this one, albeit that we also added our own pear repo server, using http://github.com/fabpot/Pirum

We decided to store all our modules in our vcs and publish them to the pear server. Then when we want to install one of our modules we'd use this.

We found one drawback, however: if you commit your project with installed packages, the PEAR .reg files (created in vendor/.registry/.channel.server.tld) are also committed, with the developer's complete path to his workspace, which then makes it impossible for another developer to install or update any new packages.

Might there be a workaround for this? We haven't found it yet, and resorted to a shared user that commits newly installed packages, since we don't want to install these packages again on deployment... User: leening - Date: 2010/02/05 22:10

Post A Comment

 
 
 
 
::Back To The Top