PageRenderTime 164ms CodeModel.GetById 80ms app.highlight 9ms RepoModel.GetById 72ms app.codeStats 0ms

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

https://bitbucket.org/rkcbabu/zurmo
PHP | 184 lines | 125 code | 13 blank | 46 comment | 6 complexity | 0233dc325e1a0b468676919db9810af7 MD5 | raw file
  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    /**
 28     * Adapter class to manipulate dynamic search information for metadata.
 29     */
 30    class DynamicSearchDataProviderMetadataAdapter
 31    {
 32        const NOT_USED_STRUCTURE_POSITION = 'notUsed';
 33
 34        protected $metadata;
 35
 36        protected $model;
 37
 38        protected $userId;
 39
 40        protected $sanitizedDynamicSearchAttributes;
 41
 42        protected $dynamicStructure;
 43
 44        public function __construct(array $metadata, SearchForm $model, $userId, $sanitizedDynamicSearchAttributes, $dynamicStructure)
 45        {
 46            assert('array($metadata)');
 47            assert('isset($metadata["clauses"])');
 48            assert('isset($metadata["structure"])');
 49            assert('is_int($userId)');
 50            assert('is_array($sanitizedDynamicSearchAttributes) && count($sanitizedDynamicSearchAttributes)  > 0');
 51            assert('is_string($dynamicStructure)');
 52            $this->metadata                         = $metadata;
 53            $this->model                            = $model;
 54            $this->userId                           = $userId;
 55            $this->sanitizedDynamicSearchAttributes = $sanitizedDynamicSearchAttributes;
 56            $this->dynamicStructure                 = $dynamicStructure;
 57        }
 58
 59        /**
 60         * Creates where clauses and adds structure information
 61         * to existing DataProvider metadata.
 62         */
 63        public function getAdaptedDataProviderMetadata()
 64        {
 65            $metadata                   = $this->metadata;
 66            $clauseCount                = count($metadata['clauses']);
 67            $structure                  = $this->dynamicStructure;
 68            $correctlyPositionedClauses = array();
 69            $this->processData($this->sanitizedDynamicSearchAttributes, $clauseCount, $correctlyPositionedClauses, $metadata);
 70            krsort($correctlyPositionedClauses);
 71            //Resolve any unused clauses first before replacing real clauses.
 72            foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
 73            {
 74                if ($correctlyPositionedClauseData[$position] == self::NOT_USED_STRUCTURE_POSITION)
 75                {
 76                    $structure = strtr(strtolower($structure), $correctlyPositionedClauseData);
 77                    unset($correctlyPositionedClauses[$position]);
 78                }
 79            }
 80            //add mapping to alpha code and back again.  This avoids mismatches with over 10 clauses for example.
 81            $alphaToNumberMap = array();
 82            foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
 83            {
 84                $alphaCode = static::getAlphaCodeByInteger((int)$correctlyPositionedClauseData[$position]);
 85                $correctlyPositionedClauses[$position][$position] = $alphaCode;
 86                $alphaToNumberMap[] = array($alphaCode => $correctlyPositionedClauseData[$position]);
 87            }
 88            //Replace clauses still used.
 89            foreach ($correctlyPositionedClauses as $position => $correctlyPositionedClauseData)
 90            {
 91                $structure = strtr(strtolower($structure), $correctlyPositionedClauseData);
 92            }
 93            foreach ($alphaToNumberMap as $alphaCodeToNumber)
 94            {
 95                $structure = strtr(strtolower($structure), $alphaCodeToNumber);
 96            }
 97            //Now resolve and remove any unused clauses and nearby operators.
 98            $structure = str_ireplace(' or '  . self::NOT_USED_STRUCTURE_POSITION,           '', $structure);
 99            $structure = str_ireplace(' and ' . self::NOT_USED_STRUCTURE_POSITION,           '', $structure);
100            $structure = str_ireplace('('     . self::NOT_USED_STRUCTURE_POSITION . ' or ',  '(', $structure);
101            $structure = str_ireplace('('     . self::NOT_USED_STRUCTURE_POSITION . ' and ', '(', $structure);
102            if (empty($metadata['structure']))
103            {
104                $metadata['structure'] = '(' . $structure . ')';
105            }
106            else
107            {
108                $metadata['structure'] = '(' . $metadata['structure'] . ') and (' . $structure . ')';
109            }
110            return $metadata;
111        }
112
113        /**
114         * @returns 6 digit alpha code that can be swapped later for the proper structure.
115         * @param Integer $integer
116         */
117        protected static function getAlphaCodeByInteger($integer)
118        {
119            assert('is_int($integer)');
120            $alphaCode = DynamicSearchDataProviderMetadataAdapter::numberToLetter($integer);
121            return str_pad($alphaCode, 6, "z");
122        }
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
151        protected static function resolveUnsetAndGetSructurePosition(& $searchAttribute)
152        {
153            if (isset($searchAttribute['structurePosition']))
154            {
155                $structurePosition = $searchAttribute['structurePosition'];
156                unset($searchAttribute['structurePosition']);
157                return $structurePosition;
158            }
159        }
160
161        protected static function resolveUnsetAttributeIndexOrDerivedType(& $searchAttribute)
162        {
163            if (isset($searchAttribute['attributeIndexOrDerivedType']))
164            {
165                unset($searchAttribute['attributeIndexOrDerivedType']);
166            }
167        }
168
169        /**
170         * Public for testing purposes
171         * Takes a number and converts it to a-z,aa-zz,aaa-zzz, etc with uppercase option
172         * @param	int	number to convert
173         * @param	bool	upper case the letter on return?
174         * @return	string	letters from number input
175         */
176        public static function numberToLetter($num, $uppercase = false)
177        {
178            $num -= 1;
179            $letter  =  chr(($num % 26) + 97);
180            $letter .=  (floor($num / 26) > 0) ? str_repeat($letter, floor($num / 26)) : '';
181            return      ($uppercase ? strtoupper($letter) : $letter);
182        }
183    }
184?>