a phing fairy tale - confoo13
TRANSCRIPT
A Phing fairy taleStephan Hochdörfer, bitExpert AG
A Phing fairy tale
About me
Stephan Hochdörfer
Head of IT at bitExpert AG, Germany
enjoying PHP since 1999
@shochdoerfer
Disclaimer
A Phing fairy tale
Warning: You will see a hell lot of XML.
What is Phing?
A Phing fairy tale
What is Phing?
A Phing fairy tale
It is a PHP project build system or build tool based on Apache Ant.
What is Phing?
A Phing fairy tale
Domain Specific Language for an project build system.
What is Phing?
A Phing fairy tale
Enables one button push automation.
Project build system?
A Phing fairy tale
Project build system?
A Phing fairy tale
Automation of non-development tasks
Project build system?
A Phing fairy tale
Automate absolutely everything.
Project build system?
A Phing fairy tale
If you use Phing, only use Phing.
Why Phing?
A Phing fairy tale
Why Phing?
A Phing fairy tale
Runs everywhere where PHP runs.
Why Phing?
A Phing fairy tale
No additional depencendies needed(e.g. Java, …).
Why Phing?
A Phing fairy tale
More than 120 predefinedtasks to choose from.
Why Phing?
A Phing fairy tale
Easy to extend by writing custom tasks in PHP.
How to install Phing?
A Phing fairy tale
$> pear channeldiscover pear.phing.info$> pear install phing/phing
How to install Phing? The PEAR way...
A Phing fairy tale
Installing Phing
$> phing vPhing 2.4.14
$> pear channeldiscover pear.phing.info$> pear install phing/phing
How to install Phing? The PEAR way...
A Phing fairy tale
Installing Phing
Running Phing:
{"require": {
"phing/phing": "2.4.14"}
}
How to install Phing? The Composer way...
A Phing fairy tale
composer.json:
$> php composer.phar installLoading composer repositories with package informationInstalling dependencies Installing phing/phing (2.4.14) Downloading: 100%
Writing lock fileGenerating autoload files
{"require": {
"phing/phing": "2.4.14"}
}
How to install Phing? The Composer way...
A Phing fairy tale
composer.json:
Running Composer:
How to install Phing? The Composer way...
A Phing fairy tale
/home/shochdoerfer/myproject |vendor |bin |@phing |composer |phing |phing |bin |phing |build |classes |docs |etc |test
How to install Phing? The Composer way...
A Phing fairy tale
/home/shochdoerfer/myproject |vendor |bin |@phing |composer |phing |phing |bin |phing |build |classes |docs |etc |test
$> ./vendor/bin/phing vPhing DEV
Running Phing:
Phing Basics
A Phing fairy tale
Phing Basics
A Phing fairy tale
Project, Target, Task, Properties
Phing Basics: Project
A Phing fairy tale
Root node of a build file containing one or more targets.
Phing Basics: Target
A Phing fairy tale
A group of tasks that run as an entity.
Phing Basics: Task
A Phing fairy tale
Custom piece of code to perform a specific function.
Phing Basics: Properties
A Phing fairy tale
Properties (Variables) help to customize execution.
Phing Basics: Built-In Properties
A Phing fairy tale
e.g. host.os, line.separator, phing.version, php.version, …
<?xml version="1.0"?><project name="myproject" default="init">
<target name="init">
<! insert logic here ></target>
</project>
Phing Basics: Sample Build File
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says Hello, world!">
<echo msg="Hello, world!" /></target>
</project>
Build File – Hello World example
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says Hello, world!">
<echo msg="Hello, world!" /></target>
</project>
Build File – Hello World example
A Phing fairy tale
$> phingBuildfile: /home/shochdoerfer/build.xml
myproject > hello:
[echo] Hello, world!
BUILD FINISHED
Total time: 0.0595 seconds
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says Hello, world!">
<property name="Hello" value="Hello, world!" />
<echo msg="${Hello}" /></target>
</project>
Build File – Introducing Properties
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<property name="Hello" value="Hello, world!" /> <target name="hello"
description="Says Hello, world!">
<echo msg="${Hello}" /></target>
</project>
Build File – Introducing Properties
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says whatever you want to say"
<echo msg="${Hello}" /></target>
</project>
Build File – Externalizing Properties
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says whatever you want to say"
<echo msg="${Hello}" /></target>
</project>
Build File – Externalizing Properties (CLI)
A Phing fairy tale
$> phing DHello="Hello from CLI"Buildfile: /tmp/build.xml
myproject > hello:
[echo] Hello from CLI
BUILD FINISHED
Total time: 0.0599 seconds
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says whatever you want to say">
<propertyfile="./build.properties" />
<echo msg="${Hello}" /></target>
</project>
Build File – Externalizing Properties (File)
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says whatever you want to say">
<propertyfile="./build.properties" />
<echo msg="${Hello}" /></target>
</project>
Build File – Externalizing Properties (File)
A Phing fairy tale
Hello=Hello, world!build.properties:
$> phingBuildfile: /home/shochdoerfer/build.xml
myproject > hello:
[property] Loading /home/shochdoerfer/build.properties [echo] Hello, world!
BUILD FINISHED
Total time: 0.0601 seconds
Build File – Externalizing Properties (File)
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<property name="Hello" value="Hello, world!" /> <target name="hello"
description="Says Hello, world!">
<echo msg="${Hello}" /></target>
<target name="goodbye" description="Says goodbye!">
<echo msg="Goodbye!" /></target>
</project>
Build File – Defining multiple targets
A Phing fairy tale
$> phing helloBuildfile: /tmp/build.xml
myproject > hello:
[echo] Hello, world!
BUILD FINISHED
Total time: 0.0612 seconds
Build File – Defining multiple targets
A Phing fairy tale
$> phing helloBuildfile: /tmp/build.xml
myproject > hello:
[echo] Hello, world!
BUILD FINISHED
Total time: 0.0612 seconds
$> phing goodbyeBuildfile: /tmp/build.xml
myproject > goodbye:
[echo] Goodbye!
BUILD FINISHED
Total time: 0.0619 seconds
Build File – Defining multiple targets
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="init" description="Property initialization">
<property name="Hello" value="Hello, world!" /></target>
<target name="hello" depends="init">
<echo msg="${Hello}" /></target>
</project>
Build File – Target dependencies
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="init" description="Property initialization">
<property name="Hello" value="Hello, world!" /></target>
<target name="customcode" description="Some custom logic">
</target>
<target name="hello" depends="init, customcode">
<echo msg="${Hello}" /></target>
</project>
Build File – Target dependencies
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="preinit"><property name="World" value="world" />
</target>
<target name="init" depends="preinit"><property name="Hello"
value="Hello, ${World}!" /></target>
<target name="hello" depends="init">
<echo msg="${Hello}" /></target>
</project>
Build File – Target dependencies
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="print"><echo msg="Processing: ${filename}" />
</target>
<target name="run"><!
loop through files and call print target ><foreach param="filename"
absparam="filename" target="print">
<fileset dir="."><include name="*.php"/>
</fileset></foreach>
</target></project>
Build File – Calling targets programmatically I
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="print"><echo msg="Processing: ${filename}" />
</target>
<target name="run">
<! calling target with given property ><phingcall target="print">
<property name="filename" value="test.php" />
</phingcall></target>
</project>
Build File – Calling targets programmatically II
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run">
<! calling target in print.xml with given property >
<phing phingfile="print.xml" target="print"><property name="filename"
value="test.php" /></phing>
</target></project>
Build File – Calling targets programmatically III
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run">
<! Copy files matching the expression > <copy todir="/tmp/deploy">
<fileset dir="." includes="**/*.php"><and>
<size value="1024" when="more" /><date
datetime="01/01/2013 10:00 AM" when="after" />
</and></fileset>
</copy></target>
</project>
Build File – Fileset
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run"> <! Copy files and replace tokens > <copy todir="/tmp/deploy">
<filterchain><replacetokens begintoken="##"
endtoken="##"><token key="VERSION"
value="${app.version}"</replacetokens>
</filterchain>
<fileset dir="."> <include name="**/*.php"/></fileset>
</copy></target>
</project>
Build File – Filters
A Phing fairy tale
Phing – What can it do for me?
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run"> <! correct file permissions > <chmod file="${project.basedir}/cache"
mode="0777" /> <chmod file="${project.basedir}/uploads"
mode="0777" /></target>
</project>
Phing – What can it do for me?
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run"> <! create API documentation > <docblox title="My project"
destdir="apidocs" template="new_black">
<fileset dir="${project.basedir}/src"> <include name="**/*.php" /> </fileset>
</docblox></target>
</project>
Phing – What can it do for me?
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run"> <! minify javascript >
<jsMin targetDir="${project.basedir}/web/"><fileset dir="${project.basedir}/web/js/">
<include name="**/*.js"/></fileset>
</jsMin></target>
</project>
Phing – What can it do for me?
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run"> <! exec database migrations >
<liquibaseupdate jar="/opt/liquibase/liquibase.jar" classpathref="/opt/liquibase/lib/mysql.jar" changelogFile="${project.basedir}/diff.xml" username="liquibase" password="liquibase" url="jdbc:mysql://localhost/myproject"/>
</target></project>
Phing – What can it do for me?
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run"> <! deploy via rsync to dev server >
<exec command="rsync vraCz ./ ${deploy.dev.url}" dir="${project.basedir}" checkreturn="true" />
</target></project>
Phing – Task missing? Use exec...
A Phing fairy tale
Build File – Advanced usage
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" depends="init"> <echo msg="${Hello}" />
</target>
<target name="init" depends="prop, localprop"<! some more init logic >
</target>
<target name="prop"><echo message="Load default build.properties"<property
file="./build.properties" /></target>
Properties File - Improved version
A Phing fairy tale
<target name="localprop"if="localprop.exists"depends="localpropcheck">
<echo message="Loading custom properties!"<property
file="${project.basedir}/local.properties"override="true"/>
</target>
<target name="localpropcheck"><available
file="${project.basedir}/local.properties"property="localprop.exists" />
</target></project>
Properties File - Improved version
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="init" description="Property initialization">
<property name="Hello" value="Hello, world!" /></target>
<target name="hello" depends="init">
<echo msg="${Hello}" /></target>
</project>
Enforce Internal Targets
A Phing fairy tale
User can call both targets from command line. We do not want that.
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="init" description="Property initialization">
<property name="Hello" value="Hello, world!" /></target>
<target name="hello" depends="init">
<echo msg="${Hello}" /></target>
</project>
Enforce Internal Targets
A Phing fairy tale
Prefixing a targets with a „-“ prevents the target from being called from the command line.
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="init"> <adhoctask name="mytask"><![CDATA[class MyTask extends Task {
/** * (nonPHPdoc) * @see \Task::main() */public function main() {
// Custom code here...}
}]]></adhoctask>
</target>
<target name="hello" depends="init">
<mytask /></target>
</project>
Custom Task (Adhoc definition)
A Phing fairy tale
<?phprequire_once 'phing/Task.php';
class MyTask extends Task {/** * (nonPHPdoc) * @see \Task::main() */public function main() {
// Custom code here...}
}
Custom Task (External file)
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="init"> <taskdef
name="mytask"classpath="${project.basedir}"classname="MyApp.Common.Phing.MyTask" />
</target>
<target name="hello" depends="init">
<mytask /></target>
</project>
Custom Task (External file)
A Phing fairy tale
<?phprequire_once 'phing/Task.php';
class MyTask extends Task {protected $file;
/** * @param string $file */public function setFile($file) {
$this>file = $file;}
/** * @see \Task::main() */public function main() {
// Custom code here...}
}
Custom Task with Parameters
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="init"> <taskdef
name="mytask"classpath="${project.basedir}"classname="MyApp.Common.Phing.MyTask" />
</target>
<target name="hello" depends="init">
<mytask file="myfile.txt" /></target>
</project>
Custom Task with Parameters
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="app:run">
<!The following target namespaces exist:db:* Database specific targetsapp:* Application specific tasksci:* CI server specific tasks><import file="build/build.db.xml" /><import file="build/build.app.xml" /><import file="build/build.ci.xml" />
</project>
Imports for Targets can help structuring
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="ci:runtests">
<target name="app:cleancache"></target>
<target name="app:createcache"></target>
<target name="db:migrate"></target>
<target name="js:minifiy"></target>
<target name="ci:lint"></target>
<target name="ci:runtests"></target>
</project>
Distinct Target Naming
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run"> <! tag the database →
<input propertyname="tag" defaultValue="mytag">Tag to create?</input>
<liquibasetag tag="${tag}" jar="/opt/liquibase/liquibase.jar" classpathref="/opt/liquibase/lib/mysql.jar" changelogFile="${project.basedir}/diff.xml" username="liquibase" password="liquibase" url="jdbc:mysql://localhost/myproject"/>
</target></project>
Prompt user for input
A Phing fairy tale
<?xml version="1.0"?><project name="myproject" default="run">
<target name="run">
<! Returns canonicalized absolute pathname >
<php function="realpath" returnProperty="app.dir">
<param value="${app.dir}"/> </php></target>
</project>
Calling PHP functions from Phing
A Phing fairy tale
Follow conventions
A Phing fairy tale
Phing expects your build file to be called build.xml and the build’s properties file
build.properties
Follow conventions
A Phing fairy tale
Pick meaningful, human-readable names for targets and properties.
Follow conventions
A Phing fairy tale
Make build files self-contained.
Thank you!
http://joind.in/7949