<?php

$categories = '
    Категория 1
    -1.0
    -1.1
    --1.1.0    
    ---1.1.1.0
    ----1.1.1.1.0
    -----1.1.1.1.1.0
    -----1.1.1.1.1.1
    ------chunks:myChunk1
    -----1.1.1.1.1.2
    Категория 2
    -2.0    
    -2.1
    --2.1.0
    --2.1.1
    --2.1.2
    ---2.1.2.0
    ---2.1.2.1
    ----2.1.2.1.0
    -----chunks:myChunk2
    ----2.1.2.1.1
    ----2.1.2.1.2
    ---2.1.2.2
    --2.1.3
    ---chunks:myChunk3|myChunk4
';

$modx = & $transport->xpdo;

// преобразуем текст с категориями в массив (с чисткой)
$categories = trim($categories);
$categories = explode("\r\n", $categories);
$categories = array_map('trim', $categories);
$categories = array_diff($categories, ['']);
$categories = array_values($categories);

// узнать уровень вложенности по префиксу в начале строки
function getLevel($str) {
    preg_match_all("#^[\-]+#", $str, $matches);

    $level = 0;
    if(!empty($matches[0][0])) {
        $level = substr_count($matches[0][0], '-');
    }
    return $level;
}

// преобразуем массив в правильный для работы массив-дерево
function strToTree($lines) {
    // ищём корневые узлы
    $knots = [];             // массив корневых узлов (строки)
    $knots_count = 0;        // счётчик корневых узлов

    foreach ($lines as $line) {
        $level = getLevel($line);

        // уровень 0
        if($level===0) {
            $knots_count++;

            $knots[$knots_count-1] = $line;
            $child_knots[$knots_count-1] = [];      // массив дочерних узлов (строки) по родителям
        }

        // уровень 1 и выше
        if($level>0) {
            $new_line = preg_replace("#^-#", '', $line);    // удаляем маркер
            $child_knots[$knots_count-1][] = $new_line;
        }
    }

    $output = [];
    foreach ($knots as $key => $knot) {
        $output[$key]['name'] = $knot;
        $subcats = strToTree($child_knots[$key]);
        if($subcats) {
            $output[$key]['subcats'] = $subcats;
        }
    }

    return $output;
}

// преобразованный массив
$categories = strToTree($categories);

// обходим корневые директории (должны быть заранее созданы)
foreach ($categories as $category) {
    global $modx;

    $obj = $modx->getObject('modCategory', [
        'parent' => 0,
        'category' => $category['name']
    ]);

    if($obj and $category['subcats']) {
        // рекурсивно обходим массив с подкатегориями
        bypassCats($category['subcats'], $obj->id);
    }
}

// рекурсивный обход массива подкатегорий
function bypassCats($categories, $parent) {
    foreach ($categories as $category) {
        if(substr_count($category['name'], ':') > 0) {
            // устанавливаем категорию объекту
            setObjectCategory($category['name'], $parent);
            continue;
        }

        // добавляем категорию
        $id = addCat($category['name'], $parent);

        if (!empty($category['subcats'])) {
            // перебираем дочерние
            bypassCats($category['subcats'], $id);
        }
    }
}

// устанавливаем категорию объекту
function setObjectCategory($name, $category) {
    global $modx;

    preg_match("#^(.+):(.+)#", $name, $matches);
    $index = trim($matches[1]);
    $values = trim($matches[2]);
    $values = explode("|", $values);
    $values = array_map('trim', $values);

    $classes = [
        'snippets' => ['modSnippet', 'name'],
        'chunks' => ['modChunk','name'],
        'plugins' => ['modPlugin','name'],
        'templates' => ['modTemplate','templatename']
    ];

    foreach ($values as $value) {
        $obj = $modx->getObject($classes[$index][0], [
            $classes[$index][1] => $value
        ]);

        if($obj) {
            $obj->set('category', $category);
            $obj->save();
        }
    }
}

// добавление новой подкатегории
function addCat($category, $parent) {
    global $modx;

    $obj = $modx->getObject('modCategory', [
        'parent' => $parent,
        'category' => $category
    ]);

    if(!$obj) {
        $obj = $modx->newObject('modCategory');

        $obj->set('parent', $parent);
        $obj->set('category', $category);
        $obj->save();
    }
    return $obj->id;
}

return true;