2015-11-27 117 views
1

編輯對象的數組:輸出代碼AT BOTTOM問題創建數據映射器模式

我剛剛發佈了一個問題,思考我的問題是查詢,但事實證明,這是我的PHP代碼。

這是問題所在。我有一個GoalChallenge類,它有許多屬性,其中一個屬性應該是一個,或者是一個ProductService對象數組;請參閱下面的GoalChallenge類(注意我已經剝離了其他getter和setter,並且留下了與ProductService類有關的那些類

當我使用GoalChallenge :: findByPersonaId時,會創建一個ProductService對象並與匹配的GoalChallenge對象,但GoalChallenge-> product_service屬性中應該有2個ProductService對象(查詢應該匹配2行),而是創建一個重複的GoalChallenge對象,其中包含與product_service屬性不同的所有其他屬性值,其中包含查詢中第二個匹配對象

我需要兩個匹配的ProductService對象作爲同一個GoalChallenge對象的一部分(與查詢匹配) - 我該如何做到這一點?

如果您還有其他問題,請詢問。真的很感謝任何幫助!下面的代碼;

GoalChallenge.class.php

<?php 

class GoalChallenge 
{ 
    private $id; 
    private $persona_id; 
    private $title; 
    private $item_category; 
    private $description; 
    private $solution; 
    private $product_service; 
    private $research_checklist; 
    private $subtopics; 
    private $keywords; 
    private $status; 


    public function __construct(
     $id = null, 
     $persona_id = null, 
     $title = null, 
     $item_category = null, 
     $description = null, 
     $solution = null, 
     ProductService $product_service = null, 
     $research_checklist = null, 
     $subtopics = null, 
     $keywords = null, 
     $status = null 
    ) { 
     $this->id = $id; 
     $this->persona_id = $persona_id; 
     $this->title = $title; 
     $this->item_category = $item_category; 
     $this->description = $description; 
     $this->solution = $solution; 
     $this->product_service = $product_service; 
     $this->research_checklist = $research_checklist; 
     $this->subtopics = $subtopics; 
     $this->keywords = $keywords; 
     $this->status = $status; 
    } 

    public function getProductService() 
    { 
     return $this->product_service; 
    } 

    public function setProductService(ProductService $product_service) 
    { 
     $this->product_service = $product_service; 
    } 

} 

而我GoalChallengeMapper.class.php;

class GoalChallengeMapper 
{ 

    protected $dblayer; 

    public function __construct(PDO $dblayer) 
    { 
     $this->dblayer = $dblayer; 
    } 

    public function saveField($id, $field, $data) 
    { 
     try { 
      $this->dblayer->beginTransaction(); 
      $stmt = $this->dblayer->prepare("UPDATE goals_challenges SET $field = :data WHERE id = :id"); 
      $stmt->bindParam(':id', $id); 
      $stmt->bindParam(':data', $data); 
      $stmt->execute(); 

      $this->dblayer->commit(); 

      return $stmt->rowCount(); 

     } catch(PDOException $e) { 
      $this->dblayer->rollBack(); 
      echo $e->getMessage(); 
      exit; 
     } 

    } 

    public function findByPersonaId($persona_id) 
    { 
     try { 
      $this->dblayer->beginTransaction(); 
      $stmt = $this->dblayer->prepare("SELECT goals_challenges.*, products_services.id as psid, products_services.url, products_services.feature_benefit from goals_challenges LEFT JOIN products_services ON goals_challenges.id = products_services.goal_challenge_id WHERE goals_challenges.persona_id = :persona_id"); 
      $stmt->bindParam(':persona_id', $persona_id); 
      $stmt->execute(); 

      $this->dblayer->commit(); 

      $result_set = array(); 

      while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
       $result_set[] = $this->mapObject($row); 
      } 

      return $result_set; 

     } catch (PDOException $e) { 
      $this->dblayer->rollBack(); 
      echo $e->getMessage(); 
      exit; 
     } 
    } 

    public function mapObject(array $row) 
    { 
     $entry = new GoalChallenge(); 
     $entry->setId($row['id']); 
     $entry->setPersonaId($row['persona_id']); 
     $entry->setTitle($row['title']); 
     $entry->setItemCategory($row['item_category']); 
     $entry->setDescription($row['description']); 
     $entry->setSolution($row['solution']); 
     $entry->setProductService(new ProductService($row['psid'], $row['id'], $row['url'], explode(',', $row['feature_benefit']))); 
     $entry->SetResearchChecklist($row['research_checklist']); 
     $entry->setSubtopics($row['subtopics']); 
     $entry->setKeywords($row['keywords']); 
     $entry->setStatus($row['status']); 

     return $entry; 
    } 
} 

最後,我ProductService類(減去getter和setter)

class ProductService 
{ 
    private $id; 
    private $goal_challenge_id; 
    private $url; 
    private $feature_benefit = []; 

    public function __construct($id = null, $goal_challenge_id = null, $url = null, array $feature_benefit = null) 
    { 
     $this->id = $id; 
     $this->goal_challenge_id = $goal_challenge_id; 
     $this->url = $url; 
     $this->feature_benefit = $feature_benefit; 
    } 
} 

這是輸出

GoalChallenge Object 
(
    [id:GoalChallenge:private] => 173 
    [persona_id:GoalChallenge:private] => 14 
    [title:GoalChallenge:private] => Lead Gen 
    [item_category:GoalChallenge:private] => Business Challenge 
    [description:GoalChallenge:private] => 


    [solution:GoalChallenge:private] => Advertising 
    [product_service:GoalChallenge:private] => ProductService Object 
     (
      [id:ProductService:private] => 1 
      [goal_challenge_id:ProductService:private] => 173 
      [url:ProductService:private] => www.google.com 
      [feature_benefit:ProductService:private] => Array 
       (
        [0] => good for testing 
        [1] => mobile 
       ) 

     ) 

    [research_checklist:GoalChallenge:private] => 0,0,0,0,0,0 
    [subtopics:GoalChallenge:private] => 
    [keywords:GoalChallenge:private] => ,,,, 
    [status:GoalChallenge:private] => 1 
) 

GoalChallenge Object 
(
    [id:GoalChallenge:private] => 173 
    [persona_id:GoalChallenge:private] => 14 
    [title:GoalChallenge:private] => Lead Gen 
    [item_category:GoalChallenge:private] => Business Challenge 
    [description:GoalChallenge:private] => 


    [solution:GoalChallenge:private] => Advertising 
    [product_service:GoalChallenge:private] => ProductService Object 
     (
      [id:ProductService:private] => 3 
      [goal_challenge_id:ProductService:private] => 173 
      [url:ProductService:private] => www.test.com 
      [feature_benefit:ProductService:private] => Array 
       (
        [0] => good for searching 
        [1] => well known 
       ) 

     ) 

    [research_checklist:GoalChallenge:private] => 0,0,0,0,0,0 
    [subtopics:GoalChallenge:private] => 
    [keywords:GoalChallenge:private] => ,,,, 
    [status:GoalChallenge:private] => 1 
) 

的mysql> SELECT goals_challenges。*,products_services.id的PSID, products_services.url,products_services.feature_benefit FROM goals_challenges LEFT JOIN products_services ON goals_challenges.id = products_services.goal_challenge_id WHERE goals_challenges.persona_id = 14 ;在集

+-----+------------+----------+--------------------+-------------+-------------+-----------------+--------------------+-----------+----------+--------+------+----------------+--------------------------------+ 
| id | persona_id | title | item_category  | description | solution | product_service | research_checklist | subtopics | keywords | status | psid | url   | feature_benefit    | 
+-----+------------+----------+--------------------+-------------+-------------+-----------------+--------------------+-----------+----------+--------+------+----------------+--------------------------------+ 
| 173 |   14 | Lead Gen | Business Challenge |    | Advertising | NULL   | 0,0,0,0,0,0  | NULL  | ,,,,  |  1 | 1 | www.google.com | good for testing, mobile  | 


| 173 |   14 | Lead Gen | Business Challenge |    | Advertising | NULL   | 0,0,0,0,0,0  | NULL  | ,,,,  |  1 | 3 | www.test.com | good for searching, well known | 


+-----+------------+----------+--------------------+-------------+-------------+-----------------+--------------------+-----------+----------+--------+------+----------------+--------------------------------+ 

2行(0.00秒)

的print_r($ goals_challenges)

Array 
(
    [173] => Array 
     (
      [id] => 173 
      [persona_id] => 14 
      [title] => Lead Gen 
      [item_category] => Business Challenge 
      [description] => 


      [solution] => Advertising 
      [research_checklist] => 0,0,0,0,0,0 
      [subtopics] => 
      [keywords] => ,,,, 
      [status] => 1 
      [psid] => 1 
      [url] => www.google.com 
      [feature_benefit] => good for testing, mobile 
      [product_services] => Array 
       (
        [0] => Array 
         (
          [0] => 1 
          [1] => www.google.com 
          [2] => good for testing, mobile 
         ) 

        [1] => Array 
         (
          [0] => 3 
          [1] => www.test.com 
          [2] => good for searching, well known 
         ) 

       ) 

     ) 

) 
+0

聽起來好像連接查詢返回許多相關表的列值(正如在一對多關係中所預期的那樣)。請發佈由查詢產生的輸出示例,以幫助我們瞭解重複的內容。您可能需要更復雜的邏輯來對其進行排序 –

+0

在前端發佈了foreach循環的輸出代碼。如您所見,除了 - > product_service,第一個對象具有查詢中的第一個匹配行之外,這兩個對象是相同的,然後新的GoalChallenge類包含查詢中第二個匹配的行 – DJC

+0

如果您真的會更有幫助將查詢結果作爲來自SQL客戶端的表粘貼,而不是從PHP轉儲。 –

回答

1

由於嫌,JOIN查詢結果集需要更多一點的邏輯來格式化你想要的方式比你給出的還要多。 SQL結果集始終是二維結構,即使它包含的數據具有更復雜的關係(如一對多關係)。

有幾種方法可以解決這個問題,而我認爲最接近現有模式的方法是改變您稍微獲取行的方式。取而代之的是獲取一行,然後立即映射它,在獲取循環中創建一些邏輯來創建連接表達的嵌套結構,其中ProductService是一個或多個對象的數組。然後,您將能夠修改mapObject()方法來處理嵌套的ProductService對象的數組。

因此,不是像您抓取時那樣進行映射,而是創建一個數組,在其上附加提取的行。在每次迭代中,您都必須檢查公共值(GoalChallenge)是否已更改。如果沒有,則繼續爲ProductService構建陣列。如果它們發生了變化(就像您的查詢返回多個不同的GoalChallenge一樣),則會啓動一個新的外部結構。

$ result_set = array();

// Temp variable to remember what goals_challenges.id is being grouped 
$current_id = null; 
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
    // Create a new structure if the id changed 
    if($row['id'] !== $current_id) { 
     $current_id = $row['id']; 
     // Store a new row for goal_challenges, holding all 
     // the common columns in its outer structure 
     $goal_challenges[$row['id']] = $row; 
     // and it has a sub-array for product services 
     $goal_challenges[$row['id']]['product_servies'] = array(); 
    } 
    // Append the product_services columns as an array onto the subarray 
    $goal_challenges[$row['id']]['product_services'][] = array('psid'=>$row['psid'], 'url'=>$row['url'], 'feature_benefit'=>$row['feature_benefit']); 
} 

// Now you can pass each row of the $goal_challenges array 
// to mapObject. There should be only one row, but if you 
// use the same pattern for queries that return many rows it 
// will work without much modification 
$result_set = array(); 
foreach ($goal_challenges as $gc) { 
    $result_set[] = $this->mapObject($gc); 
} 
// Return the array of results (which probably has only one element) 
return $result_set; 

好的,那應該修復抓取模式來做你需要的。另一個問題是使mapObject()方法處理產品服務的內部數組。循環很簡單。

public function mapObject(array $row) 
{ 
    $entry = new GoalChallenge(); 
    $entry->setId($row['id']); 
    $entry->setPersonaId($row['persona_id']); 
    $entry->setTitle($row['title']); 
    $entry->setItemCategory($row['item_category']); 
    $entry->setDescription($row['description']); 
    $entry->setSolution($row['solution']); 
    $entry->SetResearchChecklist($row['research_checklist']); 
    $entry->setSubtopics($row['subtopics']); 
    $entry->setKeywords($row['keywords']); 
    $entry->setStatus($row['status']); 

    // Create ProductService objects for each item in the sub-array 
    foreach ($row['product_services'] as $ps) { 
     $entry->setProductService(new ProductService($ps['psid'], $row['id'], $ps['url'], explode(',', $ps['feature_benefit']))); 
    } 

    return $entry; 
} 

最後,使setProductService()方法附加到一個陣列,而不是設置一個單一的屬性:

public function setProductService(ProductService $product_service) 
{ 
    // Append onto an array 
    $this->product_service[] = $product_service; 
} 

GoalChallenge::__construct()參數,使其接受和默認的陣列而不是單個ProductService對象的,更改爲$product_service = array()

所以這是各種各樣的複雜,它說明爲什麼預建ORM libraries like Doctrine是常用的。這種邏輯以易於重用的方式被抽象出來。 PDO確實有一個FETCH_GROUP方法,但它只是將一列(如id)分組爲一個外部數組鍵和所有其他列作爲子數組。你的情況是,大多數列屬於外層,只有那些與加入的ProductService相關的列作爲內部子數組,所以這不起作用。

+0

非常感謝您採取時間來構建這個答案,非常感謝。我認爲它快到了,但是我得到了通知:未定義的索引:在第225行(這是$ entry-> setProductService())行中的psid,對於url和feature_benefit也是如此,並且在goalChallenge對象中返回的是首先是一個空數組,然後是一個ProductService對象,但只有顯示爲 – DJC

+0

的goal_challenge id好了。出於興趣,$ current_id方法是如何工作的 - 它永遠不會從null改變,所以它將如何等於$ row ['id']? – DJC

+0

仍然看不到它! – DJC