Php 在数据映射器模式中创建对象数组
编辑:在问题的底部输出代码 我刚刚发布了一个问题,以为我的问题是查询,但结果是我的PHP代码 问题出在这里。我有一个GoalChallenge类,它有许多属性,其中一个属性应该是一个,或者一个ProductService对象数组;请参见下面的GoalChallenge类(注意,我已经去掉了其他getter和setter,并留下了与ProductService类相关的getter和setter 当我使用GoalChallenge::findByPersonaId时,会创建一个ProductService对象并与匹配的GoalChallenge对象相关联,但GoalChallenge->product\u服务属性中应该有两个ProductService对象(查询应该匹配两行)。相反,将创建一个重复的GoalChallenge对象,该对象包含除product_service属性之外的所有属性值,该属性包含查询中的第二个匹配对象 我需要两个匹配的ProductService对象成为同一个GoalChallenge对象的一部分(与查询匹配)-我如何才能做到这一点 如果您还需要什么,请询问。非常感谢您的帮助!代码如下 GoalChallenge.class.phpPhp 在数据映射器模式中创建对象数组,php,mysql,oop,pdo,Php,Mysql,Oop,Pdo,编辑:在问题的底部输出代码 我刚刚发布了一个问题,以为我的问题是查询,但结果是我的PHP代码 问题出在这里。我有一个GoalChallenge类,它有许多属性,其中一个属性应该是一个,或者一个ProductService对象数组;请参见下面的GoalChallenge类(注意,我已经去掉了其他getter和setter,并留下了与ProductService类相关的getter和setter 当我使用GoalChallenge::findByPersonaId时,会创建一个ProductServ
<?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;
}
}
最后是我的ProductService类(减去getter和setter)
这是输出
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>选择目标挑战。*,products\u services.id作为psid,products\u services.url,products\u services.feature\u从目标挑战中获益左加入目标挑战中的产品服务。id=产品服务。目标挑战。id,其中目标挑战。人物角色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秒)
打印(目标和挑战)
正如所怀疑的那样,
JOIN
查询的结果集需要比您给定的更多的逻辑来格式化。SQL结果集始终是二维结构,即使它包含的数据具有更复杂的关系(如一对多关系)
有几种方法可以实现这一点,我认为最接近您现有模式的一种方法是稍微更改获取行的方式。与其获取行然后立即映射它,不如在获取循环中构建一些逻辑来创建join表达式的嵌套结构,其中ProductService
是一个由一个r更多对象。然后您将能够修改mapObject()
方法来处理嵌套ProductService
对象数组
因此,不要在获取时进行映射,而是创建一个数组,将获取的行附加到该数组上。在每次迭代中,必须检查公共值(那些GoalChallenge
)是否已更改。如果未更改,则继续为ProductService
构建一个数组(例如,如果查询返回多个不同的GoalChallenge
),则启动一个新的外部结构
$result_set=array()
好的,这应该可以修复fetch模式以满足您的需要。另一个问题是让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::u construct()
参数中,使其接受并默认一个数组,而不是单个ProductService
对象,更改为$product\u service=array()
因此,这有点复杂,它说明了为什么通常使用预构建。这种逻辑以一种易于重用的方式为您抽象出来。PDO确实有一种
FETCH_GROUP
方法,但它仅用于对一列进行分组(如id
)作为外部数组键,所有其他列作为子数组。您的情况是,大多数列属于外部级别,只有与联接的ProductService
相关的列作为内部子数组,因此这实际上不起作用。听起来联接查询为相关表返回了许多相同的列值(如一对多关系中所预期的)。请发布查询产生的输出示例,以帮助我们了解重复的内容。您可能需要更复杂的逻辑来对它们进行排序。前端foreach循环的输出代码输出。如您所见,这两个对象除了->product\u service之外是相同的,第一个对象具有查询中的第一个匹配行,然后是一个新的GoalChallenge类包含查询中的第二个匹配行。如果您将查询结果粘贴为SQL客户机的表,而不是从PHP转储,那么它实际上会更有用。好的,我现在正尝试这样做,永远不要使用mysql命令行,所以请容忍我,非常感谢您在获取mysql数据方面提供的帮助ce方法包括在上面-我很感激这是我应该创建数组的地方,但不确定当前如何进行。非常感谢您花时间构建这个答案,非常感激。我认为它就在那里,但我得到了通知:第225行(即$entry->setProductService()中的未定义索引:psid)行和相同的url和feature_方法也有好处,并且在goalChallenge对象中首先返回一个空数组,然后返回一个ProductService对象,但只有goal_挑战id showingOk可以。出于兴趣,$current_id方法是如何工作的?它从不从null更改,那么它怎么会等于$row['id']?不确定我做了什么。它现在就在那里。可能无法解决问题。需要查看print\r($goal\u challenges)
。好的,我已经添加了print\u r-这是在前端的foreach循环中打印的。真的很抱歉-我在等待别人回复时添加了这个-现在删除,让我看看我得到了什么
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
)
)
)
)
// 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;
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;
}
public function setProductService(ProductService $product_service)
{
// Append onto an array
$this->product_service[] = $product_service;
}