Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting yourself out of trouble with PHP anti-patterns

Getting yourself out of trouble with PHP anti-patterns

Do you have code that you’re afraid to touch because nobody really knows what it does any more? Do you have systems which would be easier to re-write than to maintain? Are developers avoiding working on various tickets because it’ll involve working with a particularly painful part of the code?

Maybe a few developers have tried refactoring over the years but given up (or made things worse!), and certain ‘bad smells’ in the code are stunting progress.

While ‘Design Patterns’ tell us how to design code upfront to solve a common problem, ‘Anti-patterns’ tell us how to rescue a struggling PHP application before it leads to a company’s downfall.

Together we’ll explore some of the common pitfalls, find out how to recognise issues before they become serious, and we’ll see how to move a failing project back into the limelight.

By the end of this session everybody will be eager to tackle those parts of your codebase that the whole team has been steering clear of for months!

nealio82

June 10, 2019
Tweet

More Decks by nealio82

Other Decks in Programming

Transcript

  1. People who, unfamiliar with a new technology, copy & paste

    examples from stack overflow and just modify to their needs Typical Causes
  2. Found 35 clones with 1873 duplicated lines in 44 files:

    .../campaign_groups/lib/ManageCampaignGroups.php:258-462 (204 lines) .../campaign/lib/ManageCampaigns.php:335-539
  3. Found 35 clones with 1873 duplicated lines in 44 files:

    .../campaign_groups/lib/ManageCampaignGroups.php:258-462 (204 lines) .../campaign/lib/ManageCampaigns.php:335-539
  4. Found 35 clones with 1873 duplicated lines in 44 files:

    .../campaign_groups/lib/ManageCampaignGroups.php:258-462 (204 lines) .../campaign/lib/ManageCampaigns.php:335-539
  5. Found 35 clones with 1873 duplicated lines in 44 files:

    .../campaign_groups/lib/ManageCampaignGroups.php:258-462 (204 lines) .../campaign/lib/ManageCampaigns.php:335-539
  6. Found 35 clones with 1873 duplicated lines in 44 files:

    .../campaign_groups/lib/ManageCampaignGroups.php:258-462 (204 lines) .../campaign/lib/ManageCampaigns.php:335-539
  7. Found 35 clones with 1873 duplicated lines in 44 files:

    .../campaign_groups/lib/ManageCampaignGroups.php:258-462 (204 lines) .../campaign/lib/ManageCampaigns.php:335-539
  8. /** * filters out campaigns. * * @param ArrayManipulation $campaigns

    * @param array $filtersSpec * * @throws Exception */ public static function filterCampaignsList(ArrayManipulation $campai $filterRules = array(); foreach ($filtersSpec as $filter) { if ($filter['name'] == '-custom-ysdb') { $operator = $filter['comparator']; $expectedValue = $filter['value']; $campaignFbIds = self::pluckFbCampaignIds($campaigns->getValue if (!$campaignFbIds) { continue; } // get yesterday spend. used in `yday spnd/dly bdgt` filter $spec = DWEndpointSpec::create() ->setIds($campaignFbIds) ->addFields(array('spend')) ->setDateFrom((new DateTime())->modify('-1 DAY')) ->setDateTo(new DateTime()) campaign ManageCampaignGroups.php campaign_groups
  9. /** * @param $filtersArray * * @return array */ public

    static function parseFiltersArray($filtersArray) { $pre = array(); $post = array(); $preFiltersNames = array( 'statusIds' => 'statusIds', 'name' => 'name', 'budget' => 'budget', 'objective' => 'objective', 'spend_cap' => 'spend_cap' ); $in_array_match = function (&$value, $array) { foreach ($array as $pattern => $newValue) { if (preg_match('/^' . $pattern . '$/', $value)) { $value = $newValue; return true; } } return false; }; campaign ManageCampaignGroups.php campaign_groups
  10. ManageCampaigns.php /** * @param $filtersArray * * @return array */

    public static function parseFiltersArray($filtersArray) { $pre = array(); $post = array(); $preFiltersNames = array( 'dimensionTag_\d+' => 'dimensionTag', 'statusIds' => 'statusIds', 'bidTypes' => 'bidTypes', 'campaignGroupIds' => 'campaignGroupIds', 'name' => 'name', 'budget' => 'budget', 'optimisationGoal' => 'optimisationGoal', 'billingEvent' => 'billingEvent', '-custom-dayparting' => '-custom-dayparting', '-custom-dimension' => '-custom-dimension', ); $in_array_match = function (&$value, $array) { foreach ($array as $pattern => $newValue) { if (preg_match('/^' . $pattern . '$/', $value)) { $value = $newValue; return true; campaign campaign_groups
  11. /** * @param $filtersArray * * @return array */ public

    static function parseFiltersArray($filtersArray) { $pre = array(); $post = array(); $preFiltersNames = array( 'dimensionTag_\d+' => 'dimensionTag', 'statusIds' => 'statusIds', 'bidTypes' => 'bidTypes', 'bidModel' => 'bidModel', 'campaignIds' => 'campaignIds', 'campaignGroupIds' => 'campaignGroupIds', 'uploadId' => 'uploadId', 'creative_title' => 'creative_title', 'creative_body' => 'creative_body', 'name' => 'name', 'maxBid' => 'maxBid', '-custom-dimension' => '-custom-dimension', ); $in_array_match = function (&$value, $array) { foreach ($array as $pattern => $newValue) { if (preg_match('/^' . $pattern . '$/', $value)) { $value = $newValue; campaign campaign_groups campaign_ads ManageAds.php
  12. abstract class CampaignManagement { abstract protected static function getFilters(): array;

    public static function parseFiltersArray(): array { $pre = array(); $post = array(); $preFiltersNames = static::getFilters(); $in_array_match = function (&$value, $array) { foreach ($array as $pattern => $newValue) { if (preg_match('/^' . $pattern . '$/', $value)) { $value = $newValue; return true; } } return false; }; foreach ($filtersArray as $filter) { if ($in_array_match($filter['name'], $preFiltersNames)) { campaign campaign_groups campaign_ads CampaignManagement.php Management
  13. abstract class CampaignManagement { abstract protected static function getFilters(): array;

    public static function parseFiltersArray(): array { $pre = array(); $post = array(); $preFiltersNames = static::getFilters(); $in_array_match = function (&$value, $array) { foreach ($array as $pattern => $newValue) { if (preg_match('/^' . $pattern . '$/', $value)) { $value = $newValue; return true; } } return false; }; foreach ($filtersArray as $filter) { if ($in_array_match($filter['name'], $preFiltersNames)) { campaign campaign_groups campaign_ads CampaignManagement.php Management
  14. abstract class CampaignManagement { abstract protected static function getFilters(): array;

    public static function parseFiltersArray(): array { $pre = array(); $post = array(); $preFiltersNames = static::getFilters(); $in_array_match = function (&$value, $array) { foreach ($array as $pattern => $newValue) { if (preg_match('/^' . $pattern . '$/', $value)) { $value = $newValue; return true; } } return false; }; foreach ($filtersArray as $filter) { if ($in_array_match($filter['name'], $preFiltersNames)) { campaign campaign_groups campaign_ads CampaignManagement.php Management
  15. class ManageAdsPage extends CampaignManagement { protected static function getFilters(): array

    { return array( 'dimensionTag_\d+' => 'dimensionTag', 'statusIds' => 'statusIds', 'bidTypes' => 'bidTypes', 'bidModel' => 'bidModel', 'campaignIds' => 'campaignIds', 'campaignGroupIds' => 'campaignGroupIds', 'uploadId' => 'uploadId', 'creative_title' => 'creative_title', 'creative_body' => 'creative_body', 'name' => 'name', 'maxBid' => 'maxBid', '-custom-dimension' => '-custom-dimension', ); } } campaign campaign_groups campaign_ads ManageAds.php Management
  16. class ManageAdsPage extends CampaignManagement { protected static function getFilters(): array

    { return array( 'dimensionTag_\d+' => 'dimensionTag', 'statusIds' => 'statusIds', 'bidTypes' => 'bidTypes', 'bidModel' => 'bidModel', 'campaignIds' => 'campaignIds', 'campaignGroupIds' => 'campaignGroupIds', 'uploadId' => 'uploadId', 'creative_title' => 'creative_title', 'creative_body' => 'creative_body', 'name' => 'name', 'maxBid' => 'maxBid', '-custom-dimension' => '-custom-dimension', ); } } campaign campaign_groups campaign_ads ManageAds.php Management
  17. class ManageAdsPage extends CampaignManagement { protected static function getFilters(): array

    { return array( 'dimensionTag_\d+' => 'dimensionTag', 'statusIds' => 'statusIds', 'bidTypes' => 'bidTypes', 'bidModel' => 'bidModel', 'campaignIds' => 'campaignIds', 'campaignGroupIds' => 'campaignGroupIds', 'uploadId' => 'uploadId', 'creative_title' => 'creative_title', 'creative_body' => 'creative_body', 'name' => 'name', 'maxBid' => 'maxBid', '-custom-dimension' => '-custom-dimension', ); } } campaign campaign_groups campaign_ads ManageAds.php Management
  18. But it works so we just leave it alone We’re

    not really sure what that code does
  19. actions.class.php actions <?php class inlinebuilderActions extends sfActions { public function

    executeProcess(sfWebRequest $request) { $uploadId = $request->getParameter('uploadId'); $clientId = $this->getUser()->getAttribute('clientSessionId'); $inlineBuilderUpload = Doctrine::getTable('InlineBuilderUpload')- >findOneByIdAndClientId($uploadId, $clientId); if ($inlineBuilderUpload instanceof InlineBuilderUpload) { # We only allow to process builds from the last step of the builde it (saved) if (in_array($inlineBuilderUpload->getStatus(), array(InlineBuilderUpload::STATUS_EDITING,InlineBuilderUpload::STATUS_SA $inlineBuilderUpload->setStatus(InlineBuilderUpload::STATUS_IN_Q $inlineBuilderUpload->save(); } } /* $bulkUpload = $inlineBuilderUpload->loadBulkUpload(); $conn = sfContext::getInstance()->getDatabaseManager()->getDatabase( >getDoctrineConnection();
  20. actions.class.php actions } } /* $bulkUpload = $inlineBuilderUpload->loadBulkUpload(); $conn =

    sfContext::getInstance()->getDatabaseManager()->getDatabase('d >getDoctrineConnection(); try { $conn->beginTransaction(); $bulkUpload->saveIntoDB(); // Commit the transaction when done $conn->commit(); $inlineBuilderUpload->setStatus(InlineBuilderUpload::STATUS_PROCESSE $inlineBuilderUpload->save(); } catch (Exception $e) { // Rollback if transaction fail $conn->rollback(); $bulkError = new BulkError(); $bulkError->setClass('BulkDB'); $bulkError->setFunction('BulkDB.saveIntoDB'); $bulkError->setType(BulkError::TYPE_ERROR); $bulkError->setMessage($e->getMessage());
  21. actions.class.php actions $bulkError->setFunction('BulkDB.saveIntoDB'); $bulkError->setType(BulkError::TYPE_ERROR); $bulkError->setMessage($e->getMessage()); $bulkError->setObject('inlineBuilderUpload'); $bulkError->setAccountId($inlineBuilderUpload->getAccountId()); $bulkError->save(); $inlineBuilderUpload->setStatus(InlineBuilderUpload::STATUS_ERROR); $inlineBuilderUpload->save();

    } */ $this->redirect('/inlinebuilder/uploads'); } public function executeDownloadOLD(sfWebRequest $request) { // ... } public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } }
  22. a315cb4a (Jordi 2014-07-01) /* 9dedbd66 (Jordi 2014-06-30) $conn = sfContext::getInstance()->getDatabaseManager()->

    9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) try { 9dedbd66 (Jordi 2014-06-30) $conn->beginTransaction(); 9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) $bulkUpload->saveIntoDB(); 144398e4 (Jordi 2014-06-30) 9dedbd66 (Jordi 2014-06-30) $conn->commit(); 9dedbd66 (Jordi 2014-06-30)
  23. a315cb4a (Jordi 2014-07-01) /* 9dedbd66 (Jordi 2014-06-30) $conn = sfContext::getInstance()->getDatabaseManager()->

    9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) try { 9dedbd66 (Jordi 2014-06-30) $conn->beginTransaction(); 9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) $bulkUpload->saveIntoDB(); 144398e4 (Jordi 2014-06-30) 9dedbd66 (Jordi 2014-06-30) $conn->commit(); 9dedbd66 (Jordi 2014-06-30)
  24. a315cb4a (Jordi 2014-07-01) /* 9dedbd66 (Jordi 2014-06-30) $conn = sfContext::getInstance()->getDatabaseManager()->

    9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) try { 9dedbd66 (Jordi 2014-06-30) $conn->beginTransaction(); 9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) $bulkUpload->saveIntoDB(); 144398e4 (Jordi 2014-06-30) 9dedbd66 (Jordi 2014-06-30) $conn->commit(); 9dedbd66 (Jordi 2014-06-30)
  25. a315cb4a (Jordi 2014-07-01) /* 9dedbd66 (Jordi 2014-06-30) $conn = sfContext::getInstance()->getDatabaseManager()->

    9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) try { 9dedbd66 (Jordi 2014-06-30) $conn->beginTransaction(); 9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) $bulkUpload->saveIntoDB(); 144398e4 (Jordi 2014-06-30) 9dedbd66 (Jordi 2014-06-30) $conn->commit(); 9dedbd66 (Jordi 2014-06-30)
  26. a315cb4a (Jordi 2014-07-01) /* 9dedbd66 (Jordi 2014-06-30) $conn = sfContext::getInstance()->getDatabaseManager()->

    9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) try { 9dedbd66 (Jordi 2014-06-30) $conn->beginTransaction(); 9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) $bulkUpload->saveIntoDB(); 144398e4 (Jordi 2014-06-30) 9dedbd66 (Jordi 2014-06-30) $conn->commit(); 9dedbd66 (Jordi 2014-06-30)
  27. a315cb4a (Jordi 2014-07-01) /* 9dedbd66 (Jordi 2014-06-30) $conn = sfContext::getInstance()->getDatabaseManager()->

    9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) try { 9dedbd66 (Jordi 2014-06-30) $conn->beginTransaction(); 9dedbd66 (Jordi 2014-06-30) 144398e4 (Jordi 2014-06-30) $bulkUpload->saveIntoDB(); 144398e4 (Jordi 2014-06-30) 9dedbd66 (Jordi 2014-06-30) $conn->commit(); 9dedbd66 (Jordi 2014-06-30)
  28. commit a315cb4a741f7dec51376477c8c66419991aa22d Author: Jordi Date: Tue Jul 1 13:08:15 2014

    +0100 [Inline Builder] - DB Process -- Cron added. + task/BuilderTask.class.php
  29. commit a315cb4a741f7dec51376477c8c66419991aa22d Author: Jordi Date: Tue Jul 1 13:08:15 2014

    +0100 [Inline Builder] - DB Process -- Cron added. + task/BuilderTask.class.php
  30. BuilderTask.class.php task <?php class BuilderTask extends sfBaseTask { private function

    _createInlineBuilders($inlineBuilders) { TerminalHelper::log("Found " . count($inlineBuilders) . " Inline Buil created", "yellow"); if(count($inlineBuilders) > 0) { /** @var InlineBuilderUpload $inlineBuilder */ foreach ($inlineBuilders as $inlineBuilder) { TerminalHelper::log("Loading Bulk Upload for Inline Job " . $inli "yellow"); $bulkUpload = $inlineBuilder->loadBulkUpload(); $conn = sfContext::getInstance()->getDatabaseManager()->getDataba >getDoctrineConnection(); try { $conn->beginTransaction(); TerminalHelper::log("Saving Job to DB", "yellow"); $bulkUpload->saveIntoDB(); actions
  31. actions.class.php actions it (saved) if (in_array($inlineBuilderUpload->getStatus(), array(InlineBuilderUpload::STATUS_EDITING,InlineBuilderUpload::STATUS_SAVE $inlineBuilderUpload->setStatus(InlineBuilderUpload::STATUS_IN_QUE $inlineBuilderUpload->save(); }

    } /* * DELETE ALL THE COMMENTED-OUT CODE! */ $this->redirect('/inlinebuilder/uploads'); } public function executeDownloadOLD(sfWebRequest $request) { // ... } public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } } task
  32. actions.class.php actions it (saved) if (in_array($inlineBuilderUpload->getStatus(), array(InlineBuilderUpload::STATUS_EDITING,InlineBuilderUpload::STATUS_SAVE $inlineBuilderUpload->setStatus(InlineBuilderUpload::STATUS_IN_QUE $inlineBuilderUpload->save(); }

    } /* * DELETE ALL THE COMMENTED-OUT CODE! */ $this->redirect('/inlinebuilder/uploads'); } public function executeDownloadOLD(sfWebRequest $request) { // ... } public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } } task
  33. actions.class.php actions it (saved) if (in_array($inlineBuilderUpload->getStatus(), array(InlineBuilderUpload::STATUS_EDITING,InlineBuilderUpload::STATUS_SAVE $inlineBuilderUpload->setStatus(InlineBuilderUpload::STATUS_IN_QUE $inlineBuilderUpload->save(); }

    } /* * DELETE ALL THE COMMENTED-OUT CODE! */ $this->redirect('/inlinebuilder/uploads'); } public function executeDownloadOLD(sfWebRequest $request) { // ... } public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } } task
  34. commit d4e72ab65850ef49fd829e367fe6970025f180bb Author: Daniel Date: Thu Oct 15 15:34:31 2015

    +0300 Excel download button last page of inline builder. PR-4971 commit 937a9d05b5a9120e9345d8784814ff5dc7a1f51a Author: Radu Date: Thu Oct 15 10:14:09 2015 +0100 PR-4972 #resolve Duplicate Excel download from the upload's page
  35. commit d4e72ab65850ef49fd829e367fe6970025f180bb Author: Daniel Date: Thu Oct 15 15:34:31 2015

    +0300 Excel download button last page of inline builder. PR-4971 commit 937a9d05b5a9120e9345d8784814ff5dc7a1f51a Author: Radu Date: Thu Oct 15 10:14:09 2015 +0100 PR-4972 #resolve Duplicate Excel download from the upload's page
  36. commit d4e72ab65850ef49fd829e367fe6970025f180bb Author: Daniel Date: Thu Oct 15 15:34:31 2015

    +0300 Excel download button last page of inline builder. PR-4971 commit 937a9d05b5a9120e9345d8784814ff5dc7a1f51a Author: Radu Date: Thu Oct 15 10:14:09 2015 +0100 PR-4972 #resolve Duplicate Excel download from the upload's page
  37. commit d4e72ab65850ef49fd829e367fe6970025f180bb Author: Daniel Date: Thu Oct 15 15:34:31 2015

    +0300 Excel download button last page of inline builder. PR-4971 commit 937a9d05b5a9120e9345d8784814ff5dc7a1f51a Author: Radu Date: Thu Oct 15 10:14:09 2015 +0100 PR-4972 #resolve Duplicate Excel download from the upload's page
  38. actions.class.php actions task public function executeDownloadOLD(sfWebRequest $request) { // ...

    } public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } }
  39. actions.class.php actions public function executeDownloadOLD(sfWebRequest $request) { // ... }

    public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } } task
  40. actions.class.php actions task public function executeDownload(sfWebRequest $request) { // ...

    } public function executeOldDownload(sfWebRequest $request) { // ... } }
  41. actions.class.php actions task public function executeVersion2Download(sfWebRequest $request) { // ...

    } public function executeVersion1Download(sfWebRequest $request) { // ... } }
  42. That code is a mess! Making a change in one

    place breaks something in another
  43. 10af6d6 adding privacy policy page 93ddb94 i bcb7319 ii 8747627

    Finishing up Website Usage Page 2414eb8 iwq 2a5910d ii eadc6e8 ii 0d23c1d ii e6a97b1 wq 5780487 i 64eea96 ii 6914478 qwe 1f06a5d iq 07d15b8 wr 1d6df82 echo fc014f1 Adding new background c7ed903 Here we go 9040b40 Testing 4523f29 testing 66e7e60 iok 965d026 Making modifications a5f58f8 Adding Google Manager codes 08f91d9 wq ff555c1 removing header 23d07b1 Removing content 61e480d ok trying this out
  44. 10af6d6 adding privacy policy page 93ddb94 i bcb7319 ii 8747627

    Finishing up Website Usage Page 2414eb8 iwq 2a5910d ii eadc6e8 ii 0d23c1d ii e6a97b1 wq 5780487 i 64eea96 ii 6914478 qwe 1f06a5d iq 07d15b8 wr 1d6df82 echo fc014f1 Adding new background c7ed903 Here we go 9040b40 Testing 4523f29 testing 66e7e60 iok 965d026 Making modifications a5f58f8 Adding Google Manager codes 08f91d9 wq ff555c1 removing header 23d07b1 Removing content 61e480d ok trying this out
  45. campaigns.php functions function deleteCampaignGuestsViaCampaignId($campaign_id) { $dbh = getNewPDOInstance(‘MY_DB_NAME’); $sql =

    'DELETE FROM campaign_guest WHERE campaign_id = ‘ . $campaign_id; $stmt = $dbh->prepare($sql); if ($stmt->execute()) { return true; } } function deletePhotosFromCampaignFolderViaCampaignId($campaign_id) { global $root_prefix; global $rootd; $path = $root_prefix . "/uploads/campaigns/" . $campaign_id; $real_file_path = $rootd . "/uploads/campaigns/" . $campaign_id; $photos = scandir($_SERVER['DOCUMENT_ROOT'] . $path); // print_r($photos); foreach ($photos as $key => $photo) { // this is to skip . and .. in the folder. if ("." === substr($photo, 0, 1)) {
  46. function deleteCampaignGuestsViaCampaignId($campaign_id) { $dbh = getNewPDOInstance(‘MY_DB_NAME’); $sql = 'DELETE FROM

    campaign_guest WHERE campaign_id = ‘ . $campaign_id; $stmt = $dbh->prepare($sql); if ($stmt->execute()) { return true; } } function deletePhotosFromCampaignFolderViaCampaignId($campaign_id) { global $root_prefix; global $rootd; $path = $root_prefix . "/uploads/campaigns/" . $campaign_id; $real_file_path = $rootd . "/uploads/campaigns/" . $campaign_id; $photos = scandir($_SERVER['DOCUMENT_ROOT'] . $path); // print_r($photos); foreach ($photos as $key => $photo) { // this is to skip . and .. in the folder. if ("." === substr($photo, 0, 1)) { campaigns.php functions
  47. function deleteCampaignGuestsViaCampaignId($campaign_id) { $dbh = getNewPDOInstance(‘MY_DB_NAME’); $sql = 'DELETE FROM

    campaign_guest WHERE campaign_id = ‘ . $campaign_id; $stmt = $dbh->prepare($sql); if ($stmt->execute()) { return true; } } function deletePhotosFromCampaignFolderViaCampaignId($campaign_id) { global $root_prefix; global $rootd; $path = $root_prefix . "/uploads/campaigns/" . $campaign_id; $real_file_path = $rootd . "/uploads/campaigns/" . $campaign_id; $photos = scandir($_SERVER['DOCUMENT_ROOT'] . $path); // print_r($photos); foreach ($photos as $key => $photo) { // this is to skip . and .. in the folder. if ("." === substr($photo, 0, 1)) { campaigns.php functions
  48. function createUpdateLoginClient($client){ $password_hash = password_hash($client['password'], PASSWORD_DEFAULT); $id = $client['id']; $dbh

    = getNewPDOInstance(‘login_clients'); if($id){ // ... } if($client['password'] && $id){ // ... } if(!$id){ $client_id = createClient($client['user_name'], $client['email'], $ // ... } if($result){ return true; } else{ return true; } } function createClient($email){ $dbh = getNewPDOInstance('MY_DB_NAME'); // ... } campaigns.php functions clients.php
  49. function createUpdateLoginClient($client){ $password_hash = password_hash($client['password'], PASSWORD_DEFAULT); $id = $client['id']; $dbh

    = getNewPDOInstance(‘login_clients'); if($id){ // ... } if($client['password'] && $id){ // ... } if(!$id){ $client_id = createClient($client['user_name'], $client['email'], $ // ... } if($result){ return true; } else{ return true; } } function createClient($email){ $dbh = getNewPDOInstance('MY_DB_NAME'); // ... } campaigns.php functions clients.php
  50. function createUpdateLoginClient($client){ $password_hash = password_hash($client['password'], PASSWORD_DEFAULT); $id = $client['id']; $dbh

    = getNewPDOInstance(‘login_clients'); if($id){ // ... } if($client['password'] && $id){ // ... } if(!$id){ $client_id = createClient($client['user_name'], $client['email'], $ // ... } if($result){ return true; } else{ return true; } } function createClient($email){ $dbh = getNewPDOInstance('MY_DB_NAME'); // ... } campaigns.php functions clients.php
  51. function createUpdateLoginClient($client){ $password_hash = password_hash($client['password'], PASSWORD_DEFAULT); $id = $client['id']; $dbh

    = getNewPDOInstance(‘login_clients'); if($id){ // ... } if($client['password'] && $id){ // ... } if(!$id){ $client_id = createClient($client['user_name'], $client['email'], $ // ... } if($result){ return true; } else{ return true; } } function createClient($email){ $dbh = getNewPDOInstance('MY_DB_NAME'); // ... } campaigns.php functions clients.php
  52. index.php functions <?php error_reporting(0); //ini_set('display_errors', E_ALL); $IN_PRODUCTION = true; $root_prefix

    = true||$IN_PRODUCTION?”/campaign”:""; $rootd = $_SERVER['DOCUMENT_ROOT'].$root_prefix."/"; require $rootd.'/lib/init/init.php'; $do = _get("do"); $get = _get("get"); $page = _get("page"); $app = _get("app"); $folder = _get("folder"); if (isset($app)) { header('Content-Type: application/json'); $path = $rootd.'lib/app/'.$app.'.php'; if (!file_exists($path)) exit(header("location: /404")); include $path; }elseif (isset($do)) { $path = $rootd.'lib/do/'.$do.'.php'; if (!file_exists($path)) exit(header("location: /404")); include $path;
  53. index.php functions if($folder){ $path = $rootd.'lib/get/'.$folder.'/'.$get.'.php'; }else{ $path = $rootd.'lib/get/'.$get.'.php';

    } if (!file_exists($path)) exit(header("location: /404")); include $path; } elseif (isset($page)) { $path = $rootd.'lib/pages_data/'.$page.'.php'; if (!file_exists($path)){ error_log('lol ' . $path); exit(header("location: /404")); } include $rootd.'lib/init/html.php'; include $path; } elseif (isset($_SESSION['my_id'])) { $path = $rootd.'lib/pages_data/home.php'; if (!file_exists($path)) exit(header("location: /404")); include $rootd.'lib/init/html.php'; include $path; } else { $path = $rootd.'lib/pages_data/sign-up.php'; if (!file_exists($path)) exit(header("location: /404")); include $rootd.'lib/init/html.php'; include $path; }
  54. index.php functions if($folder){ $path = $rootd.'lib/get/'.$folder.'/'.$get.'.php'; }else{ $path = $rootd.'lib/get/'.$get.'.php';

    } if (!file_exists($path)) exit(header("location: /404")); include $path; } elseif (isset($page)) { $path = $rootd.'lib/pages_data/'.$page.'.php'; if (!file_exists($path)){ error_log('lol ' . $path); exit(header("location: /404")); } include $rootd.'lib/init/html.php'; include $path; } elseif (isset($_SESSION['my_id'])) { $path = $rootd.'lib/pages_data/home.php'; if (!file_exists($path)) exit(header("location: /404")); include $rootd.'lib/init/html.php'; include $path; } else { $path = $rootd.'lib/pages_data/sign-up.php'; if (!file_exists($path)) exit(header("location: /404")); include $rootd.'lib/init/html.php'; include $path; }
  55. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  56. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  57. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  58. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  59. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  60. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  61. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  62. // Init MySQL logins function getNewPDOInstance($db_name) { require $_SERVER['DOCUMENT_ROOT']."/master_config.php"; $db_hostname

    = $lab_hostname; $db_username = $lab_username; $db_password = $lab_password; if($is_live & $db_name == “MY_DB_NAME” || $db_name == “OTHER_DB_NAME” || $db_name == “YET_ANOTHER_DB_NAME” ){ $db_hostname = $tracking_machine_hostname; $db_username = $tracking_machine_username; $db_password = $tracking_machine_password; } if($is_live & $db_name == "login"){ $db_hostname = $login_machine_hostname; $db_username = $login_machine_username; $db_password = $login_machine_password; } index.php functions database connection.php
  63. $db_username = $login_machine_username; $db_password = $login_machine_password; } if($is_live & $db_name

    == “login_clients"){ $db_hostname = $login_clients_machine_hostname; $db_username = $login_clients_machine_username; $db_password = $login_clients_machine_password; } $dbh = null; try { $dbh = new PDO("mysql:host=$db_hostname;dbname=$db_name;charset=utf8mb4 $db_password); } catch(PDOException $e) { error_log("Error in newPDOInstance: ".$e->getMessage()); print_r($e); return false; } //print_r($e); return $dbh; } index.php functions database connection.php
  64. $db_username = $login_machine_username; $db_password = $login_machine_password; } if($is_live & $db_name

    == “login_clients"){ $db_hostname = $login_clients_machine_hostname; $db_username = $login_clients_machine_username; $db_password = $login_clients_machine_password; } $dbh = null; try { $dbh = new PDO("mysql:host=$db_hostname;dbname=$db_name;charset=utf8mb4 $db_password); } catch(PDOException $e) { error_log("Error in newPDOInstance: ".$e->getMessage()); print_r($e); return false; } //print_r($e); return $dbh; } index.php functions database connection.php
  65. $db_username = $login_machine_username; $db_password = $login_machine_password; } if($is_live & $db_name

    == “login_clients"){ $db_hostname = $login_clients_machine_hostname; $db_username = $login_clients_machine_username; $db_password = $login_clients_machine_password; } $dbh = null; try { $dbh = new PDO("mysql:host=$db_hostname;dbname=$db_name;charset=utf8mb4 $db_password); } catch(PDOException $e) { error_log("Error in newPDOInstance: ".$e->getMessage()); print_r($e); return false; } //print_r($e); return $dbh; } index.php functions database connection.php
  66. $db_username = $login_machine_username; $db_password = $login_machine_password; } if($is_live & $db_name

    == “login_clients"){ $db_hostname = $login_clients_machine_hostname; $db_username = $login_clients_machine_username; $db_password = $login_clients_machine_password; } $dbh = null; try { $dbh = new PDO("mysql:host=$db_hostname;dbname=$db_name;charset=utf8mb4 $db_password); } catch(PDOException $e) { error_log("Error in newPDOInstance: ".$e->getMessage()); print_r($e); return false; } //print_r($e); return $dbh; } index.php functions database connection.php
  67. index.php functions database <?php $is_live = true; $lab_hostname = '...';

    $lab_username = '...'; $lab_password = '...'; $tracking_machine_hostname = '...'; $tracking_machine_username = '...'; $tracking_machine_password = '...'; $login_machine_hostname = '...'; $login_machine_username = '...'; $login_machine_password = '...'; $login_clients_machine_hostname = '...'; $login_clients_machine_username = '...'; $login_clients_machine_password = '...'; master_config.php
  68. index.php functions database <?php $is_live = true; $lab_hostname = '...';

    $lab_username = '...'; $lab_password = '...'; $tracking_machine_hostname = '...'; $tracking_machine_username = '...'; $tracking_machine_password = '...'; $login_machine_hostname = '...'; $login_machine_username = '...'; $login_machine_password = '...'; $login_clients_machine_hostname = '...'; $login_clients_machine_username = '...'; $login_clients_machine_password = '...'; master_config.php
  69. index.php functions database <?php class Config { private const IS_LIVE

    = true; private const LAB_HOSTNAME = '...'; private const LAB_USERNAME = '...'; private const LAB_PASSWORD = '...'; // ... public static function isLive(): bool { return self::IS_LIVE; } public static function labDBHostname(): string { return self::LAB_HOSTNAME; } } Config.php
  70. index.php functions database class Database { private $default = null;

    private $lab = null; private $login_clients = null; public function getConnectionFor(string $databaseName): \PDO { if (false === array_key_exists( $databaseName, get_object_vars($this)) ) { throw new \InvalidArgumentException(‘Invalid DB requested'); } if (null === $this->{$databaseName}) { $this->{$databaseName} = $this->createConnection($databaseName); } return $this->{$databaseName}; } Config.php Database.php
  71. index.php functions database class Database { private $default = null;

    private $lab = null; private $login_clients = null; public function getConnectionFor(string $databaseName): \PDO { if (false === array_key_exists( $databaseName, get_object_vars($this)) ) { throw new \InvalidArgumentException(‘Invalid DB requested'); } if (null === $this->{$databaseName}) { $this->{$databaseName} = $this->createConnection($databaseName); } return $this->{$databaseName}; } Config.php Database.php
  72. index.php functions database class Database { private $default = null;

    private $lab = null; private $login_clients = null; public function getConnectionFor(string $databaseName): \PDO { if (false === array_key_exists( $databaseName, get_object_vars($this)) ) { throw new \InvalidArgumentException(‘Invalid DB requested'); } if (null === $this->{$databaseName}) { $this->{$databaseName} = $this->createConnection($databaseName); } return $this->{$databaseName}; } Config.php Database.php
  73. index.php functions database class Database { private $default = null;

    private $lab = null; private $login_clients = null; public function getConnectionFor(string $databaseName): \PDO { if (false === array_key_exists( $databaseName, get_object_vars($this)) ) { throw new \InvalidArgumentException(‘Invalid DB requested'); } if (null === $this->{$databaseName}) { $this->{$databaseName} = $this->createConnection($databaseName); } return $this->{$databaseName}; } Config.php Database.php
  74. index.php functions database private function createConnection(string $databaseName): \PDO { if

    ('lab' === $databaseName) { return new \PDO( Config::labDBHostname(), Config::labDBUsername(), Config::labDBPassword() ); } if ('login_clients' === $databaseName) { return new \PDO( // ... ); } } Config.php Database.php
  75. index.php functions database private function createConnection(string $databaseName): \PDO { if

    ('lab' === $databaseName) { return new \PDO( Config::labDBHostname(), Config::labDBUsername(), Config::labDBPassword() ); } if ('login_clients' === $databaseName) { return new \PDO( // ... ); } } Config.php Database.php
  76. index.php repository database Config.php functions ClientRepository.php class ClientRepository { private

    $db; public function __construct(Database $db) { $this->db = $db; } function createUpdateLoginClient($client) { $password_hash = password_hash($client['password'], PASSWORD_DEFAUL $id = $client['id']; $dbh = this->db->getConnectionFor('login_clients'); if ($id) { // ... } if ($client['password'] && $id) { // ... } if (!$id) { $client_id = $this->createClient($client['user_name'], $client[ // ... } }
  77. { function createUpdateLoginClient($client) { if ($id) { // ... }

    if ($client['password'] && $id) { // ... } if (!$id) { $client_id = $this->createClient( $client['user_name'], $client[‘email'], $client['security_clearance'] ); // ... } } function createClient($email) { $this->db->getConnectionFor('login_clients'); // ... } } index.php repository database Config.php functions ClientRepository.php
  78. { function createUpdateLoginClient($client) { if ($id) { // ... }

    if ($client['password'] && $id) { // ... } if (!$id) { $client_id = $this->createClient( $client['user_name'], $client[‘email'], $client['security_clearance'] ); // ... } } function createClient($email) { $this->db->getConnectionFor('login_clients'); // ... } } index.php repository database Config.php functions ClientRepository.php
  79. class Client { private $id; private $email; private $password; private

    $securityClearance; public function __construct( int $id, string $email, string $password, string $securityClearance = 'CLIENT' ) { $this->id = $id; $this->email = $email; $this->password = $password; $this->securityClearance = $securityClearance; } public function getEmail(): string { return $this->email; } public function getPassword(): string index.php repository database Config.php functions Client.php model
  80. index.php repository database Config.php functions Client.php model class Client {

    private $id; private $email; private $password; private $securityClearance; public function __construct( int $id, string $email, string $password, string $securityClearance = 'CLIENT' ) { $this->id = $id; $this->email = $email; $this->password = $password; $this->securityClearance = $securityClearance; } public function getEmail(): string { return $this->email; } public function getPassword(): string
  81. index.php repository database Config.php functions Client.php model class Client {

    private $id; private $email; private $password; private $securityClearance; public function __construct( int $id, string $email, string $password, string $securityClearance = 'CLIENT' ) { $this->id = $id; $this->email = $email; $this->password = $password; $this->securityClearance = $securityClearance; } public function getEmail(): string { return $this->email; } public function getPassword(): string
  82. index.php repository database Config.php functions Client.php model class Client {

    private $id; private $email; private $password; private $securityClearance; public function __construct( int $id, string $email, string $password, string $securityClearance = 'CLIENT' ) { $this->id = $id; $this->email = $email; $this->password = $password; $this->securityClearance = $securityClearance; } public function getEmail(): string { return $this->email; } public function getPassword(): string
  83. { function createUpdateLoginClient(Client $client) { $password_hash = password_hash($client->getPassword(), PASSWORD_DEF $this->db->getConnectionFor('login_clients');

    if ($client->getId()) { // ... } if ($client->getPassword() && $client->getId()) { // ... } if (!$client->getId()) { $client_id = $this->createClient($client); // ... } } function createClient(Client $client) { $this->db->getConnectionFor('login_clients'); // ... } } index.php repository database Config.php functions ClientRepository.php model
  84. { function createUpdateLoginClient(Client $client) { $password_hash = password_hash($client->getPassword(), PASSWORD_DEF $this->db->getConnectionFor('login_clients');

    if ($client->getId()) { // ... } if ($client->getPassword() && $client->getId()) { // ... } if (!$client->getId()) { $client_id = $this->createClient($client); // ... } } function createClient(Client $client) { $this->db->getConnectionFor('login_clients'); // ... } } index.php repository database Config.php functions ClientRepository.php model
  85. Class is too inefficient or excessively complex for reuse and

    testing, or uses excessive resources even for simple operations Symptoms
  86. <?php class ReportFactory { /** * class to query the

    db for reports grids while using PDO prepared queri * temporary tables to increase performance. can return both a main selec * and several 'tmp_tables' queries which are required for the main query * * tmp tables must be executed first in the calling script as they provid * cleanup operations and facilitate the execution of the main query. * * example usage: * * $factory = new ReportFactory; * $factory->setSuperCampaign($super); * $factory->setReportType('persona'); * $factory->addSortColumn($col, $order); * * foreach($factory->getTmpTablesSql() AS $tmp) { * $stmt = $conn->prepare($tmp); * $stmt->execute($pdo_tmp_params); * } * * $stmt = $conn->prepare($factory->getSql()); * $stmt->execute($pdo_params); * $array = $stmt->fetchAll(); * * note: $pdo_params is an array of parameters such as 'clientId', reporting ReportFactory.php
  87. <?php class ReportFactory { /** * class to query the

    db for reports grids while using PDO prepared queri * temporary tables to increase performance. can return both a main selec * and several 'tmp_tables' queries which are required for the main query * * tmp tables must be executed first in the calling script as they provid * cleanup operations and facilitate the execution of the main query. * * example usage: * * $factory = new ReportFactory; * $factory->setSuperCampaign($super); * $factory->setReportType('persona'); * $factory->addSortColumn($col, $order); * * foreach($factory->getTmpTablesSql() AS $tmp) { * $stmt = $conn->prepare($tmp); * $stmt->execute($pdo_tmp_params); * } * * $stmt = $conn->prepare($factory->getSql()); * $stmt->execute($pdo_params); * $array = $stmt->fetchAll(); * * note: $pdo_params is an array of parameters such as 'clientId', reporting ReportFactory.php
  88. <?php class ReportFactory { /** * class to query the

    db for reports grids while using PDO prepared queri * temporary tables to increase performance. can return both a main selec * and several 'tmp_tables' queries which are required for the main query * * tmp tables must be executed first in the calling script as they provid * cleanup operations and facilitate the execution of the main query. * * example usage: * * $factory = new ReportFactory; * $factory->setSuperCampaign($super); * $factory->setReportType('persona'); * $factory->addSortColumn($col, $order); * * foreach($factory->getTmpTablesSql() AS $tmp) { * $stmt = $conn->prepare($tmp); * $stmt->execute($pdo_tmp_params); * } * * $stmt = $conn->prepare($factory->getSql()); * $stmt->execute($pdo_params); * $array = $stmt->fetchAll(); * * note: $pdo_params is an array of parameters such as 'clientId', reporting ReportFactory.php
  89. CampaignID DateTime Event 1234 2019-01-01 13:37:00 click 1234 2019-01-01 12:34:56

    view 9876 2019-01-02 18:00:01 view 1234 2019-01-02 23:33:32 click … … … … … … … … …
  90. CampaignID DateTime Event 1234 2019-01-01 13:37:00 click 1234 2019-01-01 12:34:56

    view 9876 2019-01-02 18:00:01 view 1234 2019-01-02 23:33:32 click … … … … … … … … … CampaignID Date Clicks Likes Follows … 1234 2019-01-01 39480120 1398473 32424 … 3482 2019-01-01 23482134 235019934 94512 … 9876 2019-01-02 9324243 123489132 405202 … 9231 2019-01-02 1249823 509847 3248 …
  91. CampaignID DateTime Event 1234 2019-01-01 13:37:00 click 1234 2019-01-01 12:34:56

    view 9876 2019-01-02 18:00:01 view 1234 2019-01-02 23:33:32 click … … … … … … … … … CampaignID Date Event Total 1234 2019-01-01 click 1398473 1234 2019-01-01 view 235019934 9876 2019-01-02 view 123489132 1234 2019-01-02 click 509847 CampaignID Date Event Total 1234 2019-01-01 click 1398473 1234 2019-01-01 view 235019934 9876 2019-01-02 view 123489132 1234 2019-01-02 click 509847 CampaignID Date Event Total 1234 2019-01-01 click 1398473 1234 2019-01-01 view 235019934 9876 2019-01-02 view 123489132 1234 2019-01-02 click 509847 CampaignID Date Clicks Likes Follows … 1234 2019-01-01 39480120 1398473 32424 … 3482 2019-01-01 23482134 235019934 94512 … 9876 2019-01-02 9324243 123489132 405202 … 9231 2019-01-02 1249823 509847 3248 …
  92. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {} function addSortColumn($col, $order) {} function setReportType($report_type) {} function addTmpOr($status) {} function setWhere($where) {} function addWhere($where) {} function getWhere() {} function setColumns($col) {} function addColumn($col) {} function setParameters($params) {} function addParam($param) {}
  93. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {} function addSortColumn($col, $order) {} function setReportType($report_type) {} function addTmpOr($status) {} function setWhere($where) {} function addWhere($where) {} function getWhere() {} function setColumns($col) {} function addColumn($col) {} function setParameters($params) {} function addParam($param) {}
  94. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {} function addSortColumn($col, $order) {} function setReportType($report_type) {} function addTmpOr($status) {} function setWhere($where) {} function addWhere($where) {} function getWhere() {} function setColumns($col) {} function addColumn($col) {} function setParameters($params) {} function addParam($param) {}
  95. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {} function addSortColumn($col, $order) {} function setReportType($report_type) {} function addTmpOr($status) {} function setWhere($where) {} function addWhere($where) {} function getWhere() {} function setColumns($col) {} function addColumn($col) {} function setParameters($params) {} function addParam($param) {}
  96. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {} function addSortColumn($col, $order) {} function setReportType($report_type) {} function addTmpOr($status) {} function setWhere($where) {} function addWhere($where) {} function getWhere() {} function setColumns($col) {} function addColumn($col) {} function setParameters($params) {} function addParam($param) {}
  97. <?php class QueryBuilder { public function addSortColumn($col, $order) {} public

    function setReportType($report_type) {} public function addTmpOr($status) {} public function setWhere($where) {} // ... } reporting QueryBuilder.php Tmp
  98. <?php class ReportFactory { private $queryBuilder; private $sql; public function

    __construct() { $this->queryBuilder = new QueryBuilder(); } public function getQueryBuilder() { return $this->queryBuilder; } public function getSql() { return $sql; } // ... } reporting ReportFactory.php Tmp
  99. function someAction() { $factory = new ReportFactory(); // ... $factory->addWhere('status

    = '. $st); $factory->addTmpOr('(c.status <= '.$st.')'); $factory->addWhere('(time_start <= "' . date("Y-m-d H:i:s", time()) . '" OR time_start is null)’ ); } reporting Controller.php Tmp
  100. function someAction() { $factory = new ReportFactory(); $builder = $factory->getQueryBuilder();

    // ... $builder->addWhere('status = '. $st); $builder->addTmpOr('(c.status <= '.$st.')'); $builder->addWhere('(time_start <= "' . date("Y-m-d H:i:s", time()) . '" OR time_start is null)’ ); } reporting Controller.php Tmp
  101. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {} function addSortColumn($col, $order) {} function setReportType($report_type) {} function addTmpOr($status) {} function setWhere($where) {} function addWhere($where) {} function getWhere() {} function setColumns($col) {} function addColumn($col) {} function setParameters($params) {} function addParam($param) {}
  102. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {}
  103. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {}
  104. <?php class TemporaryTable { public function createTmpTables(string $reportType) {} private

    function createSuperCampaignsTable() {} private function createCampaignGroupsTable() {} private function createSuperCampaignsStatusesTable() {} private function createCampaignGroupsStatusesTable() {} private function createSuperCampaignsStatsTable() {} private function createCampaignGroupsStatsTable() {} private function createCampaignsStatsTable() {} // ... } reporting TmpTable.php Tmp QueryBuilder.php
  105. <?php class TemporaryTable { public function createTmpTables(string $reportType) { switch

    ($reportType) { case 'clicks': $this->createCampaignGroupsTable(); $this->createCampaignGroupsStatsTable(); $this->createClicksMetricsTable(); break; case 'views': // ... break; } } } reporting TmpTable.php Tmp QueryBuilder.php
  106. function _createTmpTables() {} function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function

    _getPersonaSelectSql() {} function _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {} function _createSuperCampaignsTable() {} function _createCampaignGroupsTable() {} function _createSuperCampaignsStatusesTable() {} function _createCampaignGroupsStatusesTable() {} function _createSuperCampaignsStatsTable() {} function _createCampaignGroupsStatsTable() {} function _createCampaignsStatsTable() {}
  107. function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function _getPersonaSelectSql() {} function

    _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {}
  108. <?php class MetricsQuery { private $tmpTable; public function __construct(TmpTable $tmpTable)

    { $this->tmpTable = $tmpTable; } public function getScheduledReportsSelectSql() {} public function getCampaignSelectSql() {} public function getPersonaSelectSql() {} public function getImageSelectSql() {} public function getTitleSelectSql() {} public function getOverviewSelectSql() {} // ... } reporting MetricsQuery.php Tmp QueryBuilder.php TmpTable.php
  109. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere …
  110. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere …
  111. <?php abstract class MetricsReport extends ReportFactory { private $connection; public

    function __construct(\PDO $connection) { $this->connection = $connection; } abstract public function setQueryConditions(); public function getReport() { $this->setQueryConditions(); $sql = $this->getSql(); $query = $this->pdo->prepare($sql); return $query->execute(); } } reporting MetricsQuery.php Tmp QueryBuilder.php TmpTable.php MetricsReport.php
  112. <?php abstract class MetricsReport extends ReportFactory { private $connection; public

    function __construct(\PDO $connection) { $this->connection = $connection; } abstract public function setQueryConditions(); public function getReport() { $this->setQueryConditions(); $sql = $this->getSql(); $query = $this->pdo->prepare($sql); return $query->execute(); } } reporting MetricsQuery.php Tmp QueryBuilder.php TmpTable.php MetricsReport.php
  113. <?php abstract class MetricsReport extends ReportFactory { private $connection; public

    function __construct(\PDO $connection) { $this->connection = $connection; } abstract public function setQueryConditions(); public function getReport() { $this->setQueryConditions(); $sql = $this->getSql(); $query = $this->pdo->prepare($sql); return $query->execute(); } } reporting MetricsQuery.php Tmp QueryBuilder.php TmpTable.php MetricsReport.php
  114. function someAction() { $factory = new ReportFactory(); // ... $factory->addWhere('status

    = '. $st); $factory->addTmpOr('(c.status <= '.$st.')'); $factory->addWhere('(time_start <= "' . date("Y-m-d H:i:s", time()) . '" OR time_start is null)’ ); } reporting Controller.php Tmp
  115. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere …
  116. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … MetricsReport ReportFactory setQueryConditions
  117. <?php abstract class MetricsReport extends ReportFactory { private $connection; public

    function __construct(\PDO $connection) { $this->connection = $connection; } abstract public function setQueryConditions(); public function getReport() { $this->setQueryConditions(); $sql = $this->getSql(); $query = $this->pdo->prepare($sql); return $query->execute(); } } reporting MetricsQuery.php Tmp QueryBuilder.php TmpTable.php MetricsReport.php
  118. <?php abstract class MetricsReport extends ReportFactory { private $connection; public

    function __construct(\PDO $connection) { $this->connection = $connection; } abstract public function getQuery(); public function getReport() { $sql = $this->getQuery(); $query = $this->pdo->prepare($sql); return $query->execute(); } } reporting MetricsQuery.php Tmp QueryBuilder.php TmpTable.php MetricsReport.php
  119. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … getQuery MetricsReport ReportFactory
  120. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … getQuery MetricsReport ReportFactory
  121. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … MetricsReport getQuery
  122. <?php class SomeTempTable implements TmpTableSql { private $sql; public function

    __construct(TmpTableSql $sql) { $this->sql = $sql; } public function getSql(): string { return $this->sql->getSql() . ' CREATE TABLE ... ;'; } } reporting TmpTableSql.php Query Tmp SomeTmpTable.php
  123. MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql … << interface >> TmpTable getSql

    Controller QueryBuilder addColumn addSortColumn addWhere … MetricsReport getQuery
  124. <?php class MetricsReport { private $connection; public function __construct(\PDO $connection)

    { $this->connection = $connection; } abstract protected function setupTables(): TmpTable; abstract protected function getSql(): string; public function getReport() { $tmpTables = $this->connection->prepare($this->setupTables()); $tmpTables->execute(); $query = $this->connection->prepare($this->getSql()); $query->execute(); return $query->fetchAll(); } reporting TmpTableSql.php Query Tmp MetricsReport.php SomeTmpTable.php
  125. <?php class MetricsReport { private $connection; public function __construct(\PDO $connection)

    { $this->connection = $connection; } abstract protected function setupTables(): TmpTable; abstract protected function getSql(): string; public function getReport() { $tmpTables = $this->connection->prepare($this->setupTables()); $tmpTables->execute(); $query = $this->connection->prepare($this->getSql()); $query->execute(); return $query->fetchAll(); } reporting TmpTableSql.php Query Tmp MetricsReport.php SomeTmpTable.php
  126. <?php class MetricsReport { private $connection; public function __construct(\PDO $connection)

    { $this->connection = $connection; } abstract protected function setupTables(): TmpTable; abstract protected function getSql(): string; public function getReport() { $tmpTables = $this->connection->prepare($this->setupTables()); $tmpTables->execute(); $query = $this->connection->prepare($this->getSql()); $query->execute(); return $query->fetchAll(); } reporting TmpTableSql.php Query Tmp MetricsReport.php SomeTmpTable.php
  127. The project is almost finished, we’ve been a great team

    Everybody got on so well & worked so hard together
  128. The project is almost finished, we’ve been a great team

    Everybody got on so well & worked so hard together It’s going to be a disaster
  129. Team members build relationships which they subconsciously don’t want to

    break up at the end of the project Typical Causes
  130. People have assumed roles / status within the team which

    they don’t want to lose when the project is completed Typical Causes
  131. We spent 6 months waiting for requirements from management But

    they’ll cancel the project unless it’s completed soon
  132. We spent 6 months waiting for requirements from management They’ve

    given us 4 weeks But they’ll cancel the project unless it’s completed soon
  133. After a few months management calls an emergency launch meeting,

    setting unrealistic deadlines & threatening to cancel the project Symptoms