Иерархическая модель объекта на MongoDB. Версия 3.0

Компонент добавляет на сайт компонент иерархическую модель атрибутов, которая позволяет реализовать широкий вид функцианала, вроде каталога товаров, раздела статей и новостей и т.д.

Для работы компонента на ваш сервер должен быть установлен MongoDB. Установка под различные системы хорошо описана на официальном сайте:
http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/
Если вы разрабатываете ваш сайт под Windows, то для тестирования на локальной машине рекомендуем вам установить Open Server. Он сам устанавливает MongoDB на локальную машину и так же ставит полезный инструмент rockmongo (аналог phpmyadmin для MySQL).
Заметим что Denwer на текущий момент (июнь 2015 года) такими возможностями не обладает.

Возможности компонента

Всё что вам нужно для работы с компонентом - это создать модель, унаследованную от класса NodeMongoModel и в её конструкторе указать список полей, которые должны быть у объекта, и название коллекции (таблицы).
Пример:


    class ItemNodeModel extends NodeMongoModel
    {
        public function __construct($id = NULL, $onlyShow = false, $lang = LANG)
        {
            parent::__construct("items", $id, $onlyShow, $lang); // Базовый констуктор всегда вызываем самым первым и прописываем в нём имя таблицы. Этот вызов идёт первым.

            $this->NInit('code',          NT_STR,   'Артикул');
            $this->NInitMultiLang('name', NT_STR,   'Название');
            $this->NInitMultiLang('text', NT_TEXT,  'Описание');
            $this->NInit('price_rub',     NT_FLOAT, 'Цена рублей');
            $this->NInit('photo',         NT_IMG,   'Фотография');

            $this->NSetClassTitle('Товар'); // Не обязательно, но желательно для админки
        }
    }
    

Теперь в скриптах сайта вы можете работать с объектами этого типа:

        $item = new ItemNodeModel();
        $item->code      = "АЛ109941";
        $item->price_rub = 1999.95;
        $item->photo     = "photo1.jpg"; // Фото должно находиться в папке указанной в $g_config['node_model']['upl_file_path']
        $item_id = $item->Flush(); // Сохранить объект
    

После этого новый элемент был добавлен в базу. Зная id элемента можно создать его экземпляр:

        $item = new ItemNodeModel($item_id);
    

Этот же id можно получить обратившись к полю _id:

        echo $item->_id; // Вернёт что-то наподобие "507f191e810c19729de860ea"
    

Подробнее об _id в MongoDB и о том как он генерируется можно почитать в официальной документации:
http://docs.mongodb.org/manual/reference/object-id/

Созданые объекты можно изменять:

        $item = new ItemNodeModel($item_id);
        $item->price_rub = 2499.95;
        $item->Flush(); // Записать изменения
    

Редактировать на разных языках:

        $item = new ItemNodeModel($item_id);
        $item->NSetCurLang('ru'); // Код языка это ключ из $g_arrLangs
        $item->name = "Игрушка";
        $item->NSetCurLang('en');
        $item->name = "Toy";
        $item->Flush(); // Записать изменения
    

Поиск реализован через основной метод NFind() и дополнительные NFindEx(), NFindAll(), NFindOne(). Получить все существующие объекты:

       
        $model = new ItemNodeModel();
        $total = 0;
        $ids = $model->NFind($total); // Здесь получаем id всех объектов.
    

Теперь имя id элементов можно создать и сами объекты:


        $all = array();
        foreach($ids as $id)
        {
            $all[] = new ItemNodeModel($id);
        }
    

Более сложный случай:


        $filter = array();
        $filter["price_rub"] = 1999.95; // Будем искать все объекты у которых цена равна 1999.95
                   
        $skip  = 20; // Начиная с какого элемента
        $count = 10; // Сколько элементов извлечь
       
        $model = new ItemNodeModel();
        $total = 0; // Сюда будет записано общее количество подходящих элементов
        $ids = $model->Find($total, $filter, $skip, $count, "price_rub"); // Здесь получаем id найденых элементов. Полученные элементы будут упорядочены по полю price_rub.
    

С найдеными элементами можно выполнять любые операции, в том числе вывести в шаблоне:

        
    <?php foreach ($all as $a):?>
  • <?= "ID объекта: {$a->_id}, Артикул: {$a->code}, Цена: {$a->price_rub}"?>
  • <?php endforeach?>

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

Несколько значений у одного атрибута

Каждый атрибут может иметь ни только одно значение, а намного больше. По сути значение всегда является массивом значений. Просто при использовании привычной записи $a->some_field, мы просто всегда обращаемся к первому элементу массива.

Записать более одного значения атрибута можно используя следующий синтаксис:


        $item->category(0, "Куртка"); // Аналог: $item->category = "Куртка";
        $item->category(1, "Жакет");
        $item->category(2, "Ветровка");
    

Чтение тогда будет выглядеть следующим образом:


        echo $item->category(0); // Выведет "Куртка". Аналог: echo $item->category;
        echo "
"; echo $item->category(1); // Выведет "Жакет". echo "
"; echo $item->category(2); // Выведет "Ветровка".

Массив всех значений аттрибута можно получить, используя следующий синтаксис:


        echo implode(", ", $item->category()); // Выведет "Куртка, Жакет, Ветровка"
    

Ещё один вариант вывести список значений поля:

        
    <?php for ($i = 0; $i < count($item->category()); ++$i):?>
  • <?= $item->category($i)?>
  • <?php endfor?>

Инициализация атрибутов

Для инициализации атрибутов существуют следующие основные методы:

Так же есть дополнительные методы:

Простая инициализация атрибута NInit() и NInitMultiLang()

Как вы заметили базовая инилицализация полей объекта осуществляется через методы NInit и NInitMultiLang. Каждый принимает 3 параметра:

Инициализация допустимого количества значений NCount()

В административном разеде по умочанию считается что у атрибута всегда редкатируется только одно значение. Но используя метод NCount() при инициализации, можно это исправить и указать до сколько значений вы хотели бы иметь возможность вписать в аттрибут.

        class ItemNodeModel extends NodeMongoModel
        {
            public function __construct($id = NULL, $onlyShow = false, $lang = LANG)
            {
                parent::__construct("items", $id, $onlyShow, $lang); // Базовый констуктор всегда вызываем самым первым

                $this->NInit('customer', NT_ENUM, 'Покупатель');
                $this->NCount('customer', 3); // Число покупателей может быть до трёх
            }
        };
    

То есть теперь в админке мы можем добавлять дополнительные значения для атрибута, но не больше чем заданное число.
Не ставьте это число слишком большим - в силу технических причин это может привести к замедлению работы административного раздела во время редактирования/добавления объекта.

Инициализация допустимого значений у перечисления NInitEnum()

Если аттрибут имеет тип NT_ENUM (перечисление), то при инициализации с помощью NInitEnum() нужно указать допустимый список значений.
Подрбнее это описано в описании типа NT_ENUM.

Типы атрибутов

В компоненте существуют следующие типы атрибутов:

Базовые типы NT_STR, NT_TEXT, NT_TEXTAREA, NT_INT, NT_FLOAT, NT_DATE, NT_TIME, NT_COLOR

Работа с данными типами уже описана выше. Полученное значение всегда аналогично присвоенному, даже при использовании метода NRender().

Тип NT_OBJ

Тип позволяет создавать у объектов вложенную/иерархическую структуру. Пример инициализации данного типа:

        class EventNodeModel extends NodeMongoModel
        {
            public function InitEventBasics()
            {
                $this->NInit('photo', NT_OBJ, 'Фотография');
                $this->NInit('photo.file',  NT_IMG, 'Фото');
                $this->NInit('photo.title', NT_STR, 'Подпись');
                $this->NCount('photo', 24);
            }
        }
    

Пример использвания на сайте:

        $event = new EventNodeModel();

        $event->photo->file  = "1.png";       // Можно записать так: $event->photo(0)->file
        $event->photo->title = "First photo"; // Можно записать так: $event->photo(0)->title

        $event->photo(1)->file  = "2.png";
        $event->photo(1)->title = "Second photo";

        echo $event->photo(1)->file;  // Выведет "2.png"
        echo $event->photo(1)->title; // Выведет "Second photo"
        echo NodeImgUrl($event->photo(1)->file, 200, 100, "fitout"); // Выведет ссылку на провью изображение 200x100
    

Указывать NT_OBJ является хорошим тоном, но совершенно не обязательно. Такой код тоже будет работать:

        class EventNodeModel extends NodeMongoModel
        {
            public function InitEventBasics()
            {
                $this->NInit('photo.file',  NT_IMG, 'Фото');
                $this->NInit('photo.title', NT_STR, 'Подпись');
                $this->NCount('photo', 24);
            }
        }
    

Тип NT_IMG

Пример использвания на сайте:

        $gallery = new GalleryNodeModel();

        $gallery->photo = "photo.png"; // Файл "photo.png" должен находится в $g_config['node_model']['upl_file_path']

        echo $gallery->photo;  // Выведет "photo.png"
        echo NodeImgUrl($gallery->photo, 200, 100); // Выведет ссылку на провью изображение 200x100
        echo NodeImgUrl($gallery->photo, 200, 100, "scale");  // Выведет ссылку на прeвью изображение 200x100
        echo NodeImgUrl($gallery->photo, 200, 100, "fitin");  // Выведет ссылку на прeвью изображение 200x100 с дорисовкой фона до точного разрешения
        echo NodeImgUrl($gallery->photo, 200, 100, "fitout"); // Выведет ссылку на прeвью изображение 200x100 с обрезкой картинки до точного разрешения
    

Для получения ссылки на изображение, используется функция NodeImgUrl(). Перым параметом у неё идёт имя файла. Вторым и третьим параметом она принимает ширину и высоту до которой нужно уменьшить изображения, а способ уменьшения.
Если указывать только первый параметр, то метод вернёт ссылку на оригинальное изображение.

Подробнее о значениях scale, fitin и fitout в четвертом параметре функции NodeImgUrl() можно почитать в описании компонента Получение обработанного изображения

Тип NT_FILE

Пример использвания на сайте:

        $item = new ItemNodeModel();

        $item->file = "file.doc"; // Файл "photo.png" должен находится в $g_config['node_model']['upl_file_path']

        echo $item->file;  // Выведет "photo.png"
        echo NodeFileUrl($item->file); // Выведет ссылку на файл
    

Для получения ссылки на файл, используется функция NodeFileUrl(). Перым параметом у неё идёт имя файла.

Для скачивания файлов используется компонент BrowserDataCache, поэтому по умолчанию разрешено скачивать только некоторые типы файлов (это можно изменить настроив компонент).

Тип перечисление NT_ENUM

Пример инициализации данного типа:

        define("SEX_NONE",   1);
        define("SEX_MALE",   2);
        define("SEX_FEMALE", 3);

        class UserNodeModel extends NodeMongoModel
        {
            const REMEMBER_PERIOD = 604800; // Время хранения авторизации (в секундах)
       
            public function __construct($id = NULL, $onlyShow = false, $lang = LANG)
            {
                parent::__construct("users", $id, $onlyShow, $lang);
       
                $this->NInit('sex', NT_ENUM, 'Пол'); // Декларация
                // Возможные варианты
                $this->NInitEnum('sex', SEX_NONE,   'Не указан');
                $this->NInitEnum('sex', SEX_MALE,   'Мужской');
                $this->NInitEnum('sex', SEX_FEMALE, 'Женский');
            }
        };
    

Пример использвания на сайте:

        $user = new UserNodeModel();
        $user->sex = SEX_FEMALE;

        echo $user->sex; // Выведет "3"
        echo $user->NRender("sex"); // Выведет "Женский"
    

При этом значения перечислений могут быть не только целыми числами, допустимы и обычные строки:

        define("SEX_NONE",   "none");
        define("SEX_MALE",   "male");
        define("SEX_FEMALE", "female");
    

Тип NT_BOOL

Пример использвания на сайте:

        $item = new ItemNodeModel();

        $item->is_show = true;
        echo $item->is_show;  // Вернет 1
        echo $user->NRender("is_show"); // Выведет 'Да' или 'Yes'

        $item->is_show = false;
        echo $item->is_show;  // Вернет 0
        echo $item->NRender("is_show"); // Выведет 'Нет' или 'No'
    

Тип NT_UDATE

Пример использвания на сайте:

        $item = new ItemNodeModel();

        $item->date = 1403896653;
        echo $item->date;  // Выведет 1403896653
        echo $item->NRender("date"); // Выведет '27.06.2014'
    

Тип NT_AUTOINC

Автоматически увеличивающийся целочисленный счётчик. Аналог AUTO_INCREMENT поля в MySQL.
В работе атрибут аналогичен типу NT_INT. Но отличается тем, что сам автоматически записывается при создании объекта (т.е. при первом сохранении), хотя можно задать и своё значние вручную.
Алгоритм таков, что запишется макс. значение, найденное среди все объектов, увеличенное на единицу. Если создаётся первый объект то запишется 1.
!!! Работает пока только для корневых полей.

Тип NT_SPECIAL

Специальный тип для инициализации виртуальных атрибутов, который позволяет делать своё поле отображения/сохранения значения в админке. Для работы нужно переопределять метод NRenderSpecialInput(). Пример использования:

        class CityNodeModel extends NodeMongoModel
        {
            public function __construct($id = NULL, $onlyShow = false, $lang = LANG)
            {
                // ...
                $this->NInitVirt('set_region', NT_SPECIAL, 'Регион к которому принадлежит'); // После NInitVirt() аттрибут будет доступен в админке
                $this->NInit('_region_id',     NT_MONGOID, 'Регион к которому принадлежит');
                // ...
            }

            //...

            protected function NGetVirt($name, $index)
            {
                if ($name == "set_region")
                {
                    return $this->_region_id;
                }
                return parent::NGetVirt($name, $index);
            }
           
            protected function NSetVirt($name, $index, $value)
            {
                if ($name == "set_region")
                {
                    return $this->_region_id = $value;
                }
                return parent::NSetVirt($name, $index, $value);
            }
       
            public function NRenderSpecialInput($name, $data)
            {
                if ($name == "set_region")
                {
                    ob_start();
                        IncludeCom("admin/my_node_input_regions", $data);
                    return ob_get_clean();
                }
                return parent::RenderSpecialInput($name, $data);
            }
        }

        //** Содержимое файла "/tpl/admin/my_node_input_regions.php":
        
        
        

    

Поиск элементов через NFind()

Метод NFind() предоставляет широкие возможности по поиску нужных объектов в базе. Метод имеет следующие аргументы:

Аргумент $total - это ссылка на переменную, в которую будет записано общее число объектов, удовлетворяющее аргументу $filter.

Аргумент $filter позволяет задавать атрибуты, по которым нужно произвести поиск.
Ключ массива обозначает название атрибута, по которому нужно провести поиск, а значение - параметр по которому это поле фильтруется. Причём значение может быть не прямым значением атрибута в объекте, а содержать в себе диапазон, массив допустимых значений и т.д.
Возможности поиска представлены в следующем примере:

        $filter = array();
        $filter["some_val"] = 'Ololo'; // Все элементы у которых параметр 'some_val' равен "Ololo".
        $filter["some_int"] = array('min' => 3007); // Все элементы у которых числовой параметр 'some_int' больше 3007.
        $filter["some_int"] = array('min' => 3007,  'max'  => 4020); // Все элементы у которых числовой параметр 'some_int' больше 3007 и меньше 4020.
        $filter["some_int"] = array('emin' => 3007, 'emax' => 4020); // Все элементы у которых числовой параметр 'some_int' больше-равно 3007 и меньше-равно 4020.
        $filter["some_val"] = array('a1', 'a2', 'a3'); // Все элементы у которых 'some_val' равно 'a1' или 'a2' или 'a3'.
        $filter["text1,text2"] = "ABC";                // Все элементы у которых либо параметр 'text1' либо параметр 'text2' равен 'ABC'.
        $filter["some_val"] = array('like' => "text"); // Все элементы у которых параметр 'some_val' содержит подстроку "text". Не чувствителен к регистру.
        $filter["some_val"] = array('not'  => "text"); // Все элементы у которых параметр 'some_val' не равен "text".
        $filter["some_val"] = array('exists' => true); // Все элементы у которых параметр 'some_val' существует (если false то не существует).

        // Допустимы и вложенные атрибуты:
        $filter["preview.file"] = array('like' => ".png"); // У поля preview подполе file должна быть подстрока содержащая ".png"
    

ВАЖНО!!! Помните что атрибут дожен быть реальным полем. Виртуальные атрибуты не работают.

Аргумент $skip - сколько элементов пропустить с начала списка.

Аргумент $count - сколько элементов должно быть в списке.

Аргумент $orderBy - название поля, по которому нужно упорядочить элементы. Примеры принимаемых значений:

Если сортировка идёт по мультиязычным полям, то сортировка произойдет в пределах языка, переданного в аргументе $lang (певрый элемент $lang, если $lang это массив).
!!! ВАЖНО: Сортировка по двум атрибутам сразу в данный момент не работает.

Аргумент $lang - применим только строковых многоязычных параметров. Поиск будет произовдиться только в пределах данного языка. По умолчанию равен текущему языку. Можно задать массив языков, например array("en", "ru").

Дополнительные методы поиска

Форматирование значение атрибутов с помощью NRender()

Любой атрибут можно получить в более удобном для восприятия отформатированном виде. Особенно это актуально для типов: NT_ENUM, NT_BOOL, NT_UDATE. Для получения отформатированного значения используется метод NRender(). Он принимает название атрибута, индекс и разделитель. Если индекс не задан и в аттрибуте находится больше одного значения, то будут возвращены все значения, через разделитель. Примеры:

        $user->sex = SEX_FEMALE;
        echo $user->sex;  // Выведет 2
        echo $user->NRender("sex");    // Выведет "Женский"
        echo $user->NRender("sex", 0); // Выведет "Женский"
        
        $user->sex(0, SEX_FEMALE);
        $user->sex(1, SEX_MALE);
        echo $user->NRender("sex", 0); // Выведет "Женский"
        echo $user->NRender("sex", 1); // Выведет "Мужской"
        echo $user->NRender("sex");    // Выведет "Женский, Мужской"
        echo $user->NRender("sex", NULL, "|");    // Выведет "Женский|Мужской"

        //**

        $user->is_valid = false;
        echo $user->is_valid;  // Выведет 0
        echo $user->is_valid("sex"); // Выведет "Нет"

        $user->is_valid = true;
        echo $user->is_valid;  // Выведет 1
        echo $user->is_valid("sex"); // Выведет "Да"
        
        //**

        $item->date = 1403896653;
        echo $item->date;  // Выведет 1403896653
        echo $item->NRender("date"); // Выведет '27.06.2014'

        $item->date(0, 1403896653 + 0 * 24 * 60 * 60);
        $item->date(1, 1403896653 + 1 * 24 * 60 * 60);
        $item->date(2, 1403896653 + 2 * 24 * 60 * 60);
        echo $item->NRender("date", 1); // Выведет '28.06.2014'
        echo $item->NRender("date"); // Выведет '27.06.2014, 28.06.2014, 29.06.2014'
    

Важно отметить ещё одну важную особенность метода NRender() касающуюся многоязычных полей. Если не удалось получить не пустое значение аттрибута на текущем языке объекта, то будет попытка получить такое же значение на языке по умолчанию. Пример:

        // Пускай DEF_LANG равен 'en'. Тогда:
        
        $user->NSetCurLang('en');
        $user->name = "Item";

        echo $user->name; // Выведет "Item"
        echo $user->NRender("name"); // Выведет "Item"

        $user->NSetCurLang('ru');

        echo $user->name; // Выведет "", так как значение на русском не задано.
        echo $user->NRender("name"); // Выведет "Item". Хоть значение на русском у нас и не задано, но NRender() возьмёт значение на языке по умолчанию.
        
        $user->name = "Изделие";

        echo $user->name; // Выведет "Изделие"
        echo $user->NRender("name"); // Выведет "Изделие"
    

Виртуальные атрибуты

Виртуальные атрибуты, это не сущетвующие реально атрибуты, но тем не менее доступные для установки и запросе значений.
Действие выполняемое при запросе или установке атрибута определяется в методах NGetVirt() и NSetVirt().
Первый параметр в обоих методах это название атрибута, а третий в NSetVirt() это присваиваемое значение.
Пример:

        class UserNodeModel extends NodeMongoModel
        {
            // ...
            
            protected function NGetVirt($name, $index)
            {
                if ($name == "full_name")
                {
                    return $this->first_name . " " . $this->last_name;
                }
                return parent::NGetVirt($name, $index);
            }
           
            protected function NSetVirt($name, $index, $value)
            {
                if ($name == "full_name")
                {
                    $arr = explode(" ", $value);
                    $this->first_name = $arr[0];
                    $this->last_name  = $arr[1];
                    return;
                }
                return parent::NSetVirt($name, $index, $value);
            }
        }

        // Использование:
        $user->full_name = "Владимир Ильич";
        echo $user->full_name; // Выведет "Владимир Ильич"
    

Второй параметр в обоих методах нужен для того случая, когда виртуальный аттрибут представляет собой массив значений. Параметр представляет собой индекс в массиве.
Но в этом случае желательно переопределить метод NGetVirtCount(), иначе метод NRender() для такого виртуального атрибута может работать некорректно.
Пример:

        class UserNodeModel extends NodeMongoModel
        {
            $private $inner = array();

            // ...

            protected function NGetVirt($name, $index)
            {
                if ($name == "arr")
                {
                    return @$this->inner[$index];
                }
                return parent::NGetVirt($name, $index);
            }
           
            protected function NSetVirt($name, $index, $value)
            {
                if ($name == "arr")
                {
                    return $this->inner[$index] = $value;
                }
                return parent::NSetVirt($name, $index, $value);
            }

            protected function NGetVirtCount($name)
            {
                if ($name == "arr")
                {
                    return count($this->inner);
                }
                return parent::NGetVirtCount($name);
            }
        }
        
        // Использование:
        $user->arr  = "A";
        $user->arr(1, "B");
        $user->arr(4, "C");

        print_r($user->arr()); // Выведет ["A", "B", "C"]
        echo $user->NRender("arr"); // Выведет "A, B, C"
    

Так же есть дополнительный метод NIsVirt() позволяющий узнать является ли аттрибут виртуальным или нет:

        echo $user->NIsVirt("arr");
        echo $user->NIsVirt("map.image");
        echo $user->map->NIsVirt("image");
    

!!! ВАЖНО: Методы NGetVirt(), NSetVirt(), NGetVirtCount() работают только для корневых атрибутов.
Если вам нужно определить дейтствия для вложенных атрибутов, то следует унаследоваться от NodeMongoModelBase и зарегестрировать класс методом NInitObj().
Более подробно это описано в соответствующем разделе.

Виртуальные атрибуты в админке

Виртуальный атрибут можно зарегистрировать в конструктуре с помощью метода NInitVirt().
После этого виртуальный атрибут станет доступен для редактирования в админке, как другие обычные атрибуты.
Аргументы метода аналогичны методу NInit(). Второй параметр (тип) в данном случае определяет то, в каком поле ввода будет редактироваться значение.

        class ItemNodeModel extends NodeMongoModel
        {
            public function __construct($attr_id = NULL, $onlyShow = false, $lang = LANG)
            {
                // ...
                $this->NInitVirt("category", NT_STR, "Категория");
            }
        }
        // ...
    

Назнечение действий на события сохранения и валидации объекта

У класса можно перегрузить следующие функции:

Пример:

        class ItemNodeModel extends NodeMongoModel
        {
            // ...

            public function NOnValidate()
            {
                $errs = parent::NOnValidate(); // Можно и просто array()
                if ($this->name == "")
                {
                    $errs[] = "Пустое имя";
                }
                return $errs;
            }
            
            public function NOnFirstSave()
            {
                $this->_added = time();
            }
           
            public function NOnSave()
            {
                $this->_modified = time();
            }
        }
        // ...
    

Смена языка на ходу

Текущий язык объекта можно завдать в третьем параметре конструктора (по умолчанию текущий язык).
Но так же язык можно менять прямо на ходу с помощью метода NSetCurLang():

        $user->NSetCurLang('ru');
    

Получить текущий язык можно с помощью метода NGetCurLang():

        echo $user->NGetCurLang(); // Вернёт 'ru' или другой доступный язык
    

Задание класса для атрибута с типом NT_OBJ через NInitObj()

Фактически необходимо лишь во вложенных узлах для обработки виртуальных атрибутов и для переопределения NRender().

@todo Пример.

Дополнительные методы

У класса можно перегрузить следующие функции:

Стандартные методы модели

Присутствуют и в других видах моделей и имеют тот же смысл:

Работа с админкой

Создать административный раздел для редактирование объектов какой либо модели довольно просто.
Всё что нужно - это создать файл раздела, например /src/admin/items.php и вызвать в нём IncludeCom("admin/node_model/list", array(/* Параметры */)).
Данный вызов создаст на этой странице блок поиска (фильтрации) и таблицу со списком объектов.
В данном примере показано какие параметры нужно передать в компонент:

        IncludeCom("admin/node_model/list", array
        (
            // Атрибуты, которые будут являться столбцами в таблице объектов (на данный момент поддерживаются не все типы)
            "table"  => array("name", "desc", "photo", "price_rub", "is_show", "_added"), 

            // Имя нашего класса
            "class"  => "ItemNodeModel", 

            // Атрибуты, по которым можно будет производить поиск/фильтрацию. Будут отображаться в специальном блоке над таблицей.
            // Если параметр не указан, то будет равен значению указанному в "table".
            "search"  => array("name", "inner_code"),

            // Поле, по которому сортировать элементы по умолчанию. Не обязательный параметр.
            "order"  => "_added",

            // Прямой (1) или обратный (-1) порядок сортировки по умолчанию. Не обязательный параметр.
            "order_dir" => -1, 
            
            // Базовый фильтр, по которому будут отобраны объекты. Аналогичен параметру filter в NFind().
            // При поиске/фильтрации по параметрами указанным в "search", эти параметры будут накладываться на базовый фильтр.
            // Не обязательный параметр, по умолчанию array().
            "filter"  => array("sex" => array(SEX_MALE, SEX_FEMALE), "is_show" => true),
        ));
    

Важно не забыть добавить раздел в главное меню админки. Достаточно в файле конфигурации (папка /core/config/) указать что-то вроде:

    <?php

        require_once BASEPATH . 'core/config/admin_menu.php';
      
        GetQuery(); // Чтобы фунция SiteRoot корректно заработала нужно проинициализировать LANG в функции GetQuery()
        $g_config['admin_menu'][]   = array
        (
            'link'  => SiteRoot('admin/items'),
            'name'  => 'Изделия', // Название пункта меню
            'label' => '',
            'css'   => '',
            'list'  => array()
        );
     ?>