CakePHP 3.8 将数组转换为 Cake\ORM\Entity
CakePHP 3.8 convert array to Cake\ORM\Entity
我目前正在参与一个 CakePHP 项目,不知道如何将修改后的 query/array 传递给分页器。
这是我的控制器:
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
采用转换后的数据库查询,进行一些调整,添加两个新属性和 returns 一个嵌套数组。它将 id
映射到 parent_id
以获得 children 和关卡描述。级别描述将用于视图中的缩进以显示层次顺序。
重要提示: 我已经注意到 CakePHP 中的 TreeBehavior,但问题是我们的数据库没有 left/right 字段,我无法添加它们。在这个项目中,我必须选择这种方式。
但是 $data
包含我想要的内容,但我需要将其转换为兼容的 object 以进行分页。
编辑:感谢 ndm,我可以构建一个具有必要约束的可分页 object。摆在我面前的最后一个问题是合并所有 children 和可能的 sub-children。 parent 可以有第 n 个 children 并且 children 有时可以有第 n 个 sub-children。因此,我通过在 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);
});
});
也许“组合->”调用可能是解决方案,但我不确定。
欢迎任何帮助
一般来说,如果您需要以某种方式格式化结果,您很可能应该使用结果格式化程序,以便能够保持查询对象的完整性,并查看您的函数生成的结果格式,即在这种情况下,您应该使用结果格式化程序。
如果您需要排序,您已经可以在 SQL 级别上进行排序,并且为了嵌套结果,您可以使用结果集合的 nest()
方法,即您可以放弃使用 Hash
class:
$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);
});
请注意,您必须 return 来自结果格式化程序的 \Cake\Collection\CollectionInterface
实例。文档说 returning an(y) 迭代器就足够了,但是一旦附加了期望集合的额外格式化程序,事情就会崩溃。
另见
我目前正在参与一个 CakePHP 项目,不知道如何将修改后的 query/array 传递给分页器。
这是我的控制器:
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
采用转换后的数据库查询,进行一些调整,添加两个新属性和 returns 一个嵌套数组。它将 id
映射到 parent_id
以获得 children 和关卡描述。级别描述将用于视图中的缩进以显示层次顺序。
重要提示: 我已经注意到 CakePHP 中的 TreeBehavior,但问题是我们的数据库没有 left/right 字段,我无法添加它们。在这个项目中,我必须选择这种方式。
但是 $data
包含我想要的内容,但我需要将其转换为兼容的 object 以进行分页。
编辑:感谢 ndm,我可以构建一个具有必要约束的可分页 object。摆在我面前的最后一个问题是合并所有 children 和可能的 sub-children。 parent 可以有第 n 个 children 并且 children 有时可以有第 n 个 sub-children。因此,我通过在 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);
});
});
也许“组合->”调用可能是解决方案,但我不确定。 欢迎任何帮助
一般来说,如果您需要以某种方式格式化结果,您很可能应该使用结果格式化程序,以便能够保持查询对象的完整性,并查看您的函数生成的结果格式,即在这种情况下,您应该使用结果格式化程序。
如果您需要排序,您已经可以在 SQL 级别上进行排序,并且为了嵌套结果,您可以使用结果集合的 nest()
方法,即您可以放弃使用 Hash
class:
$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);
});
请注意,您必须 return 来自结果格式化程序的 \Cake\Collection\CollectionInterface
实例。文档说 returning an(y) 迭代器就足够了,但是一旦附加了期望集合的额外格式化程序,事情就会崩溃。
另见