Cakephp 3 - 如何在 table 中集成外部资源?

Cakephp 3 - How to integrate external sources in table?

我正在开发一个应用程序,它有自己的数据库并从另一个服务获取用户信息(在这种情况下是 LDAP,通过 API 包)。

假设我有一个名为 Articles 的 table,其中有一列 user_id。没有 Users table,而是通过外部 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();
}

我不确定如何处理这个问题。

我应该将代码放在 table 对象中的什么位置以允许与外部 API 集成?

还有一个额外的问题:如何在填充实体时最小化 LDAP 查询的数量?
即,通过首先使用单个 ->getUsers() 检索相关用户并稍后放置它们似乎要快得多,即使遍历文章并使用多个 ->getUser() 可能更简单。

最简单的解决方案是使用结果格式化程序来获取和注入外部数据。

更复杂的解决方案是自定义关联和自定义关联加载器,但考虑到以数据库为中心的关联,您可能还必须想出一个 table 和一个查询实现处理您的 LDAP 数据源。虽然将其移动到自定义关联中会相当简单,但包含该关联将查找匹配项 table,导致模式被检查等

因此,我将坚持为第一个选项提供示例。结果格式化程序会非常简单,像这样:

$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() returns.

除此之外,示例应该是不言自明的,首先获取在查询文章中找到的用户 ID 的唯一列表,获取使用这些 ID 的 LDAP 用户,然后将用户注入文章。

如果您想在结果中包含实体,请从用户数据创建实体,例如:

$userData = $usersMap[$article['user_id']];
$article['user'] = new \App\Model\Entity\User($userData);

为了更好的可重用性,请将格式化程序放在自定义查找器中。在你的 ArticlesTable class:

public function findWithUsers(\Cake\ORM\Query $query, array $options)
{
    return $query->formatResults(/* ... */);
}

那你就可以$this->Articles->find('withUsers'),就这么简单

另见