38 private const ENTITY_ID_PREFIX =
'HLBLOCK_';
40 private const ENTITY_ID_MASK =
'/^HLBLOCK_(\d+)$/';
47 return 'b_hlblock_entity';
52 return HighloadBlock::class;
57 IncludeModuleLangFile(__FILE__);
64 'data_type' =>
'integer',
66 'autocomplete' =>
true
69 'data_type' =>
'string',
71 'validation' => array(__CLASS__,
'validateName')
73 'TABLE_NAME' => array(
74 'data_type' =>
'string',
76 'validation' => array(__CLASS__,
'validateTableName')
78 'FIELDS_COUNT' => array(
79 'data_type' =>
'integer',
80 'expression' => array(
81 '(SELECT COUNT(ID) FROM b_user_field WHERE b_user_field.ENTITY_ID = '.
82 $sqlHelper->getConcatFunction(
"'".self::ENTITY_ID_PREFIX.
"'", $sqlHelper->castToChar(
'%s')).
')',
86 'LANG' =>
new Entity\ReferenceField(
88 'Bitrix\Highloadblock\HighloadBlockLangTable',
89 array(
'=this.ID' =>
'ref.ID',
'ref.LID' =>
new Main\DB\
SqlExpression(
'?', LANGUAGE_ID))
102 public static function add(array $data)
104 $result = parent::add($data);
106 if (!$result->isSuccess(
true))
113 $dbtype = $connection->getType();
114 $sqlHelper = $connection->getSqlHelper();
116 if ($dbtype ==
'mysql')
119 CREATE TABLE '.$sqlHelper->quote($data[
'TABLE_NAME']).
' (ID int(11) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (ID))
122 elseif ($dbtype ==
'pgsql')
125 CREATE TABLE '.$sqlHelper->quote($data[
'TABLE_NAME']).
' (ID serial NOT NULL, PRIMARY KEY (ID))
128 elseif ($dbtype ==
'mssql')
131 CREATE TABLE '.$sqlHelper->quote($data[
'TABLE_NAME']).
' (ID int NOT NULL IDENTITY (1, 1),
132 CONSTRAINT '.$data[
'TABLE_NAME'].
'_ibpk_1 PRIMARY KEY (ID))
135 elseif ($dbtype ==
'oracle')
138 CREATE TABLE '.$sqlHelper->quote($data[
'TABLE_NAME']).
' (ID number(11) NOT NULL, PRIMARY KEY (ID))
142 CREATE SEQUENCE sq_'.$data[
'TABLE_NAME'].
'
146 CREATE OR REPLACE TRIGGER '.$data[
'TABLE_NAME'].
'_insert
148 ON '.$sqlHelper->quote($data[
'TABLE_NAME']).
'
151 IF :NEW.ID IS NULL THEN
152 SELECT sq_'.$data[
'TABLE_NAME'].
'.NEXTVAL INTO :NEW.ID FROM dual;
171 public static function update($primary, array $data)
173 global $USER_FIELD_MANAGER;
176 $oldData = static::getByPrimary($primary)->fetch();
179 $result = parent::update($primary, $data);
181 if (!$result->isSuccess(
true))
187 if (isset($data[
'TABLE_NAME']) && $data[
'TABLE_NAME'] !== $oldData[
'TABLE_NAME'])
190 $sqlHelper = $connection->getSqlHelper();
191 $connection->renameTable($oldData[
'TABLE_NAME'], $data[
'TABLE_NAME']);
196 $connection->query(sprintf(
197 "EXEC sp_rename %s, %s, 'OBJECT'",
198 $sqlHelper->quote($oldData[
'TABLE_NAME'].
'_ibpk_1'),
199 $sqlHelper->quote($data[
'TABLE_NAME'].
'_ibpk_1')
205 foreach ($USER_FIELD_MANAGER->getUserFields(static::compileEntityId($oldData[
'ID'])) as $field)
207 if ($field[
'MULTIPLE'] ==
'Y')
209 $oldUtmTableName = static::getMultipleValueTableName($oldData, $field);
210 $newUtmTableName = static::getMultipleValueTableName($data, $field);
212 $connection->renameTable($oldUtmTableName, $newUtmTableName);
225 public static function delete($primary)
227 global $USER_FIELD_MANAGER;
230 $hlblock = static::getByPrimary($primary)->fetch();
233 $result = parent::delete($primary);
235 if (!$result->isSuccess(
true))
241 $file_fields = array();
243 $fields = $USER_FIELD_MANAGER->getUserFields(static::compileEntityId($hlblock[
'ID']));
245 foreach ($fields as $name => $field)
247 if ($field[
'USER_TYPE'][
'BASE_TYPE'] ===
'file')
249 $file_fields[] = $name;
254 if (!empty($file_fields))
256 $oldEntity = static::compileEntity($hlblock);
258 $query =
new Entity\Query($oldEntity);
261 $query->setSelect($file_fields);
264 $filter = array(
'LOGIC' =>
'OR');
266 foreach ($file_fields as $file_field)
268 $filter[
'!'.$file_field] =
false;
271 $query->setFilter($filter);
274 $iterator = $query->exec();
276 while ($row = $iterator->fetch())
278 foreach ($file_fields as $file_field)
280 if (!empty($row[$file_field]))
282 if (is_array($row[$file_field]))
284 foreach ($row[$file_field] as $value)
286 \CFile::delete($value);
291 \CFile::delete($row[$file_field]);
296 unset($row, $iterator);
301 foreach ($fields as $field)
304 if ($field[
'USER_TYPE'][
'BASE_TYPE'] ===
'enum')
306 $enumField = new \CUserFieldEnum;
307 $enumField->DeleteFieldEnum($field[
'ID']);
310 $connection->query(
"DELETE FROM b_user_field_lang WHERE USER_FIELD_ID = ".$field[
'ID']);
311 $connection->query(
"DELETE FROM b_user_field WHERE ID = ".$field[
'ID']);
314 if ($field[
'MULTIPLE'] ==
'Y')
316 $utmTableName = static::getMultipleValueTableName($hlblock, $field);
317 $connection->dropTable($utmTableName);
323 if(CACHED_b_user_field !==
false)
325 $managedCache->cleanDir(
"b_user_field");
329 $res = HighloadBlockLangTable::getList(array(
330 'filter' => array(
'ID' => $primary)
332 while ($row = $res->fetch())
334 HighloadBlockLangTable::delete([
336 'LID' => $row[
'LID'],
341 $res = HighloadBlockRightsTable::getList(array(
342 'filter' => array(
'HL_ID' => $primary)
344 while ($row = $res->fetch())
346 HighloadBlockRightsTable::delete($row[
'ID']);
350 $connection->dropTable($hlblock[
'TABLE_NAME']);
361 if (!is_array($hlblock))
363 if (is_int($hlblock) || is_numeric(mb_substr($hlblock, 0, 1)))
366 $hlblock = HighloadBlockTable::getById($hlblock)->fetch();
368 elseif (is_string($hlblock) && $hlblock !==
'')
371 $hlblock = HighloadBlockTable::query()->addSelect(
'*')->where(
'NAME', $hlblock)->exec()->fetch();
381 if (!isset($hlblock[
'ID']))
383 if (!isset($hlblock[
'NAME']) || !preg_match(
'/^[a-z0-9_]+$/i', $hlblock[
'NAME']))
385 if (empty($hlblock[
'TABLE_NAME']))
397 public static function compileEntity($hlblock)
399 global $USER_FIELD_MANAGER;
401 $rawBlock = $hlblock;
402 $hlblock = static::resolveHighloadblock($hlblock);
406 'Invalid highloadblock description `%s`.', mydump($rawBlock)
412 $fieldsMap = array();
415 $fieldsMap[
'ID'] = array(
416 'data_type' =>
'integer',
418 'autocomplete' =>
true
422 $entity_name = $hlblock[
'NAME'];
423 $entity_data_class = $hlblock[
'NAME'].
'Table';
425 if (class_exists($entity_data_class))
428 Entity\Base::destroy($entity_data_class);
432 $entity_table_name = $hlblock[
'TABLE_NAME'];
436 class '.$entity_data_class.
' extends '.__NAMESPACE__.
'\DataManager
438 public static function getTableName()
440 return '.var_export($entity_table_name,
true).
';
443 public static function getMap()
445 return '.var_export($fieldsMap,
true).
';
448 public static function getHighloadBlock()
450 return '.var_export($hlblock,
true).
';
460 $entity = $entity_data_class::getEntity();
463 $uFields = $USER_FIELD_MANAGER->getUserFields(static::compileEntityId($hlblock[
'ID']));
465 foreach ($uFields as $uField)
467 if ($uField[
'MULTIPLE'] ==
'N')
471 'required' => $uField[
'MANDATORY'] ==
'Y'
473 $field = $USER_FIELD_MANAGER->getEntityField($uField, $uField[
'FIELD_NAME'], $params);
474 $entity->addField($field);
475 foreach ($USER_FIELD_MANAGER->getEntityReferences($uField, $field) as $reference)
477 $entity->addField($reference);
483 static::compileUtmEntity($entity, $uField);
487 return Entity\Base::getInstance($entity_name);
496 return self::ENTITY_ID_PREFIX.$id;
501 if (preg_match(self::ENTITY_ID_MASK, $field[
'ENTITY_ID'], $matches))
503 if (mb_substr($field[
'FIELD_NAME'], -4) ==
'_REF')
511 $APPLICATION->ThrowException(
512 Main\Localization\
Loc::getMessage(
'HIGHLOADBLOCK_HIGHLOAD_BLOCK_ENTITY_FIELD_NAME_REF_RESERVED')
519 return array(
'PROVIDE_STORAGE' =>
false);
528 global $APPLICATION, $USER_FIELD_MANAGER;
530 if (preg_match(self::ENTITY_ID_MASK, $field[
'ENTITY_ID'], $matches))
532 $field[
'USER_TYPE'] = $USER_FIELD_MANAGER->getUserType($field[
'USER_TYPE_ID']);
535 $hlblock_id = $matches[1];
536 $hlblock = HighloadBlockTable::getById($hlblock_id)->fetch();
540 $APPLICATION->throwException(sprintf(
541 'Entity "'.static::compileEntityId(
'%s').
'" wasn\'t found.', $hlblock_id
548 $sql_column_type = $USER_FIELD_MANAGER->getUtsDBColumnType($field);
552 $sqlHelper = $connection->getSqlHelper();
554 $connection->query(sprintf(
555 'ALTER TABLE %s ADD %s %s',
556 $sqlHelper->quote($hlblock[
'TABLE_NAME']), $sqlHelper->quote($field[
'FIELD_NAME']), $sql_column_type
559 if ($field[
'MULTIPLE'] ==
'Y')
562 $hlentity = static::compileEntity($hlblock);
565 $utmEntity->createDbTable();
568 $connection->query(sprintf(
569 'CREATE INDEX %s ON %s (%s)',
570 $sqlHelper->quote(
'IX_UTM_HL'.$hlblock[
'ID'].
'_'.$field[
'ID'].
'_ID'),
571 $sqlHelper->quote($utmEntity->getDBTableName()),
572 $sqlHelper->quote(
'ID')
575 $connection->query(sprintf(
576 'CREATE INDEX %s ON %s (%s)',
577 $sqlHelper->quote(
'IX_UTM_HL'.$hlblock[
'ID'].
'_'.$field[
'ID'].
'_VALUE'),
578 $sqlHelper->quote($utmEntity->getDBTableName()),
579 $sqlHelper->quote(
'VALUE')
583 return array(
'PROVIDE_STORAGE' =>
false);
589 public static function OnBeforeUserTypeDelete($field)
591 global $USER_FIELD_MANAGER;
593 if (preg_match(self::ENTITY_ID_MASK, $field[
'ENTITY_ID'], $matches))
596 $hlblock_id = $matches[1];
597 $hlblock = HighloadBlockTable::getById($hlblock_id)->fetch();
602 return array(
'PROVIDE_STORAGE' =>
false);
606 $fieldType = $USER_FIELD_MANAGER->getUserType($field[
"USER_TYPE_ID"]);
608 if ($fieldType[
'BASE_TYPE'] ==
'file')
611 $entity = static::compileEntity($hlblock);
614 $dataClass = $entity->getDataClass();
616 $rows = $dataClass::getList(array(
'select' => array($field[
'FIELD_NAME'])));
618 while ($oldData = $rows->fetch())
620 if (empty($oldData[$field[
'FIELD_NAME']]))
625 if(is_array($oldData[$field[
'FIELD_NAME']]))
627 foreach($oldData[$field[
'FIELD_NAME']] as $value)
629 \CFile::delete($value);
634 \CFile::delete($oldData[$field[
'FIELD_NAME']]);
641 $connection->dropColumn($hlblock[
'TABLE_NAME'], $field[
'FIELD_NAME']);
644 if ($field[
'MULTIPLE'] ==
'Y')
646 $utmTableName = static::getMultipleValueTableName($hlblock, $field);
647 $connection->dropTable($utmTableName);
650 return array(
'PROVIDE_STORAGE' =>
false);
656 protected static function compileUtmEntity(Entity\Base $hlentity, $userfield)
658 global $USER_FIELD_MANAGER;
662 $hlDataClass = $hlentity->getDataClass();
663 $hlblock = $hlDataClass::getHighloadBlock();
665 $utmClassName = static::getUtmEntityClassName($hlentity, $userfield);
666 $utmTableName = static::getMultipleValueTableName($hlblock, $userfield);
668 if (class_exists($utmClassName.
'Table'))
671 Entity\Base::destroy($utmClassName.
'Table');
672 $utmEntity = Entity\Base::getInstance($utmClassName);
677 $utmEntity = Entity\Base::compileEntity($utmClassName, array(), array(
678 'table_name' => $utmTableName,
679 'namespace' => $hlentity->getNamespace()
684 $utmValueField = $USER_FIELD_MANAGER->getEntityField($userfield,
'VALUE');
686 $utmEntityFields = array(
687 new Entity\IntegerField(
'ID'),
692 $references = $USER_FIELD_MANAGER->getEntityReferences($userfield, $utmValueField);
694 foreach ($references as $reference)
696 $utmEntityFields[] = $reference;
699 foreach ($utmEntityFields as $field)
701 $utmEntity->addField($field);
705 $referenceField =
new Entity\ReferenceField(
708 array(
'=this.ID' =>
'ref.ID')
711 $utmEntity->addField($referenceField);
714 $aliasField =
new Entity\ExpressionField(
715 $userfield[
'FIELD_NAME'].
'_SINGLE',
717 $utmEntity->getFullName().
':'.
'OBJECT.VALUE',
719 'data_type' => get_class($utmEntity->getField(
'VALUE')),
720 'required' => $userfield[
'MANDATORY'] ==
'Y'
724 $hlentity->addField($aliasField);
734 $cacheField =
new Main\ORM\Fields\ArrayField($userfield[
'FIELD_NAME'], array(
735 'required' => $userfield[
'MANDATORY'] ==
'Y'
738 Main\UserFieldTable::setMultipleFieldSerialization($cacheField, $userfield);
740 $hlentity->addField($cacheField);
747 return $hlentity->getName().
'Utm'.Main\Text\StringHelper::snake2camel($userfield[
'FIELD_NAME']);
752 return $hlblock[
'TABLE_NAME'].
'_'.mb_strtolower($userfield[
'FIELD_NAME']);
758 new Entity\Validator\Unique,
759 new Entity\Validator\Length(
762 array(
'MAX' => GetMessage(
'HIGHLOADBLOCK_HIGHLOAD_BLOCK_ENTITY_NAME_FIELD_LENGTH_INVALID'))
764 new Entity\Validator\RegExp(
765 '/^[A-Z][A-Za-z0-9]*$/',
766 GetMessage(
'HIGHLOADBLOCK_HIGHLOAD_BLOCK_ENTITY_NAME_FIELD_REGEXP_INVALID')
768 new Entity\Validator\RegExp(
770 GetMessage(
'HIGHLOADBLOCK_HIGHLOAD_BLOCK_ENTITY_NAME_FIELD_TABLE_POSTFIX_INVALID')
778 new Entity\Validator\Unique,
779 new Entity\Validator\Length(
782 array(
'MAX' => GetMessage(
'HIGHLOADBLOCK_HIGHLOAD_BLOCK_ENTITY_TABLE_NAME_FIELD_LENGTH_INVALID'))
784 new Entity\Validator\RegExp(
786 GetMessage(
'HIGHLOADBLOCK_HIGHLOAD_BLOCK_ENTITY_TABLE_NAME_FIELD_REGEXP_INVALID')
788 array(__CLASS__,
'validateTableExisting')
804 $oldData = static::getByPrimary($primary)->fetch();
806 if ($value != $oldData[
'TABLE_NAME'])
813 if (!empty($checkName))
817 return GetMessage(
'HIGHLOADBLOCK_HIGHLOAD_BLOCK_ENTITY_TABLE_NAME_ALREADY_EXISTS',
818 array(
'#TABLE_NAME#' => $value)
static getMessage($code, $replace=null, $language=null)