Merge lp:~henrik-lochmann/goobi-presentation/bug-985487 into lp:goobi-presentation/1.1
- bug-985487
- Merge into 1.1
Status: | Merged |
---|---|
Merged at revision: | 108 |
Proposed branch: | lp:~henrik-lochmann/goobi-presentation/bug-985487 |
Merge into: | lp:goobi-presentation/1.1 |
Diff against target: |
438 lines (+314/-7) 9 files modified
dlf/common/class.tx_dlf_solr.php (+30/-1) dlf/ext_autoload.php (+1/-0) dlf/ext_emconf.php (+1/-0) dlf/ext_localconf.php (+2/-0) dlf/plugins/search/class.tx_dlf_search.php (+108/-5) dlf/plugins/search/class.tx_dlf_search_suggest.php (+140/-0) dlf/plugins/search/search_suggest.js (+29/-0) dlf/plugins/search/template.tmpl (+2/-1) dlf/t3jquery.txt (+1/-0) |
To merge this branch: | bzr merge lp:~henrik-lochmann/goobi-presentation/bug-985487 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henrik Lochmann (community) | Needs Information | ||
Sebastian Meyer | Needs Fixing | ||
Review via email: mp+104405@code.launchpad.net |
Commit message
Description of the change
Implementation of feature/wishlist bug #985487.
Henrik Lochmann (henrik-lochmann) wrote : | # |
> Great work, but there are some more things to do:
>
> - Please add t3jquery to the dependencies in ext_emconf.php.
Ok.
> - Check for the extension to be loaded und use its API to integrate the
> libraries.
> (see http://
Ok.
> - I suggest moving the getSolrSuggestUrl() method from tx_dlf_
> to tx_dlf_solr. Also it should respect username and password if necessary (see
> solrConnect() in tx_dlf_solr) and handle the core correctly (currently the
> core isn't regarded at all although there is a variable named $core).
Ok, see below.
> - According to the Coding Guidelines tx_dlf_
> of tx_dlf_plugin instead of tslib_pibase.
The class tx_dlf_
Unfortunately, at least proper Solr core handling requires frontend access, because the core is adjusted in the corresponding frontend plugin instance of the rendered page. In order to avoid the instantiation of the frontend only to read the configured Solr core, I propose to render a hidden field, as part of the search form, that contains the atcual Solr core value.
> - Please make all private methods protected in order to allow proper class
> inheritage.
Ok.
Sebastian Meyer (sebastian-meyer) wrote : | # |
Rendering a hidden field for the Solr core number in the search form could be a security issue, because the field's value can be manipulated and thus a user could query any Solr core.
Although I admit that initializing the whole TSFE object in tx_dlf_
http://
That way you could read the plugin's configuration and get the Solr core number without ignoring the proper access conditions.
Henrik Lochmann (henrik-lochmann) wrote : | # |
I'm seriously concerned about the performance loss, coming with the instantiation of the t3 frontend for every single letter typed in the search field.
What if we encrypt the hidden field in a way that ensures its value is 1) unreadable for the user and 2) definitely unchanged when comes back to the server? For instance, Yavor Atanasov proposed a solution which seems pretty strong:
- http://
- 81. By Henrik Lochmann
-
- fixed review todos
Sebastian Meyer (sebastian-meyer) wrote : | # |
This should be merged into goobi-presentat
Henrik Lochmann wrote:
Unfortunately, my local commit messages obviously did not reach LP. Thus, here at least a textual summary of the changes:
- dlf/ext_emconf.php: dependency to t3jquery
- dlf/ext_
- dlf/common/
- dlf/plugins/
+ t3jquery dependencies are properly included when using search suggestions
+ search form, suggestions and search template work on secured hidden input that contains the index name of the incorporated solr core (this code only works when PHP mcrypt extension is installed, otherwise nothing happens)
Preview Diff
1 | === modified file 'dlf/common/class.tx_dlf_solr.php' |
2 | --- dlf/common/class.tx_dlf_solr.php 2012-03-30 09:14:14 +0000 |
3 | +++ dlf/common/class.tx_dlf_solr.php 2012-06-04 15:53:22 +0000 |
4 | @@ -29,7 +29,7 @@ |
5 | /** |
6 | * Solr class 'tx_dlf_solr' for the 'dlf' extension. |
7 | * |
8 | - * @author Sebastian Meyer <sebastian.meyer@slub-dresden.de> |
9 | + * @author Sebastian Meyer <sebastian.meyer@slub-dresden.de>, Henrik Lochmann <dev@mentalmotive.com> |
10 | * @copyright Copyright (c) 2011, Sebastian Meyer, SLUB Dresden |
11 | * @package TYPO3 |
12 | * @subpackage tx_dlf |
13 | @@ -46,6 +46,35 @@ |
14 | public static $extKey = 'dlf'; |
15 | |
16 | /** |
17 | + * Returns the request url for Solr-based search suggestions. |
18 | + * |
19 | + * @access public |
20 | + * |
21 | + * @return string The request url for Solr-based search suggestions. |
22 | + */ |
23 | + public static function getSolrUrl($core) { |
24 | + // Extract extension configuration. |
25 | + $conf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][tx_dlf_solr::$extKey]); |
26 | + |
27 | + // Derive Solr host name. |
28 | + $host = ($conf['solrHost'] ? $conf['solrHost'] : 'localhost'); |
29 | + |
30 | + // Prepend username and password to hostname. |
31 | + if ($conf['solrUser'] && $conf['solrPass']) { |
32 | + $host = $conf['solrUser'].':'.$conf['solrPass'].'@'.$host; |
33 | + } |
34 | + |
35 | + // Set port if not set. |
36 | + $port = t3lib_div::intInRange($conf['solrPort'], 1, 65535, 8180); |
37 | + |
38 | + // Append core name to path. |
39 | + $path = trim($conf['solrPath'], '/').'/'.$core; |
40 | + |
41 | + // Return entire request url. |
42 | + return 'http://'.$host.':'.$port.'/'.$path; |
43 | + } |
44 | + |
45 | + /** |
46 | * Get SolrPhpClient service object and establish connection to Solr server |
47 | * @see EXT:dlf/lib/SolrPhpClient/Apache/Solr/Service.php |
48 | * |
49 | |
50 | === modified file 'dlf/ext_autoload.php' |
51 | --- dlf/ext_autoload.php 2012-04-30 16:05:21 +0000 |
52 | +++ dlf/ext_autoload.php 2012-06-04 15:53:22 +0000 |
53 | @@ -49,6 +49,7 @@ |
54 | 'tx_dlf_oai' => $extensionPath.'plugins/oai/class.tx_dlf_oai.php', |
55 | 'tx_dlf_pageview' => $extensionPath.'plugins/pageview/class.tx_dlf_pageview.php', |
56 | 'tx_dlf_search' => $extensionPath.'plugins/search/class.tx_dlf_search.php', |
57 | + 'tx_dlf_search_suggest' => $extensionPath.'plugins/search/class.tx_dlf_search_suggest.php', |
58 | 'tx_dlf_statistics' => $extensionPath.'plugins/statistics/class.tx_dlf_statistics.php', |
59 | 'tx_dlf_toc' => $extensionPath.'plugins/toc/class.tx_dlf_toc.php', |
60 | 'tx_dlf_toolbox' => $extensionPath.'plugins/toolbox/class.tx_dlf_toolbox.php', |
61 | |
62 | === modified file 'dlf/ext_emconf.php' |
63 | --- dlf/ext_emconf.php 2012-05-15 08:01:44 +0000 |
64 | +++ dlf/ext_emconf.php 2012-06-04 15:53:22 +0000 |
65 | @@ -44,6 +44,7 @@ |
66 | 'depends' => array( |
67 | 'php' => '5.3.0-', |
68 | 'typo3' => '4.3.0-', |
69 | + 't3jquery' => '2.1.2-', |
70 | ), |
71 | 'conflicts' => array( |
72 | ), |
73 | |
74 | === modified file 'dlf/ext_localconf.php' |
75 | --- dlf/ext_localconf.php 2012-05-08 07:41:38 +0000 |
76 | +++ dlf/ext_localconf.php 2012-06-04 15:53:22 +0000 |
77 | @@ -66,4 +66,6 @@ |
78 | // Register command line scripts. |
79 | $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys'][$_EXTKEY] = array ('EXT:'.$_EXTKEY.'/cli/class.tx_dlf_cli.php', '_CLI_dlf'); |
80 | |
81 | +// Register solr suggest eID. |
82 | +$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_suggest'] = 'EXT:'.$_EXTKEY.'/plugins/search/class.tx_dlf_search_suggest.php'; |
83 | ?> |
84 | \ No newline at end of file |
85 | |
86 | === modified file 'dlf/plugins/search/class.tx_dlf_search.php' |
87 | --- dlf/plugins/search/class.tx_dlf_search.php 2012-05-05 11:10:37 +0000 |
88 | +++ dlf/plugins/search/class.tx_dlf_search.php 2012-06-04 15:53:22 +0000 |
89 | @@ -29,7 +29,7 @@ |
90 | /** |
91 | * Plugin 'DLF: Search' for the 'dlf' extension. |
92 | * |
93 | - * @author Sebastian Meyer <sebastian.meyer@slub-dresden.de> |
94 | + * @author Sebastian Meyer <sebastian.meyer@slub-dresden.de>, Henrik Lochmann <dev@mentalmotive.com> |
95 | * @copyright Copyright (c) 2011, Sebastian Meyer, SLUB Dresden |
96 | * @package TYPO3 |
97 | * @subpackage tx_dlf |
98 | @@ -39,6 +39,103 @@ |
99 | |
100 | public $scriptRelPath = 'plugins/search/class.tx_dlf_search.php'; |
101 | |
102 | + /** |
103 | + * Adds the HTML content for two hidden input fields, namely 'encrypted' and 'hashed', containing |
104 | + * the index_name if the passed solrCore number, to the passed marker arrays value |
105 | + * '###ADDITIONAL_INPUTS###'. This is necessary to savely render search suggestions. |
106 | + * |
107 | + * @access protected |
108 | + * |
109 | + * @return array |
110 | + */ |
111 | + protected function addEncryptedSolrCore($markerArray, $solrCore) { |
112 | + |
113 | + // Extract internal dlf core name. |
114 | + $table = 'tx_dlf_solrcores'; |
115 | + |
116 | + $_result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
117 | + $table.'.index_name AS index_name', |
118 | + $table, |
119 | + $table.'.uid='.$solrCore.tx_dlf_helper::whereClause($table), |
120 | + '', |
121 | + '', |
122 | + '1' |
123 | + ); |
124 | + |
125 | + $dlfCoreName = ''; |
126 | + |
127 | + if ($GLOBALS['TYPO3_DB']->sql_num_rows($_result) > 0) { |
128 | + |
129 | + $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result); |
130 | + |
131 | + $dlfCoreName = $resArray['index_name']; |
132 | + |
133 | + } |
134 | + |
135 | + if (empty($dlfCoreName)) { |
136 | + |
137 | + trigger_error('Failed to query for internal solr core name of core number '.$solrCore, E_USER_NOTICE); |
138 | + |
139 | + return; |
140 | + |
141 | + } |
142 | + |
143 | + $encryptedCore = tx_dlf_search_suggest::encrypt($dlfCoreName); |
144 | + |
145 | + if (empty($encryptedCore)) { |
146 | + |
147 | + $markerArray['###ADDITIONAL_INPUTS###'] = ''; |
148 | + |
149 | + } else { |
150 | + |
151 | + $markerArray['###ADDITIONAL_INPUTS###'] = '<input type="hidden" name="encrypted" value="'.$encryptedCore['value'].'"/>' |
152 | + .'<input type="hidden" name="hashed" value="'.$encryptedCore['hash'].'"/>'; |
153 | + |
154 | + } |
155 | + |
156 | + return $markerArray; |
157 | + |
158 | + } |
159 | + |
160 | + /** |
161 | + * Adds the JS files necessary for search sugestions to the |
162 | + * page header. |
163 | + * |
164 | + * @access protected |
165 | + * |
166 | + * @return void |
167 | + */ |
168 | + protected function addSuggestSupport() { |
169 | + // ensure jquery is loaded |
170 | + if (t3lib_extMgm::isLoaded('t3jquery')) { |
171 | + require_once(t3lib_extMgm::extPath('t3jquery').'class.tx_t3jquery.php'); |
172 | + } |
173 | + |
174 | + // if t3jquery is loaded and the custom Library had been created |
175 | + if (T3JQUERY === true) { |
176 | + tx_t3jquery::addJqJS(); |
177 | + } else { |
178 | + /* |
179 | + * suggestions will not work; we don't indicate an no error |
180 | + * because this is caused by insufficient configuration and |
181 | + * this feature does not harm the rest of the framework's |
182 | + * functionality |
183 | + */ |
184 | + return; |
185 | + } |
186 | + |
187 | + $libs = array( |
188 | + "search_suggest" => "search_suggest.js" |
189 | + ); |
190 | + |
191 | + foreach ($libs as $lib_key => $lib_file) { |
192 | + $GLOBALS['TSFE']->additionalHeaderData[$this->prefixId.$lib_key] = ' <script type="text/javascript" src="' |
193 | + .t3lib_extMgm::siteRelPath($this->extKey) |
194 | + .'plugins/search/'.$lib_file |
195 | + .'"></script>'; |
196 | + } |
197 | + } |
198 | + |
199 | /** |
200 | * The main method of the PlugIn |
201 | * |
202 | @@ -58,15 +155,18 @@ |
203 | |
204 | // Quit without doing anything if required variables are not set. |
205 | if (empty($this->conf['solrcore'])) { |
206 | - |
207 | + |
208 | trigger_error('Incomplete configuration for plugin '.get_class($this), E_USER_NOTICE); |
209 | |
210 | return $content; |
211 | |
212 | } |
213 | - |
214 | + |
215 | if (empty($this->piVars['query'])) { |
216 | - |
217 | + |
218 | + // Add suggest JavaScript file. |
219 | + $this->addSuggestSupport(); |
220 | + |
221 | // Load template file. |
222 | if (!empty($this->conf['templateFile'])) { |
223 | |
224 | @@ -97,7 +197,10 @@ |
225 | '###FIELD_QUERY###' => $this->prefixId.'[query]', |
226 | '###QUERY###' => htmlspecialchars($lastQuery), |
227 | ); |
228 | - |
229 | + |
230 | + // Encrypt solr core name and add as hidden input field to marker array to enable for search suggestions. |
231 | + $markerArray = $this->addEncryptedSolrCore($markerArray, $this->conf['solrcore']); |
232 | + |
233 | // Display search form. |
234 | $content .= $this->cObj->substituteMarkerArray($this->template, $markerArray); |
235 | |
236 | |
237 | === added file 'dlf/plugins/search/class.tx_dlf_search_suggest.php' |
238 | --- dlf/plugins/search/class.tx_dlf_search_suggest.php 1970-01-01 00:00:00 +0000 |
239 | +++ dlf/plugins/search/class.tx_dlf_search_suggest.php 2012-06-04 15:53:22 +0000 |
240 | @@ -0,0 +1,140 @@ |
241 | +<?php |
242 | +/*************************************************************** |
243 | + * Copyright notice |
244 | + * |
245 | + * (c) 2012 Henrik Lochmann <dev@mentalmotive.com> |
246 | + * All rights reserved |
247 | + * |
248 | + * This script is part of the TYPO3 project. The TYPO3 project is |
249 | + * free software; you can redistribute it and/or modify |
250 | + * it under the terms of the GNU General Public License as published by |
251 | + * the Free Software Foundation; either version 2 of the License, or |
252 | + * (at your option) any later version. |
253 | + * |
254 | + * The GNU General Public License can be found at |
255 | + * http://www.gnu.org/copyleft/gpl.html. |
256 | + * |
257 | + * This script is distributed in the hope that it will be useful, |
258 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
259 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
260 | + * GNU General Public License for more details. |
261 | + * |
262 | + * This copyright notice MUST APPEAR in all copies of the script! |
263 | + ***************************************************************/ |
264 | + |
265 | +/** |
266 | + * Search suggestion Ajax backend for the Plugin 'DLF: Search' of the |
267 | + * 'dlf' extension. This class is invoked using the eID bypass. |
268 | + * |
269 | + * @author Henrik Lochmann <dev@mentalmotive.com> |
270 | + * @copyright Copyright (c) 2012, Zeutschel GmbH |
271 | + * @package TYPO3 |
272 | + * @subpackage tx_dlf |
273 | + * @access public |
274 | + */ |
275 | +require_once (PATH_tslib . 'class.tslib_pibase.php'); |
276 | +class tx_dlf_search_suggest extends tslib_pibase { |
277 | + |
278 | + private $content; |
279 | + |
280 | + private static $ENCRYPTION_KEY = 'b8b311560d3e6f8dea0aa445995b1b2b'; |
281 | + |
282 | + private static $ENCRYPTION_IV = '381416de30a5c970f8f486aa6d5cc932'; |
283 | + |
284 | + public $scriptRelPath = 'plugins/search/class.tx_dlf_search_suggest.php'; |
285 | + |
286 | + public static function encrypt($original_value) { |
287 | + |
288 | + if (!extension_loaded('mcrypt')) { |
289 | + |
290 | + trigger_error('Mycrpt PHP extension not installed, falling back to TSFE instantiation for '.get_class(), E_USER_NOTICE); |
291 | + |
292 | + return NULL; |
293 | + |
294 | + } |
295 | + |
296 | + $iv = substr( self::$ENCRYPTION_IV, 0, mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CFB) ); |
297 | + |
298 | + $encryptedValue = base64_encode( mcrypt_encrypt(MCRYPT_BLOWFISH, self::$ENCRYPTION_KEY, $original_value, MCRYPT_MODE_CFB, $iv) ); |
299 | + |
300 | + $salt = substr( md5(uniqid(rand(), true)), 0, 10 ); |
301 | + |
302 | + $hash = $salt . substr(sha1($salt . $original_value),-10); |
303 | + |
304 | + return array( 'value' => $encryptedValue, 'hash' => $hash); |
305 | + |
306 | + } |
307 | + |
308 | + public static function decrypt($encrypted, $hash) { |
309 | + |
310 | + if (!extension_loaded('mcrypt')) { |
311 | + |
312 | + trigger_error('Mycrpt PHP extension not installed, falling back to TSFE instantiation for '.get_class(), E_USER_NOTICE); |
313 | + |
314 | + return NULL; |
315 | + |
316 | + } |
317 | + |
318 | + if (empty($encrypted) || empty($hash)) { |
319 | + |
320 | + return NULL; |
321 | + |
322 | + } |
323 | + |
324 | + $result = NULL; |
325 | + |
326 | + $iv = substr(self::$ENCRYPTION_IV, 0, mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CFB)); |
327 | + |
328 | + $decrypted_value = mcrypt_decrypt(MCRYPT_BLOWFISH, self::$ENCRYPTION_KEY, base64_decode($encrypted), MCRYPT_MODE_CFB, $iv); |
329 | + |
330 | + $salt = substr($hash, 0, 10); |
331 | + |
332 | + $new_hashed_value = $salt . substr(sha1($salt . $decrypted_value), -10); |
333 | + |
334 | + if ($new_hashed_value == $hash) { |
335 | + |
336 | + $result = $decrypted_value; |
337 | + |
338 | + } |
339 | + |
340 | + return $result; |
341 | + |
342 | + } |
343 | + |
344 | + public function main() { |
345 | + |
346 | + $core = self::decrypt(t3lib_div::_POST('encrypted'), t3lib_div::_POST('hashed')); |
347 | + |
348 | + // Mcrypt is not available, solr core did not arrive or was manipulated: give uo here. |
349 | + if (empty($core)) { |
350 | + |
351 | + return; |
352 | + |
353 | + } |
354 | + |
355 | + $url = trim(tx_dlf_solr::getSolrUrl($core), '/') . '/suggest/?q=' . t3lib_div::_POST('q'); |
356 | + |
357 | + if ($stream = fopen($url, 'r')) { |
358 | + |
359 | + $this -> content .= stream_get_contents($stream); |
360 | + |
361 | + fclose($stream); |
362 | + |
363 | + } else { |
364 | + |
365 | + $this -> content .= "Could not connect to index server."; |
366 | + |
367 | + } |
368 | + } |
369 | + |
370 | + public function printContent() { |
371 | + echo $this -> content; |
372 | + } |
373 | + |
374 | +} |
375 | + |
376 | +$suggest = t3lib_div::makeInstance('tx_dlf_search_suggest'); |
377 | +$suggest->main(); |
378 | +$suggest->printContent(); |
379 | + |
380 | +?> |
381 | \ No newline at end of file |
382 | |
383 | === added file 'dlf/plugins/search/search_suggest.js' |
384 | --- dlf/plugins/search/search_suggest.js 1970-01-01 00:00:00 +0000 |
385 | +++ dlf/plugins/search/search_suggest.js 2012-06-04 15:53:22 +0000 |
386 | @@ -0,0 +1,29 @@ |
387 | +$( |
388 | + function(){ |
389 | + // jQuery autocomplete integration |
390 | + $(".autocomplete").autocomplete({ |
391 | + source: function( request, response ) { |
392 | + return $.post( |
393 | + '/', |
394 | + { |
395 | + eID: "tx_dlf_suggest", |
396 | + q: escape(request.term), |
397 | + encrypted: $("input[name='encrypted']").val(), |
398 | + hashed: $("input[name='hashed']").val() |
399 | + }, |
400 | + function( xmlData ) { |
401 | + var result = new Array(); |
402 | + |
403 | + $('arr[name="suggestion"] str', xmlData).each(function(i) { |
404 | + if ($(this).text().indexOf(request.term) == 0) { |
405 | + result.push($(this).text()); |
406 | + } |
407 | + }); |
408 | + |
409 | + return response(result); |
410 | + }, |
411 | + 'xml'); |
412 | + } |
413 | + }); |
414 | + } |
415 | +); |
416 | \ No newline at end of file |
417 | |
418 | === modified file 'dlf/plugins/search/template.tmpl' |
419 | --- dlf/plugins/search/template.tmpl 2012-03-16 09:06:25 +0000 |
420 | +++ dlf/plugins/search/template.tmpl 2012-06-04 15:53:22 +0000 |
421 | @@ -1,7 +1,8 @@ |
422 | <!-- ###TEMPLATE### --> |
423 | <form class="tx-dlf-search-form" action="###ACTION_URL###" method="post" enctype="multipart/form-data"> |
424 | <label for="###FIELD_QUERY###">###LABEL_QUERY###</label> |
425 | - <input type="text" id="###FIELD_QUERY###" name="###FIELD_QUERY###" value="###QUERY###" /> |
426 | + <input type="text" id="###FIELD_QUERY###" name="###FIELD_QUERY###" value="###QUERY###" class="autocomplete" autocomplete="off" role="textbox" aria-autocomplete="list" aria-haspopup="true"> |
427 | <input type="submit" value="###LABEL_SUBMIT###" /> |
428 | + ###ADDITIONAL_INPUTS### |
429 | </form> |
430 | <!-- ###TEMPLATE### --> |
431 | \ No newline at end of file |
432 | |
433 | === added file 'dlf/t3jquery.txt' |
434 | --- dlf/t3jquery.txt 1970-01-01 00:00:00 +0000 |
435 | +++ dlf/t3jquery.txt 2012-06-04 15:53:22 +0000 |
436 | @@ -0,0 +1,1 @@ |
437 | +components=jQuery,Core,Position,Autocomplete |
438 | \ No newline at end of file |
Great work, but there are some more things to do:
- Please add t3jquery to the dependencies in ext_emconf.php.
- Check for the extension to be loaded und use its API to integrate the libraries. typo3.org/ extension- manuals/ t3jquery/ 2.2.0/view/ 1/5/)
(see http://
- I suggest moving the getSolrSuggestUrl() method from tx_dlf_ search_ suggest to tx_dlf_solr. Also it should respect username and password if necessary (see solrConnect() in tx_dlf_solr) and handle the core correctly (currently the core isn't regarded at all although there is a variable named $core).
- According to the Coding Guidelines tx_dlf_ search_ suggest should be a child of tx_dlf_plugin instead of tslib_pibase.
- Please make all private methods protected in order to allow proper class inheritage.
Thanks! :o)