Использование программных перечислений, ч.1: строковые константы




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

43 Comments

  1. VitaliyCeban

    Хорошее решение, разве что только скобки () глаза мусолят, но это терпимо.

    Вот бы сделали «свойства», как в C#. С виду, обычные поля, а на деле — методы.

    Хотя, если уж вносить изменения в встроенный язык 1С, то относительно этой задачи, надо сразу enum’ы делать.

    Reply
  2. CyberCerber

    Главная проблема, что для этого перечисления не сработает контекстная подсказка. Т.е. все равно придется идти и смотреть, какие значения бывают, копировать, вставлять…

    Reply
  3. JohnGalt

    Актуальная проблема. Исходя из собственного опыта, лучше все настройки, в том числе и сравнения «повесить» на пользователя. Назначить ответственных за механизмы/процессы. Для этого лучше всего сделать справочник или несколько с набором реквизитов/табличных частей для различных настроек. И настройки получать, например, ПриНачалеРаботыСистемы()

    Reply
  4. unichkin

    (4) Ну, тут речь не совсем об этом. Вам к уже введенным настройкам надо как-то обращаться в коде. То что должен быть момент передачи ответственности — полностью согласен, как и с тем что лучше такое реализовать пользовательской настройкой. Только имхо, это не взлетит в 90% случаев фикси. Но это уже тема для отдельной беседы)

    Reply
  5. alex-l19041

    (1)

    Хорошее решение

    — можно уточнить о чем идет речь ? (обсуждается какая-то публикация ?)

    Reply
  6. unichkin

    Что-то на ИС с комментариями, не видел (1) и (2)

    (1) Ну да, мозолят) Идея использовать структуру для этих целей и появилась после того как прочитал чей-то коммент про отсутствие таких вещей в 1С, там тоже человек с любовью С вспоминал)

    (6) я так понимаю, текущая 😉

    Reply
  7. v3rter

    автор забыл ссылку на публикацию http://infostart.ru/public/566908/ ?

    Reply
  8. корум

    (8) это скорей не автор забыл, а движок инфостарта заглючил…

    Reply
  9. v3rter

    Если взять не общий случай — ветвление кода, а частный — выбор набора параметров или макета, то чем плох обыкновенный справочник?

    Reply
  10. shurik_shurik

    Это очень хорошо, если во входящем файле статусы заявок без пробелов записаны. А если с пробелами, как тогда поступать?

    Идея конечно интересная.

    Reply
  11. herfis

    Честно говоря, профита не так много как хотелось бы.

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

    Т.е. в сложных случаях имеет смысл использовать. В простых — вряд ли.

    Reply
  12. unichkin

    (8)(10) не понял вопросов?

    (11) Любую коллекцию параметров удобно так использовать — посмотрите последний пример с планом счетов. В примере — сравниваются значения структуры. Ну добавьте такой элемент:

    СтруктураСтатусыЗаявок.Вставить(«ТоварВПути»    , «Товар в пути»);
    Reply
  13. unichkin

    (13) Основной профит — в удобной структуре кода. Кроме того, автоматически получается оптимизация — в том смысле что коллекция параметров не будет рассчитываться по 10 раз подряд. Неоднократно видел как люди в цикле пишут что-то вроде сч70_1_1 = ПланыСчетов.Хозрасчетный.НайтиПоКоду(«70.1.1»).

    В каких случаях использовать — я теперь только так работаю, если есть несколько строковых констант, даже не задаюсь вопросом «надо ли». Это похоже на рассуждение: «зачем оформлять код по правилам ИТС, для своей разовой доработки?» — т. е. человек не понимает зачем вообще его нужно оформлять, не видит в чем удобство. Я например даже для небольших работ все оформляю — это копейки времени, которые окупаются с лихвой если из разовой доработки понадобится ваять что-то серьезное, или передать кому-то на анализ, или вспомнить что делалось через полгода. Это на подкорке. Чтобы я забыл код оформить — никогда такого не было. Также и здесь. Но это конечно мое «имхо»)

    Reply
  14. vasilev2015

    Может, лучше использовать соответствие ?

    Синтаксис похожий, плюшек больше.

    Подходит для больших списков.

    Reply
  15. herfis

    (15) «Основной профит — в удобной структуре кода». Не согласен. «Структура кода» удобнее не становится. Я не про счета и кэширование (это уже несколько про другое), а про саму идею программных перечислений. В плане удобства — получаем сомнительный аргумент «красивенько» против дополнительного времени на реализацию и въезжание постороннего программиста в этот код. Вот своевременное падение в рантайме для легкого поиска ошибки — это профит. Если бы во время компиляции ругалось — это вообще был бы всем профитам профит. А если бы еще и автокомплишн в конфигураторе — практически полноценные перечисления бы вышли.

    Reply
  16. unichkin

    (17) Именно в нем. «Тупой код с хорошей структурой, лучше чем тупая структура с гениальным кодом». Про время на реализацию — расхожее заблуждение. Дровосек рубит деревья, у него спрашивают — мужик, че ты мучаешься, у тебя ж топор тупой. Наточи топор. А он отвечает: «мне НЕКОГДА! мне надо РУБИТЬ». И все «рубят». Код должен читаться как книга.

    По приоритету, для меня так:

    — «въехать» в это можно достаточно быстро

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

    Reply
  17. unichkin

    (16) Используйте то, что вам удобнее) Но соответствие не выдаст исключения при получении отсутствующего значения, а вернет неопределено. У него несколько иное назначение, чем у структуры.

    Reply
  18. =Kollega=

    Идея хорошая, но все же ИМХО лучше один раз вызвать функцию и вернуть в локальную переменную структуру и работать с ней, чем 10 раз вызывать и проверять, проиницилизирована ли нужная нам структура.

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

    Reply
  19. herfis

    (20) Тут как раз все в порядке.

    Во-первых, ленивая инициализация — это само по себе хорошо.

    Во-вторых, явная инициализация на старте — это еще одна «точка привязки» в коде для реализации этой концепции. Абсолютно лишняя.

    ЗЫ. Поиск в структуре по ключу не должен стать ощутимым, даже если ключей будет много. Если я правильно помню — это хэшированная структура данных. Ну, разве что свопить начнет 🙂 А копирования тут нет.

    Reply
  20. DrAku1a

    Мне кажется, что автор начиная со первого примера «СтруктураСтатусыЗаявок» забыл про своё-же замечание: (буква «О» <> «о»).

    Reply
  21. sulfur17

    А можно функцию СтатусыЗаявок() разместить в глобальном общем модуле с повторным использованием возвращаемых значений на время сеанса?

    Тогда и переменная мСтруктураКэшПрограммныхПеречислений не нужна и можно будет использовать СтатусыЗаявок() в других модулях.

    Например если я хочу передать СтатусыЗаявок().Отказ в качестве параметра из другого модуля, то в другом модуле функцию СтатусыЗаявок() не видно. А если разместить ее в глобальном модуле, то будет видно.

    unichkin, Что об этом думаете?

    Reply
  22. корум

    (0) Более другой вариант.

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

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

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

    тавар ф пути

    номенклатуро в перевозке

    и ТоварВпути

    обработаются одинаково корректно.

    Reply
  23. unichkin

    (23)

    Мне кажется, что автор начиная со первого примера «СтруктураСтатусыЗаявок» забыл про своё-же замечание: (буква «О» <> «о»).

    — не вижу ошибки, ткните пальцем если не сложно.

    (24) Я думаю, если дорабатываете конфу — то добавьте нормальное перечисление.

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

    Еще пример с потолка (кривая методология, просто чтобы отразить суть вопроса): скажем в документе оператор заполняет строковое поле «Причина отказа». Причина может вводиться как из заранее определенного списка, так и произвольно — если установлен соотв. флаг. Так вот — если не добавлять в конфигурации нормальное перечисление (а лучше добавить, сделав «причину» составным полем), то да, наверное логично так сделать. Только модуль ПовтИсп хранит кэш 20 минут. Возможно лучше использовать какие-то существующие кэши конфигурации. И «мСтруктураКэшПрограммныхПеречислений» не будет нужна только для этого конкретного случая.

    (25) Если рассуждать только с позиции загрузки заявок — то конечно, да, лучше дать на откуп пользователю. А еще лучше проговорить это все в ТЗ. Потом при формировании структуры перечисления собрать данные из таблицы формы — да, логично, почему нет. Но загрузка заявок — это ведь частный случай, я его использовал для примера. У меня например была задача, в которой я создавал программное перечисление для событий журнала регистрации. Т.е. было примерно так:

    СтруктураСобытийЖурнала = Новый Структура();
    СтруктураСобытийЖурнала.Вставить(«НачалоСеанса», «_$Session$_.Start»);
    СтруктураСобытийЖурнала.Вставить(«КонецСеанса», «_$Session$_.Finish»);
    СтруктураСобытийЖурнала.Вставить(«Проведение», «_$Data$_.Post»);
    // ну и т. д.
    

    Потом для фильтров использовал СобытияЖР().Проведение и т.п.

    Reply
  24. vlad.frost

    Если инвертировать проверку свойства в мСтруктураКэшПрограммныхПеречислений, то это позволит уменьшить уровни вложенности и код будет читаться легче. Сравните:

    Функция СтатусыЗаявок()
    
    Если мСтруктураКэшПрограммныхПеречислений.Свойство(«СтатусыЗаявок») Тогда
    Возврат мСтруктураКэшПрограммныхПеречислений.СтатусыЗаявок;
    КонецЕсли;
    
    СтруктураСтатусыЗаявок = Новый Структура;
    СтруктураСтатусыЗаявок.Вставить(«НаУтверждении», «НаУтверждении»);
    СтруктураСтатусыЗаявок.Вставить(«ТоварвПути», «ТоварВПути»);
    СтруктураСтатусыЗаявок.Вставить(«КОтгрузке», «КОтгрузке»);
    СтруктураСтатусыЗаявок.Вставить(«Отказ», «Отказ»);
    
    мСтруктураКэшПрограммныхПеречислений.Вставить(«СтатусыЗаявок», Новый ФиксированнаяСтруктура(СтруктураСтатусыЗаявок));
    
    Возврат мСтруктураКэшПрограммныхПеречислений.СтатусыЗаявок;
    
    КонецФункции

    Показать

    Reply
  25. unichkin

    (28) Я обычно стремлюсь к сокращению «Возвратов», если можно рассчитать значение внутри функции и вернуть результат в конце метода — так и делаю; приведенный вами код не кажется мне более читабельным решением, может дело вкуса. Делайте как вам удобнее) Я останусь при своем.

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

    Reply
  26. vlad.frost

    (29) Единая точка выхода, ага, нас тоже так в школе учили. Но если уж вы предлагаете способы, как улучшить читаемость кода, идите дальше. Согласен, в приведённом мной примере данное изменение не сильно улучшит читаемость, но примените его к вашей функции ИспользуемыеСчета(), и там такое улучшение будет уже более актуально. Матчасть: Замена вложенных условных операторов граничным оператором.

    Reply
  27. unichkin

    (30) Да нет в «ИспользуемыеСчета()» ветка условия всего одна, так что принцип тот же что и в (29). То, что описывает приведенная вами статья я стараюсь соблюдать, и это как-то всегда на уровне спинного мозга осознавал — что не стоит допускать дебрей Case-Of Если-Тогда. Однако за наводку и интерес к моей статье — спасибо)

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

    Функция ИспользуемыеСчета()
    
    Если НЕ мСтруктураКэшПрограммныхПеречислений.Свойство(«ИспользуемыеСчета») Тогда
    СтруктураИспользуемыеСчета = Новый Структура;
    
    // Чтобы добавить счет, добавьте сюда его код
    СтрокаКодовСчетов = «10, 10.3, 19, 60.1, 60.2, 62, 51, 51, 70, 70.1, 76.АВ, 90, 90.01, 90.02»;
    СтруктураИспользуемыеСчета = ОбщегоНазначенияБП.СтруктураСчетовПоСтрокеКодов(СтрокаКодовСчетов );
    
    мСтруктураКэшПрограммныхПеречислений.Вставить(«ИспользуемыеСчета», Новый ФиксированнаяСтруктура(СтруктураИспользуемыеСчета));
    КонецЕсли;
    
    Возврат мСтруктураКэшПрограммныхПеречислений.ИспользуемыеСчета;
    
    КонецФункции
    

    Показать

    Reply
  28. neikist

    Понимаю что поздновато отписываюсь, но как вам такой вариант?

    #Область ПрограммноеПеречисление_СтатусыЗаявок
    
    Функция _СтатусыЗаявок_НаУтверждении() Возврат «НаУтверждении» КонецФункции
    Функция _СтатусыЗаявок_ТоварВПути()  Возврат «ТоварВПути»  КонецФункции
    Функция _СтатусыЗаявок_КОтгрузке()   Возврат «КОтгрузке»  КонецФункции
    Функция _СтатусыЗаявок_Отказ()   Возврат «Отказ»   КонецФункции
    
    
    #КонецОбласти
    
    Функция ДанныеФайлаУспешноСчитаны() Экспорт
    
    //…
    СтатусЗаявки = СокрЛП(Excel.Cells(1, Сч).Text);
    
    Если СтатусЗаявки = _СтатусыЗаявок_НаУтверждении() Тогда
    //…
    ИначеЕсли СтатусЗаявки = _СтатусыЗаявок_ТоварВПути() Тогда
    //…
    ИначеЕсли СтатусЗаявки = _СтатусыЗаявок_КОтгрузке() Тогда
    //…
    КонецЕсли;
    
    Возврат Истина;
    
    КонецФункции
    

    Показать

    Плюсы:

    1. Можно использовать в формах &НаСервере, вместо того чтобы каждый раз инициализировать переменную после клиента;

    2. Есть автодополнение и контекстная подсказка;

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

    4. По идее возвращаемое значение таких функций должно «инлайниться» в место использования, так что производительность должна быть такая же как при обычном сравнении со значением, а если и нет то что у меня, что у Вас накладные расходы на вызов функции так или иначе идут.

    Минусов с ходу могу назвать только два:

    1. Засорение контекстной подсказки, для чего и добавил в начало _;

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

    Reply
  29. unichkin

    (32)

    1. Объявляете реквизит формы «СтруктураКэшПрограммныхПеречислений», с произвольным типом реквизита… А остальное все то-же) Это если для формы. Вообще правильнее все-же к форме относить то, что касается *формы* — интерактив, все расчеты лучше отправлять на сервер, т.е. в модуль объекта. Ну тут можно много рассуждать и говорить — по всякому можно. Если говорим о внешней обработке можно сделать реквизит обработки произвольного типа — он будет доступен и с сервера и с клиента. Если о объекте конфигурации — сделайте реквизит формы. Или — вызов из модуля ПовтИсп.

    2. Если учесть что различие только в префиксе — имхо, не очень удобно для набора, когда много коллекций.

    С моей точки зрения, когда перечисление обосабливается в свой метод — это и нагляднее и удобнее. Ну да, синтакс контроль не заругается. Пишите аккуратнее) Каждому свое конечно, используйте то что вам больше подходит. Но мне с таким кодом было бы работать тяжеловато. Подчеркивание в начале метода — это нарушение правил образования имен переменных. Ну и плюшки с ленивой инициализацией теряются.

    Reply
  30. tailer2

    >через предопределенный список элементов плана счетов, т.е. туда надо провалиться, найти код счета, скопировать имя… — долго

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

    Reply
  31. SergeyFirst

    Красиво и лаконично! Молодца!

    Reply
  32. Tapochki-tmn

    Возможно, я чего-то не понял, но мне кажется в коде примера использования ошибка.

    Строка «ВидОпределенияКонтрагента = ВидыОпределенияКонтрагента().Контрагент;» не корректна, т.к. структура СтруктураВидыОпределенияКонтрагента не содержит свойства «Контрагент», зато содержит «Документ».

    И чтобы сработало вот это:

    Если СвойстваИсточника().ВидОпределенияКонтрагента = ВидыОпределенияКонтрагента().Документ Тогда

    Контрагент = мИсточник.Контрагент;

    наверное, нужно было написать так:

    Если ТипЗнч(мИсточник) = Тип(«ДокументОбъект.РеализацияТоваровУслуг») Тогда

    ВидОпределенияКонтрагента = ВидыОпределенияКонтрагента().Документ;

    Сори, если туплю…

    Но может кому сбережет нервы при копипасте примера 🙂

    Reply
  33. IvSchekin

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

    Reply
  34. unichkin

    (36) Все верно, спасибо, поправил

    Reply
  35. Sei Souma

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

    Reply
  36. webester

    Прошу прощения за глупые вопросы. Но вся суть это длинной статьи, отсылки на вики, простыней кода, заключаются в фразе: «Если вам нужно использовать несколько строк в операторах сравнения, используйте структуру» ? Или я чего то не заметил?

    Reply
  37. Digest08

    Отменил свой коммент

    Reply
  38. markers

    Если религия не запрещает, то можно использовать сами чистокровные перечисления без регистрации, смс и совершенно без серверных вызовов, спросите как? Очень просто!

    1) Создаем реквизит формы произвольного типа, Назовем её к примеру «Переч_Статусы»

    2) При создании формы на сервере (или любой другой метод, выполняющимся одним из первых на сервере) выполняете такой код для нужных перечислений:

    Переч_СтатусыВрем = Новый Структура;
    Итератор = 0;
    
    Для Каждого стр из Метаданные.Перечисления.Статусы.ЗначенияПеречисления Цикл
    
    Переч_СтатусыВрем.Вставить(стр.Имя, Перечисления.Статусы[Итератор]);
    Итератор = Итератор + 1;
    
    КонецЦикла;
    
    Переч_СтатусыВрем.Вставить(«ПустаяСсылка», Перечисления.Статусы.ПустаяСсылка());
    Переч_Статусы = Новый ФиксированнаяСтруктура(Переч_СтатусыВрем);

    Показать

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

    3) Там где надо получить значения перечисления пишите так:

    Если Статус = Переч_Статусы[«Готово»] Тогда
    // Ваш код
    КонецЕсли;

    Так можно без вызова сервера проверять/устанавливать значения перечислений, единственный минус, это отсутствие подсказки, но если вы ошибётесь в копипейсте значения перечисления при вставке в код, то так-же как и в данной публикации, будет выдана ошибка при выполнении.

    PS: Так как это реквизит формы, а не переменная, то данный код можно использовать и на сервере (дабы не мучить базу лишними запросами).

    Reply
  39. unichkin

    (42) Клиент-серверный кэш на форме нужен крайне редко. Кэшировать именно значения предопределенных элементов значения перечислений самостоятельно не требуется — для этого есть метод «ПредопределенноеЗначение». В том случае если на форме нужен кэш — это бывает, когда архитектурно невозможно вынести код в модуль объекта, можно также использовать глобальную переменную (в данные формы таблицу значений например не поместишь). Я это делаю примерно так:

    
    &НаСервере
    Перем мСтруктураКэшДанных;
    
    //…
    
    &НаСервере
    Функция КэшСервера()
    Если мСтруктураКэшДанных = Неопределено Тогда
    мСтруктураКэшДанных = Новый Структура;
    
    КонецЕсли;
    
    Возврат мСтруктураКэшДанных;
    
    КонецФункции
    
    &НаСервере
    Функция ДокументыКАнализу()
    
    Если НЕ КэшСервера().Свойство(«ДокументыКАнализу») Тогда
    
    ДокументыКАнализу = Новый Массив;
    //…
    КэшСервера().Вставить(«ДокументыКАнализу», ДокументыКАнализу);
    КонецЕсли;
    
    Возврат КэшСервера().ДокументыКАнализу;
    
    КонецФункции
    
    

    Показать

    Reply
  40. markers

    (43)

    ПредопределенноеЗначение

    я возможно сделаю для вас открытие, но данный метод делает серверный вызов и если сервер рядом, этим можно и пренебречь, но я как-то заметно ускорил РМК из 1С:Розница 2.2 особенно на слабом интернете, заменив ПредопределенноеЗначение на нечто подобное описанное в (42) ничего не потеряв при этом.

    Reply
  41. unichkin

    (44) я руководствуюсь этой статьей https://its.1c.ru/db/v8std#content:443:hdoc

    «При этом не следует в прикладном коде реализовывать собственные механизмы кеширования на клиенте предопределенных значений. Функция ПредопределенноеЗначение не ухудшает клиент-серверное взаимодействие: серверный вызов выполняется только при первом обращении к значению, а результат автоматически кешируется в кеше конфигурации на клиенте до следующего обновления версии конфигурации или версии платформы.»

    з.ы. не умаляю ваших результатов, но по своему опыту — сначала делаю как сказано на ИТС, если не катит начинаю изобретать велосипеды. А «не катит» довольно редко, до сих пор только один случай могу вспомнить.

    Reply
  42. markers

    (45) По моему субъективному опыту, кешируется на время сеанса. И это кеширование несколько дороговатое, если можно это сделать самостоятельно, один раз и при создании формы на сервере. Я ни чуть не осуждаю вас, но к сожалению должен констатировать, что 1С делая Розницу, походу полагала что сервер будет находится за стенкой с гигабитной сетью и будет всего один магазин. И там много где используются избыточные вызовы сервера и много где используется в том числе ПредопределенноеЗначение на клиенте. Даже просто запуск сеанса в рознице и то удалось сильно ускорить (не смотря на то, что там ещё и мои обработчики навешаны по мимо типовых) заменив в куче мест вызовы модулей с галочкой «вызов сервера» и даже с галочкой «повторное использование» заменив всё это тем, что получаю все эти необходимые значения в типовую глобальную переменную «ПараметрыПриложения» один раз, делая один серверный вызов и просто в местах где это вызывалось, заменил на получение значения из этой клиентской переменной. Конечно, таким способом можно ускорить только получение некой статичной информации, но я даже некоторую потенциально не статичную информацию засунул туда, только сделал кнопочку «Обновить» на всякий случай, которая требуется раз в пятилетку.

    PS: Но в любом случае, спасибо за ссылку!

    Reply
  43. markers

    Да, ещё хочется припомнить 1С один курьёзный случай в РМК (Розница 2.2), точно его не помню, по этому опишу по своему:

    &НаСервере
    Процедура ЧтоТоДеламемНаСервере()
    а = НайтиЭлемент(«а»);
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ЧтоТоДеламемНаКлиенте()
    б = НайтиЭлемент(«б»);
    КонецПроцедуры
    
    &НаСервере
    Функция НайтиЭлемент(Имя)
    Возврат Элементы[Имя]; // Этот кусок я точно помню, именно для этого и вызывался сервер
    КонецФункции

    Показать

    И вот этот «НайтиЭлемент» вызывался на клиенте при наборе и пробитии одного чека что-то около 40 раз. Мне даже те кто пользуются файловой базой, начали жаловаться на тормоза. Что уже говорить о том, когда клиент отнесен от сервера на десятки и сотни километров и работает через тонкий клиент. Но это просто у меня наболело, извините

    Reply

Leave a Comment

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