2015-11-27 2 views
1

EDIT: ВЫХОДНОЙ КОД НА ДНЕ ВОПРОСАСоздания массива объектов в данном шаблоне картографа

Я просто разместил вопрос, думаю моя проблема была запросом, но оказывается, что это мой PHP код.

В этом проблема. У меня есть класс GoalChallenge, который имеет множество свойств, один из которых должен быть один или массив объектов ProductService; см. ниже класс GoalChallenge (обратите внимание, что я удалил другие геттеры и сеттеры и оставил те, которые относятся к классу ProductService.

Когда я использую GoalChallenge :: findByPersonaId, создается объект ProductService и относится к соответствующему GoalChallenge объекта, но должно быть два объекта ProductService в свойстве GoalChallenge-> product_service (запрос должен соответствовать 2 строкам). Вместо этого создается дублирующий объект GoalChallenge, содержащий те же значения свойств для всего, кроме свойства product_service, который содержит 2-й совпадающий объект из запроса.

Мне нужны два соответствующих объекта 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 (минус методы получения и установки)

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 goal_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 на переднем конце. Как вы можете видеть, 2 объекта идентичны, кроме -> product_service, первый объект имеет первую сопоставимую строку из запроса, тогда новый класс GoalChallenge содержит вторую строку соответствия из запроса – DJC

+0

. Было бы более полезно, если бы вы вставлял результаты запроса в виде таблицы из SQL-клиента, а не сбрасывался с PHP. –

ответ

1

Как и предполагалось, результирующий набор в JOIN Query требует немного больше логики для форматирования, как вы хотите чем вы его дали. Набор результатов 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

Большое спасибо за то, что вы приняли время, чтобы построить этот ответ, очень ценится. Я думаю, что это почти есть, но я получаю уведомление: неопределенный индекс: psid в строке 225 (это строка $ entry-> setProductService() и то же самое для url и feature_benefit тоже, и возврат в объект goalChallenge сначала пустым массивом, затем объектом ProductService, но с идентификатором только target_challenge, отображающим – DJC

+0

. Оказывается, как работает метод $ current_id - он никогда не изменяется от нуля, поэтому как бы он был когда-либо равным $ row ['id']? – DJC

+0

Не могу это увидеть! – DJC

Смежные вопросы