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!

Da2d2829b89cde136392973a35b68959?s=128

nealio82

June 10, 2019
Tweet

Transcript

  1. 2.
  2. 3.
  3. 4.
  4. 7.
  5. 10.
  6. 15.
  7. 16.
  8. 17.
  9. 18.
  10. 29.
  11. 30.

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

    examples from stack overflow and just modify to their needs Typical Causes
  12. 34.

    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
  13. 35.

    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
  14. 36.

    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
  15. 37.

    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
  16. 38.

    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
  17. 39.

    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
  18. 40.
  19. 42.

    /** * 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
  20. 43.
  21. 44.

    /** * @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
  22. 45.

    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
  23. 46.

    /** * @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
  24. 47.

    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
  25. 48.

    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
  26. 49.

    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
  27. 50.

    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
  28. 51.

    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
  29. 52.

    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
  30. 55.
  31. 58.

    But it works so we just leave it alone We’re

    not really sure what that code does
  32. 59.
  33. 69.

    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();
  34. 70.

    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());
  35. 71.

    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) { // ... } }
  36. 72.
  37. 75.

    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)
  38. 76.

    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)
  39. 77.

    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)
  40. 78.

    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)
  41. 79.

    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)
  42. 80.

    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)
  43. 82.

    commit a315cb4a741f7dec51376477c8c66419991aa22d Author: Jordi Date: Tue Jul 1 13:08:15 2014

    +0100 [Inline Builder] - DB Process -- Cron added. + task/BuilderTask.class.php
  44. 83.

    commit a315cb4a741f7dec51376477c8c66419991aa22d Author: Jordi Date: Tue Jul 1 13:08:15 2014

    +0100 [Inline Builder] - DB Process -- Cron added. + task/BuilderTask.class.php
  45. 84.

    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
  46. 85.

    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
  47. 86.

    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
  48. 87.

    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
  49. 89.

    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
  50. 90.

    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
  51. 91.

    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
  52. 92.

    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
  53. 94.
  54. 95.
  55. 96.
  56. 97.
  57. 98.

    actions.class.php actions task public function executeDownloadOLD(sfWebRequest $request) { // ...

    } public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } }
  58. 99.

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

    public function executeDownload(sfWebRequest $request) { // ... } public function executeOldDownload(sfWebRequest $request) { // ... } } task
  59. 100.

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

    } public function executeOldDownload(sfWebRequest $request) { // ... } }
  60. 101.

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

    } public function executeVersion1Download(sfWebRequest $request) { // ... } }
  61. 102.
  62. 106.

    That code is a mess! Making a change in one

    place breaks something in another
  63. 119.

    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
  64. 120.

    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
  65. 121.

    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)) {
  66. 122.

    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
  67. 123.

    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
  68. 124.

    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
  69. 125.

    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
  70. 126.

    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
  71. 127.

    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
  72. 128.

    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;
  73. 129.

    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; }
  74. 130.

    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; }
  75. 131.

    // 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
  76. 132.

    // 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
  77. 133.

    // 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
  78. 134.

    // 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
  79. 135.

    // 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
  80. 136.

    // 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
  81. 137.

    // 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
  82. 138.

    // 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
  83. 139.

    $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
  84. 140.

    $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
  85. 141.

    $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
  86. 142.

    $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
  87. 143.

    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
  88. 144.
  89. 146.

    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
  90. 147.

    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
  91. 148.

    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
  92. 149.

    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
  93. 150.

    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
  94. 151.

    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
  95. 152.

    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
  96. 153.

    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
  97. 154.

    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[ // ... } }
  98. 156.

    { 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
  99. 157.

    { 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
  100. 159.

    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
  101. 160.

    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
  102. 161.

    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
  103. 162.

    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
  104. 163.

    { 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
  105. 164.

    { 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
  106. 166.
  107. 171.
  108. 174.

    Class is too inefficient or excessively complex for reuse and

    testing, or uses excessive resources even for simple operations Symptoms
  109. 179.

    <?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
  110. 180.

    <?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
  111. 181.

    <?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
  112. 182.

    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 … … … … … … … … …
  113. 183.

    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 …
  114. 184.

    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 …
  115. 186.

    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) {}
  116. 187.

    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) {}
  117. 188.

    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) {}
  118. 189.

    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) {}
  119. 190.
  120. 192.

    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) {}
  121. 193.

    <?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
  122. 194.

    <?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
  123. 195.

    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
  124. 196.

    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
  125. 197.

    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) {}
  126. 198.

    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() {}
  127. 199.

    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() {}
  128. 200.

    <?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
  129. 201.

    <?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
  130. 202.

    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() {}
  131. 203.

    function _getScheduledReportsSelectSql() {} function _getCampaignSelectSql() {} function _getPersonaSelectSql() {} function

    _getImageSelectSql() {} function _getTitleSelectSql() {} function _getOverviewSelectSql() {} function _getExcelDownloadSelectSql() {} function _getCampaignsOverviewSelectSql() {}
  132. 204.

    <?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
  133. 206.
  134. 211.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere …
  135. 212.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere …
  136. 213.

    <?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
  137. 214.

    <?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
  138. 215.

    <?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
  139. 216.

    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
  140. 218.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere …
  141. 219.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … MetricsReport ReportFactory setQueryConditions
  142. 220.

    <?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
  143. 221.

    <?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
  144. 222.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … getQuery MetricsReport ReportFactory
  145. 223.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … getQuery MetricsReport ReportFactory
  146. 224.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql ReportFactory getQueryBuilder getSql … … TmpTable

    createTmpTables createCampaignsTable createStatsTable … Controller QueryBuilder addColumn addSortColumn addWhere … MetricsReport getQuery
  147. 226.
  148. 228.

    <?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
  149. 232.

    MetricsQuery getCampaignSelectSql getImageSelectSql getTitleSelectSql … << interface >> TmpTable getSql

    Controller QueryBuilder addColumn addSortColumn addWhere … MetricsReport getQuery
  150. 234.

    <?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
  151. 235.

    <?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
  152. 236.

    <?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
  153. 242.
  154. 245.

    The project is almost finished, we’ve been a great team

    Everybody got on so well & worked so hard together
  155. 246.

    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
  156. 254.

    Team members build relationships which they subconsciously don’t want to

    break up at the end of the project Typical Causes
  157. 255.

    People have assumed roles / status within the team which

    they don’t want to lose when the project is completed Typical Causes
  158. 260.

    We spent 6 months waiting for requirements from management But

    they’ll cancel the project unless it’s completed soon
  159. 261.

    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
  160. 262.
  161. 265.

    After a few months management calls an emergency launch meeting,

    setting unrealistic deadlines & threatening to cancel the project Symptoms
  162. 267.
  163. 271.
  164. 274.
  165. 275.
  166. 276.
  167. 277.
  168. 278.