Рекурсивный обход дерева значений с пересчетом иерархических итогов группировок




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2025-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='\

39 Comments

  1. Ish_2

    Замечание.

    «Приятней глазу» следующее дерево:

    Склад

    —- Группа товаров

    ——Товар

    Т.е. в одной колонке Склад и товар.

    Как в запросе получить такое дерево описано у Alex-is http://infostart.ru/public/71130/

    Reply
  2. v.l.

    (1) Спасибо, исправлю.

    Reply
  3. pashoid

    Молодец, что все так аккуратно формализовал.

    Reply
  4. detec

    Огромный плюс за качественное оформление.

    Reply
  5. v.l.

    (1) Ish_2, спасибо за идею. 2 недели бился, пока не закомментировал первую строчку запроса. Теперь всё красиво.

    Reply
  6. v.l.

    (4) Спасибо, что оценили старания. Для меня кроме красившести важно, чтобы было правильно и доступно описано.

    Reply
  7. wing

    (0) В порядке занудства: заметил странную семерку на первом дереве в группе ПО:

    4 винды + 1 Бух + 1 Аспект = 7? В классической арифметике это будет 6 … какая же используется у Вас? 😉

    Reply
  8. v.l.

    (7) Спасибо! Как доберусь до 1С, поправлю!

    Действительно, арифметика не та…

    По картинкам прошелся — вроде нирмально. На последней даже правильно 😉

    Reply
  9. rusrus

    Очень помог, спасибо.

    Reply
  10. tango

    мдя. ну и цветы цветут бывает

    — : информатику в школе учить надо было

    Reply
  11. v.l.

    (10) А что не так?

    Инфматику в школе учили — алгоритмический язык, листок разлинеенный, для каждой переменной своя колонка. Каждый шаг программы — новая строчка и ручками писали новое значение переменной.

    Я так понимаю, что-то Вам не понравись. Но что?

    Reply
  12. tango

    (11) не понравилось:

    а) вся публикация в целом в духе:

    «Для примера я взял демо-базу «Примеры ИТС» с диска ИТС.

    В Конфигураторе создадим новый внешний отчет, назовём его ПримерИспользованияДереваЗначений.

    Свойства отчета

    Создадим форму отчета, нажав на лупу в поле Основная форма внешнего отчета.»

    ну, как бы «профессиональное» сообщество, а не «мастер-класс по нажиманию лупы для создания отчета»…

    б) КолонкиВыборки в процедуре КнопкаСформироватьНажатие не определена

    в)ЭлементыФормы.ТЗВыборка.Значение = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

    vc

    ТЗВыборка = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

    а дольше уже ниасилил, мильпардон

    Reply
  13. tango

    (0) извини, ничего личного, но:

    а) демпинг из-за множества нулевых 1снегов реально достал

    из практики, собеседование, на з/п 80:

    вопрос: зачем нужны оборотные регистры?

    ответ (дословно): для учета взаиморасчетов

    пс: наверное, ты не поймешь этот пост. если втянешься — поймешь потом

    Reply
  14. hohmankia

    спасибо

    Reply
  15. Igortid

    Огромный плюс …после прочтения «вырастил » первое дерево

    Reply
  16. v.l.

    (15) Igortid, спасибо, приятно знать, что не зря старался.

    Reply
  17. v.l.

    (17) Eugeneer, не ставь. Используй итоги из запроса.

    Reply
  18. v.l.

    (19) Eugeneer, это можно самому сделать. При обходе смотреть — группировка это или строка.

    Reply
  19. Raminus

    Оформлено хорошо, ознакомился, спасибо 🙂

    Reply
  20. v.l.

    (21) Raminus, Спасибо.

    Reply
  21. galinka1c8

    Спасибо большое, статья очень понравилась. Все четко и просто изложено. До этого в деревьях вообще плавала, поиск по инету давал только отдельные не связанные обрывки информации. А тут все и сразу. Еще понравилось дополнение по двухуровневое дерево. Пригодилось.

    Reply
  22. v.l.

    (23) galinka1c8, спасибо за отзыв. Я тоже как столкнулся, только обрывками всё видел. Потом разобрался и поделился.

    Reply
  23. nano1c

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

    Reply
  24. v.l.

    (25) nano1c, «кружочки с плюсиками» — 8.2? )))

    Т.е. само дерево рисуется с группировками, но справа строковое значение группировки не показано?

    Не УФ случайно?

    Reply
  25. nano1c

    как на рисунке. это просто какаято жесть — я раньше отчеты сам рисовал в виде деревьев (даже не подозревал что они могут от отрисовываться), а теперь в конфе первобит-финанс хрень какаято — ну нивкакую деревья не рисуются. что только не перепробовал — только кружочки! но я правда сам не рисую рекурсией — рисую вашим методом но нифига не получается. хотя претензий к самим данным дерева нет — все там правильно. а на форме не дерево а хрень с кружками…

    платформа последняя 8.2

    Reply
  26. Cemen82

    Сори, очень нужны WM

    Хочу поделиться своим опытом работы с деревом значений. Оно во многом напоминает таблицу значений, но в отличие от неё кроме строк имеет группировки, которые можно обходить иерархически на манер дерева справочника. Но что больше всего мне понравилось, так это возможность вычислять итоги группировок с учетом иерархии на манер группировок запроса.

    Reply
  27. v.l.

    (28) Если нужны стартмани — попроси, но не спамь.

    Тебе нужна эта обработка? Попроси — я вышлю. Как она создаётся расписано пошагово.

    Reply
  28. v.l.

    (27) nano1c, я попробовал в 8.2 — рисует. А в обычной консоли запросов этот запрос в дерево выгружается? Если выгружается, то в каком виде?

    ________________________

    Проблема в задваивании строк, как на картинке?

    Reply
  29. nano1c

    дело конечно же не в задвоении. в консолиЗапросов дерево имеет точно такой же вид «кружочки». см. рисунок

    Reply
  30. v.l.

    (31) nano1c, ну с версии 8.2 кружочки и рисуются. А в 8.0 и и 8.1 — квадратики. Что за безобразие!

    Reply
  31. nano1c

    кружочки, ладно еще. но вот что веточки не рисует — это плохо. не знал что в 8.2 их впринципе нельзя нарисовать..

    Reply
  32. link_l

    Очень помогло, спасибо! =)))

    Reply
  33. v.l.

    (34) На это и рассчитано.

    Reply
  34. potyomkin

    Скажите, есть тоже самое для управляемых форм?

    Reply
  35. DexterMorgan777

    Спасибо

    Reply
  36. v.l.

    (36) potyomkin, пока нет. Но недавно мне попадалась тема про дерево на УФ на этом форуме или другом.

    Reply
  37. Юлия:)

    Спасибо!

    Reply
  38. v.l.

    (39) Спасибо за отзыв.

    Может, что-то еще подсказать?

    Reply
  39. Юлия:)

    (40) Пока не знаю. Спасибо! Данный материал очень помог — впервые работаю с деревом.

    Reply

Leave a Comment

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