Fi1osof 08 мая 2013 0 2
Сегодня вкратце расскажу о том, как я решал одну непростую задачку. Суть ее заключается в том, что мне надо было создать большую таблицу (98 колонок), но не просто так, а из полей имеющейся формы на одном сайте. То есть там уже есть имена полей (в итоге — колонок), лейблы этих полей (они пойдут в комменты колонок и человекопонятные названия полей в итоговой форме).

Само собой вручную создавать таблицу, все 98 колонок и т.п. — это во-первых, лениво, а во-вторых, не очень продуктивно. Я решил все это сделать программно. Вот это здесь и опишу вкратце.

Краткий план работ.
План простой:
  1. Посредством jQuery собрать информацию о полях (названия, лейблы, дефолтовые значения), упаковать это все в JSON.
  2. Средствами PHP на своем уже сервере преобразовать JSON в массив исходных данных. Сгенерировать и записать модель xPDO-объекта
  3. Из описания 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 имеются методы изменения таблиц, удаления и добавления колонок и т.п. Но это уже тема для отдельного топика.
2 комментария
abaddon651
abaddon65 08 мая 2013г в 15:02 #
А вот это очень полезная штука. Спасибо, вот и тема, которую можно потыркать на праздниках)
Fi1osof1
Fi1osof 08 мая 2013г в 23:33 #
Пожалуйста.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.