Получение массива имен реквизитов обычной формы и имя ее основного реквизита




Принцип обмена данными из 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='\

47 Comments

  1. German

    Браво …

    Reply ↓
  2. German

    У Брикса вся фишка в том что он не мог на основе двоичных данных(текстовых) получить форму.

    Код
    СтрокаФормы = ЗначениеВСтрокуВнутр(Форма);
    Форма=ЗначениеИзСтрокиВнутр(СтрокаФормы ); //ошибка 

    Показать полностью

    Потому и затеял эти дела. Форму теперь можно получить из двоичных данных (Как это сделать можно будет посмотреть в новой версии Ei ). Ну а когда есть форма.

    Код
    Для каждого Элемент из Форма.Элементы.Формы Цикл
    Сообщить(Элемент.Имя);
    КонецЦикла; 

    Показать полностью

    Reply ↓
  3. tormozit

    Боюсь, я не смогу получить двоичные данные формы в общем случае. Поэтому данный способ — единственный.

    Reply ↓
  4. tormozit

    Ждите скорого появления функции для получения основного реквизита формы. Она уже есть, токо оформить надо.

    Reply ↓
  5. coder1cv8

    Высший класс!!! +100 от меня!

    Reply ↓
  6. coder1cv8

    +(5) Про основной реквизит тоже очень интересно посмотреть.

    Reply ↓
  7. tormozit

    (6) Готово. Реквизиты формы покорены… )

    Reply ↓
  8. Sol

    А в этой части не напутано?

    > //{ Заменяем символы, критичные для XML

    >// & на &

    ………

    Вроде в http://infostart.ru/profile/16971/blogs/344/ в (11) было правильно:

    > //{ Заменяем символы, критичные для XML

    >// & на &

    ………

    Reply ↓
  9. tormozit

    (8) Это движок форума постарался 😉

    Reply ↓
  10. tormozit

    Теперь стало некрасиво, зато правильно) Не знаю как в новом форуме оформить код… =(

    Reply ↓
  11. Sol

    А я не пойму даже, как комментарии упорядочить, чтобы как раньше — новые были сверху.

    Reply ↓
  12. tormozit

    (12) Согласен. Последние сверху — очень рульно было.

    Reply ↓
  13. tormozit

    (8) Люди, помогите с проблемой отображения злых символов (&)!

    Reply ↓
  14. larisab

    Не могли бы вы еще раз привести функцию ЛксСтрокаВнутрВХМЛТело в виде кода, а не текста, без лишних , видимо убирая их, что то оставила или удалила лишнюю. Дает ошибку в XMLСтрокаФормы.

    Reply ↓
  15. larisab

    Сделала, в итоге применения этого метода (0) параметр: КакойТоОбъект.ПолучитьФорму(«ФормаЭлемента»)), возращает строку «СправочникОбъект», а не массив реквизитов формы и ее основной реквизит.

    Reply ↓
  16. tormozit

    (15) Вставил как есть. Теперь отображается вроде нормально.

    Reply ↓
  17. larisab

    (16) А насчет «возращает строку «СправочникОбъект», а не массив реквизитов формы и ее основной реквизит.»

    Как получить элементы формы?

    Reply ↓
  18. tormozit

    (17) Вопрос не ясен. Прошу сформулировать четко, что ты хочешь получить. Функции проверены на практике. Они возвращают именно то, что заявлено.

    Reply ↓
  19. larisab

    ФормаОбъекта = ГрафикОбъект.ПолучитьФорму(«ФормаЭлемента»);

    ПолученнаяФорма = ЛксПолучитьИмяОсновногоРеквизитаФормы(ФормаОбъекта);

    Хочу в текст кнопки Месяц вставить:

    ТекущаяКнопка = Формат(ДатаМесяца, «ДФ=»»ММММ гггг»»»);

    ПолученнаяФорма.КоманднаяПанельКалендаря.Кнопки.Месяц.Текст = ТекущаяКнопка;

    Reply ↓
  20. larisab

    +19 ГрафикОбъект это уже полученный СправочникОбъект ГрафикиРаботы в ЗУПе.

    Reply ↓
  21. vladnet

    +1 Искал давно как то как получить имя основного реквизита формы, жаль тогда не нашел )

    Reply ↓
  22. vladnet

    В 8.2 не работает ни получение списка реквизитов, ни получение основного реквизита. 🙁

    Reply ↓
  23. tormozit

    (22) Теперь работает и в 8.2. Единственное — не стал делать получение версии платформы из системной информации в нужном формате. Т.е. нужно в функцию версию платформы передавать в виде строки «81» или «82»

    Reply ↓
  24. vladnet

    (23) Спасибо )

    Reply ↓
  25. Akela_Crimea

    Я так понял, что с управляемыми формами эта фича не работает?

    Или это я глючу?

    Reply ↓
  26. tormozit

    (25) Да. Управляемые формы не поддерживаются.

    Reply ↓
  27. mt171

    tormozit, спасибо за разработку!

    Только у меня (8.2.12.80 + ЗУП 2.5.27.6) выдаёт ошибку:

    Ошибка при вызове метода контекста (Прочитать): Ошибка разбора XML: — [1,1]

    Фатальная ошибка:

    Document is empty

    ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);

    по причине:

    Ошибка разбора XML: — [1,1]

    Фатальная ошибка:

    Document is empty

    В чём может быть причина? Вызываю из модуля формы при открытии, в качестве параметра ЭтаФорма,»82″. Сама строка XMLСтрокаФормы заполнена

    Reply ↓
  28. Sergey K

    Кто-нибудь приведите пример, для чего м.б. использован данный функционал? когда требуется программное определения реквизитов формы?

    Reply ↓
  29. HIgor

    Вещь полезная. Для неуправляемых форм видимо единственное решение. Но давайте здесь тоже не кастрированную функцию ЛксСтрокаВнутрВХМЛТело запишем :

    Функция ЛксСтрокаВнутрВХМЛТело(вхСтрока, выхХМЛТело = Неопределено) Экспорт
    
    //{ Получение одной длинной строки
    выхХМЛТело = СтрЗаменить(вхСтрока,СИМВОЛЫ.ПС,»»);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,СИМВОЛЫ.ВК,»»);
    //}
    
    //{ Заменяем символы, критичные для XML
    // & на «&»
    // < на «<»
    // > на «>»
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»&»,»&»);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»<«,»<«);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»>»,»>»);
    
    //{ Замена одинарных символов
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»,»,»</data><data>»);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»{«,»<elem><data>»);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»}»,»</data></elem>»);
    //}
    
    //{ Удаляем лишние блоки и
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»<data><elem>»,»<elem>»);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»</elem></data>»,»</elem>»);
    //}
    
    //{ Добавляем перенос строки к и к для удобства поиска различий
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»</elem>»,»</elem>»+СИМВОЛЫ.ПС);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»</data>»,»</data>»+СИМВОЛЫ.ПС);
    //}
    
    Возврат выхХМЛТело;
    
    КонецФункции
    

    Показать

    Reply ↓
  30. tormozit

    (29) Спасибо. Поправил.

    Reply ↓
  31. fomix

    Присодиняюсь к [28]

    Кто-нибудь приведите пример, для чего м.б. использован данный функционал? когда требуется программное определения реквизитов формы???????????????????????????????????????????

    Reply ↓
  32. AlexO

    Тоже не понял — а зачем этот массив получать? ну там деструктивный анализ формы — еще куда ни шло (хотя как его применяют в статьях — сомнительная цель).

    Но какое практическое применение данного массива реквизитов?

    Reply ↓
  33. tormozit

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

    Reply ↓
  34. frc

    (33)

    а что на входе? некая XML-выгрузка?

    Reply ↓
  35. frc

    (34) frc,

    а, вроде разобрался — на входе Форма, превращается СтрокаВнутр, потом эта строка разбирается по кускам и перегружается в формат XML-DOM для анализа…

    А что такое «делайте кэширование DOM»?

    Reply ↓
  36. tormozit

    (34) На входе чего? На входе команды всегда ключ записи или ссылка.

    Reply ↓
  37. frc

    (36)

    На входе чего?

    на входе в функцию «ЛксПолучитьМассивИменРеквизитовФормы»

    На входе команды всегда ключ записи или ссылка.

    т.е. ссылка на ФормаОбъект?

    Reply ↓
  38. tormozit

    (37) Под командой я подразумевал одноименный объект управляемого приложения. Но теперь я вижу что вопрос был про другое.

    Reply ↓
  39. frc

    (38)

    На тот вопрос вы и не ответили 🙂

    Вот ошибка так и возникает:

    в

    ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);

    {ОбщийМодуль.эрФункцииОбщегоНазначения.Модуль(354)}: Ошибка при вызове метода контекста (Прочитать)

    по причине:

    {ОбщийМодуль.эрФункцииОбщегоНазначения.Модуль(354)}: Ошибка при вызове метода контекста (Прочитать)

    по причине:

    Ошибка разбора XML: — [1,1]

    Фатальная ошибка:

    Document is empty

    Reply ↓
  40. frc

    Могу форму в XML (переменная ЧтениеXML) дать.

    Reply ↓
  41. frc

    В общем, значит так и нельзя получить никаких реквизитов таким методом…

    Reply ↓
  42. frc

    (27) mt171,

    ну да, видимо, с 2010 года так ничего и не изменилось по 8.2 — так не работает получение реквизитов.

    Reply ↓
  43. tormozit

    Правильный вывод следует сразу же после прочтения названия публикации — «Получение массива имен реквизитов ОБЫЧНОЙ формы и имя ее основного реквизита». Все, кто пробуют метод за рамками описанной области применимости, получают не ожидаемый результат.

    Reply ↓
  44. sergant500

    Если метод выдает ошибку, то заменяем строки в посте №29 (HIgor)

    выхХМЛТело = СтрЗаменить(выхХМЛТело,»&»,»&»);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»<«,»<«);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»>»,»>»);

    на

    выхХМЛТело = СтрЗаменить(выхХМЛТело,»&»,»&»);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»<«,»<«);
    выхХМЛТело = СтрЗаменить(выхХМЛТело,»>»,»>»);
    

    Спасибо за наводку Сергею Чуяну (Собеседник) http://infostart.ru/public/20069/

    вызов функции

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

    Все хорошо работает, но наблюдается потеря времени при открытии форм.

    Например функция УстановитьДоступностьПоляВводаНомера, которая вызывается ПриОткрытии() многих форм документов или элементов справочников затрачивает времени 0,003-004 сек. без проверки основного реквизита. А с проверкой 0,35 – 0,6 и больше в зависимости от сложности формы. Визуально заметна разница во времени. Придется мириться с задержкой примерно в половину секунды при открытии любой из форм.

    Reply ↓
  45. sergant500

    Почему-то движок съедает текст. Нужно читать «заменить на»

    выхХМЛТело = СтрЗаменить(выхХМЛТело,»&»,»& amp;»); // пробел убрать между & и amp

    выхХМЛТело = СтрЗаменить(выхХМЛТело,»<«,»& lt;»); // пробел убрать между & и lt

    выхХМЛТело = СтрЗаменить(выхХМЛТело,»>»,»& gt;»); // пробел убрать между & gt

    Reply ↓
  46. Sabfir

    Полезная штука, жаль только, что ресурснозатратная 🙁

    Reply ↓
  47. Andrei.Rch

    После ряда правок успешно завелось на 8.3. Во всех версиях выше есть ошибки из за кривого движка форума. Правильный тест сохранил во вложение.

    Reply ↓

Leave a Comment

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