PageRenderTime 62ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/include/QueryGenerator/QueryGenerator.php

https://bitbucket.org/thomashii/vtigercrm-6-for-postgresql
PHP | 1113 lines | 989 code | 72 blank | 52 comment | 285 complexity | d56b4dd28749380d1fbd5c24e87a0f7a MD5 | raw file
Possible License(s): Apache-2.0, LGPL-3.0, LGPL-2.1, GPL-2.0, GPL-3.0
  1. <?php
  2. /*+*******************************************************************************
  3. * The contents of this file are subject to the vtiger CRM Public License Version 1.0
  4. * ("License"); You may not use this file except in compliance with the License
  5. * The Original Code is: vtiger CRM Open Source
  6. * The Initial Developer of the Original Code is vtiger.
  7. * Portions created by vtiger are Copyright (C) vtiger.
  8. * All Rights Reserved.
  9. *
  10. *********************************************************************************/
  11. require_once 'data/CRMEntity.php';
  12. require_once 'modules/CustomView/CustomView.php';
  13. require_once 'include/Webservices/Utils.php';
  14. require_once 'include/Webservices/RelatedModuleMeta.php';
  15. /**
  16. * Description of QueryGenerator
  17. *
  18. * @author MAK
  19. */
  20. class QueryGenerator {
  21. private $module;
  22. private $customViewColumnList;
  23. private $stdFilterList;
  24. private $conditionals;
  25. private $manyToManyRelatedModuleConditions;
  26. private $groupType;
  27. private $whereFields;
  28. /**
  29. *
  30. * @var VtigerCRMObjectMeta
  31. */
  32. private $meta;
  33. /**
  34. *
  35. * @var Users
  36. */
  37. private $user;
  38. private $advFilterList;
  39. private $fields;
  40. private $referenceModuleMetaInfo;
  41. private $moduleNameFields;
  42. private $referenceFieldInfoList;
  43. private $referenceFieldList;
  44. private $ownerFields;
  45. private $columns;
  46. private $fromClause;
  47. private $whereClause;
  48. private $query;
  49. private $groupInfo;
  50. private $conditionInstanceCount;
  51. private $conditionalWhere;
  52. public static $AND = 'AND';
  53. public static $OR = 'OR';
  54. private $customViewFields;
  55. /**
  56. * Import Feature
  57. */
  58. private $ignoreComma;
  59. public function __construct($module, $user) {
  60. $db = PearDatabase::getInstance();
  61. $this->module = $module;
  62. $this->customViewColumnList = null;
  63. $this->stdFilterList = null;
  64. $this->conditionals = array();
  65. $this->user = $user;
  66. $this->advFilterList = null;
  67. $this->fields = array();
  68. $this->referenceModuleMetaInfo = array();
  69. $this->moduleNameFields = array();
  70. $this->whereFields = array();
  71. $this->groupType = self::$AND;
  72. $this->meta = $this->getMeta($module);
  73. $this->moduleNameFields[$module] = $this->meta->getNameFields();
  74. $this->referenceFieldInfoList = $this->meta->getReferenceFieldDetails();
  75. $this->referenceFieldList = array_keys($this->referenceFieldInfoList);;
  76. $this->ownerFields = $this->meta->getOwnerFields();
  77. $this->columns = null;
  78. $this->fromClause = null;
  79. $this->whereClause = null;
  80. $this->query = null;
  81. $this->conditionalWhere = null;
  82. $this->groupInfo = '';
  83. $this->manyToManyRelatedModuleConditions = array();
  84. $this->conditionInstanceCount = 0;
  85. $this->customViewFields = array();
  86. }
  87. /**
  88. *
  89. * @param String:ModuleName $module
  90. * @return EntityMeta
  91. */
  92. public function getMeta($module) {
  93. $db = PearDatabase::getInstance();
  94. if (empty($this->referenceModuleMetaInfo[$module])) {
  95. $handler = vtws_getModuleHandlerFromName($module, $this->user);
  96. $meta = $handler->getMeta();
  97. $this->referenceModuleMetaInfo[$module] = $meta;
  98. $this->moduleNameFields[$module] = $meta->getNameFields();
  99. }
  100. return $this->referenceModuleMetaInfo[$module];
  101. }
  102. public function reset() {
  103. $this->fromClause = null;
  104. $this->whereClause = null;
  105. $this->columns = null;
  106. $this->query = null;
  107. }
  108. public function setFields($fields) {
  109. $this->fields = $fields;
  110. }
  111. public function getCustomViewFields() {
  112. return $this->customViewFields;
  113. }
  114. public function getFields() {
  115. return $this->fields;
  116. }
  117. public function getWhereFields() {
  118. return $this->whereFields;
  119. }
  120. public function getOwnerFieldList() {
  121. return $this->ownerFields;
  122. }
  123. public function getModuleNameFields($module) {
  124. return $this->moduleNameFields[$module];
  125. }
  126. public function getReferenceFieldList() {
  127. return $this->referenceFieldList;
  128. }
  129. public function getReferenceFieldInfoList() {
  130. return $this->referenceFieldInfoList;
  131. }
  132. public function getModule () {
  133. return $this->module;
  134. }
  135. public function getConditionalWhere() {
  136. return $this->conditionalWhere;
  137. }
  138. public function getDefaultCustomViewQuery() {
  139. $customView = new CustomView($this->module);
  140. $viewId = $customView->getViewId($this->module);
  141. return $this->getCustomViewQueryById($viewId);
  142. }
  143. public function initForDefaultCustomView() {
  144. $customView = new CustomView($this->module);
  145. $viewId = $customView->getViewId($this->module);
  146. $this->initForCustomViewById($viewId);
  147. }
  148. public function initForCustomViewById($viewId) {
  149. $customView = new CustomView($this->module);
  150. $this->customViewColumnList = $customView->getColumnsListByCvid($viewId);
  151. foreach ($this->customViewColumnList as $customViewColumnInfo) {
  152. $details = explode(':', $customViewColumnInfo);
  153. if(empty($details[2]) && $details[1] == 'crmid' && $details[0] == 'vtiger_crmentity') {
  154. $name = 'id';
  155. $this->customViewFields[] = $name;
  156. } else {
  157. $this->fields[] = $details[2];
  158. $this->customViewFields[] = $details[2];
  159. }
  160. }
  161. if($this->module == 'Calendar' && !in_array('activitytype', $this->fields)) {
  162. $this->fields[] = 'activitytype';
  163. }
  164. if($this->module == 'Documents') {
  165. if(in_array('filename', $this->fields)) {
  166. if(!in_array('filelocationtype', $this->fields)) {
  167. $this->fields[] = 'filelocationtype';
  168. }
  169. if(!in_array('filestatus', $this->fields)) {
  170. $this->fields[] = 'filestatus';
  171. }
  172. }
  173. }
  174. $this->fields[] = 'id';
  175. $this->stdFilterList = $customView->getStdFilterByCvid($viewId);
  176. $this->advFilterList = $customView->getAdvFilterByCvid($viewId);
  177. if(is_array($this->stdFilterList)) {
  178. $value = array();
  179. if(!empty($this->stdFilterList['columnname'])) {
  180. $this->startGroup('');
  181. $name = explode(':',$this->stdFilterList['columnname']);
  182. $name = $name[2];
  183. $value[] = $this->fixDateTimeValue($name, $this->stdFilterList['startdate']);
  184. $value[] = $this->fixDateTimeValue($name, $this->stdFilterList['enddate'], false);
  185. $this->addCondition($name, $value, 'BETWEEN');
  186. }
  187. }
  188. if($this->conditionInstanceCount <= 0 && is_array($this->advFilterList) && count($this->advFilterList) > 0) {
  189. $this->startGroup('');
  190. } elseif($this->conditionInstanceCount > 0 && is_array($this->advFilterList) && count($this->advFilterList) > 0) {
  191. $this->addConditionGlue(self::$AND);
  192. }
  193. if(is_array($this->advFilterList) && count($this->advFilterList) > 0) {
  194. $this->parseAdvFilterList($this->advFilterList);
  195. }
  196. if($this->conditionInstanceCount > 0) {
  197. $this->endGroup();
  198. }
  199. }
  200. public function parseAdvFilterList($advFilterList, $glue=''){
  201. if(!empty($glue)) $this->addConditionGlue($glue);
  202. $customView = new CustomView($this->module);
  203. $dateSpecificConditions = $customView->getStdFilterConditions();
  204. foreach ($advFilterList as $groupindex=>$groupcolumns) {
  205. $filtercolumns = $groupcolumns['columns'];
  206. if(count($filtercolumns) > 0) {
  207. $this->startGroup('');
  208. foreach ($filtercolumns as $index=>$filter) {
  209. $nameComponents = explode(':',$filter['columnname']);
  210. if(empty($nameComponents[2]) && $nameComponents[1] == 'crmid' && $nameComponents[0] == 'vtiger_crmentity') {
  211. $name = $this->getSQLColumn('id');
  212. } else {
  213. $name = $nameComponents[2];
  214. }
  215. if(($nameComponents[4] == 'D' || $nameComponents[4] == 'DT') && in_array($filter['comparator'], $dateSpecificConditions)) {
  216. $filter['stdfilter'] = $filter['comparator'];
  217. $valueComponents = explode(',',$filter['value']);
  218. if($filter['comparator'] == 'custom') {
  219. if($nameComponents[4] == 'DT') {
  220. $startDateTimeComponents = explode(' ',$valueComponents[0]);
  221. $endDateTimeComponents = explode(' ',$valueComponents[1]);
  222. $filter['startdate'] = DateTimeField::convertToDBFormat($startDateTimeComponents[0]);
  223. $filter['enddate'] = DateTimeField::convertToDBFormat($endDateTimeComponents[0]);
  224. } else {
  225. $filter['startdate'] = DateTimeField::convertToDBFormat($valueComponents[0]);
  226. $filter['enddate'] = DateTimeField::convertToDBFormat($valueComponents[1]);
  227. }
  228. }
  229. $dateFilterResolvedList = $customView->resolveDateFilterValue($filter);
  230. $value[] = $this->fixDateTimeValue($name, $dateFilterResolvedList['startdate']);
  231. $value[] = $this->fixDateTimeValue($name, $dateFilterResolvedList['enddate'], false);
  232. $this->addCondition($name, $value, 'BETWEEN');
  233. }else{
  234. $this->addCondition($name, $filter['value'], $filter['comparator']);
  235. }
  236. $columncondition = $filter['column_condition'];
  237. if(!empty($columncondition)) {
  238. $this->addConditionGlue($columncondition);
  239. }
  240. }
  241. $this->endGroup();
  242. $groupConditionGlue = $groupcolumns['condition'];
  243. if(!empty($groupConditionGlue))
  244. $this->addConditionGlue($groupConditionGlue);
  245. }
  246. }
  247. }
  248. public function getCustomViewQueryById($viewId) {
  249. $this->initForCustomViewById($viewId);
  250. return $this->getQuery();
  251. }
  252. public function getQuery() {
  253. if(empty($this->query)) {
  254. $conditionedReferenceFields = array();
  255. $allFields = array_merge($this->whereFields,$this->fields);
  256. foreach ($allFields as $fieldName) {
  257. if(in_array($fieldName,$this->referenceFieldList)) {
  258. $moduleList = $this->referenceFieldInfoList[$fieldName];
  259. foreach ($moduleList as $module) {
  260. if(empty($this->moduleNameFields[$module])) {
  261. $meta = $this->getMeta($module);
  262. }
  263. }
  264. } elseif(in_array($fieldName, $this->ownerFields )) {
  265. $meta = $this->getMeta('Users');
  266. $meta = $this->getMeta('Groups');
  267. }
  268. }
  269. $query = "SELECT ";
  270. $query .= $this->getSelectClauseColumnSQL();
  271. $query .= $this->getFromClause();
  272. $query .= $this->getWhereClause();
  273. $this->query = $query;
  274. return $query;
  275. } else {
  276. return $this->query;
  277. }
  278. }
  279. public function getSQLColumn($name) {
  280. if ($name == 'id') {
  281. $baseTable = $this->meta->getEntityBaseTable();
  282. $moduleTableIndexList = $this->meta->getEntityTableIndexList();
  283. $baseTableIndex = $moduleTableIndexList[$baseTable];
  284. return $baseTable.'.'.$baseTableIndex;
  285. }
  286. $moduleFields = $this->meta->getModuleFields();
  287. $field = $moduleFields[$name];
  288. $sql = '';
  289. //TODO optimization to eliminate one more lookup of name, incase the field refers to only
  290. //one module or is of type owner.
  291. $column = $field->getColumnName();
  292. return $field->getTableName().'.'.$column;
  293. }
  294. public function getSelectClauseColumnSQL(){
  295. $columns = array();
  296. $moduleFields = $this->meta->getModuleFields();
  297. $accessibleFieldList = array_keys($moduleFields);
  298. $accessibleFieldList[] = 'id';
  299. $this->fields = array_intersect($this->fields, $accessibleFieldList);
  300. foreach ($this->fields as $field) {
  301. $sql = $this->getSQLColumn($field);
  302. $columns[] = $sql;
  303. //To merge date and time fields
  304. if($this->meta->getEntityName() == 'Calendar' && ($field == 'date_start' || $field == 'due_date' || $field == 'taskstatus' || $field == 'eventstatus')) {
  305. if($field=='date_start') {
  306. $timeField = 'time_start';
  307. $sql = $this->getSQLColumn($timeField);
  308. } else if ($field == 'due_date') {
  309. $timeField = 'time_end';
  310. $sql = $this->getSQLColumn($timeField);
  311. } else if ($field == 'taskstatus' || $field == 'eventstatus') {
  312. //In calendar list view, Status value = Planned is not displaying
  313. $sql = "CASE WHEN (vtiger_activity.status not like '') THEN vtiger_activity.status ELSE vtiger_activity.eventstatus END AS ";
  314. if ( $field == 'taskstatus') {
  315. $sql .= "status";
  316. } else {
  317. $sql .= $field;
  318. }
  319. }
  320. $columns[] = $sql;
  321. }
  322. }
  323. $this->columns = implode(', ',$columns);
  324. return $this->columns;
  325. }
  326. public function getFromClause() {
  327. if(!empty($this->query) || !empty($this->fromClause)) {
  328. return $this->fromClause;
  329. }
  330. $baseModule = $this->getModule();
  331. $moduleFields = $this->meta->getModuleFields();
  332. $tableList = array();
  333. $tableJoinMapping = array();
  334. $tableJoinCondition = array();
  335. $i =1;
  336. foreach ($this->fields as $fieldName) {
  337. if ($fieldName == 'id') {
  338. continue;
  339. }
  340. $field = $moduleFields[$fieldName];
  341. $baseTable = $field->getTableName();
  342. $tableIndexList = $this->meta->getEntityTableIndexList();
  343. $baseTableIndex = $tableIndexList[$baseTable];
  344. if($field->getFieldDataType() == 'reference') {
  345. $moduleList = $this->referenceFieldInfoList[$fieldName];
  346. $tableJoinMapping[$field->getTableName()] = 'INNER JOIN';
  347. foreach($moduleList as $module) {
  348. if($module == 'Users' && $baseModule != 'Users') {
  349. $tableJoinCondition[$fieldName]['vtiger_users'.$i] = $field->getTableName().
  350. ".".$field->getColumnName()." = vtiger_users".$i.".id";
  351. $tableJoinCondition[$fieldName]['vtiger_groups'.$i] = $field->getTableName().
  352. ".".$field->getColumnName()." = vtiger_groups".$i.".groupid";
  353. $tableJoinMapping['vtiger_users'.$i] = 'LEFT JOIN vtiger_users AS';
  354. $tableJoinMapping['vtiger_groups'.$i] = 'LEFT JOIN vtiger_groups AS';
  355. $i++;
  356. }
  357. }
  358. } elseif($field->getFieldDataType() == 'owner') {
  359. $tableList['vtiger_users'] = 'vtiger_users';
  360. $tableList['vtiger_groups'] = 'vtiger_groups';
  361. $tableJoinMapping['vtiger_users'] = 'LEFT JOIN';
  362. $tableJoinMapping['vtiger_groups'] = 'LEFT JOIN';
  363. }
  364. $tableList[$field->getTableName()] = $field->getTableName();
  365. $tableJoinMapping[$field->getTableName()] =
  366. $this->meta->getJoinClause($field->getTableName());
  367. }
  368. $baseTable = $this->meta->getEntityBaseTable();
  369. $moduleTableIndexList = $this->meta->getEntityTableIndexList();
  370. $baseTableIndex = $moduleTableIndexList[$baseTable];
  371. foreach ($this->whereFields as $fieldName) {
  372. if(empty($fieldName)) {
  373. continue;
  374. }
  375. $field = $moduleFields[$fieldName];
  376. if(empty($field)) {
  377. // not accessible field.
  378. continue;
  379. }
  380. $baseTable = $field->getTableName();
  381. // When a field is included in Where Clause, but not is Select Clause, and the field table is not base table,
  382. // The table will not be present in tablesList and hence needs to be added to the list.
  383. if(empty($tableList[$baseTable])) {
  384. $tableList[$baseTable] = $field->getTableName();
  385. $tableJoinMapping[$baseTable] = $this->meta->getJoinClause($field->getTableName());
  386. }
  387. if($field->getFieldDataType() == 'reference') {
  388. $moduleList = $this->referenceFieldInfoList[$fieldName];
  389. $tableJoinMapping[$field->getTableName()] = 'INNER JOIN';
  390. foreach($moduleList as $module) {
  391. $meta = $this->getMeta($module);
  392. $nameFields = $this->moduleNameFields[$module];
  393. $nameFieldList = explode(',',$nameFields);
  394. foreach ($nameFieldList as $index=>$column) {
  395. // for non admin user users module is inaccessible.
  396. // so need hard code the tablename.
  397. if($module == 'Users') {
  398. $instance = CRMEntity::getInstance($module);
  399. $referenceTable = $instance->table_name;
  400. $tableIndexList = $instance->tab_name_index;
  401. $referenceTableIndex = $tableIndexList[$referenceTable];
  402. } else {
  403. $referenceField = $meta->getFieldByColumnName($column);
  404. $referenceTable = $referenceField->getTableName();
  405. $tableIndexList = $meta->getEntityTableIndexList();
  406. $referenceTableIndex = $tableIndexList[$referenceTable];
  407. }
  408. if(isset($moduleTableIndexList[$referenceTable])) {
  409. $referenceTableName = "$referenceTable $referenceTable$fieldName";
  410. $referenceTable = "$referenceTable$fieldName";
  411. } else {
  412. $referenceTableName = $referenceTable;
  413. }
  414. //should always be left join for cases where we are checking for null
  415. //reference field values.
  416. $tableJoinMapping[$referenceTableName] = 'LEFT JOIN';
  417. $tableJoinCondition[$fieldName][$referenceTableName] = $baseTable.'.'.
  418. $field->getColumnName().' = '.$referenceTable.'.'.$referenceTableIndex;
  419. }
  420. }
  421. } elseif($field->getFieldDataType() == 'owner') {
  422. $tableList['vtiger_users'] = 'vtiger_users';
  423. $tableList['vtiger_groups'] = 'vtiger_groups';
  424. $tableJoinMapping['vtiger_users'] = 'LEFT JOIN';
  425. $tableJoinMapping['vtiger_groups'] = 'LEFT JOIN';
  426. } else {
  427. $tableList[$field->getTableName()] = $field->getTableName();
  428. $tableJoinMapping[$field->getTableName()] =
  429. $this->meta->getJoinClause($field->getTableName());
  430. }
  431. }
  432. $defaultTableList = $this->meta->getEntityDefaultTableList();
  433. foreach ($defaultTableList as $table) {
  434. if(!in_array($table, $tableList)) {
  435. $tableList[$table] = $table;
  436. $tableJoinMapping[$table] = 'INNER JOIN';
  437. }
  438. }
  439. $ownerFields = $this->meta->getOwnerFields();
  440. if (count($ownerFields) > 0) {
  441. $ownerField = $ownerFields[0];
  442. }
  443. $baseTable = $this->meta->getEntityBaseTable();
  444. $sql = " FROM $baseTable ";
  445. unset($tableList[$baseTable]);
  446. foreach ($defaultTableList as $tableName) {
  447. $sql .= " $tableJoinMapping[$tableName] $tableName ON $baseTable.".
  448. "$baseTableIndex = $tableName.$moduleTableIndexList[$tableName]";
  449. unset($tableList[$tableName]);
  450. }
  451. foreach ($tableList as $tableName) {
  452. if($tableName == 'vtiger_users') {
  453. $field = $moduleFields[$ownerField];
  454. $sql .= " $tableJoinMapping[$tableName] $tableName ON ".$field->getTableName().".".
  455. $field->getColumnName()." = $tableName.id";
  456. } elseif($tableName == 'vtiger_groups') {
  457. $field = $moduleFields[$ownerField];
  458. $sql .= " $tableJoinMapping[$tableName] $tableName ON ".$field->getTableName().".".
  459. $field->getColumnName()." = $tableName.groupid";
  460. } else {
  461. $sql .= " $tableJoinMapping[$tableName] $tableName ON $baseTable.".
  462. "$baseTableIndex = $tableName.$moduleTableIndexList[$tableName]";
  463. }
  464. }
  465. if( $this->meta->getTabName() == 'Documents') {
  466. $tableJoinCondition['folderid'] = array(
  467. 'vtiger_attachmentsfolder'=>"$baseTable.folderid = vtiger_attachmentsfolder.folderid"
  468. );
  469. $tableJoinMapping['vtiger_attachmentsfolder'] = 'INNER JOIN';
  470. }
  471. foreach ($tableJoinCondition as $fieldName=>$conditionInfo) {
  472. foreach ($conditionInfo as $tableName=>$condition) {
  473. if(!empty($tableList[$tableName])) {
  474. $tableNameAlias = $tableName.'2';
  475. $condition = str_replace($tableName, $tableNameAlias, $condition);
  476. } else {
  477. $tableNameAlias = '';
  478. }
  479. $sql .= " $tableJoinMapping[$tableName] $tableName $tableNameAlias ON $condition";
  480. }
  481. }
  482. foreach ($this->manyToManyRelatedModuleConditions as $conditionInfo) {
  483. $relatedModuleMeta = RelatedModuleMeta::getInstance($this->meta->getTabName(),
  484. $conditionInfo['relatedModule']);
  485. $relationInfo = $relatedModuleMeta->getRelationMeta();
  486. $relatedModule = $this->meta->getTabName();
  487. $sql .= ' INNER JOIN '.$relationInfo['relationTable']." ON ".
  488. $relationInfo['relationTable'].".$relationInfo[$relatedModule]=".
  489. "$baseTable.$baseTableIndex";
  490. }
  491. $sql .= $this->meta->getEntityAccessControlQuery();
  492. $this->fromClause = $sql;
  493. return $sql;
  494. }
  495. public function getWhereClause() {
  496. if(!empty($this->query) || !empty($this->whereClause)) {
  497. return $this->whereClause;
  498. }
  499. $deletedQuery = $this->meta->getEntityDeletedQuery();
  500. $sql = '';
  501. if(!empty($deletedQuery)) {
  502. $sql .= " WHERE $deletedQuery";
  503. }
  504. if($this->conditionInstanceCount > 0) {
  505. $sql .= ' AND ';
  506. } elseif(empty($deletedQuery)) {
  507. $sql .= ' WHERE ';
  508. }
  509. $moduleFieldList = $this->meta->getModuleFields();
  510. $baseTable = $this->meta->getEntityBaseTable();
  511. $moduleTableIndexList = $this->meta->getEntityTableIndexList();
  512. $baseTableIndex = $moduleTableIndexList[$baseTable];
  513. $groupSql = $this->groupInfo;
  514. $fieldSqlList = array();
  515. foreach ($this->conditionals as $index=>$conditionInfo) {
  516. $fieldName = $conditionInfo['name'];
  517. $field = $moduleFieldList[$fieldName];
  518. if(empty($field) || $conditionInfo['operator'] == 'None') {
  519. continue;
  520. }
  521. $fieldSql = '(';
  522. $fieldGlue = '';
  523. $valueSqlList = $this->getConditionValue($conditionInfo['value'],
  524. $conditionInfo['operator'], $field);
  525. if(!is_array($valueSqlList)) {
  526. $valueSqlList = array($valueSqlList);
  527. }
  528. foreach ($valueSqlList as $valueSql) {
  529. if (in_array($fieldName, $this->referenceFieldList)) {
  530. $moduleList = $this->referenceFieldInfoList[$fieldName];
  531. foreach($moduleList as $module) {
  532. $nameFields = $this->moduleNameFields[$module];
  533. $nameFieldList = explode(',',$nameFields);
  534. $meta = $this->getMeta($module);
  535. $columnList = array();
  536. foreach ($nameFieldList as $column) {
  537. if($module == 'Users') {
  538. $instance = CRMEntity::getInstance($module);
  539. $referenceTable = $instance->table_name;
  540. if(count($this->ownerFields) > 0 ||
  541. $this->getModule() == 'Quotes') {
  542. $referenceTable .= '2';
  543. }
  544. } else {
  545. $referenceField = $meta->getFieldByColumnName($column);
  546. $referenceTable = $referenceField->getTableName();
  547. }
  548. if(isset($moduleTableIndexList[$referenceTable])) {
  549. $referenceTable = "$referenceTable$fieldName";
  550. }
  551. $columnList[] = "$referenceTable.$column";
  552. }
  553. if(count($columnList) > 1) {
  554. $columnSql = getSqlForNameInDisplayFormat(array('first_name'=>$columnList[0],'last_name'=>$columnList[1]),'Users');
  555. } else {
  556. $columnSql = implode('', $columnList);
  557. }
  558. $fieldSql .= "$fieldGlue trim($columnSql) $valueSql";
  559. $fieldGlue = ' OR';
  560. }
  561. } elseif (in_array($fieldName, $this->ownerFields)) {
  562. $concatSql = getSqlForNameInDisplayFormat(array('first_name'=>"vtiger_users.first_name",'last_name'=>"vtiger_users.last_name"), 'Users');
  563. $fieldSql .= "$fieldGlue trim($concatSql) $valueSql or "."vtiger_groups.groupname $valueSql";
  564. } else {
  565. if($fieldName == 'birthday' && !$this->isRelativeSearchOperators(
  566. $conditionInfo['operator'])) {
  567. $fieldSql .= "$fieldGlue TO_CHAR(".$field->getTableName().'.'.
  568. $field->getColumnName().",'%m%d') ".$valueSql;
  569. } else {
  570. $fieldSql .= "$fieldGlue ".$field->getTableName().'.'.
  571. $field->getColumnName().' '.$valueSql;
  572. }
  573. }
  574. $fieldGlue = ' OR';
  575. }
  576. $fieldSql .= ')';
  577. $fieldSqlList[$index] = $fieldSql;
  578. }
  579. foreach ($this->manyToManyRelatedModuleConditions as $index=>$conditionInfo) {
  580. $relatedModuleMeta = RelatedModuleMeta::getInstance($this->meta->getTabName(),
  581. $conditionInfo['relatedModule']);
  582. $relationInfo = $relatedModuleMeta->getRelationMeta();
  583. $relatedModule = $this->meta->getTabName();
  584. $fieldSql = "(".$relationInfo['relationTable'].'.'.
  585. $relationInfo[$conditionInfo['column']].$conditionInfo['SQLOperator'].
  586. $conditionInfo['value'].")";
  587. $fieldSqlList[$index] = $fieldSql;
  588. }
  589. $groupSql = $this->makeGroupSqlReplacements($fieldSqlList, $groupSql);
  590. if($this->conditionInstanceCount > 0) {
  591. $this->conditionalWhere = $groupSql;
  592. $sql .= $groupSql;
  593. }
  594. $sql .= " AND $baseTable.$baseTableIndex > 0";
  595. $this->whereClause = $sql;
  596. return $sql;
  597. }
  598. /**
  599. *
  600. * @param mixed $value
  601. * @param String $operator
  602. * @param WebserviceField $field
  603. */
  604. private function getConditionValue($value, $operator, $field) {
  605. $operator = strtolower($operator);
  606. $db = PearDatabase::getInstance();
  607. if(is_string($value) && $this->ignoreComma == false) {
  608. $valueArray = explode(',' , $value);
  609. if ($field->getFieldDataType() == 'multipicklist' && in_array($operator, array('e', 'n'))) {
  610. $valueArray = getCombinations($valueArray);
  611. foreach ($valueArray as $key => $value) {
  612. $valueArray[$key] = str_replace(' ', ' |##| ', $value);
  613. }
  614. }
  615. } elseif(is_array($value)) {
  616. $valueArray = $value;
  617. } else{
  618. $valueArray = array($value);
  619. }
  620. $sql = array();
  621. if($operator == 'between' || $operator == 'bw') {
  622. if($field->getFieldName() == 'birthday') {
  623. $valueArray[0] = getValidDBInsertDateTimeValue($valueArray[0]);
  624. $valueArray[1] = getValidDBInsertDateTimeValue($valueArray[1]);
  625. $sql[] = "BETWEEN TO_CHAR(".$db->quote($valueArray[0]).", '%m%d') AND ".
  626. "To_CHAR(".$db->quote($valueArray[1]).", '%m%d')";
  627. } else {
  628. if($this->isDateType($field->getFieldDataType())) {
  629. $valueArray[0] = getValidDBInsertDateTimeValue($valueArray[0]);
  630. $valueArray[1] = getValidDBInsertDateTimeValue($valueArray[1]);
  631. }
  632. $sql[] = "BETWEEN ".$db->quote($valueArray[0])." AND ".
  633. $db->quote($valueArray[1]);
  634. }
  635. return $sql;
  636. }
  637. foreach ($valueArray as $value) {
  638. if(!$this->isStringType($field->getFieldDataType())) {
  639. $value = trim($value);
  640. }
  641. if ($operator == 'empty' || $operator == 'y') {
  642. $sql[] = sprintf("IS NULL OR %s = ''", $this->getSQLColumn($field->getFieldName()));
  643. continue;
  644. }
  645. if((strtolower(trim($value)) == 'null') ||
  646. (trim($value) == '' && !$this->isStringType($field->getFieldDataType())) &&
  647. ($operator == 'e' || $operator == 'n')) {
  648. if($operator == 'e'){
  649. $sql[] = "IS NULL";
  650. continue;
  651. }
  652. $sql[] = "IS NOT NULL";
  653. continue;
  654. } elseif($field->getFieldDataType() == 'boolean') {
  655. $value = strtolower($value);
  656. if ($value == 'yes') {
  657. $value = 1;
  658. } elseif($value == 'no') {
  659. $value = 0;
  660. }
  661. } elseif($this->isDateType($field->getFieldDataType())) {
  662. $value = getValidDBInsertDateTimeValue($value);
  663. }
  664. if($field->getFieldName() == 'birthday' && !$this->isRelativeSearchOperators(
  665. $operator)) {
  666. $value = "TO_CHAR(".$db->quote($value).", '%m%d')";
  667. } else {
  668. $value = $db->sql_escape_string($value);
  669. }
  670. if(trim($value) == '' && ($operator == 's' || $operator == 'ew' || $operator == 'c')
  671. && ($this->isStringType($field->getFieldDataType()) ||
  672. $field->getFieldDataType() == 'picklist' ||
  673. $field->getFieldDataType() == 'multipicklist')) {
  674. $sql[] = "LIKE ''";
  675. continue;
  676. }
  677. if(trim($value) == '' && ($operator == 'k') &&
  678. $this->isStringType($field->getFieldDataType())) {
  679. $sql[] = "NOT LIKE ''";
  680. continue;
  681. }
  682. switch($operator) {
  683. case 'e': $sqlOperator = "=";
  684. break;
  685. case 'n': $sqlOperator = "<>";
  686. break;
  687. case 's': $sqlOperator = "LIKE";
  688. $value = "$value%";
  689. break;
  690. case 'ew': $sqlOperator = "LIKE";
  691. $value = "%$value";
  692. break;
  693. case 'c': $sqlOperator = "LIKE";
  694. $value = "%$value%";
  695. break;
  696. case 'k': $sqlOperator = "NOT LIKE";
  697. $value = "%$value%";
  698. break;
  699. case 'l': $sqlOperator = "<";
  700. break;
  701. case 'g': $sqlOperator = ">";
  702. break;
  703. case 'm': $sqlOperator = "<=";
  704. break;
  705. case 'h': $sqlOperator = ">=";
  706. break;
  707. case 'a': $sqlOperator = ">";
  708. break;
  709. case 'b': $sqlOperator = "<";
  710. break;
  711. }
  712. if(!$this->isNumericType($field->getFieldDataType()) &&
  713. ($field->getFieldName() != 'birthday' || ($field->getFieldName() == 'birthday'
  714. && $this->isRelativeSearchOperators($operator)))){
  715. $value = "'$value'";
  716. }
  717. if($this->isNumericType($field->getFieldDataType()) && empty($value)) {
  718. $value = '0';
  719. }
  720. $sql[] = "$sqlOperator $value";
  721. }
  722. return $sql;
  723. }
  724. private function makeGroupSqlReplacements($fieldSqlList, $groupSql) {
  725. $pos = 0;
  726. $nextOffset = 0;
  727. foreach ($fieldSqlList as $index => $fieldSql) {
  728. $pos = strpos($groupSql, $index.'', $nextOffset);
  729. if($pos !== false) {
  730. $beforeStr = substr($groupSql,0,$pos);
  731. $afterStr = substr($groupSql, $pos + strlen($index));
  732. $nextOffset = strlen($beforeStr.$fieldSql);
  733. $groupSql = $beforeStr.$fieldSql.$afterStr;
  734. }
  735. }
  736. return $groupSql;
  737. }
  738. private function isRelativeSearchOperators($operator) {
  739. $nonDaySearchOperators = array('l','g','m','h');
  740. return in_array($operator, $nonDaySearchOperators);
  741. }
  742. private function isNumericType($type) {
  743. return ($type == 'integer' || $type == 'double' || $type == 'currency');
  744. }
  745. private function isStringType($type) {
  746. return ($type == 'string' || $type == 'text' || $type == 'email' || $type == 'reference');
  747. }
  748. private function isDateType($type) {
  749. return ($type == 'date' || $type == 'datetime');
  750. }
  751. public function fixDateTimeValue($name, $value, $first = true) {
  752. $moduleFields = $this->meta->getModuleFields();
  753. $field = $moduleFields[$name];
  754. $type = $field ? $field->getFieldDataType() : false;
  755. if($type == 'datetime') {
  756. if(strrpos($value, ' ') === false) {
  757. if($first) {
  758. return $value.' 00:00:00';
  759. }else{
  760. return $value.' 23:59:59';
  761. }
  762. }
  763. }
  764. return $value;
  765. }
  766. public function addCondition($fieldname,$value,$operator,$glue= null,$newGroup = false,
  767. $newGroupType = null, $ignoreComma = false) {
  768. $conditionNumber = $this->conditionInstanceCount++;
  769. if($glue != null && $conditionNumber > 0)
  770. $this->addConditionGlue ($glue);
  771. $this->groupInfo .= "$conditionNumber ";
  772. $this->whereFields[] = $fieldname;
  773. $this->ignoreComma = $ignoreComma;
  774. $this->reset();
  775. $this->conditionals[$conditionNumber] = $this->getConditionalArray($fieldname,
  776. $value, $operator);
  777. }
  778. public function addRelatedModuleCondition($relatedModule,$column, $value, $SQLOperator) {
  779. $conditionNumber = $this->conditionInstanceCount++;
  780. $this->groupInfo .= "$conditionNumber ";
  781. $this->manyToManyRelatedModuleConditions[$conditionNumber] = array('relatedModule'=>
  782. $relatedModule,'column'=>$column,'value'=>$value,'SQLOperator'=>$SQLOperator);
  783. }
  784. private function getConditionalArray($fieldname,$value,$operator) {
  785. if(is_string($value)) {
  786. $value = trim($value);
  787. } elseif(is_array($value)) {
  788. $value = array_map(trim, $value);
  789. }
  790. return array('name'=>$fieldname,'value'=>$value,'operator'=>$operator);
  791. }
  792. public function startGroup($groupType) {
  793. $this->groupInfo .= " $groupType (";
  794. }
  795. public function endGroup() {
  796. $this->groupInfo .= ')';
  797. }
  798. public function addConditionGlue($glue) {
  799. $this->groupInfo .= " $glue ";
  800. }
  801. public function addUserSearchConditions($input) {
  802. global $log,$default_charset;
  803. if($input['searchtype']=='advance') {
  804. $json = new Zend_Json();
  805. $advft_criteria = $_REQUEST['advft_criteria'];
  806. if(!empty($advft_criteria)) $advft_criteria = $json->decode($advft_criteria);
  807. $advft_criteria_groups = $_REQUEST['advft_criteria_groups'];
  808. if(!empty($advft_criteria_groups)) $advft_criteria_groups = $json->decode($advft_criteria_groups);
  809. if(empty($advft_criteria) || count($advft_criteria) <= 0) {
  810. return ;
  811. }
  812. $advfilterlist = getAdvancedSearchCriteriaList($advft_criteria, $advft_criteria_groups, $this->getModule());
  813. if(empty($advfilterlist) || count($advfilterlist) <= 0) {
  814. return ;
  815. }
  816. if($this->conditionInstanceCount > 0) {
  817. $this->startGroup(self::$AND);
  818. } else {
  819. $this->startGroup('');
  820. }
  821. foreach ($advfilterlist as $groupindex=>$groupcolumns) {
  822. $filtercolumns = $groupcolumns['columns'];
  823. if(count($filtercolumns) > 0) {
  824. $this->startGroup('');
  825. foreach ($filtercolumns as $index=>$filter) {
  826. $name = explode(':',$filter['columnname']);
  827. if(empty($name[2]) && $name[1] == 'crmid' && $name[0] == 'vtiger_crmentity') {
  828. $name = $this->getSQLColumn('id');
  829. } else {
  830. $name = $name[2];
  831. }
  832. $this->addCondition($name, $filter['value'], $filter['comparator']);
  833. $columncondition = $filter['column_condition'];
  834. if(!empty($columncondition)) {
  835. $this->addConditionGlue($columncondition);
  836. }
  837. }
  838. $this->endGroup();
  839. $groupConditionGlue = $groupcolumns['condition'];
  840. if(!empty($groupConditionGlue))
  841. $this->addConditionGlue($groupConditionGlue);
  842. }
  843. }
  844. $this->endGroup();
  845. } elseif($input['type']=='dbrd') {
  846. if($this->conditionInstanceCount > 0) {
  847. $this->startGroup(self::$AND);
  848. } else {
  849. $this->startGroup('');
  850. }
  851. $allConditionsList = $this->getDashBoardConditionList();
  852. $conditionList = $allConditionsList['conditions'];
  853. $relatedConditionList = $allConditionsList['relatedConditions'];
  854. $noOfConditions = count($conditionList);
  855. $noOfRelatedConditions = count($relatedConditionList);
  856. foreach ($conditionList as $index=>$conditionInfo) {
  857. $this->addCondition($conditionInfo['fieldname'], $conditionInfo['value'],
  858. $conditionInfo['operator']);
  859. if($index < $noOfConditions - 1 || $noOfRelatedConditions > 0) {
  860. $this->addConditionGlue(self::$AND);
  861. }
  862. }
  863. foreach ($relatedConditionList as $index => $conditionInfo) {
  864. $this->addRelatedModuleCondition($conditionInfo['relatedModule'],
  865. $conditionInfo['conditionModule'], $conditionInfo['finalValue'],
  866. $conditionInfo['SQLOperator']);
  867. if($index < $noOfRelatedConditions - 1) {
  868. $this->addConditionGlue(self::$AND);
  869. }
  870. }
  871. $this->endGroup();
  872. } else {
  873. if(isset($input['search_field']) && $input['search_field'] !="") {
  874. $fieldName=vtlib_purify($input['search_field']);
  875. } else {
  876. return ;
  877. }
  878. if($this->conditionInstanceCount > 0) {
  879. $this->startGroup(self::$AND);
  880. } else {
  881. $this->startGroup('');
  882. }
  883. $moduleFields = $this->meta->getModuleFields();
  884. $field = $moduleFields[$fieldName];
  885. $type = $field->getFieldDataType();
  886. if(isset($input['search_text']) && $input['search_text']!="") {
  887. // search other characters like "|, ?, ?" by jagi
  888. $value = $input['search_text'];
  889. $stringConvert = function_exists(iconv) ? @iconv("UTF-8",$default_charset,$value)
  890. : $value;
  891. if(!$this->isStringType($type)) {
  892. $value=trim($stringConvert);
  893. }
  894. if($type == 'picklist') {
  895. global $mod_strings;
  896. // Get all the keys for the for the Picklist value
  897. $mod_keys = array_keys($mod_strings, $value);
  898. if(sizeof($mod_keys) >= 1) {
  899. // Iterate on the keys, to get the first key which doesn't start with LBL_ (assuming it is not used in PickList)
  900. foreach($mod_keys as $mod_idx=>$mod_key) {
  901. $stridx = strpos($mod_key, 'LBL_');
  902. // Use strict type comparision, refer strpos for more details
  903. if ($stridx !== 0) {
  904. $value = $mod_key;
  905. break;
  906. }
  907. }
  908. }
  909. }
  910. if($type == 'currency') {
  911. // Some of the currency fields like Unit Price, Total, Sub-total etc of Inventory modules, do not need currency conversion
  912. if($field->getUIType() == '72') {
  913. $value = CurrencyField::convertToDBFormat($value, null, true);
  914. } else {
  915. $currencyField = new CurrencyField($value);
  916. $value = $currencyField->getDBInsertedValue();
  917. }
  918. }
  919. }
  920. if(!empty($input['operator'])) {
  921. $operator = $input['operator'];
  922. } elseif(trim(strtolower($value)) == 'null'){
  923. $operator = 'e';
  924. } else {
  925. if(!$this->isNumericType($type) && !$this->isDateType($type)) {
  926. $operator = 'c';
  927. } else {
  928. $operator = 'h';
  929. }
  930. }
  931. $this->addCondition($fieldName, $value, $operator);
  932. $this->endGroup();
  933. }
  934. }
  935. public function getDashBoardConditionList() {
  936. if(isset($_REQUEST['leadsource'])) {
  937. $leadSource = $_REQUEST['leadsource'];
  938. }
  939. if(isset($_REQUEST['date_closed'])) {
  940. $dateClosed = $_REQUEST['date_closed'];
  941. }
  942. if(isset($_REQUEST['sales_stage'])) {
  943. $salesStage = $_REQUEST['sales_stage'];
  944. }
  945. if(isset($_REQUEST['closingdate_start'])) {
  946. $dateClosedStart = $_REQUEST['closingdate_start'];
  947. }
  948. if(isset($_REQUEST['closingdate_end'])) {
  949. $dateClosedEnd = $_REQUEST['closingdate_end'];
  950. }
  951. if(isset($_REQUEST['owner'])) {
  952. $owner = vtlib_purify($_REQUEST['owner']);
  953. }
  954. if(isset($_REQUEST['campaignid'])) {
  955. $campaignId = vtlib_purify($_REQUEST['campaignid']);
  956. }
  957. if(isset($_REQUEST['quoteid'])) {
  958. $quoteId = vtlib_purify($_REQUEST['quoteid']);
  959. }
  960. if(isset($_REQUEST['invoiceid'])) {
  961. $invoiceId = vtlib_purify($_REQUEST['invoiceid']);
  962. }
  963. if(isset($_REQUEST['purchaseorderid'])) {
  964. $purchaseOrderId = vtlib_purify($_REQUEST['purchaseorderid']);
  965. }
  966. $conditionList = array();
  967. if(!empty($dateClosedStart) && !empty($dateClosedEnd)) {
  968. $conditionList[] = array('fieldname'=>'closingdate', 'value'=>$dateClosedStart,
  969. 'operator'=>'h');
  970. $conditionList[] = array('fieldname'=>'closingdate', 'value'=>$dateClosedEnd,
  971. 'operator'=>'m');
  972. }
  973. if(!empty($salesStage)) {
  974. if($salesStage == 'Other') {
  975. $conditionList[] = array('fieldname'=>'sales_stage', 'value'=>'Closed Won',
  976. 'operator'=>'n');
  977. $conditionList[] = array('fieldname'=>'sales_stage', 'value'=>'Closed Lost',
  978. 'operator'=>'n');
  979. } else {
  980. $conditionList[] = array('fieldname'=>'sales_stage', 'value'=> $salesStage,
  981. 'operator'=>'e');
  982. }
  983. }
  984. if(!empty($leadSource)) {
  985. $conditionList[] = array('fieldname'=>'leadsource', 'value'=>$leadSource,
  986. 'operator'=>'e');
  987. }
  988. if(!empty($dateClosed)) {
  989. $conditionList[] = array('fieldname'=>'closingdate', 'value'=>$dateClosed,
  990. 'operator'=>'h');
  991. }
  992. if(!empty($owner)) {
  993. $conditionList[] = array('fieldname'=>'assigned_user_id', 'value'=>$owner,
  994. 'operator'=>'e');
  995. }
  996. $relatedConditionList = array();
  997. if(!empty($campaignId)) {
  998. $relatedConditionList[] = array('relatedModule'=>'Campaigns','conditionModule'=>
  999. 'Campaigns','finalValue'=>$campaignId, 'SQLOperator'=>'=');
  1000. }
  1001. if(!empty($quoteId)) {
  1002. $relatedConditionList[] = array('relatedModule'=>'Quotes','conditionModule'=>
  1003. 'Quotes','finalValue'=>$quoteId, 'SQLOperator'=>'=');
  1004. }
  1005. if(!empty($invoiceId)) {
  1006. $relatedConditionList[] = array('relatedModule'=>'Invoice','conditionModule'=>
  1007. 'Invoice','finalValue'=>$invoiceId, 'SQLOperator'=>'=');
  1008. }
  1009. if(!empty($purchaseOrderId)) {
  1010. $relatedConditionList[] = array('relatedModule'=>'PurchaseOrder','conditionModule'=>
  1011. 'PurchaseOrder','finalValue'=>$purchaseOrderId, 'SQLOperator'=>'=');
  1012. }
  1013. return array('conditions'=>$conditionList,'relatedConditions'=>$relatedConditionList);
  1014. }
  1015. public function initForGlobalSearchByType($type, $value, $operator='s') {
  1016. $fieldList = $this->meta->getFieldNameListByType($type);
  1017. if($this->conditionInstanceCount <= 0) {
  1018. $this->startGroup('');
  1019. } else {
  1020. $this->startGroup(self::$AND);
  1021. }
  1022. $nameFieldList = explode(',',$this->getModuleNameFields($this->module));
  1023. foreach ($nameFieldList as $nameList) {
  1024. $field = $this->meta->getFieldByColumnName($nameList);
  1025. $this->fields[] = $field->getFieldName();
  1026. }
  1027. foreach ($fieldList as $index => $field) {
  1028. $fieldName = $this->meta->getFieldByColumnName($field);
  1029. $this->fields[] = $fieldName->getFieldName();
  1030. if($index > 0) {
  1031. $this->addConditionGlue(self::$OR);
  1032. }
  1033. $this->addCondition($fieldName->getFieldName(), $value, $operator);
  1034. }
  1035. $this->endGroup();
  1036. if(!in_array('id', $this->fields)) {
  1037. $this->fields[] = 'id';
  1038. }
  1039. }
  1040. }
  1041. ?>