PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/app/protected/core/adapters/DynamicSearchDataProviderMetadataAdapter.php

https://bitbucket.org/zurmo/zurmo/
PHP | 194 lines | 125 code | 13 blank | 56 comment | 6 complexity | 4f868b6e9385a86fa2283533d604be49 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, GPL-2.0, LGPL-3.0, LGPL-2.1, BSD-2-Clause
  1. <?php
  2. /*********************************************************************************
  3. * Zurmo is a customer relationship management program developed by
  4. * Zurmo, Inc. Copyright (C) 2015 Zurmo Inc.
  5. *
  6. * Zurmo is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License version 3 as published by the
  8. * Free Software Foundation with the addition of the following permission added
  9. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  10. * IN WHICH THE COPYRIGHT IS OWNED BY ZURMO, ZURMO DISCLAIMS THE WARRANTY
  11. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  12. *
  13. * Zurmo is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  15. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License along with
  19. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  20. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21. * 02110-1301 USA.
  22. *
  23. * You can contact Zurmo, Inc. with a mailing address at 27 North Wacker Drive
  24. * Suite 370 Chicago, IL 60606. or at email address contact@zurmo.com.
  25. *
  26. * The interactive user interfaces in original and modified versions
  27. * of this program must display Appropriate Legal Notices, as required under
  28. * Section 5 of the GNU Affero General Public License version 3.
  29. *
  30. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  31. * these Appropriate Legal Notices must retain the display of the Zurmo
  32. * logo and Zurmo copyright notice. If the display of the logo is not reasonably
  33. * feasible for technical reasons, the Appropriate Legal Notices must display the words
  34. * "Copyright Zurmo Inc. 2015. All rights reserved".
  35. ********************************************************************************/
  36. /**
  37. * Adapter class to manipulate dynamic search information for metadata.
  38. */
  39. class DynamicSearchDataProviderMetadataAdapter
  40. {
  41. const NOT_USED_STRUCTURE_POSITION = 'notUsed';
  42. protected $metadata;
  43. protected $model;
  44. protected $userId;
  45. protected $sanitizedDynamicSearchAttributes;
  46. protected $dynamicStructure;
  47. public function __construct(array $metadata, SearchForm $model, $userId, $sanitizedDynamicSearchAttributes, $dynamicStructure)
  48. {
  49. assert('array($metadata)');
  50. assert('isset($metadata["clauses"])');
  51. assert('isset($metadata["structure"])');
  52. assert('is_int($userId)');
  53. assert('is_array($sanitizedDynamicSearchAttributes) && count($sanitizedDynamicSearchAttributes) > 0');
  54. assert('is_string($dynamicStructure)');
  55. $this->metadata = $metadata;
  56. $this->model = $model;
  57. $this->userId = $userId;
  58. $this->sanitizedDynamicSearchAttributes = $sanitizedDynamicSearchAttributes;
  59. $this->dynamicStructure = $dynamicStructure;
  60. }
  61. /**
  62. * Creates where clauses and adds structure information
  63. * to existing DataProvider metadata.
  64. */
  65. public function getAdaptedDataProviderMetadata()
  66. {
  67. $metadata = $this->metadata;
  68. $clauseCount = count($metadata['clauses']);
  69. $structure = $this->dynamicStructure;
  70. $correctlyPositionedClauses = array();
  71. $this->processData($this->sanitizedDynamicSearchAttributes, $clauseCount, $correctlyPositionedClauses, $metadata);
  72. krsort($correctlyPositionedClauses);
  73. //Resolve any unused clauses first before replacing real clauses.
  74. foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
  75. {
  76. if ($correctlyPositionedClauseData[$position] == self::NOT_USED_STRUCTURE_POSITION)
  77. {
  78. $structure = strtr(strtolower($structure), $correctlyPositionedClauseData);
  79. unset($correctlyPositionedClauses[$position]);
  80. }
  81. }
  82. //add mapping to alpha code and back again. This avoids mismatches with over 10 clauses for example.
  83. $alphaToNumberMap = array();
  84. foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
  85. {
  86. $alphaCode = static::getAlphaCodeByInteger((int)$position);
  87. $correctlyPositionedClauses[$position][$position] = $alphaCode;
  88. $alphaToNumberMap[] = array($alphaCode => $correctlyPositionedClauseData[$position]);
  89. }
  90. //Replace clauses still used.
  91. foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
  92. {
  93. $structure = strtr(strtolower($structure), $correctlyPositionedClauseData);
  94. }
  95. foreach ($alphaToNumberMap as $alphaCodeToNumber)
  96. {
  97. $structure = strtr(strtolower($structure), $alphaCodeToNumber);
  98. }
  99. //Now resolve and remove any unused clauses and nearby operators.
  100. $structure = str_ireplace(' or ' . self::NOT_USED_STRUCTURE_POSITION, '', $structure);
  101. $structure = str_ireplace(' and ' . self::NOT_USED_STRUCTURE_POSITION, '', $structure);
  102. $structure = str_ireplace('(' . self::NOT_USED_STRUCTURE_POSITION . ' or ', '(', $structure);
  103. $structure = str_ireplace('(' . self::NOT_USED_STRUCTURE_POSITION . ' and ', '(', $structure);
  104. if (empty($metadata['structure']))
  105. {
  106. $metadata['structure'] = '(' . $structure . ')';
  107. }
  108. else
  109. {
  110. $metadata['structure'] = '(' . $metadata['structure'] . ') and (' . $structure . ')';
  111. }
  112. return $metadata;
  113. }
  114. /**
  115. * @returns 6 digit alpha code that can be swapped later for the proper structure.
  116. * @param Integer $integer
  117. */
  118. protected static function getAlphaCodeByInteger($integer)
  119. {
  120. assert('is_int($integer)');
  121. $alphaCode = DynamicSearchDataProviderMetadataAdapter::numberToLetter($integer);
  122. return str_pad($alphaCode, 6, "z");
  123. }
  124. protected function processData($searchAttributes, & $clauseCount, & $correctlyPositionedClauses, & $metadata)
  125. {
  126. foreach ($searchAttributes as $position => $searchAttribute)
  127. {
  128. $structurePosition = self::resolveUnsetAndGetSructurePosition($searchAttribute);
  129. self::resolveUnsetAttributeIndexOrDerivedType($searchAttribute);
  130. $metadataAdapter = new SearchDataProviderMetadataAdapter(
  131. $this->model,
  132. $this->userId,
  133. $searchAttribute
  134. );
  135. $searchItemMetadata = $metadataAdapter->getAdaptedMetadata(true, ($clauseCount + 1));
  136. if (count($searchItemMetadata['clauses']) > 0)
  137. {
  138. $metadata['clauses'] = $metadata['clauses'] + $searchItemMetadata['clauses'];
  139. $clauseCount = $clauseCount + count($searchItemMetadata['clauses']);
  140. $correctlyPositionedClauses
  141. [$structurePosition][$structurePosition] = $searchItemMetadata['structure'];
  142. }
  143. else
  144. {
  145. $correctlyPositionedClauses
  146. [$structurePosition][$structurePosition] = self::NOT_USED_STRUCTURE_POSITION;
  147. }
  148. }
  149. }
  150. protected static function resolveUnsetAndGetSructurePosition(& $searchAttribute)
  151. {
  152. if (isset($searchAttribute['structurePosition']))
  153. {
  154. $structurePosition = $searchAttribute['structurePosition'];
  155. unset($searchAttribute['structurePosition']);
  156. return $structurePosition;
  157. }
  158. }
  159. protected static function resolveUnsetAttributeIndexOrDerivedType(& $searchAttribute)
  160. {
  161. if (isset($searchAttribute['attributeIndexOrDerivedType']))
  162. {
  163. unset($searchAttribute['attributeIndexOrDerivedType']);
  164. }
  165. }
  166. /**
  167. * Public for testing purposes
  168. * Takes a number and converts it to a-z,aa-zz,aaa-zzz, etc with uppercase option
  169. * @param int number to convert
  170. * @param bool upper case the letter on return?
  171. * @return string letters from number input
  172. */
  173. public static function numberToLetter($num, $uppercase = false)
  174. {
  175. $num -= 1;
  176. $letter = chr(($num % 26) + 97);
  177. $letter .= (floor($num / 26) > 0) ? str_repeat($letter, floor($num / 26)) : '';
  178. return ($uppercase ? strtoupper($letter) : $letter);
  179. }
  180. }
  181. ?>