PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/kwangchin/zurmo
PHP | 184 lines | 125 code | 13 blank | 46 comment | 6 complexity | 0233dc325e1a0b468676919db9810af7 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, GPL-2.0, GPL-3.0, BSD-3-Clause, LGPL-3.0
  1. <?php
  2. /*********************************************************************************
  3. * Zurmo is a customer relationship management program developed by
  4. * Zurmo, Inc. Copyright (C) 2012 Zurmo Inc.
  5. *
  6. * Zurmo is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU 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 General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU 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 113 McHenry Road Suite 207,
  24. * Buffalo Grove, IL 60089, USA. or at email address contact@zurmo.com.
  25. ********************************************************************************/
  26. /**
  27. * Adapter class to manipulate dynamic search information for metadata.
  28. */
  29. class DynamicSearchDataProviderMetadataAdapter
  30. {
  31. const NOT_USED_STRUCTURE_POSITION = 'notUsed';
  32. protected $metadata;
  33. protected $model;
  34. protected $userId;
  35. protected $sanitizedDynamicSearchAttributes;
  36. protected $dynamicStructure;
  37. public function __construct(array $metadata, SearchForm $model, $userId, $sanitizedDynamicSearchAttributes, $dynamicStructure)
  38. {
  39. assert('array($metadata)');
  40. assert('isset($metadata["clauses"])');
  41. assert('isset($metadata["structure"])');
  42. assert('is_int($userId)');
  43. assert('is_array($sanitizedDynamicSearchAttributes) && count($sanitizedDynamicSearchAttributes) > 0');
  44. assert('is_string($dynamicStructure)');
  45. $this->metadata = $metadata;
  46. $this->model = $model;
  47. $this->userId = $userId;
  48. $this->sanitizedDynamicSearchAttributes = $sanitizedDynamicSearchAttributes;
  49. $this->dynamicStructure = $dynamicStructure;
  50. }
  51. /**
  52. * Creates where clauses and adds structure information
  53. * to existing DataProvider metadata.
  54. */
  55. public function getAdaptedDataProviderMetadata()
  56. {
  57. $metadata = $this->metadata;
  58. $clauseCount = count($metadata['clauses']);
  59. $structure = $this->dynamicStructure;
  60. $correctlyPositionedClauses = array();
  61. $this->processData($this->sanitizedDynamicSearchAttributes, $clauseCount, $correctlyPositionedClauses, $metadata);
  62. krsort($correctlyPositionedClauses);
  63. //Resolve any unused clauses first before replacing real clauses.
  64. foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
  65. {
  66. if ($correctlyPositionedClauseData[$position] == self::NOT_USED_STRUCTURE_POSITION)
  67. {
  68. $structure = strtr(strtolower($structure), $correctlyPositionedClauseData);
  69. unset($correctlyPositionedClauses[$position]);
  70. }
  71. }
  72. //add mapping to alpha code and back again. This avoids mismatches with over 10 clauses for example.
  73. $alphaToNumberMap = array();
  74. foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
  75. {
  76. $alphaCode = static::getAlphaCodeByInteger((int)$correctlyPositionedClauseData[$position]);
  77. $correctlyPositionedClauses[$position][$position] = $alphaCode;
  78. $alphaToNumberMap[] = array($alphaCode => $correctlyPositionedClauseData[$position]);
  79. }
  80. //Replace clauses still used.
  81. foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
  82. {
  83. $structure = strtr(strtolower($structure), $correctlyPositionedClauseData);
  84. }
  85. foreach ($alphaToNumberMap as $alphaCodeToNumber)
  86. {
  87. $structure = strtr(strtolower($structure), $alphaCodeToNumber);
  88. }
  89. //Now resolve and remove any unused clauses and nearby operators.
  90. $structure = str_ireplace(' or ' . self::NOT_USED_STRUCTURE_POSITION, '', $structure);
  91. $structure = str_ireplace(' and ' . self::NOT_USED_STRUCTURE_POSITION, '', $structure);
  92. $structure = str_ireplace('(' . self::NOT_USED_STRUCTURE_POSITION . ' or ', '(', $structure);
  93. $structure = str_ireplace('(' . self::NOT_USED_STRUCTURE_POSITION . ' and ', '(', $structure);
  94. if (empty($metadata['structure']))
  95. {
  96. $metadata['structure'] = '(' . $structure . ')';
  97. }
  98. else
  99. {
  100. $metadata['structure'] = '(' . $metadata['structure'] . ') and (' . $structure . ')';
  101. }
  102. return $metadata;
  103. }
  104. /**
  105. * @returns 6 digit alpha code that can be swapped later for the proper structure.
  106. * @param Integer $integer
  107. */
  108. protected static function getAlphaCodeByInteger($integer)
  109. {
  110. assert('is_int($integer)');
  111. $alphaCode = DynamicSearchDataProviderMetadataAdapter::numberToLetter($integer);
  112. return str_pad($alphaCode, 6, "z");
  113. }
  114. protected function processData($searchAttributes, & $clauseCount, & $correctlyPositionedClauses, & $metadata)
  115. {
  116. foreach ($searchAttributes as $position => $searchAttribute)
  117. {
  118. $structurePosition = self::resolveUnsetAndGetSructurePosition($searchAttribute);
  119. self::resolveUnsetAttributeIndexOrDerivedType($searchAttribute);
  120. $metadataAdapter = new SearchDataProviderMetadataAdapter(
  121. $this->model,
  122. $this->userId,
  123. $searchAttribute
  124. );
  125. $searchItemMetadata = $metadataAdapter->getAdaptedMetadata(true, ($clauseCount + 1));
  126. if (count($searchItemMetadata['clauses']) > 0)
  127. {
  128. $metadata['clauses'] = $metadata['clauses'] + $searchItemMetadata['clauses'];
  129. $clauseCount = $clauseCount + count($searchItemMetadata['clauses']);
  130. $correctlyPositionedClauses
  131. [$structurePosition][$structurePosition] = $searchItemMetadata['structure'];
  132. }
  133. else
  134. {
  135. $correctlyPositionedClauses
  136. [$structurePosition][$structurePosition] = self::NOT_USED_STRUCTURE_POSITION;
  137. }
  138. }
  139. }
  140. protected static function resolveUnsetAndGetSructurePosition(& $searchAttribute)
  141. {
  142. if (isset($searchAttribute['structurePosition']))
  143. {
  144. $structurePosition = $searchAttribute['structurePosition'];
  145. unset($searchAttribute['structurePosition']);
  146. return $structurePosition;
  147. }
  148. }
  149. protected static function resolveUnsetAttributeIndexOrDerivedType(& $searchAttribute)
  150. {
  151. if (isset($searchAttribute['attributeIndexOrDerivedType']))
  152. {
  153. unset($searchAttribute['attributeIndexOrDerivedType']);
  154. }
  155. }
  156. /**
  157. * Public for testing purposes
  158. * Takes a number and converts it to a-z,aa-zz,aaa-zzz, etc with uppercase option
  159. * @param int number to convert
  160. * @param bool upper case the letter on return?
  161. * @return string letters from number input
  162. */
  163. public static function numberToLetter($num, $uppercase = false)
  164. {
  165. $num -= 1;
  166. $letter = chr(($num % 26) + 97);
  167. $letter .= (floor($num / 26) > 0) ? str_repeat($letter, floor($num / 26)) : '';
  168. return ($uppercase ? strtoupper($letter) : $letter);
  169. }
  170. }
  171. ?>