SlideShare a Scribd company logo
1 of 65
Download to read offline
QA	
  for	
  PHP	
  projects
using	
  PHPStorm
JetBrains	
  Webinar,	
  April	
  25	
  2013
2
Michelangelo	
  van	
  Dam
Goals
3
• improve	
  QA	
  in	
  your	
  PHP	
  projects
• deliver	
  higher	
  quality	
  of	
  applicaIons
• become	
  familiarized	
  with	
  available	
  tools
Our	
  host	
  for	
  this	
  webinar
4
Why	
  Quality	
  Assurance
5
6
Safeguarding	
  code
7
Detect	
  bugs	
  early
8
Observe	
  behaviour
9
Prevent	
  accidents
10
Tracking	
  progress
Let’s	
  get	
  our	
  hands	
  dirty
11
Revision	
  Control
12
13
FTP
Advantages of SCM
• team development possible
• tracking multi-versions of source code
• moving back and forth in history
• tagging of milestones
• backup of source code
• accessible from
- command line
- native apps
- IDE’s like JetBrain’s IDE
- analytical tools
TIP:	
  hooks	
  for	
  tools
PHP	
  Lint
15
PHP	
  Lint
16
• checks the syntax of code
• build in PHP core
• is used per file
- pre-commit hook for version control system
- batch processing of files
• can provide reports
- but if something fails -> the build fails
TIP:	
  pre-­‐commit	
  hook
Running	
  on	
  command	
  line
17
SCM	
  commit	
  hook
18
#!/bin/sh
#
# Pre-commit hook to validate syntax of incoming PHP files, if no failures it
# accepts the commit, otherwise it fails and blocks the commit
REPOS="$1"
TXN="$2"
# modify these system executables to match your system
PHP=/usr/bin/php
AWK=/usr/bin/awk
GREP=/bin/grep
SVNLOOK=/usr/bin/svnlook
# PHP Syntax checking with PHP Lint
# originally from Joe Stump at Digg
# https://gist.github.com/53225
#
for i in `$SVNLOOK changed -t "$TXN" "$REPOS" | $AWK '{print $2}'`
do
if [ ${i##*.} == php ]; then
CHECK=`$SVNLOOK cat -t "$TXN" "$REPOS" $i | $PHP -d html_errors=off -l || echo $i`
RETURN=`echo $CHECK | $GREP "^No syntax" > /dev/null && echo TRUE || echo FALSE`
if [ $RETURN = 'FALSE' ]; then
echo $CHECK 1>&2;
exit 1
fi
fi
done
No	
  syntax	
  failures
19
PHPStorm	
  syntax	
  checking
20
DocumentaIon
21
Why	
  documenIng?
22
• new	
  members	
  in	
  the	
  team
• working	
  with	
  remote	
  workers
• analyzing	
  improvements
• think	
  before	
  doing
• used	
  by	
  IDE’s	
  and	
  editors	
  for	
  code	
  hinIng	
  ;-­‐)
PHPDocumentor2
23
Class	
  details
24
Uses	
  docblock	
  in	
  code
25
Class	
  graphs
26
Debugging
27
The	
  art	
  of	
  finding	
  a	
  bug
28
• Debugging	
  allows	
  you	
  to	
  walk	
  step-­‐by-­‐step	
  
through	
  your	
  code	
  base	
  unIl	
  you	
  reach	
  the	
  
point	
  of	
  failure.
XDebug	
  php.ini	
  se`ngs
[xdebug]
zend_extension=/usr/lib/php/extensions/xdebug.so
xdebug.default_enable=1
xdebug.cli_color=1
xdebug.remote_enable=on
xdebug.remote_connect_back=1
xdebug.remote_handler=dbgp
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000
xdebug.scream=1
29
Debugging	
  in	
  PHPStorm
30
TesIng
31
Most	
  common	
  excuses
32
• no	
  Ime
• not	
  within	
  budget
• development	
  team	
  does	
  not	
  know	
  how
• tests	
  are	
  provided	
  aaer	
  delivery
• …
NO	
  EXCUSE!
33
Benefits	
  of	
  tesIng
34
• beder	
  code	
  with	
  smaller	
  footprint
• allows	
  refactoring
• detects	
  bugs	
  in	
  an	
  early	
  stage
• saves	
  Ime	
  in	
  maintenance	
  stage
Se`ng	
  things	
  up
35
ConfiguraIon:	
  phpunit.xml
36
<phpunit bootstrap="./Bootstrap.php">
<testsuite name="Unit test suite">
<directory>./</directory>
</testsuite>
<filter>
<whitelist>
<directory suffix=".php">../application/</directory>
<directory suffix=".php">../library/</directory>
</whitelist>
</filter>
</phpunit>
Bootstrapping	
  app
<?php
// set our app paths and environments
define('BASE_PATH', realpath(dirname(__FILE__) . '/../'));
define('APPLICATION_PATH', BASE_PATH . '/application');
define('TEST_PATH', BASE_PATH . '/tests');
define('APPLICATION_ENV', 'testing');
// Include path
set_include_path(
. PATH_SEPARATOR . BASE_PATH . '/library'
. PATH_SEPARATOR . get_include_path()
);
// Set the default timezone !!!
date_default_timezone_set('Europe/Brussels');
// We wanna catch all errors en strict warnings
error_reporting(E_ALL|E_STRICT);
require_once 'Zend/Application.php';
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap();
37
WriIng	
  tests
38
TesIng	
  a	
  class
39
WriIng	
  a	
  test
40
<?php
class Application_Model_CommentTest extends PHPUnit_Framework_TestCase
{
protected $_comment;
protected function setUp()
{
$this->_comment = new Application_Model_Comment();
parent::setUp();
}
protected function tearDown()
{
parent::tearDown();
$this->_comment = null;
}
public function testModelIsEmptyAtConstruct()
{
$this->assertSame(0, $this->_comment->getId());
$this->assertNull($this->_comment->getFullName());
$this->assertNull($this->_comment->getEmailAddress());
$this->assertNull($this->_comment->getWebsite());
$this->assertNull($this->_comment->getComment());
}
}
WriIng	
  the	
  class
<?php
class Application_Model_Comment
{
protected $_id = 0; protected $_fullName; protected $_emailAddress;
protected $_website; protected $_comment;
public function setId($id) { $this->_id = (int) $id; return $this; }
public function getId() { return $this->_id; }
public function setFullName($fullName) { $this->_fullName = (string) $fullName; return $this; }
public function getFullName() { return $this->_fullName; }
public function setEmailAddress($emailAddress) { $this->_emailAddress = (string) $emailAddress; return $this; }
public function getEmailAddress() { return $this->_emailAddress; }
public function setWebsite($website) { $this->_website = (string) $website; return $this; }
public function getWebsite() { return $this->_website; }
public function setComment($comment) { $this->_comment = (string) $comment; return $this; }
public function getComment() { return $this->_comment; }
public function populate($row) {
if (is_array($row)) {
$row = new ArrayObject($row, ArrayObject::ARRAY_AS_PROPS);
}
if (isset ($row->id)) $this->setId($row->id);
if (isset ($row->fullName)) $this->setFullName($row->fullName);
if (isset ($row->emailAddress)) $this->setEmailAddress($row->emailAddress);
if (isset ($row->website)) $this->setWebsite($row->website);
if (isset ($row->comment)) $this->setComment($row->comment);
}
public function toArray() {
return array (
'id' => $this->getId(),
'fullName' => $this->getFullName(),
'emailAddress' => $this->getEmailAddress(),
'website' => $this->getWebsite(),
'comment' => $this->getComment(),
);
}
}
41
Adding	
  validaIon
protected $_filters;
protected $_validators;
public function __construct($params = null)
{
$this->_filters = array (
'id' => array ('Int'),
'fullName' => array ('StringTrim', 'StripTags', new Zend_Filter_Alnum(true)),
'emailAddress' => array ('StringTrim', 'StripTags', 'StringToLower'),
'website' => array ('StringTrim', 'StripTags', 'StringToLower'),
'comment' => array ('StringTrim', 'StripTags'),
);
$this->_validators = array (
'id' => array ('Int'),
'fullName' => array (
new Zftest_Validate_Mwop(),
new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)),
),
'emailAddress' => array (
'EmailAddress',
new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)),
),
'website' => array (
new Zend_Validate_Callback(array('Zend_Uri', 'check')),
new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)),
),
'comment' => array (
new Zftest_Validate_TextBox(),
new Zend_Validate_StringLength(array ('max' => 5000)),
),
);
if (null !== $params) { $this->populate($params); }
}
42
Modify	
  seders	
  &	
  geders
public function setId($id)
{
$input = new Zend_Filter_Input($this->_filters, $this->_validators);
$input->setData(array ('id' => $id));
if (!$input->isValid('id')) {
throw new Zend_Exception('Invalid ID provided');
}
$this->_id = (int) $input->id;
return $this;
}
public function setFullName($fullName)
{
$input = new Zend_Filter_Input($this->_filters, $this->_validators);
$input->setData(array ('fullName' => $fullName));
if (!$input->isValid('fullName')) {
throw new Zend_Exception('Invalid fullName provided');
}
$this->_fullName = (string) $input->fullName;
return $this;
}
43
Modify	
  seders	
  &	
  geders	
  2
public function setEmailAddress($emailAddress)
{
$input = new Zend_Filter_Input($this->_filters, $this->_validators);
$input->setData(array ('emailAddress' => $emailAddress));
if (!$input->isValid('emailAddress')) {
throw new Zend_Exception('Invalid emailAddress provided');
}
$this->_emailAddress = (string) $input->emailAddress;
return $this;
}
public function setWebsite($website)
{
$input = new Zend_Filter_Input($this->_filters, $this->_validators);
$input->setData(array ('website' => $website));
if (!$input->isValid('website')) {
throw new Zend_Exception('Invalid website provided');
}
$this->_website = (string) $input->website;
return $this;
}
44
Modify	
  geders	
  &	
  seders	
  3
public function setComment($comment)
{
$input = new Zend_Filter_Input($this->_filters, $this->_validators);
$input->setData(array ('comment' => $comment));
if (!$input->isValid('comment')) {
throw new Zend_Exception('Invalid comment provided');
}
$this->_comment = (string) $input->comment;
return $this;
}
45
Running	
  tests
46
Or	
  in	
  PHPStorm
47
Mess	
  DetecIon
48
Mess	
  DetecIon
49
• code	
  smells
• possible	
  bugs
• sub-­‐opImal	
  code
• over	
  complicated	
  expressions
• unused	
  parameters,	
  methods	
  and	
  properIes
• wrongly	
  named	
  parameters,	
  methods	
  or	
  
properIes
Running	
  on	
  command	
  line
50
Running	
  in	
  PHPStorm
51
AutomaIon
52
Key	
  reason
53
“computers are great at doing repetitive tasks very well”
AutomaIon
54
• Limit	
  risk	
  of	
  human	
  error
• Will	
  always	
  be	
  executed	
  in	
  same	
  order
• Can	
  be	
  shared	
  amongst	
  team	
  members
• Allows	
  to	
  fine-­‐tune	
  and	
  improve	
  features
55
AutomaIon	
  with	
  Phing
Running	
  Phing	
  on	
  CLI
56
Running	
  in	
  PHPStorm
57
Summary
58
Overview	
  of	
  tools
59
• SCM	
  (SVN,	
  GIT,	
  …)
• PHP	
  Lint
• PHP	
  Document	
  Generator
• Debugging
• PHPUnit	
  TesIng
• PHP	
  Mess	
  detecIon
• Phing	
  automaIon
}
Quality	
  Assurance
• is	
  part	
  of	
  development	
  process
• will	
  only	
  work	
  if	
  the	
  tools	
  are	
  available
• and	
  developers	
  see	
  the	
  benefits	
  of	
  QA
60
PHPStorm	
  IDE
61
Contact
62
Michelangelo van Dam
Zend Certified Engineer
email: michelangelo@in2it.be
skype: michelangelovandam
twitter: @DragonBe
tel EU: +32 15 34 52 90
tel US: 202 559-7401
www.in2it.be
facebook.com/in2itvof | @in2itvof
Contact us for
Consultancy - Training - QA - Webdesign
Credits
I’d like to thank the following people for sharing their creative commons pictures
michelangelo: http://www.flickr.com/photos/dasprid/5148937451
birds: http://www.flickr.com/photos/andyofne/4633356197
safeguarding: http://www.flickr.com/photos/infidelic/4306205887/
bugs: http://www.flickr.com/photos/goingslo/4523034319
behaviour: http://www.flickr.com/photos/yuan2003/1812881370
prevention: http://www.flickr.com/photos/robertelyov/5159801170
progress: http://www.flickr.com/photos/dingatx/4115844000
file cabinet: http://www.flickr.com/photos/manc/1427691715
documentation: http://www.flickr.com/photos/dennis_matheson/3269442687
exam: http://www.flickr.com/photos/albertogp123/5843577306
dead roach: http://www.flickr.com/photos/stevensnodgrass/7504408776
garbage: http://www.flickr.com/photos/amstersam/4608512202
gears: http://www.flickr.com/photos/freefoto/5982549938
elephpant: http://www.flickr.com/photos/drewm/3191872515
Fork	
  this	
  code
http://github.com/DragonBe/zftest
64
Thank	
  you
65

More Related Content

What's hot

UA testing with Selenium and PHPUnit - PFCongres 2013
UA testing with Selenium and PHPUnit - PFCongres 2013UA testing with Selenium and PHPUnit - PFCongres 2013
UA testing with Selenium and PHPUnit - PFCongres 2013Michelangelo van Dam
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
Dependency Injection in PHP
Dependency Injection in PHPDependency Injection in PHP
Dependency Injection in PHPKacper Gunia
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsMichelangelo van Dam
 
TDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for BusinessTDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for Businesstdc-globalcode
 
PHP 7 Crash Course
PHP 7 Crash CoursePHP 7 Crash Course
PHP 7 Crash CourseColin O'Dell
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
PHP security audits
PHP security auditsPHP security audits
PHP security auditsDamien Seguy
 
Back to basics - PHP_Codesniffer
Back to basics - PHP_CodesnifferBack to basics - PHP_Codesniffer
Back to basics - PHP_CodesnifferSebastian Marek
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesCiaranMcNulty
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and youmarkstory
 
Beginning PHPUnit
Beginning PHPUnitBeginning PHPUnit
Beginning PHPUnitJace Ju
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)James Titcumb
 
Building Maintainable Applications in Apex
Building Maintainable Applications in ApexBuilding Maintainable Applications in Apex
Building Maintainable Applications in ApexJeffrey Kemp
 
Dependency Injection Smells
Dependency Injection SmellsDependency Injection Smells
Dependency Injection SmellsMatthias Noback
 

What's hot (20)

UA testing with Selenium and PHPUnit - PFCongres 2013
UA testing with Selenium and PHPUnit - PFCongres 2013UA testing with Selenium and PHPUnit - PFCongres 2013
UA testing with Selenium and PHPUnit - PFCongres 2013
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Dependency Injection in PHP
Dependency Injection in PHPDependency Injection in PHP
Dependency Injection in PHP
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
TDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for BusinessTDC2016SP - Trilha Developing for Business
TDC2016SP - Trilha Developing for Business
 
Developing for Business
Developing for BusinessDeveloping for Business
Developing for Business
 
PHP 7 Crash Course
PHP 7 Crash CoursePHP 7 Crash Course
PHP 7 Crash Course
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
PHP security audits
PHP security auditsPHP security audits
PHP security audits
 
Back to basics - PHP_Codesniffer
Back to basics - PHP_CodesnifferBack to basics - PHP_Codesniffer
Back to basics - PHP_Codesniffer
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing Strategies
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
 
Beginning PHPUnit
Beginning PHPUnitBeginning PHPUnit
Beginning PHPUnit
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Building Maintainable Applications in Apex
Building Maintainable Applications in ApexBuilding Maintainable Applications in Apex
Building Maintainable Applications in Apex
 
Dependency Injection Smells
Dependency Injection SmellsDependency Injection Smells
Dependency Injection Smells
 

Similar to Quality assurance for php projects with PHPStorm

Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress DeveloperJoey Kudish
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastMichelangelo van Dam
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinMichelangelo van Dam
 
Review unknown code with static analysis Zend con 2017
Review unknown code with static analysis  Zend con 2017Review unknown code with static analysis  Zend con 2017
Review unknown code with static analysis Zend con 2017Damien Seguy
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsClinton Dreisbach
 
Zend Certification PHP 5 Sample Questions
Zend Certification PHP 5 Sample QuestionsZend Certification PHP 5 Sample Questions
Zend Certification PHP 5 Sample QuestionsJagat Kothari
 
OOP Is More Than Cars and Dogs
OOP Is More Than Cars and DogsOOP Is More Than Cars and Dogs
OOP Is More Than Cars and DogsChris Tankersley
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2markstory
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2Elizabeth Smith
 

Similar to Quality assurance for php projects with PHPStorm (20)

Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress Developer
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublin
 
Zend Framework
Zend FrameworkZend Framework
Zend Framework
 
Fatc
FatcFatc
Fatc
 
Review unknown code with static analysis Zend con 2017
Review unknown code with static analysis  Zend con 2017Review unknown code with static analysis  Zend con 2017
Review unknown code with static analysis Zend con 2017
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP Applications
 
Zend Certification PHP 5 Sample Questions
Zend Certification PHP 5 Sample QuestionsZend Certification PHP 5 Sample Questions
Zend Certification PHP 5 Sample Questions
 
OOP Is More Than Cars and Dogs
OOP Is More Than Cars and DogsOOP Is More Than Cars and Dogs
OOP Is More Than Cars and Dogs
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2
 
My Development Story
My Development StoryMy Development Story
My Development Story
 

More from Michelangelo van Dam

GDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultGDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultMichelangelo van Dam
 
Moving from app services to azure functions
Moving from app services to azure functionsMoving from app services to azure functions
Moving from app services to azure functionsMichelangelo van Dam
 
General Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyGeneral Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyMichelangelo van Dam
 
Leveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageMichelangelo van Dam
 
Open source for a successful business
Open source for a successful businessOpen source for a successful business
Open source for a successful businessMichelangelo van Dam
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me laterMichelangelo van Dam
 
Deploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesDeploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesMichelangelo van Dam
 
Azure and OSS, a match made in heaven
Azure and OSS, a match made in heavenAzure and OSS, a match made in heaven
Azure and OSS, a match made in heavenMichelangelo van Dam
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your projectMichelangelo van Dam
 
Easily extend your existing php app with an api
Easily extend your existing php app with an apiEasily extend your existing php app with an api
Easily extend your existing php app with an apiMichelangelo van Dam
 

More from Michelangelo van Dam (20)

GDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultGDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and default
 
Moving from app services to azure functions
Moving from app services to azure functionsMoving from app services to azure functions
Moving from app services to azure functions
 
Privacy by design
Privacy by designPrivacy by design
Privacy by design
 
DevOps or DevSecOps
DevOps or DevSecOpsDevOps or DevSecOps
DevOps or DevSecOps
 
Privacy by design
Privacy by designPrivacy by design
Privacy by design
 
Continuous deployment 2.0
Continuous deployment 2.0Continuous deployment 2.0
Continuous deployment 2.0
 
Let your tests drive your code
Let your tests drive your codeLet your tests drive your code
Let your tests drive your code
 
General Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyGeneral Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's story
 
Leveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantage
 
The road to php 7.1
The road to php 7.1The road to php 7.1
The road to php 7.1
 
Open source for a successful business
Open source for a successful businessOpen source for a successful business
Open source for a successful business
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me later
 
Deploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesDeploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutes
 
Azure and OSS, a match made in heaven
Azure and OSS, a match made in heavenAzure and OSS, a match made in heaven
Azure and OSS, a match made in heaven
 
Getting hands dirty with php7
Getting hands dirty with php7Getting hands dirty with php7
Getting hands dirty with php7
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your project
 
Create, test, secure, repeat
Create, test, secure, repeatCreate, test, secure, repeat
Create, test, secure, repeat
 
The Continuous PHP Pipeline
The Continuous PHP PipelineThe Continuous PHP Pipeline
The Continuous PHP Pipeline
 
Easily extend your existing php app with an api
Easily extend your existing php app with an apiEasily extend your existing php app with an api
Easily extend your existing php app with an api
 
Your code are my tests
Your code are my testsYour code are my tests
Your code are my tests
 

Recently uploaded

"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 

Recently uploaded (20)

"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 

Quality assurance for php projects with PHPStorm

  • 1. QA  for  PHP  projects using  PHPStorm JetBrains  Webinar,  April  25  2013
  • 3. Goals 3 • improve  QA  in  your  PHP  projects • deliver  higher  quality  of  applicaIons • become  familiarized  with  available  tools
  • 4. Our  host  for  this  webinar 4
  • 11. Let’s  get  our  hands  dirty 11
  • 14. Advantages of SCM • team development possible • tracking multi-versions of source code • moving back and forth in history • tagging of milestones • backup of source code • accessible from - command line - native apps - IDE’s like JetBrain’s IDE - analytical tools TIP:  hooks  for  tools
  • 16. PHP  Lint 16 • checks the syntax of code • build in PHP core • is used per file - pre-commit hook for version control system - batch processing of files • can provide reports - but if something fails -> the build fails TIP:  pre-­‐commit  hook
  • 18. SCM  commit  hook 18 #!/bin/sh # # Pre-commit hook to validate syntax of incoming PHP files, if no failures it # accepts the commit, otherwise it fails and blocks the commit REPOS="$1" TXN="$2" # modify these system executables to match your system PHP=/usr/bin/php AWK=/usr/bin/awk GREP=/bin/grep SVNLOOK=/usr/bin/svnlook # PHP Syntax checking with PHP Lint # originally from Joe Stump at Digg # https://gist.github.com/53225 # for i in `$SVNLOOK changed -t "$TXN" "$REPOS" | $AWK '{print $2}'` do if [ ${i##*.} == php ]; then CHECK=`$SVNLOOK cat -t "$TXN" "$REPOS" $i | $PHP -d html_errors=off -l || echo $i` RETURN=`echo $CHECK | $GREP "^No syntax" > /dev/null && echo TRUE || echo FALSE` if [ $RETURN = 'FALSE' ]; then echo $CHECK 1>&2; exit 1 fi fi done
  • 22. Why  documenIng? 22 • new  members  in  the  team • working  with  remote  workers • analyzing  improvements • think  before  doing • used  by  IDE’s  and  editors  for  code  hinIng  ;-­‐)
  • 25. Uses  docblock  in  code 25
  • 28. The  art  of  finding  a  bug 28 • Debugging  allows  you  to  walk  step-­‐by-­‐step   through  your  code  base  unIl  you  reach  the   point  of  failure.
  • 32. Most  common  excuses 32 • no  Ime • not  within  budget • development  team  does  not  know  how • tests  are  provided  aaer  delivery • …
  • 34. Benefits  of  tesIng 34 • beder  code  with  smaller  footprint • allows  refactoring • detects  bugs  in  an  early  stage • saves  Ime  in  maintenance  stage
  • 36. ConfiguraIon:  phpunit.xml 36 <phpunit bootstrap="./Bootstrap.php"> <testsuite name="Unit test suite"> <directory>./</directory> </testsuite> <filter> <whitelist> <directory suffix=".php">../application/</directory> <directory suffix=".php">../library/</directory> </whitelist> </filter> </phpunit>
  • 37. Bootstrapping  app <?php // set our app paths and environments define('BASE_PATH', realpath(dirname(__FILE__) . '/../')); define('APPLICATION_PATH', BASE_PATH . '/application'); define('TEST_PATH', BASE_PATH . '/tests'); define('APPLICATION_ENV', 'testing'); // Include path set_include_path( . PATH_SEPARATOR . BASE_PATH . '/library' . PATH_SEPARATOR . get_include_path() ); // Set the default timezone !!! date_default_timezone_set('Europe/Brussels'); // We wanna catch all errors en strict warnings error_reporting(E_ALL|E_STRICT); require_once 'Zend/Application.php'; $application = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); $application->bootstrap(); 37
  • 40. WriIng  a  test 40 <?php class Application_Model_CommentTest extends PHPUnit_Framework_TestCase { protected $_comment; protected function setUp() { $this->_comment = new Application_Model_Comment(); parent::setUp(); } protected function tearDown() { parent::tearDown(); $this->_comment = null; } public function testModelIsEmptyAtConstruct() { $this->assertSame(0, $this->_comment->getId()); $this->assertNull($this->_comment->getFullName()); $this->assertNull($this->_comment->getEmailAddress()); $this->assertNull($this->_comment->getWebsite()); $this->assertNull($this->_comment->getComment()); } }
  • 41. WriIng  the  class <?php class Application_Model_Comment { protected $_id = 0; protected $_fullName; protected $_emailAddress; protected $_website; protected $_comment; public function setId($id) { $this->_id = (int) $id; return $this; } public function getId() { return $this->_id; } public function setFullName($fullName) { $this->_fullName = (string) $fullName; return $this; } public function getFullName() { return $this->_fullName; } public function setEmailAddress($emailAddress) { $this->_emailAddress = (string) $emailAddress; return $this; } public function getEmailAddress() { return $this->_emailAddress; } public function setWebsite($website) { $this->_website = (string) $website; return $this; } public function getWebsite() { return $this->_website; } public function setComment($comment) { $this->_comment = (string) $comment; return $this; } public function getComment() { return $this->_comment; } public function populate($row) { if (is_array($row)) { $row = new ArrayObject($row, ArrayObject::ARRAY_AS_PROPS); } if (isset ($row->id)) $this->setId($row->id); if (isset ($row->fullName)) $this->setFullName($row->fullName); if (isset ($row->emailAddress)) $this->setEmailAddress($row->emailAddress); if (isset ($row->website)) $this->setWebsite($row->website); if (isset ($row->comment)) $this->setComment($row->comment); } public function toArray() { return array ( 'id' => $this->getId(), 'fullName' => $this->getFullName(), 'emailAddress' => $this->getEmailAddress(), 'website' => $this->getWebsite(), 'comment' => $this->getComment(), ); } } 41
  • 42. Adding  validaIon protected $_filters; protected $_validators; public function __construct($params = null) { $this->_filters = array ( 'id' => array ('Int'), 'fullName' => array ('StringTrim', 'StripTags', new Zend_Filter_Alnum(true)), 'emailAddress' => array ('StringTrim', 'StripTags', 'StringToLower'), 'website' => array ('StringTrim', 'StripTags', 'StringToLower'), 'comment' => array ('StringTrim', 'StripTags'), ); $this->_validators = array ( 'id' => array ('Int'), 'fullName' => array ( new Zftest_Validate_Mwop(), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), ), 'emailAddress' => array ( 'EmailAddress', new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), ), 'website' => array ( new Zend_Validate_Callback(array('Zend_Uri', 'check')), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), ), 'comment' => array ( new Zftest_Validate_TextBox(), new Zend_Validate_StringLength(array ('max' => 5000)), ), ); if (null !== $params) { $this->populate($params); } } 42
  • 43. Modify  seders  &  geders public function setId($id) { $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('id' => $id)); if (!$input->isValid('id')) { throw new Zend_Exception('Invalid ID provided'); } $this->_id = (int) $input->id; return $this; } public function setFullName($fullName) { $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('fullName' => $fullName)); if (!$input->isValid('fullName')) { throw new Zend_Exception('Invalid fullName provided'); } $this->_fullName = (string) $input->fullName; return $this; } 43
  • 44. Modify  seders  &  geders  2 public function setEmailAddress($emailAddress) { $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('emailAddress' => $emailAddress)); if (!$input->isValid('emailAddress')) { throw new Zend_Exception('Invalid emailAddress provided'); } $this->_emailAddress = (string) $input->emailAddress; return $this; } public function setWebsite($website) { $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('website' => $website)); if (!$input->isValid('website')) { throw new Zend_Exception('Invalid website provided'); } $this->_website = (string) $input->website; return $this; } 44
  • 45. Modify  geders  &  seders  3 public function setComment($comment) { $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('comment' => $comment)); if (!$input->isValid('comment')) { throw new Zend_Exception('Invalid comment provided'); } $this->_comment = (string) $input->comment; return $this; } 45
  • 49. Mess  DetecIon 49 • code  smells • possible  bugs • sub-­‐opImal  code • over  complicated  expressions • unused  parameters,  methods  and  properIes • wrongly  named  parameters,  methods  or   properIes
  • 53. Key  reason 53 “computers are great at doing repetitive tasks very well”
  • 54. AutomaIon 54 • Limit  risk  of  human  error • Will  always  be  executed  in  same  order • Can  be  shared  amongst  team  members • Allows  to  fine-­‐tune  and  improve  features
  • 59. Overview  of  tools 59 • SCM  (SVN,  GIT,  …) • PHP  Lint • PHP  Document  Generator • Debugging • PHPUnit  TesIng • PHP  Mess  detecIon • Phing  automaIon }
  • 60. Quality  Assurance • is  part  of  development  process • will  only  work  if  the  tools  are  available • and  developers  see  the  benefits  of  QA 60
  • 62. Contact 62 Michelangelo van Dam Zend Certified Engineer email: michelangelo@in2it.be skype: michelangelovandam twitter: @DragonBe tel EU: +32 15 34 52 90 tel US: 202 559-7401 www.in2it.be facebook.com/in2itvof | @in2itvof Contact us for Consultancy - Training - QA - Webdesign
  • 63. Credits I’d like to thank the following people for sharing their creative commons pictures michelangelo: http://www.flickr.com/photos/dasprid/5148937451 birds: http://www.flickr.com/photos/andyofne/4633356197 safeguarding: http://www.flickr.com/photos/infidelic/4306205887/ bugs: http://www.flickr.com/photos/goingslo/4523034319 behaviour: http://www.flickr.com/photos/yuan2003/1812881370 prevention: http://www.flickr.com/photos/robertelyov/5159801170 progress: http://www.flickr.com/photos/dingatx/4115844000 file cabinet: http://www.flickr.com/photos/manc/1427691715 documentation: http://www.flickr.com/photos/dennis_matheson/3269442687 exam: http://www.flickr.com/photos/albertogp123/5843577306 dead roach: http://www.flickr.com/photos/stevensnodgrass/7504408776 garbage: http://www.flickr.com/photos/amstersam/4608512202 gears: http://www.flickr.com/photos/freefoto/5982549938 elephpant: http://www.flickr.com/photos/drewm/3191872515