/modules/main/lib/orm/fields/field.php

https://gitlab.com/alexprowars/bitrix · PHP · 654 lines · 390 code · 96 blank · 168 comment · 34 complexity · 86bbe51d921ff2b81736faf18a9cc5b0 MD5 · raw file

  1. <?php
  2. /**
  3. * Bitrix Framework
  4. * @package bitrix
  5. * @subpackage main
  6. * @copyright 2001-2012 Bitrix
  7. */
  8. namespace Bitrix\Main\ORM\Fields;
  9. use Bitrix\Main\Application;
  10. use Bitrix\Main\DB\SqlExpression;
  11. use Bitrix\Main\ORM\Entity;
  12. use Bitrix\Main\ORM\EntityError;
  13. use Bitrix\Main\ORM\Data\Result;
  14. use Bitrix\Main\ORM\Fields\Validators\IValidator;
  15. use Bitrix\Main\Localization\Loc;
  16. use Bitrix\Main\SystemException;
  17. /**
  18. * Base entity field class
  19. * @package bitrix
  20. * @subpackage main
  21. */
  22. abstract class Field
  23. {
  24. /** @var string */
  25. protected $name;
  26. /** @var string */
  27. protected $dataType;
  28. /** @var array */
  29. protected $initialParameters;
  30. /** @var string */
  31. protected $title;
  32. /** @var null|callback */
  33. protected $validation = null;
  34. /** @var null|callback[]|Validators\Validator[] */
  35. protected $validators = null;
  36. /** @var array|callback[]|Validators\Validator[] */
  37. protected $additionalValidators = array();
  38. /** @var null|callback */
  39. protected $fetchDataModification = null;
  40. /** @var null|callback[] */
  41. protected $fetchDataModifiers;
  42. /** @var null|callback[] */
  43. protected $additionalFetchDataModifiers = array();
  44. /** @var null|callback */
  45. protected $saveDataModification = null;
  46. /** @var null|callback[] */
  47. protected $saveDataModifiers;
  48. /** @var null|callback[] */
  49. protected $additionalSaveDataModifiers = array();
  50. /**
  51. * @deprecated
  52. * @see ArrayField
  53. * @var bool
  54. */
  55. protected $isSerialized = false;
  56. /** @var Field */
  57. protected $parentField;
  58. /** @var Entity */
  59. protected $entity;
  60. /**
  61. * @deprecated
  62. * @var array
  63. */
  64. protected static $oldDataTypes = array(
  65. 'float' => 'Bitrix\Main\ORM\Fields\FloatField',
  66. 'string' => 'Bitrix\Main\ORM\Fields\StringField',
  67. 'text' => 'Bitrix\Main\ORM\Fields\TextField',
  68. 'datetime' => 'Bitrix\Main\ORM\Fields\DatetimeField',
  69. 'date' => 'Bitrix\Main\ORM\Fields\DateField',
  70. 'integer' => 'Bitrix\Main\ORM\Fields\IntegerField',
  71. 'enum' => 'Bitrix\Main\ORM\Fields\EnumField',
  72. 'boolean' => 'Bitrix\Main\ORM\Fields\BooleanField'
  73. );
  74. /**
  75. * @param string $name
  76. * @param array $parameters deprecated, use configure* and add* methods instead
  77. *
  78. * @throws SystemException
  79. */
  80. public function __construct($name, $parameters = array())
  81. {
  82. if ($name == '')
  83. {
  84. throw new SystemException('Field name required');
  85. }
  86. $this->name = $name;
  87. $this->dataType = null;
  88. $this->initialParameters = $parameters;
  89. if (isset($parameters['title']))
  90. {
  91. $this->title = $parameters['title'];
  92. }
  93. // validation
  94. if (isset($parameters['validation']))
  95. {
  96. $this->validation = $parameters['validation'];
  97. }
  98. // fetch data modifiers
  99. if (isset($parameters['fetch_data_modification']))
  100. {
  101. $this->fetchDataModification = $parameters['fetch_data_modification'];
  102. }
  103. // save data modifiers
  104. if (isset($parameters['save_data_modification']))
  105. {
  106. $this->saveDataModification = $parameters['save_data_modification'];
  107. }
  108. if (!empty($parameters['serialized']))
  109. {
  110. $this->setSerialized();
  111. }
  112. }
  113. /**
  114. * @param Entity $entity
  115. *
  116. * @throws SystemException
  117. */
  118. public function setEntity(Entity $entity)
  119. {
  120. if ($this->entity !== null)
  121. {
  122. throw new SystemException(sprintf('Field "%s" already has entity', $this->name));
  123. }
  124. $this->entity = $entity;
  125. }
  126. public function resetEntity()
  127. {
  128. $this->entity = null;
  129. }
  130. abstract public function getTypeMask();
  131. /**
  132. * @param $value
  133. * @param $primary
  134. * @param $row
  135. * @param Result $result
  136. *
  137. * @return Result
  138. * @throws SystemException
  139. */
  140. public function validateValue($value, $primary, $row, Result $result)
  141. {
  142. if ($value instanceof SqlExpression)
  143. {
  144. return $result;
  145. }
  146. $validators = $this->getValidators();
  147. foreach ($validators as $validator)
  148. {
  149. if ($validator instanceof IValidator)
  150. {
  151. $vResult = $validator->validate($value, $primary, $row, $this);
  152. }
  153. else
  154. {
  155. $vResult = call_user_func_array($validator, array($value, $primary, $row, $this));
  156. }
  157. if ($vResult !== true)
  158. {
  159. if ($vResult instanceof EntityError)
  160. {
  161. $result->addError($vResult);
  162. }
  163. else
  164. {
  165. $result->addError(new FieldError($this, $vResult, FieldError::INVALID_VALUE));
  166. }
  167. }
  168. }
  169. return $result;
  170. }
  171. /**
  172. * @param $value
  173. * @param $data
  174. *
  175. * @return mixed
  176. * @throws SystemException
  177. */
  178. public function modifyValueBeforeSave($value, $data)
  179. {
  180. $modifiers = $this->getSaveDataModifiers();
  181. foreach ($modifiers as $modifier)
  182. {
  183. $value = call_user_func_array($modifier, array($value, $data));
  184. }
  185. return $value;
  186. }
  187. /**
  188. * @return callback[]|Validators\Validator[]
  189. * @throws SystemException
  190. */
  191. public function getValidators()
  192. {
  193. if ($this->validators === null)
  194. {
  195. $this->validators = array();
  196. if ($this->validation !== null)
  197. {
  198. $validators = call_user_func($this->validation);
  199. if (!is_array($validators))
  200. {
  201. throw new SystemException(sprintf(
  202. 'Validation for %s field of %s entity should return array of validators',
  203. $this->name, $this->entity->getDataClass()
  204. ));
  205. }
  206. foreach ($validators as $validator)
  207. {
  208. $this->appendValidator($validator);
  209. }
  210. }
  211. foreach ($this->additionalValidators as $validator)
  212. {
  213. $this->appendValidator($validator);
  214. }
  215. }
  216. return $this->validators;
  217. }
  218. /**
  219. * @param Validators\Validator|callable $validator
  220. *
  221. * @return $this
  222. * @throws SystemException
  223. */
  224. public function addValidator($validator)
  225. {
  226. // append only when not null. and when is null - delay it
  227. if ($this->validators === null)
  228. {
  229. $this->additionalValidators[] = $validator;
  230. }
  231. else
  232. {
  233. $this->appendValidator($validator);
  234. }
  235. return $this;
  236. }
  237. /**
  238. * @param Validators\Validator|callable $validator
  239. *
  240. * @throws SystemException
  241. */
  242. protected function appendValidator($validator)
  243. {
  244. if (!($validator instanceof Validators\Validator) && !is_callable($validator))
  245. {
  246. throw new SystemException(sprintf(
  247. 'Validators of "%s" field of "%s" entity should be a Validator\Base or callback',
  248. $this->name, $this->entity->getDataClass()
  249. ));
  250. }
  251. $this->validators[] = $validator;
  252. }
  253. /**
  254. * @return array|callback[]|null
  255. * @throws SystemException
  256. */
  257. public function getFetchDataModifiers()
  258. {
  259. if ($this->fetchDataModifiers === null)
  260. {
  261. $this->fetchDataModifiers = array();
  262. if ($this->fetchDataModification !== null)
  263. {
  264. $modifiers = call_user_func($this->fetchDataModification);
  265. if (!is_array($modifiers))
  266. {
  267. throw new SystemException(sprintf(
  268. 'Fetch Data Modification for %s field of %s entity should return array of modifiers (callbacks)',
  269. $this->name, $this->entity->getDataClass()
  270. ));
  271. }
  272. foreach ($modifiers as $modifier)
  273. {
  274. $this->appendFetchDataModifier($modifier);
  275. }
  276. }
  277. foreach ($this->additionalFetchDataModifiers as $modifier)
  278. {
  279. $this->appendFetchDataModifier($modifier);
  280. }
  281. }
  282. return $this->fetchDataModifiers;
  283. }
  284. /**
  285. * @param \callable $modifier
  286. *
  287. * @return $this
  288. * @throws SystemException
  289. */
  290. public function addFetchDataModifier($modifier)
  291. {
  292. // append only when not null. and when is null - delay it
  293. if ($this->fetchDataModifiers === null)
  294. {
  295. $this->additionalFetchDataModifiers[] = $modifier;
  296. }
  297. else
  298. {
  299. $this->appendFetchDataModifier($modifier);
  300. }
  301. return $this;
  302. }
  303. /**
  304. * @param \callable $modifier
  305. *
  306. * @throws SystemException
  307. */
  308. protected function appendFetchDataModifier($modifier)
  309. {
  310. if (!is_callable($modifier))
  311. {
  312. throw new SystemException(sprintf(
  313. 'Modifier of "%s" field of "%s" entity should be a callback',
  314. $this->name, $this->entity->getDataClass()
  315. ));
  316. }
  317. $this->fetchDataModifiers[] = $modifier;
  318. }
  319. /**
  320. * @return array|callback[]|null
  321. * @throws SystemException
  322. */
  323. public function getSaveDataModifiers()
  324. {
  325. if ($this->saveDataModifiers === null)
  326. {
  327. $this->saveDataModifiers = array();
  328. if ($this->saveDataModification !== null)
  329. {
  330. $modifiers = call_user_func($this->saveDataModification);
  331. if (!is_array($modifiers))
  332. {
  333. throw new SystemException(sprintf(
  334. 'Save Data Modification for %s field of %s entity should return array of modifiers (callbacks)',
  335. $this->name, $this->entity->getDataClass()
  336. ));
  337. }
  338. foreach ($modifiers as $modifier)
  339. {
  340. $this->appendSaveDataModifier($modifier);
  341. }
  342. }
  343. foreach ($this->additionalSaveDataModifiers as $modifier)
  344. {
  345. $this->appendSaveDataModifier($modifier);
  346. }
  347. }
  348. return $this->saveDataModifiers;
  349. }
  350. /**
  351. * @param \callable $modifier
  352. *
  353. * @return $this
  354. * @throws SystemException
  355. */
  356. public function addSaveDataModifier($modifier)
  357. {
  358. // append only when not null. and when is null - delay it
  359. if ($this->saveDataModifiers === null)
  360. {
  361. $this->additionalSaveDataModifiers[] = $modifier;
  362. }
  363. else
  364. {
  365. $this->appendSaveDataModifier($modifier);
  366. }
  367. return $this;
  368. }
  369. /**
  370. * @param \callable $modifier
  371. *
  372. * @throws SystemException
  373. */
  374. protected function appendSaveDataModifier($modifier)
  375. {
  376. if (!is_callable($modifier))
  377. {
  378. throw new SystemException(sprintf(
  379. 'Save modifier of "%s" field of "%s" entity should be a callback',
  380. $this->name, $this->entity->getDataClass()
  381. ));
  382. }
  383. $this->saveDataModifiers[] = $modifier;
  384. }
  385. /**
  386. * @return boolean
  387. */
  388. public function isSerialized()
  389. {
  390. return !empty($this->isSerialized);
  391. }
  392. /**
  393. * @throws SystemException
  394. */
  395. public function setSerialized()
  396. {
  397. if (!$this->isSerialized)
  398. {
  399. $this->isSerialized = true;
  400. // add save- and fetch modifiers
  401. $this->addSaveDataModifier(array($this, 'serialize'));
  402. $this->addFetchDataModifier(array($this, 'unserialize'));
  403. }
  404. }
  405. /**
  406. * @deprecated
  407. * @return $this
  408. * @throws SystemException
  409. */
  410. public function configureSerialized()
  411. {
  412. $this->setSerialized();
  413. return $this;
  414. }
  415. public function getName()
  416. {
  417. return $this->name;
  418. }
  419. public function setName($name)
  420. {
  421. $this->name = $name;
  422. }
  423. /**
  424. * Lang phrase
  425. *
  426. * @param $title
  427. *
  428. * @return $this
  429. */
  430. public function configureTitle($title)
  431. {
  432. $this->title = $title;
  433. return $this;
  434. }
  435. public function getTitle()
  436. {
  437. if($this->title !== null)
  438. {
  439. return $this->title;
  440. }
  441. if(($title = Loc::getMessage($this->getLangCode())) <> '')
  442. {
  443. return $this->title = $title;
  444. }
  445. return $this->title = $this->name;
  446. }
  447. public function setParameter($name, $value)
  448. {
  449. $this->initialParameters[$name] = $value;
  450. return $this;
  451. }
  452. public function getParameter($name)
  453. {
  454. return $this->initialParameters[$name];
  455. }
  456. public function hasParameter($name)
  457. {
  458. return array_key_exists($name, $this->initialParameters);
  459. }
  460. /**
  461. * @param Field $parentField
  462. */
  463. public function setParentField(Field $parentField)
  464. {
  465. $this->parentField = $parentField;
  466. }
  467. /**
  468. * @return Field
  469. */
  470. public function getParentField()
  471. {
  472. return $this->parentField;
  473. }
  474. /**
  475. * @deprecated
  476. * @return null|string
  477. */
  478. public function getDataType()
  479. {
  480. if (empty($this->dataType))
  481. {
  482. return static::getOldDataTypeByField($this);
  483. }
  484. return $this->dataType;
  485. }
  486. /**
  487. * @deprecated
  488. * @param $class
  489. *
  490. * @return bool
  491. */
  492. public static function getOldDataTypeByClass($class)
  493. {
  494. $map = array_flip(static::$oldDataTypes);
  495. return isset($map[$class]) ? $map[$class] : 'string';
  496. }
  497. /**
  498. * @deprecated
  499. * @param Field $field
  500. *
  501. * @return bool
  502. */
  503. public static function getOldDataTypeByField(Field $field)
  504. {
  505. return static::getOldDataTypeByClass(get_class($field));
  506. }
  507. /**
  508. * @deprecated
  509. * @param $dateType
  510. *
  511. * @return bool
  512. */
  513. public static function getClassByOldDataType($dateType)
  514. {
  515. return isset(static::$oldDataTypes[$dateType]) ? '\\'.static::$oldDataTypes[$dateType] : false;
  516. }
  517. public function getEntity()
  518. {
  519. return $this->entity;
  520. }
  521. public function getLangCode()
  522. {
  523. $entity = $this->getEntity();
  524. if($entity !== null)
  525. {
  526. return $entity->getLangCode().'_'.$this->getName().'_FIELD';
  527. }
  528. return null;
  529. }
  530. /**
  531. * @return \Bitrix\Main\DB\Connection
  532. * @throws SystemException
  533. */
  534. public function getConnection()
  535. {
  536. if ($this->entity)
  537. {
  538. return $this->entity->getConnection();
  539. }
  540. return Application::getConnection();
  541. }
  542. public function serialize($value)
  543. {
  544. return serialize($value);
  545. }
  546. public function unserialize($value)
  547. {
  548. return unserialize($value);
  549. }
  550. /**
  551. * Called after being initialized by Entity
  552. * @return null
  553. */
  554. public function postInitialize()
  555. {
  556. return null;
  557. }
  558. }