Программное создание динамического списка на управляемой форме. (Динамическое создание динамического списка). Готовая процедура + обработка — демонстрационный пример




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

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

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

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

25 Comments

  1. palsergeich

    Код приятный.

    Нужно только понимать, после ПриСозданииНаСервере добавлениеудаление реквизитов — очень дорогая операция…

    Reply ↓
  2. rpgshnik

    (1) спасибо, учту про стоимость операции.

    Reply ↓
  3. pm74

    (0) полезная публикация , спасибо

    Reply ↓
  4. Denis Nsk

    Спасибо большое!

    Лично для меня, очень полезная публикация. Отметил в избранное на будущее.

    Спасибо за потраченное время и подробное описание!

    Reply ↓
  5. Batchir

    Спасибо!

    Появились хотелки к статье)))

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

    В «типовом» варианте это делается на сервере:

    МойСписок.Параметры.УстановитьЗначениеПараметра(«МойПараметр»,ЗначениеМоегоПараметра);

    При программном создании «МойСписок» отсутствует и будет валиться на синтаксис.

    2. Было бы замечательно если бы описали формирование колонок динамического списка.

    Причем с возможностью указания группировок колонок. Не всегда нужно сформировать линейный динамический список.

    Reply ↓
  6. rpgshnik

    (5) Дельные хотелки, когда есть обратная связь особенно интересно.

    1. Как-то я забыл про Параметры, у меня их не было, я как-то отборами привык уже))

    Добавлю в саму процедуру, обновлю чуть позже.

    2. Я конечно не хотел преследовать супер-универсальности, возможно подумаю, но не обещаю.

    Да и цель была именно линейные списки. Возможно стоит проще постобработкой список скорректировать группировками… я и отборы не добавляю, так это точно перебор)))

    Reply ↓
  7. Vlad_2008

    Ну синтаксис можно и обойти: ЭтаФорма[«МойСписок»].Установить …

    А вот как быть с характеристиками (а-ля «доп. реквизиты» в типовых)? Их можно задать в конфигураторе в свойствах объекта, тут получается что надо все вставлять в запрос для каждой формы объекта.

    И, может кто-нибудь знает, как программно добавить колонку с характеристикой, как будто пользователь вынес на форму поле Ссылка.[Мой доп реквизит] ? В запросе-то поля нет, а вот в «Изменить форму — Ссылка — Добавить поля» — есть.

    Reply ↓
  8. rpgshnik

    (7) интересно, но не сталкивался( вообще мало работаю с новыми конфигами, увяз в совместимости 8.2.13

    Reply ↓
  9. rpgshnik

    (5) функционал в процедуру по передачи параметров добавил, публикацию обновил.

     //Заполняем параметры если они были указаны
    Если ПараметрыЗапроса <> Неопределено Тогда
    Для Каждого Параметра из ПараметрыЗапроса Цикл
    РеквизитДинамическийСписок.Параметры.УстановитьЗначениеПараметра(Параметра.Ключ,Параметра.Значение);
    КонецЦикла;
    КонецЕсли;

    на второй ваше предложение, используйте группировки, ни их не отборы в процедуру добавлять не планирую

    Reply ↓
  10. rpgshnik

    (7) Мне кажется я понял вас. Я почему-то подумал про ПВХ и дополнительные Свойства Объектов.

    А вы говорите просто об реквизитах ссылочного объекта.

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

    Пример, запрос динамического списка:

    ВЫБРАТЬ
    РеализацияТоваровУслуг.Дата,
    РеализацияТоваровУслуг.Номер,
    РеализацияТоваровУслуг.Организация,
    РеализацияТоваровУслуг.Контрагент
    ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

    Код обработки события, к примеру по нажатию кнопки:

    &НаКлиенте
    Процедура ДобавитьКолонку(Команда)
    ДобавитьКолонки();
    КонецПроцедуры
    
    &НаСервере
    Процедура ДобавитьКолонки()
    НоваяКолонкаТаблицы = Элементы.Вставить(«дСписокКонтрагентИНН»,Тип(«ПолеФормы»),Элементы.дСписок,Элементы.дСписокОрганизация);
    НоваяКолонкаТаблицы.ПутьКДанным = «дСписок.Контрагент.ИНН»;
    НоваяКолонкаТаблицы.Заголовок = «ИНН»;
    НоваяКолонкаТаблицы = Элементы.Вставить(«дСписокКонтрагентКПП»,Тип(«ПолеФормы»),Элементы.дСписок,Элементы.дСписокОрганизация);
    НоваяКолонкаТаблицы.ПутьКДанным = «дСписок.Контрагент.КПП»;
    НоваяКолонкаТаблицы.Заголовок = «КПП»;
    НоваяКолонкаТаблицы = Элементы.Добавить(«дСписокОрганизацияИНН»,Тип(«ПолеФормы»),Элементы.дСписок);
    НоваяКолонкаТаблицы.ПутьКДанным = «дСписок.Организация.ИНН»;
    НоваяКолонкаТаблицы.Заголовок = «ИНН»;
    КонецПроцедуры
    

    Показать

    Обработка прилагается:

    Reply ↓
  11. Batchir

    (9) Да я то что ))) Если мне нужно будет, то конечно буду использовать (и сам смогу дописать). Это хотелка была для полноты статьи: программное создание, размещение динамического списка есть, а программного управления колонками нет (размещение в группах вместе, горизонтально …).

    В любом случае ещё раз спасибо. Саму функцию закинул в шаблоны, думаю пригодиться.

    Reply ↓
  12. rpgshnik

    (11) ок, понял))

    Reply ↓
  13. Vlad_2008

    (10)

    Не, я как раз именно про ПВХ. С реквизитами все понятно и просто. А вот как с характеристиками — вопрос?

    В отчете на СКД я могу добавить поле программно (например в отбор) так:

    Новый ПолеКомпоновкиДанных(«Организация.[Связанный контрагент]»);

    Дин. список тоже на СКД, характеристики можно описать в свойствах объекта или в конструкторе запроса.

    Ес-но, можно программно задать текст запроса с характеристиками, после чего пользователь сможет вынести на форму колонку с произвольной характеристикой.

    Так вот и не могу понять можем ли мы программно создать такую колонку? Как указать путь к данным?

    Reply ↓
  14. antont

    (13) Можно и без изменения запроса.

    В качестве пути к данным указывается имя доступного поля выбора компоновщика настроек динамического списка.

    ЕМаил = Элементы.Добавить(«ЕМаил»,Тип(«ПолеФормы»),Элементы.Список);
    ЕМаил.ПутьКДанным =»Список.Ссылка.[E-mail]»;
    Reply ↓
  15. Vlad_2008

    (15)

    Работает, спасибо!

    Основная проблема была в том, что невозможно было определить колонку, которую пользователь добавил через «Изменить форму» … ну я никак не смог до нее достучаться … в элементах формы ее тоже нет.

    С добавленной программно колонкой все хорошо, вот только в настройках формы она «автоматом» не сохраняется, но это уже другая история …

    Reply ↓
  16. t0202

    Спасибо, успешно воспользовался Вашей процедурой.

    Заметил один недостаток.

    В массиве колонок желательно поменять местами заголовок и имя колонки.

    У меня заголовки колонок оказались с запятыми и пришлось это поправить.

    Reply ↓
  17. rpgshnik

    (17) спасибо проверю

    Reply ↓
  18. Daynestro07

    Дельная статья. Интересно только, есть ли способ получить массив выводимых колонок автоматически, из запроса?

    upd Уже неактуально

    Reply ↓
  19. Vida

    (14) В отличие от автора статьи, у вас есть реквизит дСписок — динамический список. Поэтому в указанных вводных ваш код работать не будет, а именно

    дСписок.ТекстЗапроса = ТекстЗапроса;

    по причине из (5) часть 1

    А вот как это обойти — не придумала.

    Reply ↓
  20. Vida

    (14) Так вы и есть автор! Нашла свою ошибку почему не могла параметры поменять. Создаю программно «СписокМой», а потом пытаюсь изменить параметры у «МойСписок».

    Все отлично работает

    &НаСервере
    Процедура СписокПриАктивизацииСтрокиНаСервере(ДатаР, НомерР, ИмяСписка)
    Если ЭтаФорма.Элементы.Найти(ИмяСписка) <> Неопределено Тогда
    РеквизитДинамическийСписок = ЭтаФорма[ИмяСписка];
    РеквизитДинамическийСписок.Параметры.УстановитьЗначениеПараметра(«НомерРег», НомерР);
    РеквизитДинамическийСписок.Параметры.УстановитьЗначениеПараметра(«ДатаРег», ДатаР);
    КонецЕсли;
    КонецПроцедуры
    
    &НаКлиенте
    Процедура СписокПриАктивизацииСтроки(Элемент)
    Сообщить(Элемент.ТекущиеДанные.Дата);
    СписокПриАктивизацииСтрокиНаСервере(Элемент.ТекущиеДанные.Дата, Элемент.ТекущиеДанные.Номер, «СписокМой»);
    КонецПроцедуры
    

    Показать

    Reply ↓
  21. mikl79

    Большое спасибо автору!!!

    Очень нужная Процедура — воспользовался, применил в расширении, вообще стараюсь программно в расширении добавлять на форму реквизиты, табл.части, кнопки, теперь и динам.список смогу.

    Единственное, мне нужно вывести динам.список на отдельную страницу.

    Reply ↓
  22. mikl79

    немного доработал Процедуру — добавил еще один параметр, чтобы выводилось на страницу

    Reply ↓
  23. rpgshnik

    (23) не смог понять, а параметра — «ДобавитьВ» не достаточно? Интересно.

    Reply ↓
  24. mikl79

    (24), действительно воспользовался параметром «ДобавитьВ», но перед вызовом процедуры программно создал новую страницу

    Reply ↓
  25. mikl79

    Не сразу заметил, что вы используете при добавлении элементов на форму процедуры Добавить и Вставить, в чем их разница — не понял.

    «Вставить» в отличие от «Добавить» только содержит 4-й параметр «Элемент» — Элемент, перед которым должен быть вставлен новый элемент. Если не указан, то элемент будет вставлен в конец.

    А так вроде делают одно и тоже, но это наверное вопрос риторический — разработчикам.

    Reply ↓

Leave a Comment

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