【问题标题】:Cakephp 3 - How to integrate external sources in table?Cakephp 3 - 如何在表中集成外部资源?
【发布时间】:2020-02-02 16:02:59
【问题描述】:

我正在开发一个应用程序,它有自己的数据库并从另一个服务(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() 可能更简单。

【问题讨论】:

    标签: cakephp ldap cakephp-3.0 data-retrieval


    【解决方案1】:

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

    更复杂的解决方案是自定义关联和自定义关联加载器,但考虑到以数据库为中心的关联的方式,您可能还必须想出一个表和可能的查询实现来处理您的 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'),就像包含一样简单。

    另见

    【讨论】:

    • 这正是我所希望的优雅解决方案!这可以与树结构的threaded finder 结合使用吗?在这种情况下,user_ids 成为嵌套的,并且更难进入一个整洁的列表。
    • @Roberto 在添加threaded finder 之前添加格式化程序/withUsers finder 应该可以正常工作,以便在结果嵌套到线程格式之前运行。否则,您必须递归地迭代结果。
    猜你喜欢
    • 1970-01-01
    • 2017-01-12
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    相关资源
    最近更新 更多