What's the Deal with Phing?


Published on

An introduction using practical examples to building, testing and deploying your PHP projects using Phing - the PHP build tool.

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • OK, so this evening I’m going to talk about Phing.\nPut very simply, Phing is a tool for BUILDING your PHP projects. Although PHP is an interpreted language, a lot of external conditions are not, and so some aspects of your site may still need to be built for deployment.\nThe plan is to introduce you to building and deploying your projects with Phing, show you some of what it can do, and give you a quick couple of scenarios where Phing way be useful.\n
  • Before I dive straight into the ins and outs of Phing, I’ll explain very briefly how to get it installed and cause some upset straight away. I know everyone is not a fan of PEAR... BUT it is the easiest way to get it installed. Just discover the phing channel, like above, and then install the latest version. I install mine with --alldeps just because phing makes use of a LOT of packages you may not already have installed, however it doesn’t NEED them, so it’s up to you. It does make use of a lot of extra PHP libraries, such as CodeSniffer, Mess Detector, PHPDocumentor, Docblox and tons more.\n\nSo there are phing’s basic command line options. It doesn’t tell you a great deal, I realise, but let’s face it, this is where most of us start with a new tool, typing help. It’s not too difficult, and everything is optional, including the targets. The standard convention is to run the Phing command from the base directory of the project you want to build, because this directory will usually contain the build file you’ll be using: build.xml.\n
  • Now I’ll give you a quick intro to Phing’s basic features. Phing uses XML files to determine exactly what it can build for a given project, very similar to Apache’s Ant. Each build file contains one project, which can have multiple targets. Each target runs tasks which are specific functions that are executed as a group within a target. The example above is one of the most simple ones, but shows you exactly what the structure of the build tool should look like. The project node is the root node of the file, and specifies the project’s name and the default target that should run if none is specified from the command line (main). Next are the targets, in this case two that both just echo messages when phing runs. The main target depends on the friendly target, so it will run that first.\n
  • So, this is what happens when you run the build file I just showed you. With no target given, phing uses the default one, in this case the main target, which runs the friendly target first, and then runs itself. Phing’s output is nice and clean with some helpful colouring (when you see red, that’s when your build failed for some reason), and tells you exactly what it is doing. The second example shows only the friendly target running, in which the main target isn’t touched at all. Brilliant!\n\nNow all this is great in theory, but really all this is doing is showing you the basic syntax and idea behind phing’s design... Practical examples would be better, yes? Agreed. Let’s make phing do something a little bit useful...\n
  • This time Phing is actually going to do something useful. On a given project, you might be needing to run some unit tests and set up some documentation every time your project is ready to go. These sort of tasks are what Phing is best at, simple automation that needs to be done at a major milestone. Here we have a build file with three targets now. One for running unit tests, one for generating documentation, and the final one for triggering the other two tests and providing an environment file. I’ve added a few things in this file, so I’ll go through them one at a time.\n
  • First things first, I’ve added a new attribute to the project. This tells phing explicitly where it should be running and basing all the tasks from. This is especially handy if you’re storing your build.xml file in a different location, or just to make doubly sure phing is running in the correct directory...\n\nThe basedir property can then be accessed from any of the nodes in an attribute by using a $ sign, then curly braces and the project.basedir property. This works for any attribute in project, such as the name, too. \n
  • I’ve also added a property to the project. Properties can be included inline, like this example, or using a link to a separate INI file which contains many properties. In this, I’m making sure the source directory is explicitly defined, because I want to make a few targets and each one needs to be using the same source. If I change this later, obviously I don’t want to be going through and changing each one, do I?\n\nUnlike basedir, when referencing the source property in an attribute, it doesn’t need any prepended container, just reference it absolutely like this.\n
  • The PHPUnit task directly ties into PHPUnit, as you’d expect. The task supports a few different attributes, very similar to PHPUnit’s command line options. In this case I’m passing it a bootstrap file. You can tell it to set certain properties on errors, whether to halt on errors, generate code coverage reports, etc.\n
  • Within the phpunit task, I’m defining a batch test (a set of tests to run). This node uses the fileset nested within it to include files, generate a list of classes and perform tests on them. Filesets are an important feature of Phing. This is how you include specific files to be used on certain tasks. In this case, I’m defining a fileset within in the ./tests/application directory. Within the fileset node, you can include as many files as you like, using wildcards if necessary. In this case, I’m including all PHP files within ALL directories (one * is any directory, two are any directory and any of their subdirectories, and so on). This is the only fileset I’ll be making use of in this build, but if you want more examples, I can provide some at the end if necessary.\n
  • The Docblox task, as you can see is in a different target to the PHPUnit task, and has different attributes! In this case, I’m giving the documentation a title, and telling Docblox which directory to output the generated documentation into. Just like with PHPUnit, I need to specify a fileset for Dropbox to generate the documentation from and the files to include from that fileset.\n
  • Finally, the main target. This target depends on, and so runs the PHPUnit and Docblox targets, and also has a separate task in itself which creates a file I use to designate this Zend Framework environment for testing. And that’s it! Not too difficult to create a Phing build that does something a little bit useful.\n\nPhing works with a LOT of different PHP libraries in a similar way to as I’ve shown you.\nIt can generate code coverage reports with PHPUnit,\nemail notifications and reports from the build,\nuse PHP Mess Detector, CodeSniffer and PHPDepend to generate reports on code violations and dependencies,\nuse PHPDocumentor to generate documentation similar to Docblox,\ninterface with SimpleTest instead of PHPUnit,\nand even zip your files together\n\nOf course, all these examples so far are all based around the idea of testing and building projects, but phing can do a lot more than that...\n
  • Here’s a different example. Let’s say instead of testing and building the documentation, you actually want to DEPLOY your project. Well, Phing can do that for you, too. Phing supports various means to deploy your scripts, such as FTP, SCP, and VCS too such as CVS, subversion and Git. I’ve carried on from the previous example, so my phpunit and docblox targets are still included...\n\n
  • Because I’m using so many properties to specify the parameters for connecting to the FTP server, I’ve decided this time to store all my properties in a separate INI-style file instead of inline. Then, I only need to change the properties in this file in case I add a lot more things to the build file...\n
  • Now, for the FTP task itself, it does need quite a few parameters. All of it is standard FTP connectivity stuff, such as host, port, username, password, remote directory to upload to, whether to use passive mode or not, and the FTP mode to use, be it ASCII or binary. Once your connection info is all specified, you just need to tell the task which files you want to upload...\n\nWith this example, I’m including EVERY file in the source directory, not just PHP files, obviously as I’ll want my CSS and images I would think... BUT I don’t need my phing build file, my properties file, or the documentation or test information being uploaded on the server, that just wastes space, so I exclude these from the fileset implicitly.\n\nSo now, when I run phing within my Demo project, it tests everything, builds the documentation, and deploys my application onto the remote server via FTP. And all I have to do is type “phing” into the command-line, excellent.\n\nNow, let’s try injecting a bit of version control into Phing...\n
  • With VCS integration in Phing, you can do everything you’d normally need to within git, for example such as pushing, pulling, fetching, cloning, tagging, and even branching and merging.\n\nThis time, instead of running git from where I’m developing, I’m going to start running it on the remote server. This, of course, presumes you have a command-line accessible remote environment, such as a VPS. If you haven’t, you can stick to FTP deployment as before.\n\nI store my project in a Github repository now, and use a develop-master branching technique where I develop on the develop branch, aptly, and use the master branch for reflecting what the live environment is. So before deploying, I can choose whether to merge the branches or just use the current master branch within using the develop branch.\n
  • Firstly, the init target is used on the remote server to CLONE the repository in an initial state. This should be run as “phing init” before the first main or merge target is run, otherwise they will fail because the local git copy will be missing...\n\nGit init takes the repository’s location (e.g. github using the git:// protocol) and needs a target for where to clone the repository into.\n
  • The main target has been changed quite a bit. Firstly, it now depends on the new pull target, which I’ll explain last, just for ease,but still only carries out one task.\n\nThe main target now checks out the latest master branch of the git repository, which is the ONLY branch that should be used on the live server. The quiet attribute is used just to keep git’s output to a minimum and not to clog up the command line...\n\nThe gitcheckout task uses the repository attribute again, and is given the branchname to explicitly checkout.\n
  • The new merge target is one that is intended to be run separately to main. This will use the main target checkout the latest master changes, but will then merge the latest DEVELOP branch changes into master (which you can see in the remote attribute, here you can specify as many branches to merge), rather than just using the master branch. As you can see, this is NOT the default task, because obviously this could be destructive in some cases, so I’ve left the simple checkout as the default task, and this should be run only when needed using ‘phing merge’.\n
  • Finally, the pull target is used by both main and merge to pull ALL remote changes from github (in this case for both branches), but any changes will be checked out separately even before a merge, to make sure the master branch is the one being used by phing on the live server. The “all” attribute is used to specify all branches should be pulled from the remote git repo.\n\nThat’s pretty much all there is to using git with phing on your remote server. Of course, you could generate pre-merging tags and make a “rollback” target too just in case the merge causes some problems, but I think it’s a good idea to try and figure these things out yourselves sometimes (all that means is that I haven’t done it)\n
  • The last challenge with using Phing is deploying to multiple locations, which is something I took a bit of a different view on.\n\nAs in the previous example, I run the deployment on a remote server, but in a slightly different way. I have a local script I run that connects over SSH to each remote server in turn and runs phing independently on that box. This way, the boxes can be separated as necessary and don’t have to communicate with each other, for a more secure deployment environment. Each server runs exactly the same phing script, because it is contained within the git repository.\n\nThis example assumes you have SSH keys/passwords set up on all your remote servers, I’m not going to be going into all that stuff...\n\nNow, once I’ve explained what the script does and shown you the phing build file, I am going to run a LIVE demonstration! This may be my undoing, so you should all stay focused for this one ;)\n\nOK, so the script at the top is the actual script I’m using, it’s that simple. It connects to three servers, goes to the correct directory for the deployment (the software is called gigo for this project, and is not strictly a web project, hence the /opt location) and phing is then run under sudo because some of the filesystem tasks need elevated privileges.\n\nWithin my git folder on my local machine, I have the build.xml file as normal, which isn’t supposed to run here, and the build-remote script which I can run.\n
  • Luckily, the phing file for this project isn’t too complicated.\n\nI should probably explain that this project is one of Ling’s chinese ventures, but I do have permission to show you this tonight, so don’t worry, no nuclear missile trucks are going to roll up outside...\n\nThis build file assumes there is already a working git deployment on the remote box, the first one must be performed manually, as the build file won’t exist on the remote server until the git repo is pulled. That’s one of the disadvantages of this method...\n\nI do have an init method in this build file, but all it does is make sure the directories I need for storing files that are ignored by my git repo are present.\n\nThe perms target sets up the permissions on these folders (tasks run automatically using cron on all these boxes, so this needs to be correct), and sets up the log folders for any to write to them, just in case I’m logging in and doing a live-test.\n\nFinally, the dist target, the default, pulls the latest changes from the master branch. I’ve set it to output git information for this so I can get a clear idea of what’s going on...\n\nAnd that’s all there is to it! Now, to the live demo...\n
  • \n
  • Now I’ve shown you everything there is to phing on it’s on, but I haven’t shown you how to integrate it with jenkins yet, which is something I agreed to do as part of the talk. Nothing like a bit of CI to get everyone excited...\n\nThis is another live CI environment that I set up, although I haven’t been using it too much for a while, so it may not look entirely complete or functional. Please ignore that and concentrate on the settings I’m going to show you.\n\nThis is a jenkins CI setup that builds periodically, and also builds when a new push is made to the develop branch. To get it to build the project using phing, you must have the phing plugin installed for Jenkins first. When you’ve got the phing plugin installed, and have created a new job for jenkins, you’ll get to the build section on the “configure” page.\n
  • To get phing working, all you need to do is tell Jenkins to invoke a phing target when building, like I have already on this with my test target. That’s it! This phing build has a lot to do though...\n
  • The phing build file has a lot to do, all run from the “test” target, which I’ll show you last. The clean target makes sure all the folders that contain the previous build information are empty and ready to receive logs, build information and api docs.\n\nThe phpunit task is similar to before, but this time also outputs some coverage reports that are shown for me in Jenkins.\n\n\n
  • The parallel tasks target makes sure a lot of phing targets are all called at the same time, just to speed up the build process.\n\nThe pdepend target builds logs and reports for the dependency information within the project, and saves them for Jenkins to display on the project dashboard.\n\nThe phpmd target invokes mess detector to generate even more reports on unused code, naming problems and code sizing.\n
  • The phpcpd target uses Seb Bergman’s copy-paste detector to further expand on the mess detector logs\n\nPHPLOC generates a lines of code report in CSV format to display in jenkins\n\nPHPCS invokes code sniffer to check the coding STYLE of the files, and make sure I’m conforming to Zend standards (since this is a ZF project)\n\nPHPdoc is fairly simple, and builds my API documentation to browse through using the default smarty template.\n\n\n
  • PHP CB uses Code browser to generate a lovely output of all the code in the project to be browsed through, highlighting any errors and information needed...\n\nFinally, the test target is the one that invokes everything, as you can see by its dependencies. It makes sure jenkins can write to the logs folder for the build, and sets up the testing environment for Zend Framework.\n\nNow I’ve ran through this bit really quickly, so I appreciate that a lot of you might not have taken this in. But, if anyone needs any more help with jenkins, or wants a chat afterwards, I’ll be around in the pub for a while :)\n
  • This is the only slide I managed to make with bullet points!\n\nThese are some important sites you might want to have a glance over. Especially the likes of the phing documentation, which is very very helpful and very thorough for all the tasks I’ve shown you today.\n\nThere is a great example that is very well explained of using phing with dbdeploy, which i haven’t shown today, at that link.\n\nThe jenkins PHP template is an excellent start for getting php projects integrated with jenkins and includes most of the stuff I went through today. It actually uses ant instead of phing, but it can be very very easily converted to use phing instead.\n\nFinally, Janky is a new project by some of the github team to integrate jenkins with github and hubot, an automated platform, to make things a little bit easier. Might be worth a look.\n\nThanks for listening, I hope at least some of you found it useful!\n
  • What's the Deal with Phing?