Пример универсальной функции для создания схемы компоновки данных




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

30 Comments

  1. glek

    Полезно. Спасибо.

    Reply
  2. Evil Beaver

    А теперь бы все это выложить в gist на гитхабе, чтобы можно было допилить всем желающим

    Reply
  3. pbazeliuk

    Пройдусь по явным недочетам:

    1.Описание процедур и функций;

    2. Не хватает обработки Настроек.ПараметровДанных по умолчанию;

    3. Недопустимо перехватывать любые исключения, бесследно для системного администратора.

    В остальном бесспорно плюс.

    Reply
  4. dbachinsky

    (2) Спасибо за совет.

    Reply
  5. dbachinsky

    (3) Конструктивная критика. Спасибо

    Reply
  6. Evil Beaver

    (3) а внутри github эти замечания были бы еще и в виде код-ревью оформлены, и отслежено исправление 🙂

    Reply
  7. hromovanton

    Очень хорошая функция. Спасибо вам …

    Reply
  8. json

    Идея интересная.

    Но попытка явно лишняя. Ведь ошибка может выскочить только в том случае, если вызывающий код передал неправильные параметры. Почему вы считаете, что в этом случае нужно возвратить пустое значение? Это же не логично. Намного проще и быстрее будет найти ошибку, если выскочит исключение с описанием.

    Если же ошибку нужно скрыть от пользователя, то в попытку нужно оборачивать сам вызов данной функции.

    Reply
  9. dbachinsky

    (8) Функция не претендует на абсолютную самодостаточность. Логика такая — функция возвращает либо СКД, либо неопределенно. Если вы получаете неопределенно — действуете по усмотрению в месте вызова.

    Если хотите оборачивать вызов в попытку — это нужно будет делать при каждом вызове. «Лаконичнее» будет вынести попытку в саму функцию

    Reply
  10. json

    (9) дело ваше.

    Но на всякий случай порекомендую ознакомиться с системой стандартов и методик на эту тему.

    http://its.1c.ru/db/v8std#content:2149184148:hdoc

    см пункты 1, 2 и 3.4

    А по поводу лаконичности: лучше передавать в функцию правильные параметры, тогда попытка вообще не понадобится

    Reply
  11. artbear

    (0) (2) Создал спец.гист на гитхабе

    https://gist.github.com/artbear/e1cfd0f5dbf39373f4424a4b250fb690

    Указал ссылку на данную публикацию

    Reply
  12. dbachinsky

    (11) Как раз планировал приобщить сообщество git по рекомендации уважаемого (2) «Evil Beaver». Благодарю за оперативность и приглашаю присоединиться всех желающих

    Reply
  13. adsl

    Чтобы порядок колонок был как в тексте запроса, стоит исправить примерно так:

     //Для каждого ПолеОтбора Из ПостроительЗапроса.Отбор.ПолучитьДоступныеПоля() Цикл
    Для каждого ПолеОтбора Из ПостроительЗапроса.ВыбранныеПоля Цикл
    НоваяКолонка = КоллекцияКолонок.Добавить();
    НоваяКолонка.Имя = ПолеОтбора.Имя;
    //НоваяКолонка.ТипЗначения = ПолеОтбора.ТипЗначения;
    НоваяКолонка.ТипЗначения = ПостроительЗапроса.ДоступныеПоля[ПолеОтбора.ПутьКДанным].ТипЗначения;
    НоваяКолонка.Заголовок = ПолеОтбора.Представление
    КонецЦикла;
    

    Показать

    Reply
  14. dbachinsky

    (13) Отличное замечание. Изменение внес

    Reply
  15. Nebiros777

    Блин, и где я лазил все это время? Утащил в нору!

    Reply
  16. AlmazBur01

    //

    // ВноситьПоляВыбора (Тип: Булево) — Флаг добавление полей набора

    //

    В комментариях перед функцией эта строка сообщает нам: о чём?

    Reply
  17. AlmazBur01

    //

    // ВноситьПоляВыбора (Тип: Булево) — Флаг добавление полей набора

    //

    Перед функцией эта строка в комментариях сообщает нам: о чём?

    Reply
  18. proger1c81

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

    Мне по роду моих задач приходится только программно обрабатывать всякие события СКД, варианты схем, виды, группировки, оформления и т.д.. При этом саму схему (сам отчет на СКД) разрабатываю вручную в конфигураторе.

    Reply
  19. logarifm

    Большое тебе спасибо… Реально сэкономил мне время.

    Reply
  20. daho

    (18) Я так понимаю создаешь пустую СКД в отчете а в модуле объекта подсовываешь ее процедуре ПриКомпоновкеРезультата().. или как правильно?

    Reply
  21. sudmorsh

    Интересная идея, спасибо

    Reply
  22. the1

    (18) Для нас эта публикация представляет скорее художественный, нежели практический интерес.

    Reply
  23. dbachinsky

    (22) Отлично! Главное, что интересно!

    Reply
  24. German_Tagil

    Можно попросить выложить вариант работающего отчета или обработки

    Reply
  25. dbachinsky

    (24) Добавил пример

    Reply
  26. dbachinsky

    (20) Пример во вложении

    Reply
  27. kabanoff

    (22) Автору большое спасибо! Как раз искал вариант программного создания СКД по таблице значений.

    Вот конкретная производственная необходимость: отчет формируется по большой таблице (порядка 20 ТБ). Сформировать его в одном потоке за короткое время невозможно. Поэтому его приходится формировать по частям.

    Логику дробления и запуска пакетов (фоновых заданий) описывать не буду. Скажу лишь, что каждое ФЗ возвращает порцию данных в виде таблицы значений.

    Так вот для того, чтобы не создавать еще одну СКД с внешним набором данных и сложной структурой колонок, надо просто вызвать функцию, которую предложил автор, и присвоить ей настройки компоновщика, который указал пользователь. Бинго!

    Reply
  28. user774630
    А вообщем-то нет пределов вашей фантации

    или в общем-то, или вообще

    🙂

    Reply
  29. Darklight

    (2) Вот бы ещё конфигуратор (ну или хотя бы EDT) поддерживал работу с Gist — тогда да, это было бы очень полезно! А если бы Gist был бы ещё и в infotsart встроен…. эх мечты мечты!

    Reply
  30. ShantinTD

    Спасибо!

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *