PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/bitrix/modules/main/lib/userfield.php

https://gitlab.com/Rad1calDreamer/honey
PHP | 529 lines | 415 code | 60 blank | 54 comment | 15 complexity | f2ab4c8ac92e7290bc3daf29774f79c6 MD5 | raw file
  1. <?php
  2. /**
  3. * Bitrix Framework
  4. * @package bitrix
  5. * @subpackage main
  6. * @copyright 2001-2014 Bitrix
  7. */
  8. namespace Bitrix\Main;
  9. use Bitrix\Main\Entity;
  10. use Bitrix\Main\Type;
  11. /**
  12. * Class description
  13. * @package bitrix
  14. * @subpackage main
  15. */
  16. class UserFieldTable extends Entity\DataManager
  17. {
  18. // to use in uts serialized fields
  19. const MULTIPLE_DATE_FORMAT = 'Y-m-d';
  20. const MULTIPLE_DATETIME_FORMAT = 'Y-m-d H:i:s';
  21. public static function getMap()
  22. {
  23. return array(
  24. 'ID' => array(
  25. 'data_type' => 'integer',
  26. 'primary' => true,
  27. 'autocomplete' => true,
  28. ),
  29. 'ENTITY_ID' => array(
  30. 'data_type' => 'string'
  31. ),
  32. 'FIELD_NAME' => array(
  33. 'data_type' => 'string'
  34. ),
  35. 'USER_TYPE_ID' => array(
  36. 'data_type' => 'string'
  37. ),
  38. 'XML_ID' => array(
  39. 'data_type' => 'string'
  40. ),
  41. 'SORT' => array(
  42. 'data_type' => 'integer'
  43. ),
  44. 'MULTIPLE' => array(
  45. 'data_type' => 'boolean',
  46. 'values' => array('N', 'Y')
  47. ),
  48. 'MANDATORY' => array(
  49. 'data_type' => 'boolean',
  50. 'values' => array('N', 'Y')
  51. ),
  52. 'SHOW_FILTER' => array(
  53. 'data_type' => 'boolean',
  54. 'values' => array('N', 'Y')
  55. ),
  56. 'SHOW_IN_LIST' => array(
  57. 'data_type' => 'boolean',
  58. 'values' => array('N', 'Y')
  59. ),
  60. 'EDIT_IN_LIST' => array(
  61. 'data_type' => 'boolean',
  62. 'values' => array('N', 'Y')
  63. ),
  64. 'IS_SEARCHABLE' => array(
  65. 'data_type' => 'boolean',
  66. 'values' => array('N', 'Y')
  67. ),
  68. 'SETTINGS' => array(
  69. 'data_type' => 'text',
  70. 'serialized' => true
  71. )
  72. );
  73. }
  74. public static function add(array $data)
  75. {
  76. throw new NotImplementedException('Use \CUserTypeEntity API instead.');
  77. }
  78. public static function update($primary, array $data)
  79. {
  80. throw new NotImplementedException('Use \CUserTypeEntity API instead.');
  81. }
  82. public static function delete($primary)
  83. {
  84. throw new NotImplementedException('Use \CUserTypeEntity API instead.');
  85. }
  86. public static function attachFields(Entity\Base $entity, $ufId)
  87. {
  88. global $USER_FIELD_MANAGER;
  89. $utsFields = array();
  90. $utsFieldNames = array();
  91. $utmFields = array();
  92. $utmFieldNames = array();
  93. $fields = $USER_FIELD_MANAGER->getUserFields($ufId);
  94. foreach ($fields as $field)
  95. {
  96. if ($field['MULTIPLE'] === 'Y')
  97. {
  98. $utmFields[] = $field;
  99. $utmFieldNames[$field['FIELD_NAME']] = true;
  100. }
  101. else
  102. {
  103. $utsFields[] = $field;
  104. $utsFieldNames[$field['FIELD_NAME']] = true;
  105. }
  106. }
  107. if (!empty($utsFields) || !empty($utmFields))
  108. {
  109. // create uts entity & put fields into it
  110. $utsEntity = static::createUtsEntity($entity, $utsFields, $utmFields);
  111. // create reference to uts entity
  112. $utsReference = new Entity\ReferenceField('UTS_OBJECT', $utsEntity->getDataClass(), array(
  113. '=this.ID' => 'ref.VALUE_ID'
  114. ));
  115. $entity->addField($utsReference);
  116. // add UF_* aliases
  117. foreach ($fields as $userfield)
  118. {
  119. $utsFieldName = $userfield['FIELD_NAME'];
  120. /** @var Entity\ScalarField $utsField */
  121. $utsField = $utsEntity->getField($utsFieldName);
  122. $aliasField = new Entity\ExpressionField(
  123. $utsFieldName,
  124. '%s',
  125. 'UTS_OBJECT.'.$utsFieldName,
  126. array('data_type' => get_class($utsField))
  127. );
  128. if ($userfield['MULTIPLE'] == 'Y')
  129. {
  130. static::setMultipleFieldSerialization($aliasField, $userfield);
  131. }
  132. $entity->addField($aliasField);
  133. }
  134. if (!empty($utsFields))
  135. {
  136. foreach ($utsFields as $utsField)
  137. {
  138. $utsEntityField = $utsEntity->getField($utsField['FIELD_NAME']);
  139. foreach ($USER_FIELD_MANAGER->getEntityReferences($utsField, $utsEntityField) as $reference)
  140. {
  141. // rewrite reference from this.field to this.uts_object.field
  142. $referenceDesc = static::rewriteUtsReference($reference->getReference());
  143. $aliasReference = new Entity\ReferenceField(
  144. $reference->getName(),
  145. $reference->getRefEntityName(),
  146. $referenceDesc
  147. );
  148. $entity->addField($aliasReference);
  149. }
  150. }
  151. }
  152. if (!empty($utmFields))
  153. {
  154. // create utm entity & put base fields into it
  155. $utmEntity = static::createUtmEntity($entity, $utmFields);
  156. // add UF_* aliases
  157. foreach ($utmFieldNames as $utmFieldName => $true)
  158. {
  159. /** @var Entity\ScalarField $utmField */
  160. $utmField = $utmEntity->getField($utmFieldName);
  161. $aliasField = new Entity\ExpressionField(
  162. $utmFieldName.'_SINGLE',
  163. '%s',
  164. $utmEntity->getFullName().':PARENT_'.$utmFieldName.'.'.$utmField->getColumnName(),
  165. array('data_type' => get_class($utmField))
  166. );
  167. $entity->addField($aliasField);
  168. }
  169. }
  170. }
  171. }
  172. protected static function createUtsEntity(Entity\Base $srcEntity, array $utsFields, array $utmFields)
  173. {
  174. global $USER_FIELD_MANAGER;
  175. // get namespace & class
  176. /** @var Entity\DataManager $utsClassFull */
  177. $utsClassFull = static::getUtsEntityClassNameBySrcEntity($srcEntity);
  178. $utsClassPath = explode('\\', ltrim($utsClassFull, '\\'));
  179. $utsNamespace = join('\\', array_slice($utsClassPath, 0, -1));
  180. $utsClass = end($utsClassPath);
  181. // get table name
  182. $utsTable = static::getUtsEntityTableNameBySrcEntity($srcEntity);
  183. // base fields
  184. $fieldsMap = array(
  185. 'VALUE_ID' => array(
  186. 'data_type' => 'integer',
  187. 'primary' => true
  188. ),
  189. 'PARENT' => array(
  190. 'data_type' => $srcEntity->getDataClass(),
  191. 'reference' => array(
  192. '=this.VALUE_ID' => 'ref.ID'
  193. )
  194. )
  195. );
  196. // initialize entity
  197. $entity = Entity\Base::compileEntity($utsClass, $fieldsMap, array(
  198. 'namespace' => $utsNamespace, 'table_name' => $utsTable
  199. ));
  200. foreach ($utsFields as $utsField)
  201. {
  202. $field = $USER_FIELD_MANAGER->getEntityField($utsField);
  203. $entity->addField($field);
  204. foreach ($USER_FIELD_MANAGER->getEntityReferences($utsField, $field) as $reference)
  205. {
  206. $entity->addField($reference);
  207. }
  208. }
  209. foreach ($utmFields as $utmField)
  210. {
  211. // add seriazed utm cache-fields
  212. $cacheField = new Entity\TextField($utmField['FIELD_NAME']);
  213. static::setMultipleFieldSerialization($cacheField, $utmField);
  214. $entity->addField($cacheField);
  215. }
  216. return $entity;
  217. }
  218. /**
  219. * @param Entity\Field $entityField
  220. * @param Entity\Field|array $fieldAsType
  221. */
  222. public static function setMultipleFieldSerialization(Entity\Field $entityField, $fieldAsType)
  223. {
  224. global $USER_FIELD_MANAGER;
  225. if (!($fieldAsType instanceof Entity\Field))
  226. {
  227. $fieldAsType = $USER_FIELD_MANAGER->getEntityField($fieldAsType);
  228. }
  229. if ($fieldAsType instanceof Entity\DatetimeField)
  230. {
  231. $entityField->addSaveDataModifier(array(__CLASS__, 'serializeMultipleDatetime'));
  232. $entityField->addFetchDataModifier(array(__CLASS__, 'unserializeMultipleDatetime'));
  233. }
  234. elseif ($fieldAsType instanceof Entity\DateField)
  235. {
  236. $entityField->addSaveDataModifier(array(__CLASS__, 'serializeMultipleDate'));
  237. $entityField->addFetchDataModifier(array(__CLASS__, 'unserializeMultipleDate'));
  238. }
  239. else
  240. {
  241. $entityField->setSerialized();
  242. }
  243. }
  244. public static function rewriteUtsReference($referenceDesc)
  245. {
  246. $new = array();
  247. foreach ($referenceDesc as $k => $v)
  248. {
  249. if (is_array($v))
  250. {
  251. $new[$k] = static::rewriteUtsReference($v);
  252. }
  253. else
  254. {
  255. $k = str_replace('this.', 'this.UTS_OBJECT.', $k);
  256. $new[$k] = $v;
  257. }
  258. }
  259. return $new;
  260. }
  261. protected static function getUtsEntityClassNameBySrcEntity(Entity\Base $srcEntity)
  262. {
  263. return $srcEntity->getFullName().'UtsTable';
  264. }
  265. protected static function getUtsEntityTableNameBySrcEntity(Entity\Base $srcEntity)
  266. {
  267. return 'b_uts_'.strtolower($srcEntity->getUfId());
  268. }
  269. protected static function createUtmEntity(Entity\Base $srcEntity, array $utmFields)
  270. {
  271. global $USER_FIELD_MANAGER;
  272. /** @var Entity\DataManager $utmClassFull */
  273. $utmClassFull = static::getUtmEntityClassNameBySrcEntity($srcEntity);
  274. $utmClassPath = explode('\\', ltrim($utmClassFull, '\\'));
  275. $utmNamespace = join('\\', array_slice($utmClassPath, 0, -1));
  276. $utmClass = end($utmClassPath);
  277. // get table name
  278. $utmTable = static::getUtmEntityTableNameBySrcEntity($srcEntity);
  279. // coolect fields
  280. $fieldsMap = array(
  281. 'ID' => array(
  282. 'data_type' => 'integer',
  283. 'primary' => true,
  284. 'autocomplete' => true
  285. ),
  286. 'VALUE_ID' => array(
  287. 'data_type' => 'integer',
  288. 'primary' => true
  289. ),
  290. 'PARENT' => array(
  291. 'data_type' => $srcEntity->getDataClass(),
  292. 'reference' => array(
  293. '=this.VALUE_ID' => 'ref.ID'
  294. )
  295. ),
  296. 'FIELD_ID' => array(
  297. 'data_type' => 'integer'
  298. ),
  299. // base values fields
  300. 'VALUE' => array(
  301. 'data_type' => 'text'
  302. ),
  303. 'VALUE_INT' => array(
  304. 'data_type' => 'integer'
  305. ),
  306. 'VALUE_DOUBLE' => array(
  307. 'data_type' => 'float'
  308. ),
  309. 'VALUE_DATE' => array(
  310. 'data_type' => 'datetime'
  311. )
  312. );
  313. // initialize entity
  314. $entity = Entity\Base::compileEntity($utmClass, $fieldsMap, array(
  315. 'namespace' => $utmNamespace, 'table_name' => $utmTable
  316. ));
  317. // add utm fields being mapped on real column name
  318. foreach ($utmFields as $utmField)
  319. {
  320. $field = $USER_FIELD_MANAGER->getEntityField($utmField);
  321. if ($field instanceof Entity\IntegerField)
  322. {
  323. $columnName = 'VALUE_INT';
  324. }
  325. elseif ($field instanceof Entity\FloatField)
  326. {
  327. $columnName = 'VALUE_DOUBLE';
  328. }
  329. elseif ($field instanceof Entity\DateField || $field instanceof Entity\DatetimeField)
  330. {
  331. $columnName = 'VALUE_DATE';
  332. }
  333. else
  334. {
  335. $columnName = 'VALUE';
  336. }
  337. $field->setColumnName($columnName);
  338. $entity->addField($field);
  339. foreach ($USER_FIELD_MANAGER->getEntityReferences($utmField, $field) as $reference)
  340. {
  341. $entity->addField($reference);
  342. }
  343. // add back-reference
  344. $refField = new Entity\ReferenceField(
  345. 'PARENT_'.$utmField['FIELD_NAME'],
  346. $srcEntity->getDataClass(),
  347. array('=this.VALUE_ID' => 'ref.ID', '=this.FIELD_ID' => array('?i', $utmField['ID']))
  348. );
  349. $entity->addField($refField);
  350. }
  351. return $entity;
  352. }
  353. protected static function getUtmEntityClassNameBySrcEntity(Entity\Base $srcEntity)
  354. {
  355. return $srcEntity->getFullName().'UtmTable';
  356. }
  357. protected static function getUtmEntityTableNameBySrcEntity(Entity\Base $srcEntity)
  358. {
  359. return 'b_utm_'.strtolower($srcEntity->getUfId());
  360. }
  361. /**
  362. * @param Type\DateTime[] $value
  363. *
  364. * @return string
  365. */
  366. public static function serializeMultipleDatetime($value)
  367. {
  368. if (is_array($value) || $value instanceof \Traversable)
  369. {
  370. $tmpValue = array();
  371. foreach ($value as $k => $singleValue)
  372. {
  373. /** @var Type\DateTime $singleValue */
  374. $tmpValue[$k] = $singleValue->format(static::MULTIPLE_DATETIME_FORMAT);
  375. }
  376. return serialize($tmpValue);
  377. }
  378. return $value;
  379. }
  380. /**
  381. * @param string $value
  382. *
  383. * @return array
  384. */
  385. public static function unserializeMultipleDatetime($value)
  386. {
  387. if (strlen($value))
  388. {
  389. $value = unserialize($value);
  390. foreach ($value as &$singleValue)
  391. {
  392. try
  393. {
  394. //try new independent datetime format
  395. $singleValue = new Type\DateTime($singleValue, static::MULTIPLE_DATETIME_FORMAT);
  396. }
  397. catch (ObjectException $e)
  398. {
  399. //try site format
  400. $singleValue = new Type\DateTime($singleValue);
  401. }
  402. }
  403. }
  404. return $value;
  405. }
  406. /**
  407. * @param Type\Date[] $value
  408. *
  409. * @return string
  410. */
  411. public static function serializeMultipleDate($value)
  412. {
  413. if (is_array($value) || $value instanceof \Traversable)
  414. {
  415. $tmpValue = array();
  416. foreach ($value as $k => $singleValue)
  417. {
  418. /** @var Type\Date $singleValue */
  419. $tmpValue[$k] = $singleValue->format(static::MULTIPLE_DATE_FORMAT);
  420. }
  421. return serialize($tmpValue);
  422. }
  423. return $value;
  424. }
  425. /**
  426. * @param string $value
  427. *
  428. * @return array
  429. */
  430. public static function unserializeMultipleDate($value)
  431. {
  432. if (strlen($value))
  433. {
  434. $value = unserialize($value);
  435. foreach ($value as &$singleValue)
  436. {
  437. try
  438. {
  439. //try new independent datetime format
  440. $singleValue = new Type\Date($singleValue, static::MULTIPLE_DATE_FORMAT);
  441. }
  442. catch (ObjectException $e)
  443. {
  444. //try site format
  445. $singleValue = new Type\Date($singleValue);
  446. }
  447. }
  448. }
  449. return $value;
  450. }
  451. }