Phing buildfiles are written in XML, and so you will need to know at least some basic things about XML to understand the following chapter. There is a lot of information available on the web:
A valid Phing buildfile has the following basic structure:
The Foobar project installs some PHP files from a source location to a target location, creates an archive of this files and provides an optional clean-up of the build tree:
<?xml version="1.0" encoding="UTF-8"?> <project name="FooBar" default="dist"> <!-- ============================================ --> <!-- Target: prepare --> <!-- ============================================ --> <target name="prepare"> <echo msg="Making directory ./build" /> <mkdir dir="./build" /> </target> <!-- ============================================ --> <!-- Target: build --> <!-- ============================================ --> <target name="build" depends="prepare"> <echo msg="Copying files to build directory..." /> <echo msg="Copying ./about.php to ./build directory..." /> <copy file="./about.php" tofile="./build/about.php" /> <echo msg="Copying ./browsers.php to ./build directory..." /> <copy file="./browsers.php" tofile="./build/browsers.php" /> <echo msg="Copying ./contact.php to ./build directory..." /> <copy file="./contact.php" tofile="./build/contact.php" /> </target> <!-- ============================================ --> <!-- (DEFAULT) Target: dist --> <!-- ============================================ --> <target name="dist" depends="build"> <echo msg="Creating archive..." /> <tar destfile="./build/build.tar.gz" compression="gzip"> <fileset dir="./build"> <include name="*" /> </fileset> </tar> <echo msg="Files copied and compressed in build directory OK!" /> </target> </project>
A phing build file is normally given the name build.xml which is the default file name that the Phing executable will look for if no other file name is specified.
To run the above build file and execute the default target (assuming it is stored in the current directory with the default name) is only a matter of calling:
$ phing
This will then execute the dist target. While executing the build file each task performed will print some information on what actions and what files have been affected.
To run any of the other target is only a matter of providing the name of the target on the command line. So for example to run the build target one would have to execute
$ phing build
It is also possible to specify a number of additional command line arguments as described in Appendix A
The first element after the document prolog is the root element named <project> on line 3. This element is a container for all other elements and can/must have the following attributes:
Attribute | Meaning | Required |
---|---|---|
name | The name of the project | No |
basedir | The base directory of the project, use "." do denote the current directory. Note: if none is specified, the parent directory of the build file is used! | No |
default | The default target that is to be executed if no target(s) are specified when calling this build file. | Yes |
description | The description of the project. | Yes |
A target can depend on other targets. You might have a target for installing the files in the build tree, for example, and a target for creating a distributable tar.gz archive. You can only build a distributable when you have installed the files first, so the distribute target depends on the install target. Phing resolves these dependencies.
It should be noted, however, that Phing's depends attribute only specifies the order in which targets should be executed - it does not affect whether the target that specifies the dependency(s) gets executed if the dependent target(s) did not (need to) run.
Phing tries to execute the targets in the depends attribute in the order they appear (from left to right). Keep in mind that it is possible that a target can get executed earlier when an earlier target depends on it, in this case the dependant is only executed once:
<target name="D" depends="C,B,A" />
Suppose we want to execute target D . From its depends attribute, you might think that first target C , then B and then A is executed. Wrong! C depends on B , and B depends on A , so first A is executed, then B , then C , and finally D .
A target gets executed only once, even when more than one target depends on it (see the previous example).
The optional description attribute can be used to provide a one-line description of this target, which is printed by the -projecthelp command-line option.
You can specify one or more of the following attributes within the target element.
Attribute | Meaning | Required |
---|---|---|
name | The name of the target | Yes |
depends | A comma-seperated list of targets this target depends on. | No |
if | The name of the Property that has to be set in order for this target to be executed | No |
unless | The name of the Property that must not be set in order for this target to be executed. |
A task is a piece of PHP code that can be executed. This code implements a particular action to perform (i.e. install a file). Therefore it must be defined in the buildfile so that it is actually invoked by Phing.
These references will be resolved before the task is executed.
Tasks have a common structure:
<name attribute1="value1" attribute2="value2" ... />
where name is the name of the task, attributeN is the attribute name, and valueN is the value for this attribute.
There is a set of core tasks (see Appendix B) along with a number of optional tasks. It is also very easy to write your own tasks (see Extending Phing).
Tasks can be assigned an id attribute:
<taskname id="taskID" ... />
By doing this you can refer to specific tasks later on in the code of other tasks.
Properties are essentially variables that can be used in the buildfile. These might be set in the buildfile by calling the PropertyTask, or might be set outside Phing on the command line (properties set on the command always line override the ones in the buildfile). A property has a name and a value only. Properties may be used in the value of task attributes. This is done by placing the property name between " ${ " and " } " in the attribute value. For example, if there is a BC_BUILD_DIR property with the value 'build', then this could be used in an attribute like this: ${BC_BUILD_DIR}/en . This is resolved to build/en.
It should be noted that if you use a property that is not defined via the property task, the system environment table is searched for this name. For example, if you would use the property ${BCHOME} and you did not define this prior in the buildfile or at the command line, Phing uses the environment variable BCHOME if it exists.
Phing provides access to system properties as if they had been defined using a <property> task. For example, ${os.name} expands to the name of the operating system. See Appendix A for a complete list
<?xml version="1.0" encoding="UTF-8" ?> <project name="testsite" basedir="." default="main"> <property file="./build.properties" /> <property name="package" value="${phing.project.name}" override="true" /> <property name="builddir" value="./build/testsite" override="true" /> <property name="srcdir" value="${project.basedir}" override="true" /> <!-- Fileset for all files --> <fileset dir="." id="allfiles"> <include name="**" /> </fileset> <!-- ============================================ --> <!-- (DEFAULT) Target: main --> <!-- ============================================ --> <target name="main" description="main target"> <copy todir="${builddir}"> <fileset refid="allfiles" /> </copy> </target> <!-- ============================================ --> <!-- Target: Rebuild --> <!-- ============================================ --> <target name="rebuild" description="rebuilds this package"> <delete dir="${builddir}" /> <phingcall target="main" /> </target> </project>
This build file first defines some properties with the <property> task call to PropertyTask. Then, it defines a fileset and two targets. Let us have a quick rundown of this build file.
The first five four within the project tag define properties. They appear in the two ways this tag can occur:
The next noticeable thing in the build file is the <fileset> tag. It defines a fileset, i.e. a set of multiple files. You can include and exclude Files with include and exclude tags within the fileset tag. For more information concerning Filesets (i.e. Patterns) see Appendix D. The fileset is given an id attribute, so it can be referenced later on.
One thing is worth noting here though and that is the use of double star expression, i.e. "**". This special regexp refers to all files in all subdirectories as well. Compare this with a single "*" which would only refer to all files in the current subdirectory. So for example the expression "**/*.phps" would refer to all files with suffix "'.phps" in all subdirectories below the current directory.
The first task only contains a call to CopyTask via <copy>. The interesting thing is within the copy tag. Here, a fileset task is not written out with nested include or exclude elements, but via the refid, the earlier create Fileset is referenced. This way, you can use a once defined fileset multiple times in your build files.
The only noticeable thing in the second target is the call to PhingTask with the <phingcall> tag (see Appendix B for more information). The task executes a specified target within the same build file. So, the second target removes the build directory and calls main anew so the project is rebuilt.
A variant is to override properties defined in the build file with properties specified on the command line using the -D switch. For example to override the builddir in the build file above one could call Phing as
$ phing -Dbuilddir=/tmp/system-test
With a little bit of experience it is not that difficult to write and understand Phing build files since the XML format in itself tends to be quite verbose. However, it can become a bit tedious and the large (and growing) amount of built-in tasks and filters can sometimes make it difficult to remember the exact syntax of all the available features.
To help with this the Phing distribution contains a Relax NG Grammar (REgular LAnguage for XML Next Generation, http://www.relaxng.org/) that describes the (formal) syntax of the build files. This grammar can help validate and write Phing build files since there are many XML editors which can make use of this type of grammar to validate, on the fly, as well as do context-sensitive auto-completion. Especially the auto-complete feature can significantly reduce the time it takes to write a correct, and possible complex, Phing build files.
This grammar is available (as a plain text file) in the distribution at:
/etc/phing-grammar.rng
Since we do not want to neither endorse nor forget any particular XML editor with this capability we do not make available such a list of editors. Instead, spending a few minutes with Google searching for XML-editors is bound to find a number of editors with this capability.
For only validating Phing build files there are several excellent free Java based command line tool validators (unfortunately we are not aware of any existing PHP based validator). One such validator is Sun Microsystems "Sun Multi-Schema Validator" or MSV (available at https://msv.dev.java.net/). This validator can take an RNG grammar and validate a given XML file against the supplied grammar.
For example, to use MSV to validate a Phing build file the following command line could be used:
$ java -jar msv.jar phing-grammar.rng build.xml start parsing a grammar. validating /home/joe/build.xml the document is valid. $