Total Complexity | 90 |
Total Lines | 477 |
Duplicated Lines | 0 % |
Changes | 8 | ||
Bugs | 4 | Features | 0 |
Complex classes like AdvancedSearchListModule often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AdvancedSearchListModule, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
5 | class AdvancedSearchListModule extends ListModule { |
||
6 | /** |
||
7 | * Constructor. |
||
8 | * |
||
9 | * @param int $id unique id |
||
10 | * @param array $data list of all actions |
||
11 | */ |
||
12 | public function __construct($id, $data) { |
||
32 | ]; |
||
33 | } |
||
34 | |||
35 | /** |
||
36 | * Executes all the actions in the $data variable. |
||
37 | */ |
||
38 | #[Override] |
||
39 | public function execute() { |
||
40 | foreach ($this->data as $actionType => $action) { |
||
41 | if (isset($actionType)) { |
||
42 | try { |
||
43 | $store = $this->getActionStore($action); |
||
44 | $parententryid = $this->getActionParentEntryID($action); |
||
|
|||
45 | $entryid = $this->getActionEntryID($action); |
||
46 | |||
47 | switch ($actionType) { |
||
48 | case "list": |
||
49 | case "updatelist": |
||
50 | $this->getDelegateFolderInfo($store); |
||
51 | $this->messageList($store, $entryid, $action, $actionType); |
||
52 | break; |
||
53 | |||
54 | case "search": |
||
55 | $this->search($store, $entryid, $action, $actionType); |
||
56 | break; |
||
57 | |||
58 | case "updatesearch": |
||
59 | $this->updatesearch($store, $entryid, $action); |
||
60 | break; |
||
61 | |||
62 | case "stopsearch": |
||
63 | $this->stopSearch($store, $entryid, $action); |
||
64 | break; |
||
65 | |||
66 | case "delete_searchfolder": |
||
67 | $this->deleteSearchFolder($store, $entryid, $action); |
||
68 | break; |
||
69 | } |
||
70 | } |
||
71 | catch (MAPIException $e) { |
||
72 | // This is a very nasty hack that makes sure that grommunio Web doesn't show an error message when |
||
73 | // search wants to throw an error. This is only done because a proper fix for this bug has not |
||
74 | // been found yet. When WA-9161 is really solved, this should be removed again. |
||
75 | if ($actionType !== 'search' && $actionType !== 'updatesearch' && $actionType !== 'stopsearch') { |
||
76 | $this->processException($e, $actionType); |
||
77 | } |
||
78 | else { |
||
79 | if (DEBUG_LOADER === 0) { |
||
80 | // Log all info we can get about this error to the error log of the web server |
||
81 | error_log("Error in search: \n" . var_export($e, true) . "\n\n" . var_export(debug_backtrace(), true)); |
||
82 | } |
||
83 | // Send success feedback without data, as if nothing strange happened... |
||
84 | $this->sendFeedback(true); |
||
85 | } |
||
86 | } |
||
87 | } |
||
88 | } |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Function which retrieves a list of messages in a folder. |
||
93 | * |
||
94 | * @param object $store MAPI Message Store Object |
||
95 | * @param string $entryid entryid of the folder |
||
96 | * @param array $action the action data, sent by the client |
||
97 | * @param string $actionType the action type, sent by the client |
||
98 | */ |
||
99 | #[Override] |
||
100 | public function messageList($store, $entryid, $action, $actionType) { |
||
101 | $this->searchFolderList = false; // Set to indicate this is not the search result, but a normal folder content |
||
102 | $data = []; |
||
103 | |||
104 | if ($store && $entryid) { |
||
105 | // Restriction |
||
106 | $this->parseRestriction($action); |
||
107 | |||
108 | // Sort |
||
109 | $this->parseSortOrder($action, null, true); |
||
110 | |||
111 | $limit = $action['restriction']['limit'] ?? 1000; |
||
112 | |||
113 | $isSearchFolder = isset($action['search_folder_entryid']); |
||
114 | $entryid = $isSearchFolder ? hex2bin((string) $action['search_folder_entryid']) : $entryid; |
||
115 | |||
116 | if ($actionType == 'search') { |
||
117 | $rows = [[PR_ENTRYID => $entryid]]; |
||
118 | if (isset($action['subfolders']) && $action['subfolders']) { |
||
119 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
120 | $htable = mapi_folder_gethierarchytable($folder, CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS); |
||
121 | $rows = mapi_table_queryallrows($htable, [PR_ENTRYID]); |
||
122 | } |
||
123 | $data['item'] = []; |
||
124 | foreach ($rows as $row) { |
||
125 | $items = $GLOBALS["operations"]->getTable($store, $row[PR_ENTRYID], $this->properties, $this->sort, $this->start, $limit, $this->restriction); |
||
126 | $data['item'] = array_merge($data['item'], $items['item']); |
||
127 | if (count($data['item']) >= $limit) { |
||
128 | break; |
||
129 | } |
||
130 | } |
||
131 | $data['page'] = []; |
||
132 | $data['page']['start'] = 0; |
||
133 | $data['page']['rowcount'] = 0; |
||
134 | $data['page']['totalrowcount'] = count($data['item']); |
||
135 | $data['search_meta'] = []; |
||
136 | $data['search_meta']['searchfolder_entryid'] = null; |
||
137 | $data['search_meta']['search_store_entryid'] = $action['store_entryid']; |
||
138 | $data['search_meta']['searchstate'] = null; |
||
139 | $data['search_meta']['results'] = count($data['item']); |
||
140 | $data['folder'] = []; |
||
141 | $data['folder']['content_count'] = count($data['item']); |
||
142 | $data['folder']['content_unread'] = 0; |
||
143 | } |
||
144 | else { |
||
145 | // Get the table and merge the arrays |
||
146 | $data = $GLOBALS["operations"]->getTable($store, $entryid, $this->properties, $this->sort, $this->start, $limit, $this->restriction); |
||
147 | } |
||
148 | |||
149 | // If the request come from search folder then no need to send folder information |
||
150 | if (!$isSearchFolder && !isset($data['folder'])) { |
||
151 | // Open the folder. |
||
152 | $folder = mapi_msgstore_openentry($store, $entryid); |
||
153 | $data["folder"] = []; |
||
154 | |||
155 | // Obtain some statistics from the folder contents |
||
156 | $contentcount = mapi_getprops($folder, [PR_CONTENT_COUNT, PR_CONTENT_UNREAD]); |
||
157 | if (isset($contentcount[PR_CONTENT_COUNT])) { |
||
158 | $data["folder"]["content_count"] = $contentcount[PR_CONTENT_COUNT]; |
||
159 | } |
||
160 | |||
161 | if (isset($contentcount[PR_CONTENT_UNREAD])) { |
||
162 | $data["folder"]["content_unread"] = $contentcount[PR_CONTENT_UNREAD]; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | $data = $this->filterPrivateItems($data); |
||
167 | |||
168 | // Allowing to hook in just before the data sent away to be sent to the client |
||
169 | $GLOBALS['PluginManager']->triggerHook('server.module.listmodule.list.after', [ |
||
170 | 'moduleObject' => &$this, |
||
171 | 'store' => $store, |
||
172 | 'entryid' => $entryid, |
||
173 | 'action' => $action, |
||
174 | 'data' => &$data, |
||
175 | ]); |
||
176 | |||
177 | // unset will remove the value but will not regenerate array keys, so we need to |
||
178 | // do it here |
||
179 | $data["item"] = array_values($data["item"]); |
||
180 | $this->addActionData($actionType, $data); |
||
181 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
182 | } |
||
183 | } |
||
184 | |||
185 | private function parsePatterns($restriction, &$patterns) { |
||
265 | } |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Function will set search restrictions on search folder and start search process |
||
270 | * and it will also parse visible columns and sorting data when sending results to client. |
||
271 | * |
||
272 | * @param object $store MAPI Message Store Object |
||
273 | * @param string $entryid entryid of the folder |
||
274 | * @param object $action the action data, sent by the client |
||
275 | * @param string $actionType the action type, sent by the client |
||
276 | */ |
||
277 | #[Override] |
||
482 | } |
||
483 | } |
||
484 |