0

我目前参与了一个 CakePHP 项目,但不知道如何将修改后的查询/数组传递给分页器。

这是我的控制器:

public function index($fooElement = '')
{  
      
    $query = $this->Properties->find()->where(['fooElement' => $fooElement]);
    
    //The fooFunction needs an array cause for an internal call of cakes HASH::NEST function
    $data= $this->FooModel->_fooFunction($query->enableHydration(false)->toList();
    
    //Error: Not a paginable object
    $data = $this->paginate($data) 

    $this->set(compact('fooElement', 'data'));
    $this->set('_serialize', ['data']);

    if (empty($fooElement)) {
        $this->render('otherView');
    }

}

编辑:这是 fooFunction:

public function _fooFunction($data)
{
    $out = [];
    $cache = [];

    $nested = Hash::nest($data, ['idPath' => '{n}.id', 'parentPath' => '{n}.parent_id']);


    $out = $this->_setOrderAndLevel($nested);
    return $out;
}

protected function _setOrderAndLevel($items, $level = 0, $number = 0)
{
    $out = [];
    $items = Hash::sort($items, '{n}.orderidx');
    foreach ($items as $item) {
        $item['level'] = $level;

        if (!empty($item['children'])) {
            $children = $item['children'];
            unset($item['children']);
            $out[] = $item;
            $out = array_merge($out, $this->_setOrderAndLevel($children, $level + 1));
        } else {
            $out[] = $item;
        }
    }
    return ($out);
}

接受强制转换的_fooFunction数据库查询,进行一些调整,添加两个新属性并返回一个嵌套数组。它映射idparent_id获取孩子和级别描述。级别描述将用于视图中的缩进以显示分层顺序。

重要通知:我已经提防 CakePHP 中的 TreeBehavior,但问题是我们的数据库没有左/右字段,我无法添加它们。在这个项目中,我必须选择这种方式。但是$data包含我想要的内容,但我需要将其转换为兼容的分页对象。

编辑:感谢 ndm,我可以构建一个具有必要约束的可分页对象。我面前的最后一个问题是合并所有孩子和可能的子孩子。父母可以有第 n 个孩子,孩子有时也可以有第 n 个子孩子。因此,我通过在 fooFunction 中递归调用我的 _setOrderAndLevel 函数解决了这个问题。

这是当前的结构:

array(
      [0] = fooEntity(
           id = 1,
           orderidx = 1,
           parentId = null,
           level = 0,
           children(
                id = 2,
                orderidx = 2,
                parentId = 1,
                level = 1
                children(
                    id = 3,
                    orderidx = 3,
                    parentId = 2,
                    level = 2
                           ........

但应该是这样的:

array(
      [0] = fooEntity(
                     id = 1,
                     orderidx = 1,
                     parentId = null
                     level = 0

      [1] = fooEntity(
                     id = 2,
                     orderidx = 2,
                     parentId = 1,
                     level = 1
      
      [2] = fooEntity(
                     id = 3,
                     orderidx = 3,
                     parentId = 2,
                     level = 2
       ........
          

我尝试构建第二个结果格式化程序,但它不起作用:

...
return $results
                ->nest('id', 'parent_id', 'children')
                ->map($decorate);
        })
        ->formatResults(function (\Cake\Collection\CollectionInterface $results) {
            return $results->map(function ($data) {
                call_user_func_array('array_merge', $data);
            });
        });

也许“combine->”调用可能是解决方案,但我不确定。欢迎任何帮助

4

1 回答 1

0

通常,如果您需要以某种方式格式化结果,您很可能应该使用结果格式化程序,以便能够保持查询对象的完整性,并查看函数生成的结果格式,这就是您应该使用的在这种情况下,结果格式化程序。

如果您需要排序,您已经可以在 SQL 级别执行此操作,并且对于嵌套结果,您可以使用结果集合的nest()方法,即您可以放弃使用Hash该类:

$query = $this->Properties
    ->find()
    ->where(['fooElement' => $fooElement])
    ->order(['orderidx' => 'ASC'])
    ->formatResults(function (\Cake\Collection\CollectionInterface $results) {
        $fold = function ($rows, $level = 0) use (&$fold) {
            $folded = [];
            foreach ($rows as $row) {
                $row['level'] = $level;

                $children = $row['children'] ?: null;
                unset($row['children']);

                $folded[] = $row;
                if ($children) {
                    $folded = array_merge(
                        $folded,
                        $fold($children, $level ++)
                    );
                }
            }

            return $folded;
        };

        $nested = $results->nest('id', 'parent_id', 'children');
        $folded = $fold($nested);

        return collection($folded);
    });

请注意,您必须\Cake\Collection\CollectionInterface从结果格式化程序返回一个实例。文档说返回一个(y)迭代器就足够了,但是一旦附加了额外的格式化程序来期望一个集合,事情就会中断。

也可以看看

于 2020-07-14T10:24:27.060 回答