Cake PHP 3.8 преобразовать массив в Cake \ ORM \ Entity - PullRequest
0 голосов
/ 10 июля 2020

В настоящее время я участвую в проекте Cake PHP и не знаю, как передать измененный запрос / массив в пагинатор.

Вот мой контроллер:

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');
    }

}

EDIT: вот функция 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 принимает приведенный запрос к базе данных, вносит некоторые изменения, добавляет два новых свойства и возвращает вложенный массив. Он сопоставляет id с parent_id, чтобы получить детей и описание уровня. Описание уровня будет использоваться для отступов в представлении для отображения иерархического порядка.

ВАЖНОЕ ЗАМЕЧАНИЕ: Я уже опасаюсь TreeBehavior в Cake PHP, но проблема в том, что наша база данных не имеет левого / правого полей, и я не могу их добавить. В рамках этого проекта я должен выбрать этот путь. Однако $data содержит именно то, что я хочу, но мне нужно преобразовать его в совместимый объект для разбивки на страницы.

EDIT: Благодаря ndm я смог построить разбиваемый на страницы объект с необходимыми ограничениями. Последняя проблема, стоящая передо мной, - это объединить всех дочерних элементов и возможных дочерних элементов. У родителя может быть n детей, а также у детей иногда может быть n дочерних детей. Поэтому я решил это с помощью рекурсивного вызова моей функции _setOrderAndLevel внутри fooFunction.

Это текущая структура:

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);
            });
        });

Возможно, решением может быть вызов "comb->", но я не уверен. Любая помощь приветствуется

1 Ответ

0 голосов
/ 14 июля 2020
• 1000 в этом случае вы должны использовать средство форматирования результатов.

Если вам нужен порядок, вы можете сделать это уже на уровне SQL, а для вложения результатов вы можете использовать метод nest() коллекции результатов, ie вы можете отказаться от использования класса 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) будет достаточно, но как только будут добавлены дополнительные средства форматирования, ожидающие коллекцию, все сломается.

См. Также

...