Поиск объектов типа <Объект не найден…>. Теперь на управляемых формах




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

30 Comments

  1. V.Nikonov

    А отчего же сохранили обработку под 8.2? Обратная конвертация не работает!!!

    Reply ↓
  2. ediks

    (1) Потому, что в 8.2 для реквизита GUID можно задать тип УникальныйИдентификатор, которого в 8.1 нет. Не хочется делать лишних телодвижений в условиях цейтнота, да и работаю я под 8.2.

    Reply ↓
  3. NazaroV74

    Огромное спасибо)) Вещь нужная

    Reply ↓
  4. Широкий

    Ну и зачем нужно тип объекта выбирать?

    В представлении битой ссылки эта инфа и так есть

    Reply ↓
  5. ediks

    (4) А Вы знаете, как из строкового представления извлечь тип объекта? Я бы вставил этот алгоритм в обработку.

    Reply ↓
  6. romansun

    (5)

    писал пару месяцев назад на схожую тему

    http://infostart.ru/public/80438/

    Reply ↓
  7. ediks

    (6) все равно это не решает проблемы. Вам заранее известен тип объекта для восстановления (поиска). Или что-то я не так понял?

    НовЭл = Справочники.БюджетныеЦентры.СоздатьЭлемент();

    НовЭл.УстановитьСсылкуНового(ЗначениеИзСтрокиВнутр(«{«»#»»,54c3544f-651b-4887-ae3a-2df362efbacb,9659:ab2b001b78e134e011dfec0814418025}»));

    Reply ↓
  8. Широкий
    Перем ТаблицаТипов;
    //———————————————————————//
    Процедура ОсновныеДействияФормыОсновныеДействияФормыВыполнить(Кнопка)
    СтрокаПоиска=ТаблицаТипов.Найти(«1216″,»НомерТаблицы»);
    Если СтрокаПоиска=Неопределено Тогда
    Сообщить(«Не определена таблица хранения»);
    Возврат;
    КонецЕсли;
    
    Сообщить(СтрокаПоиска.ТипОбъекта);
    КонецПроцедуры
    
    Процедура ДобавитьДанныеВТаблицуТипов(ТаблицаТипов,КоллекцияМетаданных,КоллекцияОбъектов)
    Для Каждого ОбъектМетаданных Из КоллекцияМетаданных Цикл
    ПустаяСсылка=КоллекцияОбъектов[ОбъектМетаданных.Имя].ПустаяСсылка();
    
    МСтроки=СтрЗаменить(ЗначениеВСтрокуВнутр(ПустаяСсылка),»,»,Символы.ПС);
    
    Для сч=1 По СтрЧислоСтрок(МСтроки) Цикл
    МСтрока=СтрПолучитьСтроку(МСтроки,сч);
    
    ПозицияРазделителя=Найти(МСтрока,»:»);
    Если Не ПозицияРазделителя Тогда
    Продолжить;
    КонецЕсли;
    
    НоваяСтрока=ТаблицаТипов.Добавить();
    НоваяСтрока.НомерТаблицы=Лев(МСтрока,ПозицияРазделителя-1);
    НоваяСтрока.ТипОбъекта=ТипЗнч(ПустаяСсылка);
    КонецЦикла;
    КонецЦикла;
    КонецПроцедуры
    
    Процедура ИнициализацияПеременных()
    ТаблицаТипов=Новый ТаблицаЗначений;
    ТаблицаТипов.Колонки.Добавить(«НомерТаблицы»);
    ТаблицаТипов.Колонки.Добавить(«ТипОбъекта»);
    
    ДобавитьДанныеВТаблицуТипов(ТаблицаТипов,Метаданные.Справочники,Справочники);
    
    ДобавитьДанныеВТаблицуТипов(ТаблицаТипов,Метаданные.Документы,Документы);
    
    ДобавитьДанныеВТаблицуТипов(ТаблицаТипов,Метаданные.ПланыВидовХарактеристик,ПланыВидовХарактеристик);
    
    ДобавитьДанныеВТаблицуТипов(ТаблицаТипов,Метаданные.ПланыОбмена,ПланыОбмена);
    
    ДобавитьДанныеВТаблицуТипов(ТаблицаТипов,Метаданные.Задачи,Задачи);
    
    ДобавитьДанныеВТаблицуТипов(ТаблицаТипов,Метаданные.БизнесПроцессы,БизнесПроцессы);
    КонецПроцедуры
    
    ИнициализацияПеременных();

    Показать

    Reply ↓
  9. ediks

    (8) ОК, спасибо. Действительно, достаточно просто.

    Reply ↓
  10. ilya2184

    Ну и я свой вклад внесу — у меня тоже есть подобная обработка, плодить не буду

    У меня есть кнопка создания объекта…

    Это понятно:

    Стр1 = СтрЗаменить(ИсходнаяСтрока,»<Объект не найден> («,»»);

    СтрокаНомерТипа = Лев(Стр1,Найти(Стр1,»:»)-1);

    Идентификатор = Сред(СтрЗаменить(Стр1, СтрокаНомерТипа+»:»,»»),1,32);

    СтрокаИд = Прав(Идентификатор,8)+»-»

    +Сред(Идентификатор,21,4)+»-»

    +Сред(Идентификатор,17,4)+»-»

    +Лев(Идентификатор,4)+»-»

    +Сред(Идентификатор,5,12);

    Гуид = Новый УникальныйИдентификатор(СтрокаИд);

    //Моя таблица типов содержит колонки НомерТипа(Строка), МенеджерТипа(СправочникМенеджер, ДокментМенеджер), ИмяТипа

    //например «1123», Справочники, «Номенклатура»

    СтрокаТЗ = мТаблицаТипов.Найти(СтрокаНомерТипа, «СтрокаНомерТипа»)

    //тут проверка нашли или нет — нет — плохо — была серьёзная реструктуризация — надо поднимать бэкапы.

    СсылкаНаОбъект = СтрокаТЗ.МенеджерТипа[СтрокаТЗ.ИмяТипа].ПолучитьСсылку(Гуид);

    //и полезная кнопка.

    УдаленныйОбъект = СсылкаНаОбъект.ПолучитьОбъект();

    Если УдаленныйОбъект = Неопределено Тогда

    Если СтрокаТЗ.МенеджерТипа = Документы Тогда

    УдаленныйОбъект = СтрокаТЗ.МенеджерТипа.СоздатьДокумент();

    ИначеЕсли СтрокаТЗ.МенеджерТипа = ПланыСчетов Тогда

    УдаленныйОбъект = СтруктураОбУдаленном.Менеджер.СоздатСчет();

    Иначе

    УдаленныйОбъект = СтрокаТЗ.МенеджерТипа.СоздатьЭлемент();

    КонецЕсли;

    УдаленныйОбъект.УстановитьСсылкуНового(СсылкаНаОбъект);

    КонецЕсли;

    //заполним и запишем по памяти…

    УдаленныйОбъект.ПолучитьФорму().ОткрытьМодально();

    Reply ↓
  11. Nikola23

    А чтоб не мучатся с восстановлением убитых ссылок (при наличии резервной копии) можно попробовать использовать обработку ВыгрузкаЗагрузкаДанныхXML. Выгружаем объекты из резервной копии, загружаем в рабочую. Соответствие объектов рабочей базы и копии устанавливается по внутр идентификаторам. В результате выполнения потерянные объекты будут восстановлены.

    Reply ↓
  12. ediks

    (11) Вот только осталось в резервной копии определить, какие объекты выгружать. Для этого и создавалась эта обработка. А (10) приведен как пример поиска и восстановления убитой ссылки в текущей базе.

    Reply ↓
  13. kosmo0

    В процедуре РазобратьСтрокиОбъектНеНайден() строку Счетчик = Счетчик + 1; стоит поднять выше условия, иначе если строку не удастся разобрать будет зацикливание.

    Reply ↓
  14. ediks

    (13) Исправил. Спасибо за наводку.

    Reply ↓
  15. toshka

    Спасибо! Очень помогла обработка!

    Reply ↓
  16. zse

    Не понятно зачем все это.

    Главное определить порушенный объект (справочник такой-то). А далее делаем

    выгрузку объекта из копии и подгружаем в поломанную базу.

    И не забываем еще раз проверить права на удаление объектов… 😀

    Reply ↓
  17. ediks

    (16)

    1) Как Вы определяете тип объекта? Тип битой ссылки может быть составного типа. К примеру, документ расчетов на 60 или 62 счете…

    2) А как Вы определяете объект, который необходимо выгрузить из копии???

    3) Почитайте всю ветку — я уже объяснял для чего нужна эта обработка.

    Reply ↓
  18. ELInfinito

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

    Reply ↓
  19. JohnySC

    На основании этой и других идей с этого сайта, получилась вот такая моя обработка:

    http://infostart.ru/public/91438/

    Она делает примерно то же, только еще и переносит объекты сразу из нужной копии в рабочую базу

    Reply ↓
  20. shomo

    Замечательно. Можно восстанавливать утраченные объекты. Огромное спасибо.

    Reply ↓
  21. toshka

    Спасибо за обработку! Очень нужная вещь!

    Reply ↓
  22. zabaikalka

    ПОМОГИТЕ, у меня беда!!!! Бэккапов нет, а вот таблица не найдена! Очень надо!!!

    Reply ↓
  23. ILYA1C

    нашла все битые ссылки)))

    Reply ↓
  24. dtitov

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

    Reply ↓
  25. vit59

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

    Reply ↓
  26. ediks

    (25) читайте (19) — уже все сделано

    Reply ↓
  27. Spacer

    (7) «Вам заранее известен тип объекта для восстановления (поиска). Или что-то я не так понял?»

    Если тип объекта для восстановления не известен заранее, то его всегда можно получить перебором.

    Это используется во многих обработках подобного рода, например в этой:

    http://infostart.ru/public/92259/

    Просто если он известен заранее то можно обойтись без дополнительных телодвижений.

    Reply ↓
  28. ediks

    (27) 1) Мне кажется, что вопрос решен, благодаря подсказке — тип объекта хранится в представлении битой ссылки.

    2) Перебирать каждый объект метаданных для каждой битой ссылки мне кажется неразумным. Количество итераций получается велико — туча битых ссылок, помноженная на сотни объектов метаданных.

    Reply ↓
  29. JohnConnor

    не взлетела =(

    Reply ↓
  30. ediks

    (29) Какую ошибку выдала обработка?

    Reply ↓

Leave a Comment

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