Организация сложных фильтров объединенных условием и/или (Работа со списками значений)




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

18 Comments

  1. venger

    Забыл, используется еще одна функция работы со списками:

    Автор: Сергей Попов, Усинск, Коми

    Код
    //===================================
    //Объединяются списки значений
    //Функция возвращает суммарный список
    //При этом, Спис1 выгружается, а Спис2 построчно добавляется в конец списка
    Функция гл9ОбъединитьСпискиЗначений(Спис1,Спис2) Экспорт
       //_new_ 19.03.2003 сп_
       Перем Res;
       Res=СоздатьОбъект("СписокЗначений");
       Если ВРег(СокрЛП(ТипЗначенияСтр(Спис1)))= ВРег("СписокЗначений") Тогда
          Спис1.Выгрузить(Res);
       КонецЕсли;
       Если ВРег(СокрЛП(ТипЗначенияСтр(Спис2)))= ВРег("СписокЗначений") Тогда
          N=Спис2.РазмерСписка();
          Если N>0 Тогда
             i=0;
             Пока i<N Цикл
                i=i+1;
                Sx="";
                V=Спис2.ПолучитьЗначение(i,Sx);
                Res.ДобавитьЗначение(V,Sx);
             КонецЦикла;
          КонецЕсли;
       КонецЕсли;
       Возврат Res;
    КонецФункции //гл9ОбъединитьСпискиЗначений
    //=========================================
    

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

    Reply
  2. poppy

    Чем хороша такая конструкция?

    Код
    N=Спис2.РазмерСписка();
    Если N>0 Тогда
       i=0;
       Пока i<N Цикл
          i=i+1;
           //...
       КонецЦикла;
    КонецЕсли;
    

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

    Почему не используется такая?

    Код
    Пока i = 1 По Спис2.РазмерСписка() Цикл
       //...
    КонецЦикла;
    

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

    Reply
  3. JohnyDeath

    Люди, курите прямые запросы! Зачем такой геморрой?

    Reply
  4. venger

    (2) Чем хороша такая конструкция?

    А чем плоха? Чем они вообще отличаются?:-)

    Это все-равно, что спорить, что плохо, что индексы ТаблицЗначений или СписковЗначений начинаются с 1, а не с 0.

    Я так с нуля люблю, но это дело привычки.

    1С язык мне не родной, я его вспоминаю, когда в 1С’не наваять что нуно:-)

    Reply
  5. venger

    (3) Затем что в прямых запросах нельзя строки неограниченной длины обрабатывать. Или по части поля сравнивать.

    Хотя во многих случаях это хороший вариант, более быстрый.

    Да и функции эти — работы со СпискамиЗначений — можно использовать и в других случаях, не только для этой задачи.

    Reply
  6. JohnyDeath

    (5) не понял.

    1) Ты хочешь устанавливать фильтры на основе реквизитов, которые имеют неопределённую длину?

    2) Что значит «в прямых запросах нельзя по части поля сравнивать»? (желательно пример)

    Reply
  7. venger

    (6)

    1) Я не то, чтобы хочу, но если будет такая необходимость организовать фильтрацию или поиск, то какие проблемы:-)

    2) Например, поле номер рамы: LAPP12345ERT569835789. Пользователям удобно искать или фильтровать не полный номер рамы, а только по последним символам, допустим по 5789.

    Reply
  8. venger

    И вообще, злые вы….:-)

    Хоть бы плюсик поставили:-)

    Reply
  9. venger

    По сути, ценно тут то, что можно получить объединение и пересечение двух множеств.

    А для каких задач это использовать (фильтры это так, пример), это уже второй вопрос.

    Reply
  10. tango

    прикольно

    Reply
  11. venger

    Тут пришла мысль:-)

    Объединение можно получить еще одним способом.

    Слить два списка вместе, а потом удалить двойников из результирующего.

    Хоть это тоже самое, только в профиль:-)

    Что-то типа такого:

    Код
    // ----------------------------------------------------------------------
    Функция гл8ПолучитьОбъединениеСписков(Знач Сп1, Знач Сп2) Экспорт
       Перем Сп;
    
       Сп=СоздатьОбъект("СписокЗначений");
    
       Если ВРег(СокрЛП(ТипЗначенияСтр(Сп1))) <> ВРег("СписокЗначений") Тогда
          Сп1=СоздатьОбъект("СписокЗначений");
       КонецЕсли;
    
       Если ВРег(СокрЛП(ТипЗначенияСтр(Сп2))) <> ВРег("СписокЗначений") Тогда
          Сп2=СоздатьОбъект("СписокЗначений");
       КонецЕсли;
       
       Если Сп1.РазмерСписка()<1 Тогда
          Если Сп2.РазмерСписка()<1 Тогда
             Возврат Сп;
          Иначе
             Сп2.Выгрузить(Сп);
             Возврат Сп;
          КонецЕсли;
       КонецЕсли;
    
       Если Сп2.РазмерСписка()<1 Тогда
          Если Сп1.РазмерСписка()<1 Тогда
             Возврат Сп;
          Иначе
             Сп1.Выгрузить(Сп);
             Возврат Сп;
          КонецЕсли;   
       КонецЕсли;
    
       Сп=гл9ОбъединитьСпискиЗначений(Сп1,Сп2);
       Сп=гл8УдалитьДвойниковИзСписка(Сп);
    
       Возврат Сп;
    КонецФункции   // гл8ПолучитьОбъединениеСписков
    // ----------------------------------------------------------------------
    

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

    Reply
  12. JohnyDeath

    Venger,

    фильтровать не полный номер рамы, а только по последним символам, допустим по 5789

    это очень даже просто реализуется в прямых запросах так:

    Код
     ...
    Where НомерРамы LIKE '%5789' 

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

    Я не злой, я просто пропагандирую 1с++ 😉

    По соединениям/объединениям: http://www.1cpp.ru/docum/icpp/html/IndexedTable.html#innerjoin

    Reply
  13. JohnyDeath

    +(12) она, кстати, и с буфером обмена умеет работать: http://www.1cpp.ru/docum/icpp/html/ext

    Reply
  14. JohnyDeath

    По текущей задаче (отбор элементов по полям подч. справочника):

    предложенный тобой код будет работать только для полей, у которых стоит галочк "Сортировка", т.к

    Код
    СпрРамыДвигатели.ВыбратьЭлементыПоРеквизиту("НомерРамы",НомерРамы,0,0);

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

    Примерно так будет выглядеть твоя задача с использованием 1sqlite http://infostart.ru/projects/2127/

    Код
    БД = СоздатьОбъект("SQLiteBase");
    БД.Открыть(":memory:");            
    Запрос=БД.НовыйЗапрос();
    ТекстЗапроса="
    SELECT Товары.ID [Товар :Справочник.Номенклатура]
    FROM Справочник_Номенклатура as Товары
    INNER JOIN Справочник_СертификатыРамыДвигатели as СРД ON СРД.PARENTEXT = Товары.ID
    Where СРД.НомерРамы LIKE '%5789'";
    
    спНужныхТоваров=СоздатьОбъект("СписокЗначений");
    Запрос.ВыполнитьЗапрос(ТекстЗапроса, спНужныхТоваров);
    

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

    ВСЁ! Если надо ещё и по другим подч. справочникам или добавить условие, то это легко формируется динамически, т.к. ТекстЗапроса — это строка и ей оперировать очень просто!

    А если условий будет 10? У тебя списки будут 10 раз объединятся и фильтроваться??

    Reply
  15. venger

    С этими ВК (1sqlite и 1С++) — да согласен, задача фильтров лучше решается.

    Пасибки, многие ВК я еще не изучал на предмет использования. FormEx смотрел только одним глазком, что он может.

    Но, во-первых, эти функции для списоков могут пригодится и для других целей возможно. Фильтры были как пример для этих функций.

    Во-вторых, использовать чужие ВК — это зависимость, а если там баг или глюк, а если надо что-то особенное.

    Поэтому я склонен идти по пути «придумывания велосипеда», чтоб когда надо будет «придумывать космический корабль», уже быть готовым к этому:-)

    Вот собираюсь основательно взяться за изучение Delphi вообще, и в приложении к 1С (ВК и ВП) в частности.

    Правда времени как всегда мало на это все:-)

    Но в любом случае спасибо, я всегда рад советам.

    Reply
  16. JohnyDeath

    (15) Разработчики 1с++ всегда рады помочь: есть форум, багзилла. К тому же исходники 1с++ ты всегда можешь скачать и сам у себя собрать свою собственную 1с++.

    А в каких, например, случаях могут понадобится такие объединения списков? (просто интересно)

    Лучше возьмись за изучение С++, оно к 1С ближе 😉

    Удачи!

    Reply
  17. venger

    (16) >А в каких, например, случаях могут понадобится такие объединения списков?

    Надо подумать:-) У кого-то есть идеи?:-) Самому интересно:-)

    (16) >Лучше возьмись за изучение С++, оно к 1С ближе 😉

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

    Но и Delphi не помешает;-)

    Кстати, сам язык 1С 7.7 больше Бейсик напоминает. У кого какие ассоциации?

    Понятно, что 1С на С++ писался, поэтому и ближе. Верно?

    В любом случае, я рад, что есть кому подсказать, так что Вам все-равно пасибки:-)

    Reply
  18. mirt1207

    У меня работает отбор по нескольким свойствам, создал справочник, где папка — свойство, а содержимое-возможные выборы. Меньше геморроя при заведении нового свойства и т.д. Единственно, гемор. при заполнении в номенклатуре, но написал табличную обработку…

    Вообще Юзеры довольны, когда из громадного списка мебели отбираешь : тумбочки, нужного цвета

    и нужной коллекции… (Я использовал СписокВСтроку и обратно для поиска по ТЗ)

    Reply

Leave a Comment

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