Иерархическая модель объекта на MongoDB
Компонент добавляет на сайт компонент иерархическую модель объекта, которая позволяет реализовать широкий вид функцианала, вроде каталога товаров, раздела статей и новостей и т.д.
Для работы компонента на ваш сервер должен быть установлен MongoDB. Установка под различные системы хорошо описана на официальном сайте:
http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/
Если вы разрабатываете ваш сайт под Windows, то для тестирования на локальной машине рекомендуем вам установить Open Server.
Он сам устанавливает MongoDB на локальную машину и так же ставит полезный инструмент rockmongo
(аналог phpmyadmin для MySQL).
Заметим что Denwer на текущий момент такими возможностями не обладает.
Возможности компонента
Всё что вам нужно для работы с компонентом - это создать модель, унаследованную от класса AttrComblexModel и указать в её конструкторе список полей, который должны быть у объекта.
Пример:
class ItemNodeModel extends NodeMongoModel { public function __construct($id = NULL, $onlyShow = false, $lang = LANG) { parent::__construct("items", $id, $onlyShow, $lang); // Базовый констуктор всегда вызываем самым первым и прописываем в нём имя таблицы $this->NInit('code', NT_CONST, 'Артикул'); $this->NInit('name', NT_STR, 'Название'); $this->NInit('price_rub', NT_FLOAT, 'Цена рублей'); $this->NInit('photo', NT_IMG, 'Фотография'); $this->NInit('text', NT_TEXT, 'Описание'); $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(); // Записать изменения
Когда некоторое количество объектов окажется записано в базу, вам понадобится поиск/извлечение элементов. Он реализован через метод Find(). Получить все существующие объекты:
$model = new ItemNodeModel(); $total = 0; $ids = $model->Find($total); // Здесь получаем id всех объектов.
Более сложный случай:
$filter = array(); $filter["price_rub"] = 1999.95; // Будем искать все объекты у цена равна 1999.95 $from = 0; // Начиная с какого элемента $count = 100; // Сколько элементов извлечь $model = new ItemNodeModel(); $total = 0; // Сюда будет записано общее количество подходящих элементов $ids = $model->Find($total, $filter, $from, $count, "price_rub"); // Здесь получаем id найденых элементов. Полученные элементы будут упорядочены по полю price_rub.
Теперь имя id элементов можно создать и сами объекты:
$all = array(); foreach($ids as $id) { $all[] = ItemNodeModel($id); }
С найдеными элементами можно выполнять любые операции, в том числе вывести в шаблоне:
-
<?php foreach ($all as $a):?>
- <?= "ID объекта: {$a->_id}, Артикул: {$a->code}, Цена: {$a->price_rub}"?> <?php endforeach?>
Так же существует компонент, который позволяет добавлять и редактировать объекты через административный раздел.
Несколько значений у одного поля
У любого поля, используя индекс, можно задать (и прочитать) более одного значения:
$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?>
В конструкторе можно указать сколько значений у данного поля вы планируете использовать:
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); // Число покупателей может быть до трёх } };
Но на практике эта величина влияет только на компонент админка для модели атрибутов. При записи/чтении данных это ограничение не работает.
Когда количество задано - в административном разделе можно добавлять дополнительные значения для поля, но не больше чем заданное число.
Не ставьте это число слишком большим - в силу технических причин это может привести к замедлению работы административного раздела во время редактирования объекта.
Типы полей объекта
Как вы заметили инилицализация полей объекта осуществляется через метод NInit. Он принимает 3 параметра:
- - Наименование поля, по которму мы к нему обращаемся. Для него можно использовать маленькие латинские символы, нижнее подчеркивание и цифры.
- - Тип аттрибута поля (будут перечислены далее)
- - Заголовок поля. Используется в админке и методе GetTitle(). Для многоязычных сайтов можно вынести в lang файл (в папку autoload).
В компоненте существуют следующие типы:
- NT_OBJ - контейнер. Может содержать другие под-переменные. В дальнейшем будет показан пример использования
- NT_CONST - константа. Почти аналогичен NT_STR, но сохраняет значение всегда только для одного языка (DEF_LANG)
- NT_STR - строка. Имеет поддежку многоязычности
- NT_TEXT - аналогичен классу AString. Отличается только удобным полем редактирования в административном разделе
- NT_FLOAT - число с плавающей точкой
- NT_INT - целое число
- NT_IMG - имя файла изображения. Не многоязычен. В административном разделе для этого типа можно загружать фотографии
- NT_FILE - имя файла. Не многоязычен. В административном разделе для этого типа можно загружать файлы
- NT_ENUM - перечисление. Работа с этим типом будет описана далее
- NT_BOOL - булеан. Может принимать только два значения - 0 и 1
- NT_DATE - Дата хранимая в виде строки в формате Y-m-d
- NT_TIME - Время хранимое в виде строки в формате {часы}:{минуты}
- NT_UDATE - Дата хранимая в виде unixtime
Тип перечисление 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->Render("sex"); // Выведет 'Женский'
Тип 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_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 с обрезкой картинки до точного разрешения
Подробнее о параметрах 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); // Выведет ссылку на файл
Тип NT_BOOL
Пример использвания на сайте:
$item = new ItemNodeModel(); $item->is_show = true; echo $item->is_show; // Вернет 1 echo $user->Render("is_show"); // Выведет 'Да' $item->is_show = false; echo $item->is_show; // Вернет 0 echo $item->Render("is_show"); // Выведет 'Нет'
Тип NT_UDATE
Пример использвания на сайте:
$item = new ItemNodeModel(); $item->date = 1403896653; echo $item->date; // Выведет 1403896653 echo $item->Render("date"); // Выведет '27.06.2014'
Остальные типы
Остальные типы достаточно просты и не требуют подробного пояснения. Присвоение значений происходит так же. Полученное значение всегда аналогично присвоенному, даже при использовании метода Render().
Заметим лишь, что при работе с языко-зависимыми типами (NT_STR, NT_TEXT), важно то,
какой язык задаётся в конструкторе класса (последний параметр, по умолчанию равен LANG).
При необходимости язык можно менять на ходу:
$o = new PainterNodeModel(); $o->SetCurLang('en'); $o->name = $nameEn; $o->SetCurLang('de'); $o->name = $nameDe; $o->Flush();
Возможности поиска элементов
Метод Find() предоставляет широкие возможности по поиску нужных объектов в базе. Метод имеет следующие аргументы:
Аргумент $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"
Ключ может указывать на место поля в иерархии полей класса. Например, для класса:
class ItemNodeModel extends AttrComblexModel { public function __construct($attr_id = NULL, $onlyShow = false, $lang = LANG) { parent::__construct($attr_id, $onlyShow, $lang); // Базовый констуктор всегда вызываем самым первым $this->InitAttr('code', 'AConst', 'Артикул'); $this->InitAttr("preview", 'AMImg', 'Превью изображение'); // У AMImg есть поля file и name } }
Поиск всех объектов, у которых есть превью изображения c расширением "png" будет выглядеть следующим образом:
$filter = array(); $filter["preview.file"] = array('like' => ".png"); // У поля preview подполе file должна быть подстрока содержащая ".png" $total = 0; $ids = $model->Find($total, $filter);
ВАЖНО!!! Помните что ключ дожен быть реальным полем и что виртуальные атрибуты не учитываются.
Аргумент $from - начиная с какого элемента вернуть список
Аргумент $count - сколько элементов должно быть в списке
Аргумент $orderBy - название поля, по которому нужно упорядочить элементы. Примеры принимаемых значений:
- "key1" - сортировать по ключу key1
- array("key1" => 1) - то-же самое
- array("key1" => -1) - сортировать по ключу key1 в обратном порядке
- array("key1", "key2") - сортировать по ключам key1 и key2
- array("key1" => 1, "key2" => -1) - сортировать по ключу key1 в прямом порядке и key2 в обратном порядке
- NM_SORT_RANDOM - сортировать в случайном порядке
Аргумент $lang - для строковых параметров позволяет задать язык поиска. По умолчанию равен текущему языку.