×

Битрикс D7: Запись в таблицу с множественным полем с помощью ORM

Допустим, вы прочитали инструкции тут и тут. Создали свой высоконагруженный инфоблок (по сути – почти обычную таблицу) и у вас в этом highload-блоке есть поле, в котором хранится привязка сущностей этого блока к ID элементов старых добрых инфоблоков. Поле это будет целочисленным и множественным и необязательным.

Чтобы общаться с этой таблицей, мы в каком-нибудь модуле опишем класс в папке lib. В этом классе будет метод getMap, который опишет все поля, которые мы создали в таблице.

Описание проблемы

Теперь мы попробуем создать запись в таблице вот примерно так

\ПространствоИмён\ИмяКласса::Add([
	//упустим остальные параметры
	'ИМЯ_МНОЖЕСТВЕННОГО_ПОЛЯ' => [
		123123,
		324234
	]
])

Запись может пройти все проверки (вы ведь описали Valdator для каждого поля в карте (метод getMap)?), но в интерфейсе админки битрикса, при просмотре данных в инфоблоке никаких значений во множественном поле не будет.

Вызов

ИмяКласса::getList()->fetchAll()

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

\ПространствоИмён\ИмяКласса::Add([
	//упустим остальные параметры
	'ИМЯ_МНОЖЕСТВЕННОГО_ПОЛЯ' => 3213123
])

В этом случае в админке будет пусто, но getList вернёт нам значение этого поля. В чем же подвох?

Решение проблемы

Тут всё просто — множественные поля должны сериализовываться. Странно, что в документации этого нет. Можно сильно упростить себе жизнь, описав грамотную карту таблицы. Например, если указать в описании поля параметр ‘serialized’ => true, то битрикс сам будет сериализовывать все данные перед сохранением в таблицу и при возврате. С этим параметром и в админке и в коде всё будет отображаться нормально.

НО! Возникает проблема – если ID у нас в одном экзепляре, то хотелось бы передать только его, не засовывая в массив. Но при этом, чтобы возвращался в коде всегда массив, даже если там только одно значение, чтобы не проверят каждый раз тип данных. В этом нам поможет параметр ‘save_data_modification’, который может принудительно запихнут число в массив.

Получается, что поле в методе getMap должно быть описано примерно так.

new Entity\IntegerField('ИМЯ_МНОЖЕСТВЕННОГО_ПОЛЯ', [
	'column_name' => 'UF_ИМЯ_МНОЖЕСТВЕННОГО_ПОЛЯ',
	'serialized' => true,
	//принудительно сохраняем данные в массив
	'save_data_modification' => function(){
		return [
			function($value){
				if(!is_array($value)){
					return [$value];
				}else{
					return $value;
				}
			}
		];
	},
	'validation' => function() {
		return [
			function($value){
				if(is_array($value)){
					$result = true;
					foreach($value as $item){
						if(!(is_numeric($item) and intval($item) > 0)){
							$result = false;
						}
					}
					
					if($result){
						return $result;
					}else{
						return 'Некорректный массив с ID элементов';
					}
					
				}elseif(is_numeric($value) and intval($value) > 0){
					return true;
					
				}else{
					return 'Некорректный ID элемента, ожидается целое число или
 массив целых чисел.';
				}
			}
		];
	}
]),

И тогда всё будет удобно и красиво =)

logo