Создание CMS Модель данных. Конструирование

Продолжаем тему объектной модели данных. В этой части речь пойдет о модуле Data, являющимся, по сути, ORM системой. Для наглядности работы модуля Data c его помощью будет создано содержимое простого сайта.

Модуль Data состоит из классов Data, Object, Multy, Query и набора классов Cond*. Сам модуль – это статический класс Data, остальные классы используются для представления структур данных, с которыми он работает. Для представления сущностей в программном коде используется класс Object. Не важно, какого типа сущность – класс данных, объект данных или связь между ними – для всех Object. Класс Multy используется для ассоциации с набором сущностей, в частности, для представления множественных свойств. Классы Query и Cond* необходимы для осуществления поиска по объектной модели (в базе данных) с учетом гибких условий.

Чтение сущности

Получить сущность из базы данных можно по её идентификатору следующим способом:

$obj = Object::Create(1); // сущность с идентификатором 1

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

После получения сущности, её можно полноценно использовать, например, обратиться к её классу и узнать системное имя.

echo $obj->getP('class')->getA('sys_name');

Обратите внимание, загруженная сущность – это класс, но работа выполняется с ним как с объектом. Сущность загружается из БД по требованию, то есть реальное обращение к базе данных происходит только при первом обращении к свойствам или атрибутам сущности, более того, загружаются только те свойства (сущности с которыми выполнена связь), которые используются.

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

У объекта имеются свойства (Property) и атрибуты (Attribute). Атрибут – это скалярное значение. Свойство – это связь на другой объект, фактически – объект, с которым выполнена связь. Связь на класс и связь наследования оптимизированы – представлены в БД как атрибуты, но логикой модуля данных они превращаются в свойства.
Для обращения к свойствам используется метод getP($name), возвращающий объект, с которым установлена связь. Можно обратиться к самой связи с помощью метода getL($name) – возвратится объект связи.

В приведенном примере выполняется обращение к классу, но связь с классом не реализуется объектом (так как оптимизирована), поэтому обращение к связи на класс бессмысленно – объекта-связи нет. Метод getA($name) используется для чтения значения атрибута по его имени.

Загрузка сущности автоматически инициируется при первом обращении к любому из её атрибутов или свойству. Загрузка автоматически выполняется методом Load(). Для загрузки сущности определяется её класс, определяется иерархия наследования классов. По классам определяются таблицы, из которых загружаются атрибуты сущности. Для загрузки свойств достаточно напрямую обратиться к таблице связей и загрузить все связи, у которых атрибут «primary» равен идентификатору загружаемой сущности. Загружаются только связи. Объекты, на которые ссылаются связи, загружаются по общему принципу – если будут использоваться их атрибуты или свойства.

Создание сущности

Для примера, создадим объект класса «id». Объект будет иметь только идентификатор и связь на класс, которым определяется.

$new = Object::Create();
$new->setP('class', Object::Create(1));
$new->Save();
Или сокращенно:
$new = Object::Create(null, Object::Create(1));
$new->Save();

Всё очень просто: создается пустой экземпляр сущности, создается связь на класс с идентификатором 1 и выполняется сохранение. После этого в таблице «id» появляется новая запись. Атрибут-идентификатор сущности создаётся автоматически автоинкрементом ключевого поля таблицы «id».

Создание класса происходит точно также. Для примера создадим пробный класс с именем «my» и определением атрибута «value»:

$new = Object::Create();
$new->setP('class', Object::Create(2)); // Создаём класс, поэтому связь с #2
// В зависимости от класса создаваемой сущности, определяются значения 
// атрибутов и свойств, (поэтому связь с классом определяется первой)
$new->setP('extend', Object::Create(1)); // Наследуем базовый класс
$new->setA('sys_name', 'my'); // Системное имя класса
$new->setA('final', 0);	// Можно наследовать
// Описание единственного атрибута
$new->setA_cl('value', array('type'=>'varchar', 'max'=>255)); // строковый атрибут
$new->Save();

Определение атрибута сводится к указанию параметров поля таблицы БД. После сохранения, автоматически будет создана таблица «my» с полями «id» и «value» и добавлена запись в таблице «id» и «class», ассоциируемая с сущностью-классом «my»

Описание атрибута выполняется методом setA_cl($name, $params). Ничего сложного, просто указывается имя атрибута и параметры, соответствующие параметрам поля таблицы БД.

Если нужно определить свойство, тогда методом setP_cl($name, $class) создается связь с именем $name на сущность-класс $class. При этом можно уточнить атрибуты связи, обратившись методом getL_cl($name) к автоматически созданной сущности-связи.

Теперь можно создать объект класса «my». Допустим, созданный класс «my» получил идентификатор 5.

$new_obj = Object::Create();
$new_obj->setP('class', Object::Create(5)); 
$new_obj->setA('value', 'Тра ля ля'); // Установка значения атрибута
$new_obj->Save();

Удаление сущности

Удалить сущность ещё проще:

$obj = Object::Create(6);
$obj->Delete();

Сначала создается экземпляр удаляемой сущности (сущность не загружается из БД), потом вызывается метод Delete().

При удалении сущности, автоматически удаляются все её связи. Если связь является вида «состоять» (kind=0), то будет удалена и сущность, на которую ссылается связь. Удалить сущность, являющеюся составной частью другой сущности (вид связи = «состоять»), не получится. Также не получится удалить класс, если он наследуется другим классом или имеются сущности этого класса.

Текущая версия CMS Boolive в свободном доступе в разделе скачать
Для тестирования приведенного в статье кода, вставляйте его в файл
/modules/page/templates/view/root.php

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

Моделирование содержимого

Приступим к моделированию содержимого сайта. Создадим несколько простых классов для представления строк и чисел: string, long_string, text, integer, double. Каждый класс определяет один атрибут «value» для значений. Класс «string» — для представления коротких строк размером не более 255 символов. «long_string» — для представления длинных срок, ограничения по длине не более 20486 символов (20Кбайт). Класс «text» — для очень длинных строк размером до 65535 символов включительно (64Кбайт). «integer» – для целых знаковых чисел разрядностью 32 бит (-2147483648 … +2147483647). «double» — для действительных чисел (-1.7976931348623157e+308 … 1.7976931348623157e+308). В представление значений других типов необходимости пока нет.

Все пять новых класса наследуют базовый класс «id». Определяются же они классом «class», от чего они и являются классами. На диаграмме (Рис. 1) у сущностей отображены не все атрибуты – идентификатор дублируется в заголовке прямоугольника сущности, там же указаны класс сущности его системным именем («class») и значение атрибута «sys_name» курсивом зеленым цветом.

Основные классы для представления строк и чисел.
Рис 1. Основные классы для представления строк и чисел.

Следующий программный код создаёт пять описанных классов для представления строк и чисел.

//Короткая строка (string)
$class = Object::Create();
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(1));
	$class->setA('sys_name', 'string');
	$class->setA('final', 0);	
	// Описание атрибутов
	$class->setA_cl('value', array('type'=>'varchar', 'max'=>255));
	$class->Save();

//Длинная строка (long_string)
	$class = Object::Create();
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(1));
	$class->setA('sys_name', 'long_string');
	$class->setA('final', 0);	
	// Описание атрибутов
	$class->setA_cl('value', array('type'=>'varchar', 'max'=>20486));
	$class->Save();

//Текст (text)
	$class = Object::Create(null);
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(1));
	$class->setA('sys_name', 'text');
	$class->setA('final', 0);	
	// Описание атрибутов
	$class->setA_cl('value', array('type'=>'text'));
	$class->Save();

//Целое знаковое число (integer)
	$class = Object::Create();
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(1));
	$class->setA('sys_name', 'integer');
	$class->setA('final', 0);	
	// Описание атрибутов
	$class->setA_cl('value', array('type'=>'int'));
	$class->Save();

//Действительное число (double)
	$class = Object::Create();
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(1));
	$class->setA('sys_name', 'double');
	$class->setA('final', 0);	
	// Описание атрибутов
	$class->setA_cl('value', array('type'=>'double'));
	$class->Save();

Теперь можно создавать объекты любого из новых классов. Но мы займемся другим. Добавим определение двух свойств у класса «class» и «link». Определяя два свойства в классе «class», мы тем самым добавляем соответствующие свойства всем классам: «id», «class», «link», «string» и остальным, так как они являются объектами класса «class». Также и для класса связей «link» – у всех объектов-связей появятся свойства вдобавок к существующим атрибутам.

Итак, добавляем определение, для этого создаем связь между классом «class» и классом «string» (Рис 2. #9). У связи устанавливаем значения атрибутов: вид связи («kind»=0), мощность («size»=1), признак обязательного существования определяемого свойства у объектов («is_mandat»=1). Остальные атрибуты инициализируются автоматически. Создаются две связи, одна на класс «string» другая на класс «long_string».

// Добавление описания свойств у класса #2 (у класса всех классов) 
// чтобы все классы имели нормальное название и описание 
	$class = Object::Create(2);
	// Описание свойств. По сути, просто создание связи между объектами.
	$class->setP_cl('name', Object::Create(4)); // связь с классом string
		// Уточняем атрибуты связи на объект #4
		$class->getL_cl('name')->setA('size',1); //один
		$class->getL_cl('name')->setA('kind',0); //состоять
		$class->getL_cl('name')->setA('is_mandat',1); //обязательное 
	$class->setP_cl('descript', Object::Create(5)); // связь с классом long_string
		// Уточняем атрибуты связи на объект #5
		$class->getL_cl('descript')->setA('size',1); //один
		$class->getL_cl('descript')->setA('kind',0); //состоять
		$class->getL_cl('descript')->setA('is_mandat',1); //обязательное 
	$class->Save();
	// Теперь ВСЕ классы должны иметь свойства названия и описания

После у каждого класса будет свойство «name» и «descript». Первое свойство для именования класса на русском языке, второе для описания назначения класса. Фактически, мы наделили объектную модели возможностью самой себя документировать. Для примера на сайте будет ссылка «создать Новость» при этом само слово «Новость», да ещё и описание, что такое новость или, что реально будет создано, будет осмысленно взято из БД, а не прописано в шаблоне оформления или подгружено откуда-то со стороны.

Теперь добавим определение двух свойств в классе «link». Эти свойства будут необязательны для связей (атрибут «is_mandat» = 0). Первое свойство с системным именем «label» будет использоваться для именования связи на естественном языке, второе свойство для пояснения связи (свойства объекта, владеющего связью). Рис 2. #11, #12.

// Но сначала ещё добавим описание свойств у класса #3 (у класса всех связей), чтобы все связи имели имена (ярлыки) и описания

	$class = Object::Create(3);
	// Описание атрибутов
	// связь с классом string
	$class->setP_cl('label', Object::Create(4)); 
		// Уточняем атрибуты связи на объект #4
		$class->getL_cl('label')->setA('size',1); //один
		$class->getL_cl('label')->setA('kind',0); //состоять
		$class->getL_cl('label')->setA('is_mandat',0); //необязательное 
	// связь с классом long_string
	$class->setP_cl('descript', Object::Create(5)); 
		// Уточняем атрибуты связи на объект #5
		$class->getL_cl('descript')->setA('size',1); //один
		$class->getL_cl('descript')->setA('kind',0); //состоять
		$class->getL_cl('descript')->setA('is_mandat',0); //необязательное 
	$class->Save();
	// Теперь ВСЕ связи (свойства) могут иметь название и описание на естественном языке

Созданные определения свойств для связей имеют такой же смысл, что свойства для классов. Благодаря ним объектная модель, словно сама будет говорить: «новость имеет заголовок». Объектная модель теперь способна сама себя описывать и способствовать созданию удобного пользовательского интерфейса.

Теперь необходимо у классов и связей создать свойства, наличие которых только что было определено. Начнем со связей. Так как свойства для связей определены необязательными, ограничимся лишь именованием связей у классов «class» и «link». Рис 2. #13 – #20

// добавляем свойства label для связей описывающие свойства классов и связей
	$class = Object::Create(9);
		$label = Object::Create(null, 4);
		$label->setA('value','Название класса');		
	$class->setP('label', $label); 
	$class->Save();	

	$class = Object::Create(10);
		$label = Object::Create(null, 4);
		$label->setA('value','Описание класса');		
	$class->setP('label', $label); 
	$class->Save();	

	$class = Object::Create(11);
		$label = Object::Create(null, 4);
		$label->setA('value','Название свойства');		
	$class->setP('label', $label); 
	$class->Save();	

	$class = Object::Create(12);
		$label = Object::Create(null, 4);
		$label->setA('value','Описание свойства');		
	$class->setP('label', $label); 
	$class->Save();

Теперь разберемся с классами. Всего уже 8 классов. Так как свойства для классов определены обязательными, значит, их необходимо создать у каждого класса. Фактически добавляется нормальное название и описание каждому классу. Рис 2.

// У нас уже есть 8 классов. 
// После описания обязательных свойств для классов нужно создать эти свойства у всех классов
// Сущность
	$class = Object::Create(1);
		$name = Object::Create(null, 4);
		$name->setA('value','Сущность');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Базовый класс для всех сущностей');		
	$class->setP('descript', $descript); 
	$class->Save();	
// Класс
	$class = Object::Create(2);
		$name = Object::Create(null, 4);
		$name->setA('value','Класс');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Класс для всех классов');		
	$class->setP('descript', $descript); 
	$class->Save();	
// Связь
	$class = Object::Create(3);
		$name = Object::Create(null, 4);
		$name->setA('value','Связь');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Класс для создания связей');		
	$class->setP('descript', $descript); 
	$class->Save();	
// Строка
	$class = Object::Create(4);
		$name = Object::Create(null, 4);
		$name->setA('value','Строка');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Короткая строка длиной до 255 символов');		
	$class->setP('descript', $descript); 
	$class->Save();	
// Длинная строка
	$class = Object::Create(5);
		$name = Object::Create(null, 4);
		$name->setA('value','Длинная строка');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Строка размером до 20Кбайт');		
	$class->setP('descript', $descript); 
	$class->Save();	
// Текст
	$class = Object::Create(6);
		$name = Object::Create(null, 4);
		$name->setA('value','Текст');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Текст размером до 64Кбайт (65 535 символов)');		
	$class->setP('descript', $descript); 
	$class->Save();	
// Целое число
	$class = Object::Create(7);
		$name = Object::Create(null, 4);
		$name->setA('value','Целое число');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Целое 32 битное число');		
	$class->setP('descript', $descript); 
	$class->Save();	
// Действительное число
	$class = Object::Create(8);
		$name = Object::Create(null, 4);
		$name->setA('value','Действительное число');		
	$class->setP('name', $name); 
		$descript = Object::Create(null, 5);
		$descript->setA('value','Действительное число, например -782.023');		
	$class->setP('descript', $descript); 
	$class->Save();

Основные классы данных и их описание
Рис 2. Основные классы данных и их описание.

Как видно по диаграмме (Рис 2), у каждого класса есть название и описание на русском языке. Все связи между сущностями являются объектами, что тоже видно по диаграмме. Объекты строк схематично упрощены, текст в нутрии прямоугольника – это значение единственного их атрибута «value».

Теперь ближе к теме содержимого сайта. Создадим для примера четыре класса. Первый из них – класс «content» (Материал) со свойствами «head» (Заголовок) и «text» (Текст). Это будет самый простой тип материала для сайта, который подойдет для новостей или статей. Класс «content» наследуется от базового класса «id», а в качестве свойств используются классы «string» и «text». Рис 3. #52 – #63

// Простой материал
	$class = Object::Create();
	// определение класса для объекта (создание объекта класса #2) - создается класс
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(1)); // наследует базовый класс
	$class->setA('sys_name', 'content'); //системное имя класса
	$class->setA('final',0); // можно наследовать
	// создание объекта класса #4 (создание строки)
  	$name = Object::Create(null, 4); 
	  $name->setA('value','Материал');
	$class->setP('name', $name); // свойство названия класса
	// создание объекта класса #5 (создание длинной строки)
	  $descript = Object::Create(null, 5); 
	  $descript->setA('value','Простой материал');
	$class->setP('descript', $descript); // свойство описания класса

	// опреление свойств для объектов этого класса (описание свойств)
	$class->setP_cl('head', Object::Create(4)); // заголовок - короткая строка
		// Уточняем атрибуты связи
		$class->getL_cl('head')->setA('size',1); //один
		$class->getL_cl('head')->setA('kind',0); //состоять
		$class->getL_cl('head')->setA('is_mandat',1); //обязательное 
		// название свойства
		$class->getL_cl('head')->setP('label', Object::Create(null, 4));
		$class->getL_cl('head')->getP('label')->setA('value','Заголовок');
	$class->setP_cl('text', Object::Create(6)); // текст материала
		// Уточняем атрибуты связи
		$class->getL_cl('text')->setA('size',1); //один
		$class->getL_cl('text')->setA('kind',0); //состоять
		$class->getL_cl('text')->setA('is_mandat',1); //обязательное 
		// название свойства
		$class->getL_cl('text')->setP('label', Object::Create(null, 4));
		$class->getL_cl('text')->getP('label')->setA('value','Текст');
	$class->Save();

Продемонстрируем возможности наследования. Создадим класс комментария «comment» наследуя его от класса «content», от чего он уже будут иметь определение свойства заголовок и текст. Для комментария посчитаем их достаточными и ничего нового в нем определять не будем. Рис 3. #64 – #68.

// Комментарий
	$class = Object::Create();
	// создание класса (или создание объекта класса #2)
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(53)); // наследует материал
	$class->setA('sys_name', 'comment'); //системное имя класса
	$class->setA('final',0); // можно наследовать
	// создание объекта класса #4 (создание строки)
	  $name = Object::Create(null, 4); 
	  $name->setA('value','Комментарий');
	$class->setP('name', $name); // свойство названия класса
	// создание объекта класса #5 (создание длинной строки)
	  $descript = Object::Create(null, 5); 
	  $descript->setA('value','Используется для комментирования публикаций на сайте');
	$class->setP('descript', $descript); // свойство описания класса
	$class->Save();

Для категоризации материала сайта создадим класс категории «category». Класс «category» наследует базовый класс «id», поэтому у него нет ещё определений свойств. Для категории необходимо название и его пояснение – всё те же свойства с подобным назначением. Особенностью категорий является их иерархичная структура. Чтобы можно было создавать иерархии из категорий, у каждой категории должна быть связь на родительскую категорию. Эту возможность обеспечивает свойство «parent», в определении оно связывает класс «category» с самим собой, что указывает: родитель для категории является категорией. Рис 3. #69 – #82.

// Категории
	$class = Object::Create();
	// определение класса для объекта (создание объекта класса #2) - создается класс
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(1)); // наследует базовый класс
	$class->setA('sys_name', 'category'); //системное имя класса
	$class->setA('final',0); // можно наследовать
	// создание объекта класса #4 (создание строки)
	  $name = Object::Create(null, 4); 
	  $name->setA('value','Категория');
	$class->setP('name', $name); // свойство названия класса
	// создание объекта класса #5 (создание длинной строки)
	  $descript = Object::Create(null, 5); 
	  $descript->setA('value','Используется для категоризации материала');
	$class->setP('descript', $descript); // свойство описания класса

	// Опреление свойств для объектов этого класса (описание свойств)

	// Родительская категория - связь на самого себя, что свидетельствует,
	// что родительская категория тоже должна быть класса category
	$class->setP_cl('parent', $class); 
		// Уточняем атрибуты связи
		$class->getL_cl('parent')->setA('size',1); //один
		$class->getL_cl('parent')->setA('kind',1); //использовать
		$class->getL_cl('parent')->setA('is_mandat',0); //необязательное 
		// название свойства
		$class->getL_cl('parent')->setP('label', Object::Create(null, 4));
		$class->getL_cl('parent')->getP('label')->setA('value','Родительская категория');
	$class->setP_cl('name', Object::Create(4)); // название категории
		// Уточняем атрибуты связи
		$class->getL_cl('name')->setA('size',1); //один
		$class->getL_cl('name')->setA('kind',0); //состоять
		$class->getL_cl('name')->setA('is_mandat',1); //обязательное 
		// название свойства
		$class->getL_cl('name')->setP('label', Object::Create(null, 4));
		$class->getL_cl('name')->getP('label')->setA('value','Название');
	$class->setP_cl('descript', Object::Create(5)); // описание категории
		// Уточняем атрибуты связи
		$class->getL_cl('descript')->setA('size',1); //один
		$class->getL_cl('descript')->setA('kind',0); //состоять
		$class->getL_cl('descript')->setA('is_mandat',1); //обязательное 
		// название свойства
		$class->getL_cl('descript')->setP('label', Object::Create(null, 4));
		$class->getL_cl('descript')->getP('label')->setA('value','Описание');
	$class->Save();

И последний класс, который будет нами создан – класс новостей «news». Этот класс наследует класс «content» и добавляет новые определения свойства «comments» (Комментарии) и «category» (Категория). Свойство «comments» множественное, потому что у новости может быть много комментариев. Рис 3. #83 – #90.

// Новость
	$class = Object::Create();
// определение класса для объекта (создание объекта класса #2) - создается класс
	$class->setP('class', Object::Create(2)); 
	$class->setP('extend', Object::Create(53)); // наследует простой материал
	$class->setA('sys_name', 'news'); //системное имя класса
	$class->setA('final',0); // можно наследовать
// создание объекта класса #4 (создание строки)
	  $name = Object::Create(null, 4); 
	  $name->setA('value','Новость');
	$class->setP('name', $name); // свойство названия класса
// создание объекта класса #5 (создание длинной строки)
	  $descript = Object::Create(null, 5); 
	  $descript->setA('value','Для публикаций новостей на сайте');
	$class->setP('descript', $descript); // свойство описания класса

// опреление свойств для объектов этого класса (описание свойств)
	$class->setP_cl('category', Object::Create(69)); // категория новости
		// Уточняем атрибуты связи
		$class->getL_cl('category')->setA('size',1); //один
		$class->getL_cl('category')->setA('kind',1); //использовать
		$class->getL_cl('category')->setA('is_mandat',0); //необязательное 
		// название свойства
		$class->getL_cl('category')->setP('label', Object::Create(null, 4));
		$class->getL_cl('category')->getP('label')->setA('value','Категория новости');
	$class->setP_cl('comments', Object::Create(64)); // комментарии на новость
		// Уточняем атрибуты связи
		$class->getL_cl('comments')->setA('size',0); //много
		$class->getL_cl('comments')->setA('kind',1); //использовать
		$class->getL_cl('comments')->setA('is_mandat',0); //необязательное 
		// название свойства
		$class->getL_cl('comments')->setP('label', Object::Create(null, 4));
		$class->getL_cl('comments')->getP('label')->setA('value','Комментарии');	
	$class->Save();

Классы матариала и его категоризации
Рис 3. Классы матариала и его категоризации

Все необходимые классы созданы. В рабочей CMS конечно будет множество других классов и не только для представления содержимого. Сейчас цель – продемонстрировать работу модуля Data и возможностей, предоставляемых им в управлении данными.

Создадим, наконец, несколько объектов содержимого. Три категории, две новости и два комментария, принадлежащих к одной новости. Вторая новость без комментариев. На диаграмме хорошо видны созданные объекты и их составные свойства и свойства вида «использовать». Рис 4.

// Теперь создаем само содержимое (тестовое). 
// Три категории: 
// + Мероприятия
// | + Кожаный мяч
// | + Лыжня россии

	//Мероприятия
// сокращенно: создаем новый объект класса #69 (category)
	$cat1 = Object::Create(null, 69); 
	$cat1->setP('name', Object::Create(null, 4));
		$cat1->getP('name')->setA('value','Мероприятия');
	$cat1->setP('descript', Object::Create(null, 5));
		$cat1->getP('descript')->setA('value','Все спортивные мероприятия');
	$cat1->Save();

	//Кожаный мяч
// сокращенно: создаем новый объект класса #69 (category)
	$cat2 = Object::Create(null, 69); 
	$cat2->setP('name', Object::Create(null, 4));
		$cat2->getP('name')->setA('value','Кожаный мяч');
	$cat2->setP('descript', Object::Create(null, 5));
		$cat2->getP('descript')->setA('value','Футбольный турнир школьников');
	$cat2->setP('parent', $cat1);
	$cat2->Save();

	//Лыжня россии
// сокращенно: создаем новый объект класса #69 (category)
	$cat3 = Object::Create(null, 69); 
	$cat3->setP('name', Object::Create(null, 4));
		$cat3->getP('name')->setA('value','Лыжня России');
	$cat3->setP('descript', Object::Create(null, 5));
		$cat3->getP('descript')->setA('value','Всероссийская массовая лыжная гонка');
	$cat3->setP('parent', $cat1);
	$cat3->Save();

// Первая новость
	$news = Object::Create(null, 83); // сокращенно: создаем новый объект класса #83 (news)
	$news->setP('head', Object::Create(null, 4));
		$news->getP('head')->setA('value','Первая новость');
	$news->setP('text', Object::Create(null, 6));
		$news->getP('text')->setA('value','Текст первой очень маленькой новости');
	$news->setP('category', Object::Create(94)); //Новость общей категории 
	$news->Save();

// Первый комментарий для первой новости
// создаем новый объект класса #64 (comment)
	$comment = Object::Create(null, 64); 
	$comment->setP('head', Object::Create(null, 4));
		$comment->getP('head')->setA('value','Первый коммент');
	$comment->setP('text', Object::Create(null, 6));
		$comment->getP('text')->setA('value','Супер! Отлично - это текст первого комментария');
	$comment->Save();
	// Нужно ещё этот комментарий прикрутить к первой новости
	$news = Object::Create(111); //Загрузили первую новость
	// getP('comments') возвращает объект класса Multy а не Object
$news->getP('comments')->add($comment);
	$news->Save();

// Второй комментарий для первой новости
	$comment = Object::Create(null, 64); // создаем новый объект класса #64 (comment)
	$comment->setP('head', Object::Create(null, 4));
		$comment->getP('head')->setA('value','Второй комментарий');
	$comment->setP('text', Object::Create(null, 6));
		$comment->getP('text')->setA('value','Текст второго комментария на самую первую новость');
	$comment->Save();
	// Нужно ещё этот комментарий прикрутить к первой новости
	$news = Object::Create(111); //Загрузили первую новость
	$news->getP('comments')->add($comment);
	$news->getP('comments')->Save();

// Создаём вторую новость, она будет без комментариев
	$news = Object::Create(null, 83); // сокращенно: создаем новый объект класса #83 (news)
	$news->setP('head', Object::Create(null, 4));
		$news->getP('head')->setA('value','Вторая пробная новость');
	$news->setP('text', Object::Create(null, 6));
		$news->getP('text')->setA('value','Вторая маленькая новость будет без комментариев для тестирования');
	$news->setP('category', Object::Create(105)); //Новость категории Лыжня России
	$news->Save();

Три категории, две новости и два комментария
Рис 4. Три категории, две новости и два комментария.

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

Теперь возникает вопрос, как с этим всем работать? Как, например, получить список новостей? А как насчет условий, например новости определенной категории? Все эти функциональные возможности уже реализованы. В начале статьи были упомянуты классы Query и Cond*. С помощью них осуществляется поиск сущностей. Об этом будет рассказано в продолжение статьи – в третьей части.

Модель данных. Конструирование
0 votes, 0.00 avg. rating (0% score)

Комментарии

  1. VS:

    всё дело в волшебных пузырьках! (Ц)итата
    что это за странные цифры в конструкторах? разработчику необходимо будет помнить их все? о_О

  2. VS:

    хмм… Cond* ;) )
    RewriteCond
    RewriteCond
    RewriteRule
    такая схема?
    почему не просто фильтры ( ||декораторы ||врапперы) ?

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

    Про Cond*

    // Условие - сущности у которых есть атибут value
    $q = Q::Entity(
    		Q::IsExist(
    	  		Q::Attrib('value')
    			)
    );
    // Поиск. Результат - экземпляры сущностей у которых есть атрибут value
    $list = Data::Find($q);
    
    echo $list[0]->getA('value');
    

    Это так, забегая вперед))

    P.S.: Q::Entity() возвращет объект класса CondEntity()… сделано так, чтоб код почище был, без оператора new например)))))))

  4. VS:

    > Q::Entity() возвращет объект класса CondEntity()
    это называется «фабричный метод»

    > Результат — экземпляры сущностей, у которых есть атрибут value
    не проще Entity->xpath(‘//*[@value]‘) ?

    • Поиск по базе выполняется. Из объектного (структуированного) условия проще всего генерировать соответсвующий sql. Вы просто не так поняли)

  5. VS:

    да, рекомендую избавиться от параметра в конструкторе. он ведь не является определяющим вид, тип, свойства объекта; он является внутренним идентификатором, вот пусть Object и генерит его внутри себя для себя

    • Это не временный идентификатор. Если указывается идентификатор, то будет загружаться соответствующая сущность из БД, если не указывается, то предполагается создание новой. Второй параметр в конструкторе — идентификатор класса, используется вместо $obj->setP(‘class’, Object::Create($class_id)). Вот по классу определяются атрибуты и свойства.

  6. egoholic:

    А какая программа использовалась для создания таких красивых схем?

  7. В графическом редакторе.

  8. VS:

    надеюсь, я ещё не совсем потерял нить повествования.
    где-то же должны храниться списки этих айдишников с описанием?

  9. egoholic:

    Хм… я думал что ты пользуешься каким-нить специальным средством проектирования… А что за граф.редактор если не секрет?

  10. В первой части статьи были созданы три базовые сущности – самый главный класс «id», класс для всех классов «class» и класс для связей «link». У них соответственно идентификаторы 1, 2, 3. Сам идентификатор определяется в главном классе «id», хранится в таблице с именем «id» и создаётся автоматически автоинкрементом ключевого поля так сказать при сохранении (создании) новой сущности. Эти три базовые сущности являются обязательными. А все остальное будет уже зависеть от того, что собственно мы хотим получить от CMS, т.е., сказать, что у класса «news» будет идентификатор 83 с уверенностью нельзя, так как все будет завесить от последовательности создания всех сущностей.

    Что касается примеров в статье, после создания каждого класса, я смотрел какой идентификатор они получили и в дальнейшем уже знал, что идентификатор у класса новости, например равен 83. В рабочей CMS, да и так необходимости знать идентификаторы вообще не нужно будет, так все будет выполняться непосредственно системой, и для пользователя будет все информативно, например, выбор наследуемого класса при создании нового будет происходить по имени из внизпадающего списка. Создание объектов (самих новостей) вообще не будет требовать какой-то соображалки по поводу структуры данных.

    Когда будут выработаны основные классы данных у системы (три базовых уже есть, плюс классы строковых и числовых значений) можно будет все-таки сделать типа справки и констант в программном коде, какой идентификатор у каждой из основных сущностей (в основном классов) :)

    egoholic, мне удобней примянять флэшь :) на вопрос о диаграммах уже раз 20 отвечаю

  11. VS:

    как отличить один класс от другого? пройтись по дереву предков?
    как выбирать сущности определённого конечного класса? составлять выпадающие меню надо же по определённым признакам?
    нужен же какой-то репозитарий?

    оффтопик: drop-down menu это «выпадающий список»
    может, дисклеймер на главной повесить: «все картинки сделаны во флеше»? ;)

  12. в следующей части статьи будет рассмотрен поиск/выборка сущностей по разным условиям, я же уже намикал тебе о поиске (Query и условия Cond*). Можно будет и классы выбирать и объекты определенного класса и все что угодно. О каком репозитории ты говоришь, у нас единая объектная модель (база), в ней и классы и связи и объекты всё вместе — всё осмысленно связано …и работай (используй) с чем хочешь. Классы отличаются точно также как и объекты друг от друга — значением атрибутов и свойств. Тем более в этой же статье показано определение для классов обязательных свойств названия и описания.

Комментировать



(обязательно)


(обязательно) E-mail адрес не будет отображаться на сайте

(обязательно)