apps/uvdesk/custom-fields/src/Services/CustomFieldsService.php line 35

Open in your IDE?
  1. <?php
  2. namespace UVDesk\CommunityPackages\UVDesk\CustomFields\Services;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Symfony\Component\DependencyInjection\ContainerInterface;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Contracts\Translation\TranslatorInterface;
  7. use UVDesk\CommunityPackages\UVDesk\CustomFields\EntityCustomFields;
  8. use UVDesk\CommunityPackages\UVDesk\CustomFields\Entity\CustomFields;
  9. use UVDesk\CommunityPackages\UVDesk\CustomFields\Entity\TicketCustomFieldsValues;
  10. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Attachment;
  11. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket;
  12. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketType;
  13. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  14. class CustomFieldsService
  15. {
  16. CONST DEFAULT_VALIDATION_RULES = [
  17. "fieldtype" => "text",
  18. "minNo" => "",
  19. "maxNo" => "",
  20. "allowedDomain" => "",
  21. "restrictedDomain" => "",
  22. "maxFileSize" => "",
  23. "regex" => "",
  24. "restrictedDomain" => "",
  25. ];
  26. private $entityManager = null;
  27. private $customContainer = null;
  28. private $validationService = null;
  29. private $translatorService = null;
  30. public function __construct(
  31. EntityManagerInterface $entityManager,
  32. ContainerInterface $customContainer,
  33. ValidationService $validationService,
  34. TranslatorInterface $translatorService,
  35. UserService $userService
  36. ) {
  37. $this->entityManager = $entityManager;
  38. $this->customContainer = $customContainer;
  39. $this->validationService = $validationService;
  40. $this->translatorService = $translatorService;
  41. $this->userService = $userService;
  42. }
  43. /**
  44. * customFieldValidation for Ticket, used in 1.TicketBundle, 2. SupportCenterBundle 3.ApiBundle
  45. *
  46. * @param Request $request
  47. * @param String $userType (optional) (like for user, customer, both)
  48. *
  49. * @return Array with keys: 'errorMain', 'formErrors', 'errorFlashMessage'
  50. */
  51. public function customFieldsValidation(Request $request, $userType = 'both')
  52. {
  53. $errorMain = false;
  54. $formErrors = [];
  55. $errorFlashMessage = null;
  56. $data = $request->request->all() ? : json_decode($request->getContent(), true);
  57. if(!$this->validateAttachmentsSize($request->files->get('customFields')) || !$this->validateAttachmentsSize($request->files->get('attachments'))) {
  58. $errorMain = true;
  59. $errorFlashMessage = $this->translator->trans("Warning ! Files size can not exceed %size% MB", [
  60. "%size%" => $this->customContainer->getParameter('max_upload_size')
  61. ]);
  62. } elseif($companyCustomFields = $this->getCustomFieldsArray($userType)) {
  63. foreach ($companyCustomFields as $customField) {
  64. if('file' == $customField['fieldType']) {
  65. $fileCf = $request->files->get('customFields');
  66. $customFieldValue = isset($fileCf[$customField['id']]) ? $fileCf[$customField['id']] : null;
  67. } else {
  68. $customFieldValue = isset($data['customFields'][$customField['id']]) ? $data['customFields'][$customField['id']] : null;
  69. }
  70. $customField['validation']['required'] = $customField['required'];
  71. $customField['validation']['fieldtype'] = $customField['fieldType'] ? : $customField['validation']['fieldtype'] ;
  72. if(count($customField['customFieldsDependency'])) {
  73. $ticketType = $this->entityManager->getRepository(TicketType::class)->findOneById(isset($data['type']) ? $data['type'] : '' );
  74. if($ticketType) {
  75. $typeId = $ticketType->getId();
  76. $flag = 0;
  77. foreach($customField['customFieldsDependency'] as $dependency) {
  78. if($dependency['id'] == $typeId) {
  79. $flag = 1; break;
  80. }
  81. }
  82. }
  83. if(empty($flag)) {
  84. continue;
  85. }
  86. } elseif(in_array($customField['fieldType'], ['checkbox', 'radio', 'select']) && empty($customField['customFieldValues'])) {
  87. continue;
  88. }
  89. $errorMessage = $this->validationService->messageValidate($customField['validation'], $customFieldValue);
  90. if($errorMessage) {
  91. $formErrors["customFields[".$customField['id']."]"] = $errorMessage;
  92. }
  93. }
  94. }
  95. return ['errorMain' => $errorMain, 'formErrors' => $formErrors, 'errorFlashMessage' => $errorFlashMessage];
  96. }
  97. public function customFieldsValidationWithoutRequired(Request $request, $userType = 'both')
  98. {
  99. $errorMain = false;
  100. $formErrors = [];
  101. $errorFlashMessage = null;
  102. $data = $request->request->all() ? : json_decode($request->getContent(), true);
  103. if(!$this->validateAttachmentsSize($request->files->get('customFields')) || !$this->validateAttachmentsSize($request->files->get('attachments'))) {
  104. $errorMain = true;
  105. $errorFlashMessage = $this->translator->trans("Warning ! Files size can not exceed %size% MB", [
  106. "%size%" => $this->customContainer->getParameter('max_upload_size')]);
  107. } elseif($companyCustomFields = $this->getCustomFieldsArray($userType)) {
  108. foreach ($companyCustomFields as $customField) {
  109. $customField['validation']['required'] = false;
  110. $customField['validation']['fieldtype'] = $customField['fieldType'] ? : $customField['validation']['fieldtype'] ;
  111. if('file' == $customField['fieldType']) {
  112. $fileCf = $request->files->get('customFields');
  113. $customFieldValue = isset($fileCf[$customField['id']]) ? $fileCf[$customField['id']] : null;
  114. } else {
  115. $customFieldValue = isset($data['customFields'][$customField['id']]) ? $data['customFields'][$customField['id']] : null;
  116. }
  117. if(count($customField['customFieldsDependency'])) {
  118. $ticketType = $this->entityManager->getRepository(TicketType::class)->findOneById(isset($data['type']) ? $data['type'] : '' );
  119. if($ticketType) {
  120. $typeId = $ticketType->getId();
  121. $flag = 0;
  122. foreach($customField['customFieldsDependency'] as $dependency) {
  123. if($dependency['id'] == $typeId) {
  124. $flag = 1; break;
  125. }
  126. }
  127. }
  128. if(empty($flag)) {
  129. continue;
  130. }
  131. } elseif(in_array($customField['fieldType'], ['checkbox', 'radio', 'select']) && empty($customField['customFieldValues'])) {
  132. continue;
  133. }
  134. $errorMessage = $this->validationService->messageValidate($customField['validation'], $customFieldValue);
  135. if($errorMessage) {
  136. $formErrors["customFields[".$customField['id']."]"] = $errorMessage;
  137. }
  138. }
  139. }
  140. return ['errorMain' => $errorMain, 'formErrors' => $formErrors, 'errorFlashMessage' => $errorFlashMessage];
  141. }
  142. /**
  143. * customFieldValidation for some field
  144. *
  145. * @param Request $request
  146. * @param Array $customFields , validate against these customFields
  147. *
  148. * @return Array with keys: 'errorMain', 'formErrors', 'errorFlashMessage'
  149. */
  150. public function partialCustomFieldsValidation(Request $request, Array $customFields, $prefix = '')
  151. {
  152. $errorMain = false;
  153. $formErrors = [];
  154. $errorFlashMessage = null;
  155. $data = $request->request->all() ? : json_decode($request->getContent(), true);
  156. if(!$this->validateAttachmentsSize($request->files->get('customFields')) || !$this->validateAttachmentsSize($request->files->get('attachments'))) {
  157. $errorMain = true;
  158. $errorFlashMessage = $this->translator->trans("Warning ! Files size can not exceed %size% MB", [
  159. "%size%" => $this->customContainer->getParameter('max_upload_size')]);
  160. } else {
  161. foreach ($customFields as $customField) {
  162. if('file' == $customField['fieldType']) {
  163. $fileCf = $request->files->get('customFields');
  164. $customFieldValue = isset($fileCf[$customField['id']]) ? $fileCf[$customField['id']] : null;
  165. } else {
  166. $customFieldValue = isset($data['customFields'][$customField['id']]) ? $data['customFields'][$customField['id']] : null;
  167. }
  168. $customField['validation']['required'] = $customField['required'];
  169. $customField['validation']['fieldtype'] = $customField['fieldType'] ? : $customField['validation']['fieldtype'];
  170. if(count($customField['customFieldsDependency'])) {
  171. $ticketType = $this->entityManager->getRepository(TicketType::class)->findOneById(isset($data['type']) ? $data['type'] : '' );
  172. if($ticketType) {
  173. $typeId = $ticketType->getId();
  174. $flag = 0;
  175. foreach($customField['customFieldsDependency'] as $dependency) {
  176. if($dependency['id'] == $typeId) {
  177. $flag = 1; break;
  178. }
  179. }
  180. }
  181. if(empty($flag)) {
  182. continue;
  183. }
  184. } elseif(in_array($customField['fieldType'], ['checkbox', 'radio', 'select']) && empty($customField['customFieldValues'])) {
  185. continue;
  186. }
  187. $errorMessage = $this->validationService->messageValidate($customField['validation'], $customFieldValue);
  188. if($errorMessage) {
  189. $formErrors["customFields[".$customField['id']."]"] = $errorMessage;
  190. }
  191. }
  192. }
  193. return ['errorMain' => $errorMain, 'formErrors' => $formErrors, 'errorFlashMessage' => $errorFlashMessage];
  194. }
  195. public function partialCustomFieldsValidationBinaka(Request $request, Array $customFields, $prefix = '')
  196. {
  197. $errorMain = false;
  198. $formErrors = [];
  199. $errorFlashMessage = null;
  200. $data = $request->request->all() ? : json_decode($request->getContent(), true);
  201. if(!$this->validateAttachmentsSize($request->files->get('customFields')) || !$this->validateAttachmentsSize($request->files->get('attachments'))) {
  202. $errorMain = true;
  203. $errorFlashMessage = $this->translator->trans("Warning ! Files size can not exceed %size% MB", [
  204. "%size%" => $this->customContainer->getParameter('max_upload_size')
  205. ]);
  206. } else {
  207. foreach ($customFields as $customField) {
  208. if(isset($customField['attr']['required']))
  209. $customField['validation']['required'] = $customField['attr']['required'];
  210. else
  211. $customField['validation']['required'] = false;
  212. if (!empty($customField['attr']['type']) && 'file' == $customField['attr']['type']) {
  213. $fileCf = $request->files->get('customFields');
  214. $customFieldValue = isset($fileCf[$customField['id']]) ? $fileCf[$customField['id']] : null;
  215. } else {
  216. $customFieldValue = isset($data['customFields'][$customField['id']]) ? $data['customFields'][$customField['id']] : null;
  217. }
  218. if(count($customField['dependency'])) {
  219. $ticketType = $this->entityManager->getRepository(TicketType::class)->findOneById(isset($data['type']) ? $data['type'] : '' );
  220. if($ticketType) {
  221. $typeId = $ticketType->getId();
  222. $flag = 0;
  223. foreach($customField['dependency'] as $dependency) {
  224. if($dependency['id'] == $typeId) {
  225. $flag = 1; break;
  226. }
  227. }
  228. }
  229. if(empty($flag)) {
  230. continue;
  231. }
  232. } elseif(isset($customField['fieldType']) && in_array($customField['fieldType'], ['checkbox', 'radio', 'select']) && empty($customField['customFieldValues'])) {
  233. continue;
  234. }
  235. $errorMessage = $validationService->messageValidate($customField['validation'], $customFieldValue);
  236. if($errorMessage) {
  237. $formErrors["customFields[".$customField['id']."]"] = $errorMessage;
  238. }
  239. }
  240. }
  241. return ['errorMain' => $errorMain, 'formErrors' => $formErrors, 'errorFlashMessage' => $errorFlashMessage];
  242. }
  243. /**
  244. * finds active custom fields by company and userType(agentType) , (included customFields for agentType:both)
  245. *
  246. * @param string $agentType
  247. */
  248. public function getCustomFieldsArray($agentType)
  249. {
  250. if('string' !== gettype($agentType)) {
  251. throw new \Exception('getCustomFieldsArray() expects parameter 1 to be string.');
  252. }
  253. $qb = $this->entityManager->createQueryBuilder()
  254. ->from(CustomFields::class, 'c')
  255. ->leftJoin("c.customFieldsDependency",'cfd')
  256. ->select('c,cfv,cfd')
  257. ->leftJoin("c.customFieldValues",'cfv')
  258. ->andWhere('c.status = 1')
  259. ->orderBy('c.sortOrder');
  260. if($agentType && 'both' != $agentType) {
  261. $qb->andWhere('c.agentType = :both or c.agentType = :agentType')
  262. ->setParameter('agentType',$agentType)
  263. ->setParameter('both', 'both');
  264. }
  265. $results = $qb->getQuery()->getArrayResult();
  266. foreach ($results as $key => $result) {
  267. $results[$key]['validation'] = ($result['validation']) ? json_decode($result['validation'],true) : $result['validation'];
  268. }
  269. return $results;
  270. }
  271. /**
  272. * get customFields from db using customField Ids
  273. *
  274. * @param Array $array (customFieldIds array)
  275. * @param String $resultType ('array' for array Result, 'object' for object result)
  276. *
  277. * @return Array customFieldsCollection with Array/object results
  278. */
  279. public function getCustomFieldsByIds(Array $array, $resultType = 'array')
  280. {
  281. if(!in_array($resultType, ['array', 'object'])) {
  282. throw new \Exception('getCustomFieldsByIds() expects parameter 3 to be either "array" or "object".');
  283. }
  284. $queryBuilder = $this->entityManager->createQueryBuilder()
  285. ->from(CustomFields::class, 's')
  286. ->leftJoin("s.customFieldValues",'cfv')
  287. ->leftJoin('s.customFieldsDependency','cfd')
  288. ->select('s, cfv, cfd')
  289. ->andWhere('s.status= 1')
  290. ->andWhere('s.id in (:array)')
  291. ->orderBy(
  292. 's.sortOrder'
  293. )
  294. ->setParameters(
  295. array(
  296. 'array' => $array,
  297. )
  298. )
  299. ->getQuery()
  300. ;
  301. if($resultType == 'array') {
  302. $results = $queryBuilder->getArrayResult();
  303. foreach ($results as $key => $result) {
  304. $results[$key]['validation'] = ($result['validation']) ? json_decode($result['validation'],true) : $result['validation'];
  305. }
  306. } else {
  307. $results = $queryBuilder->getResult();
  308. }
  309. return $results;
  310. }
  311. private function validateAttachmentsSize($attachments)
  312. {
  313. $filesize = 0;
  314. if($attachments) {
  315. foreach ($attachments as $attachment) {
  316. if(is_array($attachment)){
  317. foreach ($attachment as $attach) {
  318. if($attach)
  319. $filesize += $attach->getSize() / 1048576;
  320. }
  321. }elseif($attachment)
  322. $filesize += $attachment->getSize() / 1048576;
  323. }
  324. }
  325. return $filesize > $this->customContainer->getParameter('max_upload_size') ? false : true;
  326. }
  327. public function addFilesEntryToAttachmentTable($fileNames, $thread = null)
  328. {
  329. $newFilesNames = [];
  330. foreach ($fileNames as $file) {
  331. $attachment = new Attachment();
  332. $attachment
  333. ->setName($file['name'])
  334. ->setPath($file['path'])
  335. ->setContentType($file['content-type'])
  336. ->setSize($file['size'])
  337. ;
  338. if (isset($file['contentId'])) {
  339. $attachment
  340. ->setContentId($file['contentId'])
  341. ;
  342. }
  343. if (!empty($thread)) {
  344. $attachment
  345. ->setThread($thread)
  346. ;
  347. }
  348. $this->entityManager->persist($attachment);
  349. $this->entityManager->flush();
  350. $newFilesNames[] = [
  351. 'id' => $attachment->getId(),
  352. 'name' => $attachment->getName(),
  353. 'path' => $attachment->getPath(),
  354. ];
  355. }
  356. return $newFilesNames;
  357. }
  358. public function getTicketCustomFieldDetailsCollection(array $ticketReferenceIds)
  359. {
  360. $ticketReferences = array_map(function ($ticketId) {
  361. return "ticketCustomField.ticket = $ticketId";
  362. }, $ticketReferenceIds);
  363. $ticketReferencesQueryCondition = implode(" OR ", $ticketReferences);
  364. $queryBuilder = $this->entityManager->createQueryBuilder();
  365. $ticketCustomFieldDetailsCollection = $queryBuilder
  366. ->select("ticketCustomField")
  367. ->from(TicketCustomFieldsValues::class, "ticketCustomField")
  368. ->where($ticketReferencesQueryCondition)
  369. ->getQuery()
  370. ->getResult()
  371. ;
  372. if (empty($ticketCustomFieldDetailsCollection)) {
  373. return [];
  374. }
  375. $resolvedTicketCustomFieldDetailsCollection = [];
  376. foreach ($ticketCustomFieldDetailsCollection as $ticketCustomFieldDetails) {
  377. $customField = $ticketCustomFieldDetails->getTicketCustomFieldsValues();
  378. $customFieldDependencies = $customField->getCustomFieldsDependency()->getValues();
  379. $customFieldValidationRules = json_decode($customField->getValidation(), true);
  380. $resolvedCustomFieldDependencies = array_map(function ($ticketType) {
  381. return [
  382. 'id' => $ticketType->getId(),
  383. 'code' => $ticketType->getCode(),
  384. 'description' => $ticketType->getDescription(),
  385. 'isActive' => $ticketType->getIsActive(),
  386. ];
  387. }, $customFieldDependencies);
  388. $resolvedCustomFieldValidationRules = [];
  389. foreach ($customFieldValidationRules as $validationRule => $validationCriteria) {
  390. if (!empty($validationCriteria)) {
  391. $resolvedCustomFieldValidationRules[$validationRule] = $validationCriteria;
  392. }
  393. }
  394. // Resolve custom field options
  395. $customFieldOptions = array_map(function ($customFieldOption) {
  396. return [
  397. "id" => $customFieldOption->getId(),
  398. "name" => $customFieldOption->getName(),
  399. ];
  400. }, $customField->getCustomFieldValues());
  401. $customFieldDetails = [
  402. 'id' => $customField->getId(),
  403. 'name' => $customField->getName(),
  404. 'type' => $customField->getFieldType(),
  405. 'placeholder' => $customField->getPlaceholder(),
  406. 'isRequired' => $customField->getRequired(),
  407. 'isEncrypted' => $customField->getEncryption(),
  408. 'status' => $customField->getStatus(),
  409. 'sortOrder' => $customField->getSortOrder(),
  410. 'createdAt' => $this->userService->convertDateTimeToSupportedUserTimeFormat($customField->getDateAdded()),
  411. 'lastUpdatedAt' => $this->userService->convertDateTimeToSupportedUserTimeFormat($customField->getDateUpdated()),
  412. 'options' => $customFieldOptions,
  413. 'dependencies' => $resolvedCustomFieldDependencies,
  414. 'validations' => $resolvedCustomFieldValidationRules,
  415. ];
  416. $customFieldId = $customField->getId();
  417. $ticketCustomFieldValue = $ticketCustomFieldDetails->getValue();
  418. $resolvedCustomFieldValue = null;
  419. $resolvedCustomFieldValueId = null;
  420. switch ($customField->getFieldType()) {
  421. case 'select':
  422. case 'radio':
  423. case 'checkbox':
  424. $fieldId = [];
  425. $fieldValue = [];
  426. if ($ticketCustomFieldDetails->getEncrypted()) {
  427. $ticketCustomFieldDetails->decryptEntity();
  428. }
  429. $fieldOptions = json_decode($ticketCustomFieldValue, true);
  430. if (empty($fieldOptions)) {
  431. $fieldOptions = explode(',', $ticketCustomFieldValue);
  432. } else {
  433. if (!is_array($fieldOptions)) {
  434. $fieldOptions = [$fieldOptions];
  435. }
  436. }
  437. foreach ($customField->getCustomFieldValues() as $multipleFieldValue) {
  438. if (in_array($multipleFieldValue->getId(), $fieldOptions)) {
  439. $fieldId[] = $multipleFieldValue->getId();
  440. $fieldValue[] = $multipleFieldValue->getName();
  441. }
  442. }
  443. $resolvedCustomFieldValue = $ticketCustomFieldDetails->getEncrypted() ? null: implode('</br>', $fieldValue);
  444. $resolvedCustomFieldValueId = $fieldId;
  445. break;
  446. case 'file':
  447. $resolvedCustomFieldValue = $ticketCustomFieldDetails->getEncrypted() ? null : strip_tags(trim($ticketCustomFieldValue, '"'));
  448. try {
  449. if (!empty($resolvedCustomFieldValue)) {
  450. $resolvedCustomFieldValue = json_decode($resolvedCustomFieldValue, true);
  451. }
  452. } catch (\Exception $e) {
  453. // Do nothing...
  454. }
  455. break;
  456. default:
  457. if (false == $ticketCustomFieldDetails->getEncrypted()) {
  458. if (is_array(trim($ticketCustomFieldValue, '"'))) {
  459. $resolvedCustomFieldValue = json_encode(trim($ticketCustomFieldValue, '"'));
  460. } else {
  461. $resolvedCustomFieldValue = strip_tags(htmlentities(trim($ticketCustomFieldValue, '"')));
  462. }
  463. } else {
  464. $resolvedCustomFieldValue = null;
  465. }
  466. break;
  467. }
  468. $resolvedTicketCustomFieldDetailsCollection[] = [
  469. 'id' => $ticketCustomFieldDetails->getId(),
  470. 'value' => $resolvedCustomFieldValue,
  471. 'valueId' => $resolvedCustomFieldValueId,
  472. 'ticketId' => $ticketCustomFieldDetails->getTicket()->getId(),
  473. 'isEncrypted' => $ticketCustomFieldDetails->getEncrypted() ? true : false,
  474. 'customField' => $customFieldDetails,
  475. ];
  476. }
  477. $ticketCustomFieldDetailsCollectionGroupedByTicket = [];
  478. foreach ($resolvedTicketCustomFieldDetailsCollection as $ticketCustomFieldDetails) {
  479. $ticketCustomFieldDetailsCollectionGroupedByTicket[$ticketCustomFieldDetails['ticketId']][] = $ticketCustomFieldDetails;
  480. }
  481. return $ticketCustomFieldDetailsCollectionGroupedByTicket;
  482. }
  483. public function getTicketCustomFieldDetails($ticketId)
  484. {
  485. $collection = $this->entityManager->getRepository(TicketCustomFieldsValues::class)->findBy(['ticket' => $ticketId]);
  486. if (empty($collection)) {
  487. return [];
  488. }
  489. $_collection = [];
  490. foreach ($collection as $ticketCustomFieldDetails) {
  491. $customField = $ticketCustomFieldDetails->getTicketCustomFieldsValues();
  492. $customFieldDependencies = $customField->getCustomFieldsDependency()->getValues();
  493. $customFieldValidationRules = json_decode($customField->getValidation(), true);
  494. $resolvedCustomFieldDependencies = array_map(function ($ticketType) {
  495. return [
  496. 'id' => $ticketType->getId(),
  497. 'code' => $ticketType->getCode(),
  498. 'description' => $ticketType->getDescription(),
  499. 'isActive' => $ticketType->getIsActive(),
  500. ];
  501. }, $customFieldDependencies);
  502. $resolvedCustomFieldValidationRules = [];
  503. foreach ($customFieldValidationRules as $validationRule => $validationCriteria) {
  504. if (!empty($validationCriteria)) {
  505. $resolvedCustomFieldValidationRules[$validationRule] = $validationCriteria;
  506. }
  507. }
  508. // Resolve custom field options
  509. $customFieldOptions = array_map(function ($customFieldOption) {
  510. return [
  511. "id" => $customFieldOption->getId(),
  512. "name" => $customFieldOption->getName(),
  513. ];
  514. }, $customField->getCustomFieldValues());
  515. $customFieldDetails = [
  516. 'id' => $customField->getId(),
  517. 'name' => $customField->getName(),
  518. 'type' => $customField->getFieldType(),
  519. 'placeholder' => $customField->getPlaceholder(),
  520. 'isRequired' => $customField->getRequired(),
  521. 'isEncrypted' => $customField->getEncryption(),
  522. 'status' => $customField->getStatus(),
  523. 'sortOrder' => $customField->getSortOrder(),
  524. 'createdAt' => $this->userService->convertDateTimeToSupportedUserTimeFormat($customField->getDateAdded()),
  525. 'lastUpdatedAt' => $this->userService->convertDateTimeToSupportedUserTimeFormat($customField->getDateUpdated()),
  526. 'options' => $customFieldOptions,
  527. 'dependencies' => $resolvedCustomFieldDependencies,
  528. // 'agentType' => $customField->getAgentType(),
  529. 'validations' => $resolvedCustomFieldValidationRules,
  530. ];
  531. $customFieldId = $customField->getId();
  532. $ticketCustomFieldValue = $ticketCustomFieldDetails->getValue();
  533. $resolvedCustomFieldValue = null;
  534. $resolvedCustomFieldValueId = null;
  535. switch ($customField->getFieldType()) {
  536. case 'select':
  537. case 'radio':
  538. case 'checkbox':
  539. $fieldId = [];
  540. $fieldValue = [];
  541. if ($ticketCustomFieldDetails->getEncrypted()) {
  542. $ticketCustomFieldDetails->decryptEntity();
  543. }
  544. $fieldOptions = json_decode($ticketCustomFieldValue, true);
  545. if (empty($fieldOptions)) {
  546. $fieldOptions = explode(',', $ticketCustomFieldValue);
  547. } else {
  548. if (!is_array($fieldOptions)) {
  549. $fieldOptions = [$fieldOptions];
  550. }
  551. }
  552. foreach ($customField->getCustomFieldValues() as $multipleFieldValue) {
  553. if (in_array($multipleFieldValue->getId(), $fieldOptions)) {
  554. $fieldId[] = $multipleFieldValue->getId();
  555. $fieldValue[] = $multipleFieldValue->getName();
  556. }
  557. }
  558. $resolvedCustomFieldValue = $ticketCustomFieldDetails->getEncrypted() ? null: implode('</br>', $fieldValue);
  559. $resolvedCustomFieldValueId = $fieldId;
  560. break;
  561. case 'file':
  562. $resolvedCustomFieldValue = $ticketCustomFieldDetails->getEncrypted() ? null : strip_tags(trim($ticketCustomFieldValue, '"'));
  563. try {
  564. if (!empty($resolvedCustomFieldValue)) {
  565. $resolvedCustomFieldValue = json_decode($resolvedCustomFieldValue, true);
  566. }
  567. } catch (\Exception $e) {
  568. // Do nothing...
  569. }
  570. break;
  571. default:
  572. if (false == $ticketCustomFieldDetails->getEncrypted()) {
  573. if (is_array(trim($ticketCustomFieldValue, '"'))) {
  574. $resolvedCustomFieldValue = json_encode(trim($ticketCustomFieldValue, '"'));
  575. } else {
  576. $resolvedCustomFieldValue = strip_tags(htmlentities(trim($ticketCustomFieldValue, '"')));
  577. }
  578. } else {
  579. $resolvedCustomFieldValue = null;
  580. }
  581. break;
  582. }
  583. $_collection[] = [
  584. 'id' => $ticketCustomFieldDetails->getId(),
  585. 'value' => $resolvedCustomFieldValue,
  586. 'valueId' => $resolvedCustomFieldValueId,
  587. 'isEncrypted' => $ticketCustomFieldDetails->getEncrypted() ? true : false,
  588. 'customField' => $customFieldDetails,
  589. ];
  590. }
  591. return $_collection;
  592. }
  593. /**
  594. * returns custom field snippet containing html, js for ticket view
  595. */
  596. public function getCustomFieldSnippet(Ticket $ticket): array
  597. {
  598. $customFieldCollection = $this->getCustomFieldsArray('both');
  599. if (!empty($customFieldCollection)) {
  600. $ticketCustomFieldArrayCollection = [];
  601. $ticketCustomFieldCollection = $this->entityManager->getRepository(TicketCustomFieldsValues::class)->findBy(['ticket' => $ticket]);
  602. if (!empty($ticketCustomFieldCollection)) {
  603. foreach ($ticketCustomFieldCollection as $ticketCustomField) {
  604. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()] = [
  605. 'id' => $ticketCustomField->getId(),
  606. 'encrypted' => $ticketCustomField->getEncrypted() ? true : false,
  607. 'targetCustomField' => $ticketCustomField->getTicketCustomFieldsValues()->getId(),
  608. ];
  609. switch ($ticketCustomField->getTicketCustomFieldsValues()->getFieldType()) {
  610. case 'select':
  611. case 'radio':
  612. case 'checkbox':
  613. $fieldId = [];
  614. $fieldValue = [];
  615. if ($ticketCustomField->getEncrypted()) {
  616. $ticketCustomField->decryptEntity();
  617. }
  618. $fieldOptions = json_decode($ticketCustomField->getValue(), true);
  619. if (empty($fieldOptions)) {
  620. $fieldOptions = explode(',', $ticketCustomField->getValue());
  621. } else {
  622. if (!is_array($fieldOptions)) {
  623. $fieldOptions = [$fieldOptions];
  624. }
  625. }
  626. foreach ($ticketCustomField->getTicketCustomFieldsValues()->getCustomFieldValues() as $multipleFieldValue) {
  627. if (in_array($multipleFieldValue->getId(), $fieldOptions)) {
  628. $fieldId[] = $multipleFieldValue->getId();
  629. $fieldValue[] = $multipleFieldValue->getName();
  630. }
  631. }
  632. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()]['valueId'] = $fieldId;
  633. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()]['value'] = $ticketCustomField->getEncrypted() ? null: implode('</br>', $fieldValue);
  634. break;
  635. case 'file':
  636. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()]['value'] = $ticketCustomField->getEncrypted() ? null : strip_tags(trim($ticketCustomField->getValue(), '"'));
  637. break;
  638. default:
  639. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()]['value'] = (!$ticketCustomField->getEncrypted()
  640. ? (is_array(trim($ticketCustomField->getValue(), '"'))
  641. ? json_encode(trim($ticketCustomField->getValue(), '"'))
  642. : strip_tags(htmlentities(trim($ticketCustomField->getValue(), '"')))
  643. )
  644. : null
  645. );
  646. break;
  647. }
  648. }
  649. }
  650. return [
  651. 'ticket' => $ticket,
  652. 'customFieldCollection' => $customFieldCollection,
  653. 'ticketCustomFieldCollection' => $ticketCustomFieldArrayCollection
  654. ];
  655. }
  656. return [
  657. 'ticket' => $ticket,
  658. 'customFieldCollection' => [],
  659. 'ticketCustomFieldCollection' => []
  660. ];
  661. }
  662. public function getCustomerCustomFieldSnippet($ticket): array
  663. {
  664. $customFieldCollection = $this->getCustomFieldsArray('customer');
  665. $ticketCustomFieldArrayCollection = [];
  666. $ticketCustomFieldCollection = $this->entityManager->getRepository(TicketCustomFieldsValues::class)->findBy(['ticket' => $ticket]);
  667. /* load custom fields whose value is already present in ticket */
  668. $existingCfIds = array_column($customFieldCollection, 'id');
  669. $cfIds = [];
  670. foreach($ticketCustomFieldCollection as $cfValue) {
  671. $id = $cfValue->getTicketCustomFieldsValues()->getId();
  672. if($cfValue->getTicketCustomFieldsValues()->getStatus() && !in_array($id, $existingCfIds)) {
  673. $cfIds[] = $id;
  674. }
  675. }
  676. $ticketCfs = $this->getCustomFieldsByIds($cfIds);
  677. $customFieldCollection = array_merge($customFieldCollection, $ticketCfs);
  678. /* format data */
  679. if (!empty($customFieldCollection)) {
  680. foreach ($ticketCustomFieldCollection as $ticketCustomField) {
  681. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()] = [
  682. 'id' => $ticketCustomField->getId(),
  683. 'encrypted' => $ticketCustomField->getEncrypted() ? true : false,
  684. 'targetCustomField' => $ticketCustomField->getTicketCustomFieldsValues()->getId(),
  685. 'targetCustomFieldName' => $ticketCustomField->getTicketCustomFieldsValues()->getId(),
  686. ];
  687. switch ($ticketCustomField->getTicketCustomFieldsValues()->getFieldType()) {
  688. case 'select':
  689. case 'radio':
  690. case 'checkbox':
  691. $fieldId = [];
  692. $fieldValue = [];
  693. if ($ticketCustomField->getEncrypted()) {
  694. $ticketCustomField->decryptEntity();
  695. }
  696. $fieldOptions = json_decode($ticketCustomField->getValue(), true);
  697. if (empty($fieldOptions)) {
  698. $fieldOptions = explode(',', $ticketCustomField->getValue());
  699. } else {
  700. if (!is_array($fieldOptions)) {
  701. $fieldOptions = [$fieldOptions];
  702. }
  703. }
  704. foreach ($ticketCustomField->getTicketCustomFieldsValues()->getCustomFieldValues() as $multipleFieldValue) {
  705. if (in_array($multipleFieldValue->getId(), $fieldOptions)) {
  706. $fieldId[] = $multipleFieldValue->getId();
  707. $fieldValue[] = $multipleFieldValue->getName();
  708. }
  709. }
  710. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()]['valueId'] = $fieldId;
  711. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()]['value'] = $ticketCustomField->getEncrypted() ? null: implode('</br>', $fieldValue);
  712. break;
  713. default:
  714. $ticketCustomFieldArrayCollection[$ticketCustomField->getTicketCustomFieldsValues()->getId()]['value'] = (!$ticketCustomField->getEncrypted()
  715. ? (is_array(trim($ticketCustomField->getValue(), '"'))
  716. ? json_encode(trim($ticketCustomField->getValue(), '"'))
  717. : strip_tags(htmlentities(trim($ticketCustomField->getValue(), '"')))
  718. )
  719. : null
  720. );
  721. break;
  722. }
  723. }
  724. return ['ticket' => $ticket,
  725. 'customFieldCollection' => $customFieldCollection,
  726. 'ticketCustomFieldCollection' => $ticketCustomFieldArrayCollection
  727. ];
  728. }
  729. return [
  730. 'ticket' => $ticket,
  731. 'customFieldCollection' => [],
  732. 'ticketCustomFieldCollection' => []
  733. ];
  734. }
  735. private function getAvailableCustomFieldsCollection($agentType)
  736. {
  737. $queryBuilder = $this->entityManager->createQueryBuilder()
  738. ->from(CustomFields::class, 'c')
  739. ->leftJoin("c.customFieldsDependency", 'cfd')
  740. ->select('c, cfv, cfd')
  741. ->leftJoin("c.customFieldValues", 'cfv')
  742. ->andWhere('c.status = 1')
  743. ->orderBy('c.sortOrder')
  744. ;
  745. if ($agentType && 'both' != $agentType) {
  746. $queryBuilder
  747. ->andWhere('c.agentType = :both or c.agentType = :agentType')
  748. ->setParameter('agentType', $agentType)
  749. ->setParameter('both', 'both')
  750. ;
  751. }
  752. $collection = $queryBuilder->getQuery()->getArrayResult();
  753. foreach ($collection as $index => $customField) {
  754. $collection[$index]['validation'] = !empty($customField['validation']) ? json_decode($customField['validation'], true) : $customField['validation'];
  755. }
  756. return $collection;
  757. }
  758. public function validateCustomFieldsWithoutRequired($ticket, $customField, $params, $uploadedFiles, $userType = 'both')
  759. {
  760. $customFieldValue = null;
  761. if ('file' == $customField->getFieldType()) {
  762. if (!empty($uploadedFiles['ticketCustomFieldValue'])) {
  763. if (!$this->validateAttachmentsSize($uploadedFiles['ticketCustomFieldValue'])) {
  764. return [false, "File size can not exceed {$this->customContainer->getParameter('max_upload_size')} MB"];
  765. }
  766. $customFieldValue = $uploadedFiles['ticketCustomFieldValue'];
  767. }
  768. } else {
  769. if (!isset($params['customFieldValue'])) {
  770. return [false, "No custom field value was provided."];
  771. }
  772. $customFieldValue = $params['customFieldValue'];
  773. }
  774. $customFieldTicketTypeDependencies = $customField->getCustomFieldsDependency()->getValues();
  775. if (!empty($customFieldTicketTypeDependencies)) {
  776. $isTicketTypeSupported = false;
  777. $ticketType = $ticket->getType();
  778. foreach ($customFieldTicketTypeDependencies as $supportedTicketType) {
  779. if ($ticketType->getId() == $supportedTicketType->getId()) {
  780. $isTicketTypeSupported = true;
  781. break;
  782. }
  783. }
  784. if (false == $isTicketTypeSupported) {
  785. return [false, "Custom field is not applicable on ticket of type '{$ticketType->getDescription()}'."];
  786. }
  787. }
  788. $validationRules = json_decode($customField->getValidation() ?: self::DEFAULT_VALIDATION_RULES, true);
  789. $validationErrorMessage = $this->validationService->messageValidate($validationRules, $customFieldValue);
  790. if (!empty($validationErrorMessage)) {
  791. return [false, $validationErrorMessage];
  792. }
  793. return [true, null];
  794. }
  795. }