我正在开发一个应用程序,它拥有自己的数据库,并从另一个序列化中获取用户信息( LDAP就是这种情况,通过API包)。
假设我有一个名为Articles
的表,其中有一个列user_id
。没有Users
表,而是通过外部API检索用户或一组用户:
$user = LDAPConnector::getUser($user_id);
$users = LDAPConnector::getUsers([1, 2, 5, 6]);
当然,我希望从控制器内部检索数据尽可能简单,理想情况下仍然是这样:
$articles = $this->Articles->find()->contain('Users');
foreach ($articles as $article) {
echo $article->user->getFullname();
}
我不知道该怎么处理。
我应该把代码放在表对象中以便与外部API集成?
还有一个额外的问题:如何在填充实体时最小化LDAP查询的数量?
也就是说,首先使用单个->getUsers()
检索相关用户并将其放置起来似乎要快得多,尽管迭代文章和使用多个->getUser()
可能更简单。
发布于 2019-10-04 11:50:59
最简单的解决方案是使用结果格式化程序来获取和注入外部数据。
更复杂的解决方案是定制关联和自定义关联加载器,但考虑到以数据库为中心的关联是如何的,您可能还必须想出一个处理LDAP数据源的表和可能的查询实现。虽然将其移动到自定义关联中相当简单,但包含关联的关联将查找匹配表,并使模式被检查,等等。
因此,我将继续为第一个选项提供一个例子。结果格式化程序将非常简单,如下所示:
$this->Articles
->find()
->formatResults(function (\Cake\Collection\CollectionInterface $results) {
$userIds = array_unique($results->extract('user_id')->toArray());
$users = LDAPConnector::getUsers($userIds);
$usersMap = collection($users)->indexBy('id')->toArray();
return $results
->map(function ($article) use ($usersMap) {
if (isset($usersMap[$article['user_id']])) {
$article['user'] = $usersMap[$article['user_id']];
}
return $article;
});
});
该示例假设从LDAPConnector::getUsers()
返回的数据是一个关联数组的集合,其中有一个与用户id匹配的id
键。您必须相应地调整这一点,具体取决于LDAPConnector::getUsers()
返回的内容。
除此之外,这个示例应该是很清楚的,首先获得在查询的文章中找到的用户ID的唯一列表,使用这些ID获得LDAP用户,然后将用户注入文章中。
如果希望在结果中包含实体,那么从用户数据创建实体,例如:
$userData = $usersMap[$article['user_id']];
$article['user'] = new \App\Model\Entity\User($userData);
为了获得更好的可重用性,请将格式化程序放在自定义查找器中。在您的ArticlesTable
类中:
public function findWithUsers(\Cake\ORM\Query $query, array $options)
{
return $query->formatResults(/* ... */);
}
然后您可以只做$this->Articles->find('withUsers')
,就像包含一样简单。
另请参阅
https://stackoverflow.com/questions/58234308
复制相似问题