Build That Phing!

86
Build that Phing! PHing Is Not GNU make / Rick Kuipers @rskuipers [email protected]

description

PHPMD, PHPCS, PHPUnit and PHPLint; these are all tools to maintain code quality. Executing these tasks is a chore and there are many ways to automate this process, Phing being one of them. The goal of this talk is to really discover what Phing has to offer, from implementing code logic to creating your own task.

Transcript of Build That Phing!

Page 1: Build That Phing!

Build that Phing!PHing Is Not GNU make

/ Rick Kuipers @[email protected]

Page 2: Build That Phing!

whoamiRick Kuipers@rskuipersApeldoornThe WebmenMagentoZend Framework

Page 3: Build That Phing!

><A build tool developed for and in PHPInstallation through PEAR or Composer$ pear channel-discover pear.phing.info$ pear install --alldeps phing/phing

Page 4: Build That Phing!

>< vs PHPPEAR

build.xml

Javaapt-get

build.xml

Page 5: Build That Phing!

Skeleton Application

Page 6: Build That Phing!
Page 7: Build That Phing!

build.xml

Page 8: Build That Phing!

<?xml version="1.0"?><project name="zf2" default="build">

<target name="build" />

</project>

Page 9: Build That Phing!

$ phing -lBuildfile: /var/www/zf2/build.xmlWarning: target 'build' has no tasks or dependenciesDefault target:------------------------------------------------------------------------------- build

Subtargets:------------------------------------------------------------------------------- build

Page 10: Build That Phing!

$ phingBuildfile: /var/www/zf2/build.xmlWarning: target 'build' has no tasks or dependencies

zf2 tutorial > build:

BUILD FINISHED

Total time: 0.0457 seconds

Page 11: Build That Phing!

FundamentalsProperties

FileSetsPatternSets

Tasks

Page 12: Build That Phing!

Properties<property name="build.dir" value="${project.basedir}/build" /><property name="dist.dir" value="${build.dir}/dist" /><property name="logs.dir" value="${build.dir}/logs" /><property name="cache.dir" value="${build.dir}/cache" /><property name="src.dir" value="${project.basedir}/module" />

Page 13: Build That Phing!

FileSets<fileset id="php.files" dir="."> <include name="*.php" /></fileset>

.|-- build.xml|-- example.php|-- phing-logic-1| ̀-- build.xml|-- phing-logic-2| |-- build.xml| ̀-- continue|-- phing-logic-foreach| |-- build.xml| ̀-- fruits| |-- apple.php| |-- banana.xml| |-- orange.xml| ̀-- pear.php-̀- qa-basics |-- build.xml |-- example.php ̀-- tests ̀-- ExampleTest.php

Page 14: Build That Phing!

<fileset id="php.files" dir="."> <include name="*/*.php" /></fileset>

.|-- build.xml|-- example.php|-- phing-logic-1| ̀-- build.xml|-- phing-logic-2| |-- build.xml| ̀-- continue|-- phing-logic-foreach| |-- build.xml| ̀-- fruits| |-- apple.php| |-- banana.xml| |-- orange.xml| ̀-- pear.php-̀- qa-basics |-- build.xml |-- example.php ̀-- tests ̀-- ExampleTest.php

Page 15: Build That Phing!

<fileset id="php.files" dir="."> <include name="**/*.php" /></fileset>

.|-- build.xml|-- example.php|-- phing-logic-1| ̀-- build.xml|-- phing-logic-2| |-- build.xml| ̀-- continue|-- phing-logic-foreach| |-- build.xml| ̀-- fruits| |-- apple.php| |-- banana.xml| |-- orange.xml| ̀-- pear.php-̀- qa-basics |-- build.xml |-- example.php ̀-- tests ̀-- ExampleTest.php

Page 16: Build That Phing!

PatternSets<patternset id="php.patternset"> <include name="*/src/**/*.php" /> <include name="*/view/**/*.phtml" /></patternset>

<fileset id="php.files" dir="${src.dir}"> <patternset refid="php.patternset" /></fileset>

Page 17: Build That Phing!

Let's put it together!<?xml version="1.0"?><project name="zf2" default="build">

<property name="build.dir" value="${project.basedir}/build" /> <property name="dist.dir" value="${build.dir}/dist" /> <property name="logs.dir" value="${build.dir}/logs" /> <property name="cache.dir" value="${build.dir}/cache" /> <property name="src.dir" value="${project.basedir}/module" />

<fileset id="php.files" dir="${src.dir}"> <include name="*/*.php" /> <include name="*/src/**/*.php" /> <include name="*/view/**/*.phtml" /> </fileset>

<target name="build" />

</project>

Page 18: Build That Phing!

$ phingBuildfile: /var/www/zf2/build.xmlWarning: target 'build' has no tasks or dependencies

zf2 > build:

BUILD FINISHED

Total time: 0.0492 seconds

Page 19: Build That Phing!

How do we use PhingQA during module development

Combination with CI

Page 20: Build That Phing!

Quality Assurance"Quality Assurance (QA) is a way of preventing

mistakes or defects in manufactured products andavoiding problems when delivering solutions or

services to customers."

Page 21: Build That Phing!

QA ToolsPHP LintPHP Mess DetectorPHP Code SnifferPHP Unit

Page 22: Build That Phing!

Example 1. <?php 2. 3. namespace My\Module 4. 5. class Example { 6. 7. function sum($x, $y, $z) 8. { 9. return $x + $y;10. }11.12. }13. ?>

Page 23: Build That Phing!

PHP LintBuilt into the PHP executable.Checks for syntax errors.

$ php -l example.php

PHP Parse error: syntax error, unexpected 'class' (T_CLASS), expecting \\ (T_NS_SEPARATOR) or ';' or '{' in example.php on line 5Errors parsing example.php

Page 24: Build That Phing!

Example 1. <?php 2. 3. namespace My\Module 4. 5. class Example { 6. 7. function sum($x, $y, $z) 8. { 9. return $x + $y;10. }11.12. }13. ?>

Page 25: Build That Phing!

PHP Mess DetectorInstallation through Git, Composer or as a PEAR package.Detects code smells such as:

Possible bugsSuboptimal codeOvercomplicated expressionsUnused parameters, methods, properties

$ phpmd example.php text cleancode,codesize,controversial,design,naming,unusedcode

example.php:7 Avoid variables with short names like $x. Configured minimum length is 3.example.php:7 Avoid variables with short names like $y. Configured minimum length is 3.example.php:7 Avoid variables with short names like $z. Configured minimum length is 3.example.php:7 Avoid unused parameters such as '$z'.

Page 26: Build That Phing!

Example 1. <?php 2. 3. namespace My\Module; 4. 5. class Example { 6. 7. function sum($x, $y, $z) 8. { 9. return $x + $y;10. }11.12. }13. ?>

Page 27: Build That Phing!

PHP Code SnifferInstallation through Git, Composer or as a PEAR package.Checks your code for coding standards such as:

PEARPSR1PSR2ZendSquiz

$ phpcs --standard=PSR2 example.php

--------------------------------------------------------------------------------FOUND 4 ERROR(S) AFFECTING 4 LINE(S)-------------------------------------------------------------------------------- 5 | ERROR | Opening brace of a class must be on the line after the definition 7 | ERROR | Visibility must be declared on method "sum" 12 | ERROR | The closing brace for the class must go on the next line after | | the body 13 | ERROR | A closing tag is not permitted at the end of a PHP file--------------------------------------------------------------------------------

Page 28: Build That Phing!

Example 1. <?php 2. 3. namespace My\Module; 4. 5. class Example { 6. 7. function sum($x, $y, $z) 8. { 9. return $x + $y;10. }11.12. }13. ?>

Page 29: Build That Phing!

PHP UnitInstallation through PHAR, Composer or as a PEAR package.Runs tests on your code.Provides a framework to create tests.

<?php

namespace My\Module;

require_once('example.php');

class ExampleTest extends \PHPUnit_Framework_TestCase{

public function testSum() { $example = new Example(); $this->assertEquals($example->sum(2, 3, 5), 10); }}

Page 30: Build That Phing!

PHP Unit$ phpunit .

PHPUnit 3.7.29 by Sebastian Bergmann.

F

Time: 17 ms, Memory: 2.75Mb

There was 1 failure:

1) My\Module\ExampleTest::testSumFailed asserting that 5 matches expected 10.

/var/www/talk-phing/web/examples/qa-basics/tests/ExampleTest.php:13

FAILURES!Tests: 1, Assertions: 1, Failures: 1.

Page 31: Build That Phing!

Example 1. <?php 2. 3. namespace My\Module; 4. 5. class Example { 6. 7. function sum($x, $y, $z) 8. { 9. return $x + $y;10. }11.12. }13. ?>

Page 32: Build That Phing!

TasksCore Tasks

AdhocTaskdefTaskAdhocTypedefTaskAppendTaskApplyTaskAvailableTaskChmodTaskChownTaskConditionTaskCopyTaskCvsTaskCvsPassTaskDeleteTaskEchoTask

ExecTaskFailTaskForeachTaskIfTaskImportTaskIncludePathTaskInputTaskLoadFileTaskMkdirTaskMoveTaskPhingTaskPhingCallTaskPhpEvalTask

PropertyTaskPropertyPromptTaskReflexiveTaskResolvePathTaskTaskdefTaskTouchTaskTryCatchTaskTstampTaskTypedefTaskUpToDateTaskWaitForTaskXsltTask

Page 33: Build That Phing!

Optional TasksApiGenTaskCoverageMergerTaskCoverageReportTaskCoverageSetupTaskCoverageThresholdTaskDbDeployTaskDocBloxTaskExportPropertiesTaskFileHashTaskFileSizeTaskFileSyncTaskFtpDeployTaskGitInitTaskGitCloneTaskGitGcTaskGitBranchTaskGitFetchTaskGitCheckoutTaskGitCommitTaskGitMergeTask

GitPullTaskGitPushTaskGitTagTaskGitLogTaskGrowlNotifyTaskHttpGetTaskHttpRequestTaskIoncubeEncoderTaskIoncubeLicenseTaskJslLintTaskJsMinTaskLiquibaseChangeLogTaskLiquibaseDbDocTaskLiquibaseDiffTaskLiquibaseRollbackTaskLiquibaseTagTaskLiquibaseUpdateTaskMailTaskParallelTaskPatchTask

Page 34: Build That Phing!

PDOSQLExecTaskPearPackageTaskPearPackage2TaskPharPackageTaskPhkPackageTaskPhpCodeSnifferTaskPHPCPDTaskPHPLocTaskPHPMDTaskPhpDependTaskPhpDocumentorTaskDocBloxTaskPhpDocumentorExternalTaskPhpLintTaskPHPUnitTaskPHPUnitReportrSTTaskS3PutTaskS3GetTaskScpTask

SshTaskSimpleTestTaskSvnCheckoutTaskSvnCommitTaskSvnCopyTaskSvnExportTaskSvnInfoTaskSvnLastRevisionTaskSvnListTaskSvnLogTaskSvnUpdateTaskSvnSwitchTaskSymfonyConsoleTaskSymlinkTaskTarTaskUntarTaskUnzipTaskVersionTaskWikiPublishTaskXmlLintTask

Page 35: Build That Phing!

XmlPropertyTaskZendCodeAnalyzerTaskZendGuardEncodeTaskZendGuardLicenseTaskZipTask

Page 36: Build That Phing!

Automating QA

Page 37: Build That Phing!

PHPLint Task<target name="phplint"> <phplint haltonfailure="true" cachefile="${cache.dir}/lint.cache"> <fileset refid="php.files" /> </phplint></target>

Page 38: Build That Phing!

PHPCodeSniffer Task<target name="phpcs"> <phpcodesniffer standard="PSR2"> <fileset refid="php.files" /> <formatter type="full" usefile="false" /> </phpcodesniffer></target>

Page 39: Build That Phing!

PHPMD Task<target name="phpmd"> <phpmd> <fileset refid="php.files" /> </phpmd></target>

Page 40: Build That Phing!

PHPUnit Task<target name="phpunit"> <exec command="phpunit -c ${src.dir}/Application/test/" passthru="true" checkreturn="true" /> <exec command="phpunit -c ${src.dir}/Album/test/" passthru="true" checkreturn="true" /></target>

Page 41: Build That Phing!

<?xml version="1.0"?><project name="zf2" default="build"> <property name="build.dir" value="${project.basedir}/build" /> <property name="dist.dir" value="${build.dir}/dist" /> <property name="logs.dir" value="${build.dir}/logs" /> <property name="cache.dir" value="${build.dir}/cache" /> <property name="src.dir" value="${project.basedir}/module" /> <fileset id="php.files" dir="${src.dir}"> <include name="*/*.php" /> <include name="*/src/**/*.php" /> <include name="*/view/**/*.phtml" /> </fileset> <target name="build" /> <target name="phplint"> <phplint haltonfailure="true" cachefile="${cache.dir}/lint.cache"> <fileset refid="php.files" /> </phplint> </target> <target name="phpcs"> <phpcodesniffer standard="PSR2"> <fileset refid="php.files" /> <formatter type="full" usefile="false" /> </phpcodesniffer> </target> <target name="phpmd"> <phpmd> <fileset refid="php.files" /> </phpmd> </target> <target name="phpunit"> <exec command="phpunit -c ${src.dir}/Application/test/" passthru="true" checkreturn="true" /> <exec command="phpunit -c ${src.dir}/Album/test/" passthru="true" checkreturn="true" /> </target></project>

Page 42: Build That Phing!

$ phingBuildfile: /var/www/zf2/build.xmlWarning: target 'build' has no tasks or dependencies

zf2 > build:

BUILD FINISHED

Total time: 0.0540 seconds

Page 43: Build That Phing!

Dependencies<target name="build" depends="phplint, phpcs, phpmd, phpunit" />

Page 44: Build That Phing!

$ phingBuildfile: /var/www/zf2/build.xml

zf2 > phplint:

BUILD FAILEDexception 'IOException' with message 'Unable to open /var/www/zf2/build/cache/lint.cache for writing: ' in /usr/share/php/phing/system/io/FileOutputStream.php:59Stack trace:#0 /usr/share/php/phing/system/io/FileWriter.php(38): FileOutputStream->__construct(Object(PhingFile), false)#1 /usr/share/php/phing/util/DataStore.php(146): FileWriter->__construct(Object(PhingFile))#2 /usr/share/php/phing/util/DataStore.php(107): DataStore->write()#3 /usr/share/php/phing/tasks/ext/PhpLintTask.php(198): DataStore->commit()#4 /usr/share/php/phing/UnknownElement.php(96): PhpLintTask->main()#5 /usr/share/php/phing/Task.php(260): UnknownElement->main()#6 /usr/share/php/phing/Target.php(297): Task->perform()#7 /usr/share/php/phing/Target.php(320): Target->main()#8 /usr/share/php/phing/Project.php(824): Target->performTasks()#9 /usr/share/php/phing/Project.php(797): Project->executeTarget('build')#10 /usr/share/php/phing/Phing.php(586): Project->executeTargets(Array)#11 /usr/share/php/phing/Phing.php(170): Phing->runBuild()#12 /usr/share/php/phing/Phing.php(278): Phing::start(Array, NULL)#13 /usr/share/php/phing.php(43): Phing::fire(Array)#14 {main}

Total time: 0.1397 seconds

Page 45: Build That Phing!

<target name="prepare"> <mkdir dir="${build.dir}" /> <mkdir dir="${dist.dir}" /> <mkdir dir="${logs.dir}" /> <mkdir dir="${cache.dir}" /></target>

Page 46: Build That Phing!

<target name="-prepare" hidden="true"> <mkdir dir="${build.dir}" /> <mkdir dir="${dist.dir}" /> <mkdir dir="${logs.dir}" /> <mkdir dir="${cache.dir}" /></target>

© Stephan Hochdörfer

Page 47: Build That Phing!

<target name="phplint" depends="-prepare"> <!-- ... --></target>

<target name="phpcs" depends="-prepare"> <!-- ... --></target>

<target name="phpmd" depends="-prepare"> <!-- ... --></target>

<target name="phpunit" depends="-prepare"> <!-- ... --></target>

Page 48: Build That Phing!

$ phingBuildfile: /var/www/zf2/build.xml

zf2 > -prepare:

zf2 > phplint:

zf2 > phpcs:

FILE: /var/www/zf2/module/Application/view/layout/layout.phtml--------------------------------------------------------------------------------FOUND 0 ERROR(S) AND 5 WARNING(S) AFFECTING 5 LINE(S)-------------------------------------------------------------------------------- 6 | WARNING | Line exceeds 120 characters; contains 127 characters 11 | WARNING | Line exceeds 120 characters; contains 154 characters 17 | WARNING | Line exceeds 120 characters; contains 137 characters 33 | WARNING | Line exceeds 120 characters; contains 125 characters 36 | WARNING | Line exceeds 120 characters; contains 123 characters--------------------------------------------------------------------------------

Page 49: Build That Phing!

zf2 > phpmd:

[phpmd] Processing files...

/var/www/zf2/module/Album/src/Album/Form/AlbumForm.php:8 Avoid unused parameters such as '$name'./var/www/zf2/module/Album/src/Album/Model/Album.php:33 Avoid unused parameters such as '$inputFilter'. [phpmd] Finished processing files

zf2 > phpunit:

PHPUnit 4.0.14 by Sebastian Bergmann.

Configuration read from /var/www/zf2/module/Application/test/phpunit.xml.dist

.

Time: 42 ms, Memory: 5.75Mb

OK (1 test, 1 assertion)

PHPUnit 4.0.14 by Sebastian Bergmann.

Configuration read from /var/www/zf2/module/Album/test/phpunit.xml.dist

.............

Time: 72 ms, Memory: 8.50Mb

OK (13 tests, 22 assertions)

zf2 > build:

BUILD FINISHED

Page 50: Build That Phing!

Logical tasksIfTask

ConditionTaskFailTask

ForeachTask

Page 51: Build That Phing!

IfTask<property name="foo" value="bar" /><if> <equals arg1="${foo}" arg2="bar" /> <then> <echo message="The value of property foo is bar" /> </then> <else> <echo message="The value of property foo is not bar" /> </else></if>

Page 52: Build That Phing!

ConditionTask<condition property="IsPhingRecursiveAcronym"> <contains string="PHing Is Not GNU make" substring="phing" casesensitive="false" /></condition><if> <istrue value="${IsPhingRecursiveAcronym}" /> <then> <echo message="It's recursive!" /> </then> <else> <echo message="It's not recursive!" /> </else></if>

$ phingBuildfile: /var/www/talk-phing/web/examples/phing-condition-task/build.xml

Example > build:

[echo] It's recursive!

BUILD FINISHED

Total time: 0.0487 seconds

Page 53: Build That Phing!

<condition property="IsXmlRecursiveAcronym"> <contains string="Extensible Markup Language" substring="XML" casesensitive="false" /></condition><if> <istrue value="${IsXmlRecursiveAcronym}" /> <then> <echo message="It's recursive!" /> </then> <else> <echo message="It's not recursive!" /> </else></if>

$ phingBuildfile: /var/www/talk-phing/web/examples/phing-condition-task/build.xml

Example > build:

[echo] It's recursive!

BUILD FINISHED

Total time: 0.0524 seconds

Page 54: Build That Phing!

<condition property="IsXmlRecursiveAcronym"> <contains string="Extensible Markup Language" substring="XML" casesensitive="false" /></condition><if> <isset property="IsXmlRecursiveAcronym" /> <then> <echo message="It's recursive!" /> </then> <else> <echo message="It's not recursive!" /> </else></if>

$ phingBuildfile: /var/www/talk-phing/web/examples/phing-condition-task/build.xml

Example > build:

[echo] It's not recursive!

BUILD FINISHED

Total time: 0.0468 seconds

Page 55: Build That Phing!

FailTask<fail message="Failed for some reason!" />

<fail if="errorprop" message="Detected error!" />

<fail unless="dontfail" message="Detected error!" />

Page 56: Build That Phing!

ForeachTask<fileset id="fruits" dir="."> <include name="fruits/*.xml" /> <include name="**/*.php" /></fileset>

<target name="build"> <foreach param="fruit" target="displayfruit"> <fileset refid="fruits" /> </foreach> <foreach list="apple;orange;pear;banana" target="displayfruit" param="fruit" delimiter=";" /></target>

<target name="displayfruit"> <echo message="${fruit}" /></target>

Page 57: Build That Phing!

Interesting TasksPropertyPromptTask

PhpEvalTask

Page 58: Build That Phing!

PropertyPromptTask<?xml version="1.0" encoding="UTF-8"?><project name="Example" default="build">

<propertyprompt propertyName="messages.name" promptText="Please enter your name" defaultValue="anonymous" />

<property name="messages.welcome" value="Hello, ${messages.name}!" />

<target name="build" description="Displays the project name and a personalized welcome message" <echo message="${phing.project.name}: ${messages.welcome}" /> </target>

</project>

Page 59: Build That Phing!

$ phingBuildfile: /var/www/talk-phing/web/examples/phing-prompt/build.xml

Please enter your name [anonymous] ? Rick

Example > build:

[echo] Example: Hello, Rick!

BUILD FINISHED

Total time: 3.7389 seconds

Page 60: Build That Phing!

PhpEvalTask<?xml version="1.0" encoding="UTF-8"?><project name="Example" default="build">

<target name="build"> <php expression="function increment($i) { return ++$i; }" /> <php function="increment" returnProperty="result"> <param>1</param> </php> <echo message="${result}" /> </target>

</project>

Page 61: Build That Phing!

$ phingBuildfile: /var/www/talk-phing/web/examples/phing-php-eval/build.xml

Example > build:

[php] Evaluating PHP expression: function increment($i) { return ++$i; } [php] Calling PHP function: increment() [echo] 2

BUILD FINISHED

Total time: 0.0511 seconds

Page 62: Build That Phing!

<?xml version="1.0"?><project name="Testing Framework" default="build"> <property name="haltOnFail" value="true" />

<target name="build"> <php function="ucfirst" returnProperty="result"> <param>phing</param> </php> <property name="expected" value="Phing" override="true" /> <phingcall target="test" />

<php expression="preg_replace('/php/', 'xml', 'PHP')" returnProperty="result" /> <property name="expected" value="xml" override="true" /> <phingcall target="test" /> </target>

<target name="test"> <if> <equals arg1="${result}" arg2="${expected}" casesensitive="true" /> <then> <echo>✔ </echo> </then> <else> <echo>✘</echo> <fail if="haltOnFail">Expected: ${expected}Result: ${result}</fail> </else> </if> </target></project>

Page 63: Build That Phing!

$ phingBuildfile: /var/www/talk-phing/web/examples/phing-testing-framework/build.xml

Testing Framework > build:

[php] Calling PHP function: ucfirst()[phingcall] Calling Buildfile '/var/www/talk-phing/web/examples/phing-testing-framework/build.xml' with target 'test'

Testing Framework > test:

[echo] ✔ [php] Evaluating PHP expression: preg_replace('/php/', 'xml', 'PHP')[phingcall] Calling Buildfile '/var/www/talk-phing/web/examples/phing-testing-framework/build.xml' with target 'test'

Testing Framework > test:

[echo] ✘ [if] Error in IfTaskExecution of target "test" failed for the following reason: /var/www/talk-phing/web/examples/phing-testing-framework/build.xml:19:12: Error in IfTaskPrevious exception 'BuildException' with message '/var/www/talk-phing/web/examples/phing-testing-framework/build.xml:26:25: /var/www/talk-phing/web/examples/phing-testing-framework/build.xml:26:25:Expected: xmlResult: PHP

Page 64: Build That Phing!

Extending our phpunit target<target name="phpunit" depends="-prepare"> <propertyprompt defaultValue="all" promptText="Which module would you like to run the tests for?" propertyName="module" /> <if> <equals arg1="${module}" arg2="all" /> <then> <phingcall target="-run-all-tests" /> </then> <else> <property name="absFile" value="${src.dir}/${module}/test/phpunit.xml.dist" /> <phingcall target="-run-test" /> </else> </if></target>

<target name="-run-all-tests" hidden="true"> <foreach param="file" absparam="absFile" target="-run-test"> <fileset dir="${src.dir}"> <include name="*/test/phpunit.xml*" /> </fileset> </foreach></target>

<target name="-run-test" hidden="true"> <php function="dirname" returnProperty="phpunitConfigDir"> <param>${absFile}</param> </php> <exec command="phpunit -c ${phpunitConfigDir}" passthru="true" checkreturn="true" /></target>

Page 65: Build That Phing!

Create your own Task

Page 66: Build That Phing!

VDDvar_dump driven development

XDebug or PHPDBG

Page 67: Build That Phing!

VarDumpTaskAccept a filesetFind lines that contain var_dumpIgnore commentsShow the files and line numbers that matchHalt on match

Page 68: Build That Phing!

<?php

require_once 'phing/Task.php';

class VarDumpTask extends Task{

public function main() {

}}

Page 69: Build That Phing!

<?php

require_once 'phing/Task.php';include_once 'phing/types/FileSet.php';

class VarDumpTask extends Task{

protected $_fileSets = array();

public function main() {

}

public function createFileSet() { $num = array_push($this->_fileSets, new FileSet()); return $this->_fileSets[$num-1]; }}

Page 70: Build That Phing!

<?php

require_once 'phing/Task.php';include_once 'phing/types/FileSet.php';

class VarDumpTask extends Task{

protected $_fileSets = array();

public function main() { if (!count($this->_fileSets)) { throw new BuildException("Missing a nested fileset"); } }

public function createFileSet() { $num = array_push($this->_fileSets, new FileSet()); return $this->_fileSets[$num-1]; }}

Page 71: Build That Phing!

<?php

require_once 'phing/Task.php';include_once 'phing/types/FileSet.php';

class VarDumpTask extends Task{ const VAR_DUMP = 'var_dump(';

protected $_fileSets = array();

public function main() { if (!count($this->_fileSets)) { throw new BuildException("Missing a nested fileset"); }

$project = $this->getProject();

foreach ($this->_fileSets as $fs) {

$files = $fs->getDirectoryScanner($project)->getIncludedFiles(); $dir = $fs->getDir($this->project)->getPath();

foreach($files as &$file) { $fullfile = $dir . DIRECTORY_SEPARATOR . $file; if (($nr = $this->_grep($fullfile, self::VAR_DUMP, '//'))) { $this->log($fullfile . ':' . $nr); } } } }

public function createFileSet() { $num = array_push($this->_fileSets, new FileSet());

Page 72: Build That Phing!

protected function _grep($file, $val, $ignoreLinesWith = null) { $lines = file($file);

foreach ($lines as $nr => $line) { if (strpos($line, $val) !== false) { if (!isset($ignoreLinesWith) || strpos($line, $ignoreLinesWith) === false) { return $nr; } } }

return false; }

Page 73: Build That Phing!

protected $_haltOnMatch = false;

public function setHaltOnMatch($haltOnMatch = null) { if (isset($haltOnMatch)) { $this->_haltOnMatch = true; } }

Page 74: Build That Phing!

public function main() { if (!count($this->_fileSets)) { throw new BuildException("Missing a nested fileset"); }

$project = $this->getProject(); $found = false;

foreach ($this->_fileSets as $fs) { $files = $fs->getDirectoryScanner($project)->getIncludedFiles(); $dir = $fs->getDir($project)->getPath();

foreach($files as &$file) { $fullfile = $dir . DIRECTORY_SEPARATOR . $file; if (($nr = $this->_grep($fullfile, self::VAR_DUMP, '//'))) { $this->log($fullfile . ':' . $nr); $found = true; } } }

if ($found && $this->_haltOnMatch) { throw new BuildException('Found traces of var_dump in filesets'); } }

Page 75: Build That Phing!

Defining your taskAdhocTaskdefTask

TaskdefTask

Page 76: Build That Phing!

AdhocTaskdefTask<adhoc-task name="foo"> <![CDATA[ class FooTest extends Task { private $bar;

function setBar($bar) { $this->bar = $bar; }

function main() { $this->log("In FooTest: " . $this->bar); } } ]]></adhoc-task>

Page 77: Build That Phing!

TaskdefTask<taskdef name="vdd" classname="phing.tasks.VarDumpTask" />

Page 78: Build That Phing!

Using our VarDumpTask<taskdef name="vdd" classname="phing.tasks.VarDumpTask" />

<target name="vdd" depends="-prepare"> <vdd haltOnMatch="true"> <fileset refid="php.files" /> </vdd></target>

Page 79: Build That Phing!

$ phing vddBuildfile: /var/www/zf2/build.xml

zf2 > -prepare:

zf2 > vdd:

[vdd] /var/www/zf2/module/Album/Module.php:15Execution of target "vdd" failed for the following reason: /var/www/zf2/build.xml:48:25: Found traces of var_dump in filesets

BUILD FAILED/var/www/zf2/build.xml:48:25: Found traces of var_dump in filesetsTotal time: 0.0687 seconds

Page 80: Build That Phing!

<?xml version="1.0"?><project name="zf2" default="build">

<taskdef name="vdd" classname="phing.tasks.VarDumpTask" />

<property name="build.dir" value="${project.basedir}/build" /> <property name="dist.dir" value="${build.dir}/dist" /> <property name="logs.dir" value="${build.dir}/logs" /> <property name="cache.dir" value="${build.dir}/cache" /> <property name="src.dir" value="${project.basedir}/module" />

<fileset id="php.files" dir="${src.dir}"> <include name="*/*.php" /> <include name="*/src/**/*.php" /> <include name="*/view/**/*.phtml" /> </fileset>

<target name="build" depends="phplint, phpcs, phpmd, phpunit, vdd" />

<target name="-prepare" hidden="true"> <mkdir dir="${build.dir}" /> <mkdir dir="${dist.dir}" /> <mkdir dir="${logs.dir}" /> <mkdir dir="${cache.dir}" /> </target>

Page 81: Build That Phing!

<target name="phplint" depends="-prepare"> <phplint haltonfailure="true" cachefile="${cache.dir}/lint.cache"> <fileset refid="php.files" /> </phplint> </target>

<target name="phpcs" depends="-prepare"> <phpcodesniffer standard="PSR2"> <fileset refid="php.files" /> <formatter type="full" usefile="false" /> </phpcodesniffer> </target>

<target name="phpmd" depends="-prepare"> <phpmd> <fileset refid="php.files" /> </phpmd> </target>

<target name="vdd" depends="-prepare"> <vdd haltOnMatch="true"> <fileset refid="php.files" /> </vdd> </target>

Page 82: Build That Phing!

<target name="phpunit" depends="-prepare"> <propertyprompt defaultValue="all" promptText="Which module would you like to run the tests for?" propertyName="module" /> <if> <equals arg1="${module}" arg2="all" /> <then> <phingcall target="-run-all-tests" /> </then> <else> <property name="absFile" value="${src.dir}/${module}/test/phpunit.xml.dist" /> <phingcall target="-run-test" /> </else> </if> </target>

<target name="-run-all-tests" hidden="true"> <foreach param="file" absparam="absFile" target="-run-test"> <fileset dir="${src.dir}"> <include name="*/test/phpunit.xml*" /> </fileset> </foreach> </target>

<target name="-run-test" hidden="true"> <php function="dirname" returnProperty="phpunitConfigDir"> <param>${absFile}</param> </php> <exec command="phpunit -c ${phpunitConfigDir}" passthru="true" checkreturn="true" /> </target>

</project>

Page 83: Build That Phing!

Duplicate build file logicBuild file inheritance

Git submodules

Page 84: Build That Phing!

phing/default.xml<?xml version="1.0"?><project name="zf2"> <taskdef name="vdd" classname="phing.tasks.VarDumpTask" />

<property name="build.dir" value="${project.basedir}/build" /> <property name="dist.dir" value="${build.dir}/dist" /> <property name="logs.dir" value="${build.dir}/logs" /> <property name="cache.dir" value="${build.dir}/cache" /> <property name="src.dir" value="${project.basedir}/module" />

<fileset id="php.files" dir="${src.dir}"> <include name="*/*.php" /> <include name="*/src/**/*.php" /> <include name="*/view/**/*.phtml" /> </fileset>

<target name="-prepare" hidden="true"> <mkdir dir="${build.dir}" /> <mkdir dir="${dist.dir}" /> <mkdir dir="${logs.dir}" /> <mkdir dir="${cache.dir}" /> </target>

<target name="phplint" depends="-prepare"> <phplint haltonfailure="true" cachefile="${cache.dir}/lint.cache"> <fileset refid="php.files" /> </phplint> </target>

<target name="phpcs" depends="-prepare"> <phpcodesniffer standard="PSR2"> <fileset refid="php.files" /> <formatter type="full" usefile="false" />

Page 85: Build That Phing!

build.xml<?xml version="1.0"?><project name="zf2" default="build">

<import file="phing/default.xml" />

<target name="build" depends="phplint, phpcs, phpmd, phpunit, vdd" />

</project>

Page 86: Build That Phing!

Documentationhttp://www.phing.info/docs/guide/stable/https://github.com/phingofficial/phing