Сегодня вкратце расскажу о том, как я решал одну непростую задачку. Суть ее заключается в том, что мне надо было создать большую таблицу (98 колонок), но не просто так, а из полей имеющейся формы на одном сайте. То есть там уже есть имена полей (в итоге — колонок), лейблы этих полей (они пойдут в комменты колонок и человекопонятные названия полей в итоговой форме).
Само собой вручную создавать таблицу, все 98 колонок и т.п. — это во-первых, лениво, а во-вторых, не очень продуктивно. Я решил все это сделать программно. Вот это здесь и опишу вкратце.
Краткий план работ.
Посредством jQuery собрать информацию о полях (названия, лейблы, дефолтовые значения), упаковать это все в JSON.
Средствами PHP на своем уже сервере преобразовать JSON в массив исходных данных. Сгенерировать и записать модель xPDO-объекта
Из описания xPDO-объекта создать конечную таблицу.
Этап первый. Собираем данные формы и упаковываем в JSON.
В FireBug-е на нужной мне странице выполнил такой код (jQuery там был, что не удивительно):
var fieldsSer = $('Form').serializeArray(); // Собираем все поля формы
var fields = {};
var name;
for(var i in fieldsSer){
el = fieldsSer[i];
name = el.name
fields[name] = el;
// Находим лейбл для поля (у всех полей id совпадало с name, потому было просто найти лейблы для них)
label = $('[for='+ name +']')
text = label.text();
fields[name].label = text;
}
// Собираем полученный объект в JSON
JSON.stringify(fields);
Этап второй. Из JSON-строки формируем
<?php
$className = 'myClass';
$fields = array();
$fieldMeta = array();
// Формируем путь до map-файла, в который будем записывать конечные данные
$file = MODX_CORE_PATH .'components/mypackage/model/mypackage/mysql/myclass.map.inc.php';
$arr = $modx->fromJSON($JSON); // Преобразуем JSON-строку в массив
// Обрабатываем все поля
foreach($arr as $field => $meta){
$value = $meta['value'];
$dbtype = "varchar";
$phptype = "string";
$precision = 255;
$null = true;
$required = false;
if(is_numeric( $value)){
$dbtype = "int";
$phptype = "integer";
$precision = 11;
}
if($value == ''){
$value = NULL;
}
$fields[$field] = $value;
$label = trim($meta['label']);
$label = preg_replace("/[\r\n]+/", "", $label);
$label = preg_replace("/ {2,}/", " ", $label);
if(!empty($label) && strpos($label, '*')){
$required = true;
}
$fieldMeta[$field] = array(
'comment' => $label,
'dbtype' => $dbtype,
'precision' => $precision,
'phptype' => $phptype,
'null' => $null,
'default' => $value,
'required' => $required,
'in_form' => true,
);
}
/*
Готовим и записываем конечное описание объекта
*/
$xpdo_meta_map = array (
'package' => 'myPackage',
'version' => '1.1',
'table' => 'mytable',
'extends' => 'xPDOSimpleObject',
'fields' => $fields,
'fieldMeta' => $fieldMeta,
);
// Обратите внимание на функцию var_export - очень важная и полезная штука
$fileContent= "<?php\n\$xpdo_meta_map['$className']= " . var_export($xpdo_meta_map, true) . ";\n";
// Записываем полученный массив в файл
$modx->cacheManager->writeFile($file, $fileContent);
Этап третий. Из модели объекта создаем таблицу.
Здесь уже все просто и стандартно.
$manager = $modx->getManager();
// Создаем таблицу объекта
// Таблицы не должно быть изначально, этот метод только создает новую таблицу,
// не обновляет и не грохает имеющуюся
$manager->createObjectContainer('myClass');
Немного лирики.
Вообще описанный метод для меня сегодня был практически единственным приемлемым в моей ситуации. У меня многое в проекте завязано именно на map-описании объекта (Туда же записать можно все, что угодно. В частности, у меня там записаны комментарии, которые в итоге подставляются в названия полей в форме, а в базе данных они просто необходимы, чтобы разобраться в массе всяких «интуитивно-понятных» полей). И у меня был вариант или создавать таблицу, и потом из нее генерить map-файл, или наоборот, сначала создать map-файл, а потом уже создать таблицу. Я выбрал именно второй, так как описанное здесь — это только начало. Еще предстоит пройтись по всем полям, актуализировать типы данных до конца, указать длину полей и т.д. и т.п. И в этом плане с файлом работать гораздо проще, чем с таблицей, к тому же еще и гораздо быстрее. А ничего не стоит на этапе разработки грохнуть всю таблицу и в две строчки создать новую.
А еще следует сразу отметить, что в xPDO имеются методы изменения таблиц, удаления и добавления колонок и т.п. Но это уже тема для отдельного топика.