2015-09-04 8 views
5

Я ищу решение через Active Record, чтобы получить иерархические данные в одном запросе.Резьбовые данные в Yii2

То, что я делаю сейчас, сначала извлекает все данные, а затем преобразует массив в нужный массив с рекурсивной функцией.

$allUsers = User::find() 
     ->asArray() 
     ->all(); 
$arr = Yii::$app->TreeComponent->getUserChildren($allUsers, $userId, $userId); 

и TreeComponent

public function getUserChildren($src_arr, $currentId, $userId, $parentFound = false) 
{ 
    $cats = array(); 
    foreach ($src_arr as $row) { 
     if ($row['id'] == $userId) { 
      $row['parent'] = ""; 
     } 
     if ((!$parentFound && $row['id'] == $currentId) || $row['parent'] == $currentId) { 
      $rowData = array(); 
      foreach ($row as $k => $v) 
       $rowData[$k] = $v; 
      $cats[] = $rowData; 
      if ($row['parent'] == $currentId) { 
       $cats = array_merge($cats, $this->fetchRecursive($src_arr, $row['id'], true)); 
      } 
     } 
    } 
    return $cats; 
} 

Сво работает отлично. Но в последнее время я просматриваю CakePHPfind('threaded'), я думаю, что это спасет время выполнения рекурсивной функции и меньше кода.

Мне любопытно, существует ли какая-либо функция в Active Record тоже.

+2

Для этого нет функции, но вы можете использовать [вложенные списки] (https://github.com/creocoder/yii2-nested-sets). – Beowulfenator

+1

Yii's AR не может заполнять иерархические данные за один раз. Вы можете построить структуру дерева, подобную массиву, используя ссылки, чтобы избежать рекурсии. Если вас интересует, что я могу опубликовать пример. – nineinchnick

+0

@nineinchnick да, пожалуйста, я хотел бы посмотреть пример. – ankitr

ответ

2

В Yii2 таких функций нет. CakePHP также выполняет несколько запросов в фоновом режиме и просто переносит их в многопоточный вызов. Основное преимущество скорости, которое вы могли бы получить, если бы вы могли выполнить только один запрос.

Есть два способа для достижения этой цели:

  • Твоего пути ... забирающие все и объединить его в вашем коде
  • NestedSet рисунок как упомянут в комментариях выше

NestedSet

Для Yii2 у нас очень хорошее расширение, реализующее узор вложенного набора. Вы можете найти его здесь:

https://github.com/creocoder/yii2-nested-sets

Плюсы и минусы

Преимуществом является то, - очевидно, - что вы можете получить все, что с помощью одного запроса. Вы даже можете сохранить несколько деревьев в одной таблице.

Основным недостатком является сортировка по столбцам при сохранении древовидной структуры. Вложенный набор организован с двумя атрибутами: слева и справа. Это означает, что все данные сортируются в соответствии с этими двумя атрибутами. Чтобы получить древовидную структуру, отсортированную, например, по имени, вам все равно придется реализовать функциональность с кодовым разделением, чтобы изменить полученный набор данных после запроса. Чистейший способ сортировки данных при сохранении ... смысле вставить новую запись в соответствии с его местом в желаемых сортировках

Википедия имеет очень хорошую explenation вложенного набора: https://en.wikipedia.org/wiki/Nested_set_model

Эта иллюстрация показывает как это работает:

NestedSet illustration

Пример: «слабина» и «куртка» являются детьми «костюмов», как оба их левых и правых атрибуты между левым (3) и правым (8) значением ' костюмы. Если вы хотите добавить ребенка в «куртки», вы будете вводить его между 6 и 7 ... поэтому увеличивая все значения выше или равные 7 на два. Вновь введенный ребенок «куртки» затем получит левое значение 7 и правое значение 8.

Как вы можете видеть, теперь вы можете легко получить целое (под) дерево, просто фильтруя левый и правый атрибуты. Я ж вы хотели, чтобы все от вниз «костюмы» Ваш запрос будет выглядеть следующим образом:

SELECT * FROM mytable WHERE left >= 3 AND right <= 8 ORDER BY left ASC 

окончательный ответ на ваш вопрос

Если основное внимание комфорт

No. Таких функциональных возможностей нет. Если вам по-прежнему требуется регулярное дерево в вашем db и просто не хотите заботиться о слиянии данных, вам нужно будет написать эквивалентную функциональность методам CakePHP. Это должно быть довольно легко, и я думаю, что в этом будет много людей.

Если вашей главной задачей является скорость

Используйте вложенное множество. Это один чертовски простой образец и мощный!

+0

Спасибо за ответ @ PLM57. Моя главная забота - скорость, так как тысячи записей. И в моем случае может быть более 2 дочерних узлов узла, если вложенный набор будет по-прежнему действительным подходом? – ankitr

+0

Добро пожаловать! Да, вы можете иметь столько детей на узел, сколько хотите! Это не похоже на двоичное дерево, где разрешено только двум дочерним ... его регулярное дерево, но организовано по-разному (с атрибутами left/right вместо родительского идентификатора). Эта иллюстрация в wiki-статье объясняет это очень хорошо: https://en.wikipedia.org/wiki/Nested_set_model#/media/File:NestedSetModel.svg – PLM57

0

Вот еще один способ сохранить дерево и получить его без рекурсии. Он требует 2 таблицы.

tree_data 

    Column | Type |           
-----------+---------+ 
id  | integer | 
parent_id | integer | 
level  | integer | 
sort  | integer | 


tree_structure 

Column | Type |       
--------+---------+ 
parent | integer | 
child | integer | 

Пример:

select * from tree_data; 

id | parent_id | level | sort 
----+-----------+-------+------ 
    1 |   0 |  0 | 1000 
    2 |   1 |  1 | 1000 
    3 |   1 |  1 | 2000 
    4 |   1 |  1 | 1500 
    5 |   1 |  1 | 1750 
    6 |   5 |  2 | 1000 


select * from tree_structure order by parent, child; 

parent | child 
--------+------- 
     1 |  1 
     1 |  2 
     1 |  3 
     1 |  4 
     1 |  5 
     1 |  6 
     2 |  2 
     3 |  3 
     4 |  4 
     5 |  5 
     5 |  6 
     6 |  6 

Полученное дерево:

├── 1 
│ ├── 2 
│ ├── 4 
│ ├── 5 
│  ├── 6 
│ ├── 3 

Для запроса дерева:

SELECT tree_data.* 
FROM tree_data 
INNER JOIN tree_structure ON tree_data.id = tree_structure.child and tree_structure.parent = 1 
ORDER BY level, sort; 

Вот набор классов для yii2 to manage this ree

Смежные вопросы