PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/main/lib/userconsent/agreement.php

https://gitlab.com/alexprowars/bitrix
PHP | 585 lines | 351 code | 83 blank | 151 comment | 33 complexity | 00dccfa68a550c9d3861537aaa7af8dc MD5 | raw file
  1. <?php
  2. /**
  3. * Bitrix Framework
  4. * @package bitrix
  5. * @subpackage main
  6. * @copyright 2001-2016 Bitrix
  7. */
  8. namespace Bitrix\Main\UserConsent;
  9. use Bitrix\Main\Localization\Loc;
  10. use Bitrix\Main\UserConsent\Internals\FieldTable;
  11. use Bitrix\Main\Error;
  12. use Bitrix\Main\ErrorCollection;
  13. use Bitrix\Main\Type\DateTime;
  14. use Bitrix\Main\ORM;
  15. use Bitrix\Main\Web\Uri;
  16. Loc::loadLanguageFile(__FILE__);
  17. /**
  18. * Class Agreement
  19. * @package Bitrix\Main\UserConsent
  20. */
  21. class Agreement
  22. {
  23. const ACTIVE = 'Y';
  24. const NOT_ACTIVE = 'N';
  25. const TYPE_STANDARD = 'S';
  26. const TYPE_CUSTOM = 'C';
  27. /** @var integer|null $id Agreement ID. */
  28. protected $id = null;
  29. /** @var ErrorCollection $errors */
  30. protected $errors;
  31. /** @var array $data Agreement data. */
  32. protected $data = array(
  33. 'ACTIVE' => self::ACTIVE,
  34. 'TYPE' => self::TYPE_CUSTOM,
  35. );
  36. /** @var array $replace Replace data. */
  37. protected $replace = array();
  38. /** @var Intl $intl Intl. */
  39. protected $intl;
  40. /** @var DataProvider|null $dataProvider Data provider. */
  41. protected $dataProvider;
  42. private $isAgreementTextHtml;
  43. /**
  44. * Get active agreement list.
  45. *
  46. * @return array
  47. */
  48. public static function getActiveList()
  49. {
  50. $result = array();
  51. $list = Internals\AgreementTable::getList(array(
  52. 'select' => array('ID', 'NAME'),
  53. 'filter' => array('=ACTIVE' => 'Y'),
  54. 'order' => array('ID' => 'DESC')
  55. ));
  56. foreach ($list as $item)
  57. {
  58. $result[$item['ID']] = $item['NAME'];
  59. }
  60. return $result;
  61. }
  62. /**
  63. * Get types.
  64. *
  65. * @return array
  66. */
  67. public static function getTypeNames()
  68. {
  69. return array(
  70. self::TYPE_CUSTOM => Loc::getMessage('MAIN_USER_CONSENT_AGREEMENT_TYPE_N'),
  71. self::TYPE_STANDARD => Loc::getMessage('MAIN_USER_CONSENT_AGREEMENT_TYPE_S'),
  72. );
  73. }
  74. /**
  75. * Construct.
  76. *
  77. * @param integer $id Agreement ID.
  78. * @param array $replace Replace data.
  79. */
  80. public function __construct($id, array $replace = array())
  81. {
  82. $this->errors = new ErrorCollection();
  83. $this->intl = new Intl();
  84. $this->load($id);
  85. $this->setReplace($replace);
  86. $this->isAgreementTextHtml = ($this->data['IS_AGREEMENT_TEXT_HTML'] == 'Y');
  87. }
  88. /**
  89. * Return true if is used.
  90. *
  91. * @param integer $id Agreement ID.
  92. * @return string
  93. */
  94. public function load($id)
  95. {
  96. $this->id = null;
  97. if (!$id)
  98. {
  99. $this->errors->setError(new Error('Parameter `Agreement ID` required.'));
  100. return false;
  101. }
  102. $data = Internals\AgreementTable::getRowById($id);
  103. if (!$data)
  104. {
  105. $this->errors->setError(new Error("Agreement with id `$id` not found."));
  106. return false;
  107. }
  108. $this->data = $data;
  109. $this->id = $id;
  110. $this->intl->load($this->data['LANGUAGE_ID']);
  111. return true;
  112. }
  113. /**
  114. * Set replace.
  115. *
  116. * @param array $replace Replace data.
  117. * @return $this
  118. */
  119. public function setReplace(array $replace)
  120. {
  121. $this->replace = $replace;
  122. return $this;
  123. }
  124. /**
  125. * Get errors.
  126. *
  127. * @return Error[]
  128. */
  129. public function getErrors()
  130. {
  131. return $this->errors->toArray();
  132. }
  133. /**
  134. * Has errors.
  135. *
  136. * @return bool
  137. */
  138. public function hasErrors()
  139. {
  140. return !$this->errors->isEmpty();
  141. }
  142. /**
  143. * Get agreement ID.
  144. *
  145. * @return int
  146. */
  147. public function getId()
  148. {
  149. return $this->id;
  150. }
  151. /**
  152. * Get agreement data.
  153. *
  154. * @return array
  155. */
  156. public function getData()
  157. {
  158. return $this->data;
  159. }
  160. /**
  161. * Set agreement data.
  162. *
  163. * @param array $data Data.
  164. * @return void
  165. */
  166. public function setData(array $data)
  167. {
  168. unset($data['ID']);
  169. $this->data = $data;
  170. $this->isAgreementTextHtml = ($this->data['IS_AGREEMENT_TEXT_HTML'] == 'Y');
  171. }
  172. /**
  173. * Merge agreement data.
  174. *
  175. * @param array $data Data.
  176. * @return void
  177. */
  178. public function mergeData(array $data)
  179. {
  180. $this->setData($data + $this->data);
  181. }
  182. /**
  183. * Save agreement data.
  184. *
  185. * @return void
  186. */
  187. public function save()
  188. {
  189. $this->errors->clear();
  190. $data = $this->data;
  191. $fields = $data['FIELDS'];
  192. unset($data['FIELDS']);
  193. if(!$this->check())
  194. {
  195. return;
  196. }
  197. if ($this->isAgreementTextHtml)
  198. {
  199. (new \CBXSanitizer)->sanitizeHtml($data['AGREEMENT_TEXT']);
  200. }
  201. if($this->id)
  202. {
  203. $result = Internals\AgreementTable::update($this->id, $data);
  204. }
  205. else
  206. {
  207. $data['DATE_INSERT'] = new DateTime();
  208. $result = Internals\AgreementTable::add($data);
  209. $this->id = $result->getId();
  210. }
  211. if(!$result->isSuccess())
  212. {
  213. return;
  214. }
  215. Internals\FieldTable::setConsentFields($this->id, $fields);
  216. }
  217. /**
  218. * Check.
  219. *
  220. * @return bool
  221. */
  222. protected function check()
  223. {
  224. $data = $this->data;
  225. $data['DATE_INSERT'] = new DateTime();
  226. //$fields = $data['FIELDS'];
  227. unset($data['FIELDS']);
  228. $result = new ORM\Data\Result;
  229. Internals\AgreementTable::checkFields($result, $this->id, $data);
  230. if (!$result->isSuccess())
  231. {
  232. $this->errors->add($result->getErrors());
  233. }
  234. return $result->isSuccess();
  235. }
  236. /**
  237. * Return true if is exist.
  238. *
  239. * @return bool
  240. */
  241. public function isExist()
  242. {
  243. return $this->id > 0;
  244. }
  245. /**
  246. * Return true if is active.
  247. *
  248. * @return string
  249. */
  250. public function isActive()
  251. {
  252. return ($this->data['ACTIVE'] == self::ACTIVE);
  253. }
  254. public function isAgreementTextHtml(): bool
  255. {
  256. return $this->isAgreementTextHtml;
  257. }
  258. /**
  259. * Return true if is custom type.
  260. *
  261. * @return string
  262. */
  263. protected function isCustomType()
  264. {
  265. return ($this->data['TYPE'] != self::TYPE_STANDARD);
  266. }
  267. /**
  268. * Get title.
  269. *
  270. * @return string
  271. */
  272. public function getTitle()
  273. {
  274. return trim($this->getTitleFromText($this->getText()));
  275. }
  276. protected static function getTitleFromText($text)
  277. {
  278. $text = trim($text);
  279. $maxLength = 50;
  280. $pos = min(
  281. mb_strpos($text, "\n")?: 50,
  282. mb_strpos($text, "<br>")?: 50,
  283. mb_strpos($text, ".")?: 50,
  284. $maxLength
  285. );
  286. return mb_substr($text, 0, $pos);
  287. }
  288. /**
  289. * Get text.
  290. *
  291. * @param bool $cutTitle Cut title.
  292. * @return string
  293. */
  294. public function getText($cutTitle = false)
  295. {
  296. $text = $this->getContent($cutTitle);
  297. return ($this->isAgreementTextHtml ? strip_tags($text) : $text);
  298. }
  299. /**
  300. * Get html.
  301. * @return string
  302. */
  303. public function getHtml()
  304. {
  305. $text = $this->getContent();
  306. $text = ($this->isAgreementTextHtml ? $text : nl2br($text));
  307. $sanitizer = new \CBXSanitizer;
  308. $sanitizer->setLevel(\CBXSanitizer::SECURE_LEVEL_MIDDLE);
  309. $sanitizer->allowAttributes([
  310. 'target' => [
  311. 'tag' => function ($tag)
  312. {
  313. return $tag === 'a';
  314. },
  315. 'content' => function ($tag)
  316. {
  317. return true;
  318. },
  319. ]
  320. ]);
  321. return $sanitizer->sanitizeHtml($text);
  322. }
  323. private function getContent($cutTitle = false)
  324. {
  325. if ($this->isCustomType())
  326. {
  327. return $this->data['AGREEMENT_TEXT'];
  328. }
  329. $text = $this->intl->getText();
  330. $replaceData = array();
  331. $replaceData = $replaceData + $this->replace;
  332. $replaceData = $replaceData + $this->getDataProviderValues();
  333. $replaceData = $replaceData + $this->getReplaceFieldValues();
  334. $text = Text::replace($text, $replaceData, true);
  335. $text = trim($text);
  336. if ($cutTitle)
  337. {
  338. $title = self::getTitleFromText($text);
  339. if (mb_strlen($title) !== 50 && $title === mb_substr($text, 0, mb_strlen($title)))
  340. {
  341. $text = trim(mb_substr($text, mb_strlen($title)));
  342. }
  343. }
  344. return $text;
  345. }
  346. /**
  347. * Get label text.
  348. *
  349. * @return string
  350. */
  351. public function getLabelText()
  352. {
  353. return str_replace('%', '', $this->getLabel());
  354. }
  355. /**
  356. * Get url.
  357. *
  358. * @return string
  359. */
  360. public function getUrl()
  361. {
  362. return ($this->data['USE_URL'] === 'Y' && $this->data['URL'])
  363. ? (new Uri($this->data['URL']))->getLocator()
  364. : null;
  365. }
  366. /**
  367. * Get label with synbols '%' for link in label text.
  368. *
  369. * @return string
  370. */
  371. public function getLabel()
  372. {
  373. $text = $this->isCustomType() ? $this->data['LABEL_TEXT'] : $this->intl->getLabelText();
  374. $text = Text::replace($text, $this->replace);
  375. if ($this->data['USE_URL'] !== 'Y' || !$this->data['URL'])
  376. {
  377. return str_replace('%', '', $text);
  378. }
  379. $text = trim(trim($text), "%");
  380. $text = explode('%', $text);
  381. $text = array_filter($text);
  382. /** @var array $text */
  383. switch (count($text))
  384. {
  385. case 0:
  386. case 1:
  387. $text = array_merge([''], $text, ['']);
  388. break;
  389. case 2:
  390. $text[] = '';
  391. break;
  392. case 3:
  393. break;
  394. default:
  395. $text = array_merge(
  396. array_slice($text, 0, 2),
  397. [implode('', array_slice($text, 2))]
  398. );
  399. break;
  400. }
  401. return implode('%', $text);
  402. }
  403. /**
  404. * Get data provider fields.
  405. *
  406. * @return array
  407. */
  408. protected function getDataProviderValues()
  409. {
  410. if (!$this->dataProvider)
  411. {
  412. $providerCode = isset($this->data['DATA_PROVIDER']) ? $this->data['DATA_PROVIDER'] : null;
  413. $this->dataProvider = DataProvider::getByCode($providerCode);
  414. }
  415. if ($this->dataProvider)
  416. {
  417. return $this->dataProvider->getData();
  418. }
  419. return array();
  420. }
  421. /**
  422. * Return fields.
  423. *
  424. * @return array
  425. */
  426. public function getFields()
  427. {
  428. $result = array();
  429. $fields = $this->intl->getFields();
  430. $fieldValues = FieldTable::getConsentFields($this->id);
  431. foreach ($fields as $field)
  432. {
  433. $fieldCode = $field['CODE'];
  434. $field['VALUE'] = isset($fieldValues[$fieldCode]) ? $fieldValues[$fieldCode] : '';
  435. $result[$fieldCode] = $field;
  436. }
  437. return $result;
  438. }
  439. /**
  440. * Return field values.
  441. *
  442. * @return array
  443. */
  444. public function getFieldValues()
  445. {
  446. $result = array();
  447. $fields = $this->intl->getFields();
  448. $fieldValues = FieldTable::getConsentFields($this->id);
  449. foreach ($fields as $field)
  450. {
  451. $fieldCode = $field['CODE'];
  452. $result[$fieldCode] = isset($fieldValues[$fieldCode]) ? $fieldValues[$fieldCode] : '';
  453. }
  454. return $result;
  455. }
  456. protected function getReplaceFieldValues()
  457. {
  458. $result = $this->getFieldValues();
  459. $fields = $this->intl->getFields();
  460. // set default values to result
  461. foreach ($fields as $field)
  462. {
  463. if (!isset($field['DEFAULT_VALUE']) || !$field['DEFAULT_VALUE'])
  464. {
  465. continue;
  466. }
  467. if (isset($result[$field['CODE']]) && $result[$field['CODE']])
  468. {
  469. continue;
  470. }
  471. $result[$field['CODE']] = $field['DEFAULT_VALUE'];
  472. }
  473. // set values to result
  474. foreach ($fields as $field)
  475. {
  476. if ($field['TYPE'] != 'enum' || empty($field['TEXT']))
  477. {
  478. continue;
  479. }
  480. $fieldCode = $field['CODE'];
  481. $valueAsText = null;
  482. foreach ($field['ITEMS'] as $item)
  483. {
  484. // detect text item
  485. if (isset($item['IS_TEXT']) && $item['IS_TEXT'])
  486. {
  487. continue;
  488. }
  489. if ($result[$fieldCode] == $item['CODE'])
  490. {
  491. $valueAsText = $item['NAME'];
  492. }
  493. }
  494. if (!$valueAsText)
  495. {
  496. continue;
  497. }
  498. $result[$field['TEXT']] = Text::formatArrayToText(array($valueAsText));
  499. }
  500. return $result;
  501. }
  502. }