Overview

Namespaces

  • Alpha
    • Controller
      • Front
    • Exception
    • Model
      • Type
    • Task
    • Util
      • Backup
      • Cache
      • Code
        • Highlight
        • Metric
      • Config
      • Convertor
      • Email
      • Extension
      • Feed
      • File
      • Graph
      • Helper
      • Http
        • Filter
        • Session
      • Image
      • Logging
      • Search
      • Security
    • View
      • Renderer
        • Html
        • Json
      • Widget

Classes

  • ActiveRecordController
  • ArticleController
  • AttachmentController
  • CacheController
  • Controller
  • DEnumController
  • ExcelController
  • FeedController
  • GenSecureQueryStringController
  • ImageController
  • IndexController
  • InstallController
  • ListActiveRecordsController
  • LogController
  • LoginController
  • LogoutController
  • MetricController
  • PhpinfoController
  • RecordSelectorController
  • SearchController
  • SequenceController
  • TagController

Interfaces

  • ControllerInterface
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: namespace Alpha\Controller;
  4: 
  5: use Alpha\Util\Logging\Logger;
  6: use Alpha\Util\Logging\KPI;
  7: use Alpha\Util\Logging\LogProviderFile;
  8: use Alpha\Util\Config\ConfigProvider;
  9: use Alpha\Util\Http\Request;
 10: use Alpha\Util\Http\Response;
 11: use Alpha\Util\Search\SearchProviderFactory;
 12: use Alpha\View\View;
 13: use Alpha\View\Widget\Button;
 14: use Alpha\Controller\Front\FrontController;
 15: 
 16: /**
 17:  * Search engine controller.
 18:  *
 19:  * @since 1.0
 20:  *
 21:  * @author John Collins <dev@alphaframework.org>
 22:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
 23:  * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
 24:  * All rights reserved.
 25:  *
 26:  * <pre>
 27:  * Redistribution and use in source and binary forms, with or
 28:  * without modification, are permitted provided that the
 29:  * following conditions are met:
 30:  *
 31:  * * Redistributions of source code must retain the above
 32:  *   copyright notice, this list of conditions and the
 33:  *   following disclaimer.
 34:  * * Redistributions in binary form must reproduce the above
 35:  *   copyright notice, this list of conditions and the
 36:  *   following disclaimer in the documentation and/or other
 37:  *   materials provided with the distribution.
 38:  * * Neither the name of the Alpha Framework nor the names
 39:  *   of its contributors may be used to endorse or promote
 40:  *   products derived from this software without specific
 41:  *   prior written permission.
 42:  *
 43:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 44:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 45:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 46:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 47:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 48:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 49:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 50:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 51:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 52:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 53:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 54:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 55:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 56:  * </pre>
 57:  */
 58: class SearchController extends Controller implements ControllerInterface
 59: {
 60:     /**
 61:      * Trace logger.
 62:      *
 63:      * @var Alpha\Util\Logging\Logger
 64:      *
 65:      * @since 1.0
 66:      */
 67:     private static $logger = null;
 68: 
 69:     /**
 70:      * The start number for list pageination.
 71:      *
 72:      * @var int
 73:      *
 74:      * @since 1.0
 75:      */
 76:     protected $startPoint;
 77: 
 78:     /**
 79:      * The result count from the search.
 80:      *
 81:      * @var int
 82:      *
 83:      * @since 1.0
 84:      */
 85:     protected $resultCount = 0;
 86: 
 87:     /**
 88:      * The search query supplied.
 89:      *
 90:      * @var string
 91:      *
 92:      * @since 1.0
 93:      */
 94:     protected $query;
 95: 
 96:     /**
 97:      * constructor to set up the object.
 98:      *
 99:      * @param string $visibility The name of the rights group that can access this controller.
100:      *
101:      * @since 1.0
102:      */
103:     public function __construct($visibility = 'Public')
104:     {
105:         self::$logger = new Logger('SearchController');
106:         self::$logger->debug('>>__construct(visibility=['.$visibility.'])');
107: 
108:         $config = ConfigProvider::getInstance();
109: 
110:         // ensure that the super class constructor is called, indicating the rights group
111:         parent::__construct($visibility);
112: 
113:         self::$logger->debug('<<__construct');
114:     }
115: 
116:     /**
117:      * Handle GET requests.
118:      *
119:      * @param Alpha\Util\Http\Request $request
120:      *
121:      * @return Alpha\Util\Http\Response
122:      *
123:      * @since 1.0
124:      *
125:      * @throws Alpha\Exception\IllegalArguementException
126:      */
127:     public function doGET($request)
128:     {
129:         self::$logger->debug('>>doGET($request=['.var_export($request, true).'])');
130: 
131:         $params = $request->getParams();
132: 
133:         if (isset($params['start']) ? $this->startPoint = $params['start'] : $this->startPoint = 0);
134: 
135:         $config = ConfigProvider::getInstance();
136: 
137:         $KPI = new KPI('search');
138: 
139:         $body = '';
140: 
141:         if (isset($params['query'])) {
142:             $this->query = $params['query'];
143: 
144:             // replace any %20 on the URL with spaces
145:             $params['query'] = str_replace('%20', ' ', $params['query']);
146: 
147:             $this->setTitle('Search results - '.$params['query']);
148:             $body .= View::displayPageHead($this);
149: 
150:             // log the user's search query in a log file
151:             $log = new LogProviderFile();
152:             $log->setPath($config->get('app.file.store.dir').'logs/search.log');
153:             $log->writeLine(array($params['query'], date('Y-m-d H:i:s'), $request->getUserAgent(), $request->getIP()));
154: 
155:             $KPI->logStep('log search query');
156: 
157:             $provider = SearchProviderFactory::getInstance('Alpha\Util\Search\SearchProviderTags');
158: 
159:             // if a BO name is provided, only search tags on that class, otherwise search all BOs
160:             if (isset($params['ActiveRecordType'])) {
161:                 $results = $provider->search($params['query'], $params['bo'], $this->startPoint);
162:             } else {
163:                 $results = $provider->search($params['query'], 'all', $this->startPoint);
164:             }
165: 
166:             $this->resultCount = $provider->getNumberFound();
167: 
168:             $KPI->logStep('search completed using SearchProviderTags provider');
169: 
170:             $body .= $this->renderResultList($results, $params['query']);
171:         } else {
172:             $this->setTitle('Search results');
173:             $body .= View::displayPageHead($this);
174:             self::$logger->debug('No search query provided!');
175:         }
176: 
177:         $body .= View::displayPageFoot($this);
178: 
179:         $KPI->log();
180: 
181:         self::$logger->debug('<<doGET');
182: 
183:         return new Response(200, $body, array('Content-Type' => 'text/html'));
184:     }
185: 
186:     /**
187:      * Renders the search result list.
188:      *
189:      * @param array  $results
190:      * @param string $query
191:      * @param bool   $showTags
192:      *
193:      * @since 1.0
194:      *
195:      * @return string
196:      */
197:     protected function renderResultList($results, $query = '', $showTags = true)
198:     {
199:         $config = ConfigProvider::getInstance();
200: 
201:         // used to track when our pagination range ends
202:         $end = ($this->startPoint + $config->get('app.list.page.amount'));
203: 
204:         $body = '';
205: 
206:         if (!empty($query)) {
207:             $body .= '<h2>Displaying results for &quot;'.$query.'&quot;</h2>';
208:         }
209: 
210:         foreach ($results as $bo) {
211:             if ($bo instanceof \Alpha\Model\Article && $bo->get('published') == false) {
212:                 --$this->resultCount;
213:             } else {
214:                 $view = View::getInstance($bo);
215:                 $URI = $this->request->getURI();
216:                 $body .= $view->listView(array('formAction' => $URI));
217: 
218:                 if ($showTags) {
219:                     $tags = $bo->getPropObject('tags')->getRelatedObjects();
220: 
221:                     if (count($tags) > 0) {
222:                         $body .= '<p>Tags: ';
223: 
224:                         $queryTerms = explode(' ', mb_strtolower($query));
225: 
226:                         foreach ($tags as $tag) {
227:                             $body .= (in_array($tag->get('content'), $queryTerms) ? '<strong>'.$tag->get('content').' </strong>' : $tag->get('content').' ');
228:                         }
229: 
230:                         $body .= '</p>';
231:                     }
232:                 }
233:             }
234:         }
235: 
236:         return $body;
237:     }
238: 
239:     /**
240:      * Displays a search form on the top of the page.
241:      *
242:      * @return string
243:      *
244:      * @since 1.0
245:      */
246:     public function after_displayPageHead_callback()
247:     {
248:         $config = ConfigProvider::getInstance();
249: 
250:         $body = parent::after_displayPageHead_callback();
251: 
252:         $body .= '<div align="center" class="form-group"><form class="form-inline" method="GET" id="search_form" onsubmit="document.location = \''.$config->get('app.url').'search/\'+document.getElementById(\'q\').value; return false;">';
253:         $body .= '<label for="q">Search for</label><input type="text" name="q" id="q" class="form-control" style="width:50%; margin:10px;"/>';
254:         $button = new Button('document.location = \''.$config->get('app.url').'/search/\'+document.getElementById(\'q\').value', 'Search', 'searchButton');
255:         $body .= $button->render();
256:         $body .= '</p></form></div>';
257: 
258:         return $body;
259:     }
260: 
261:     /**
262:      * Method to display the page footer with pageination links.
263:      *
264:      * @return string
265:      *
266:      * @since 1.0
267:      */
268:     public function before_displayPageFoot_callback()
269:     {
270:         $body = $this->renderPageLinks();
271: 
272:         $body .= '<br>';
273: 
274:         return $body;
275:     }
276: 
277:     /**
278:      * Method for rendering the pagination links.
279:      *
280:      * @return string
281:      *
282:      * @since 1.0
283:      */
284:     protected function renderPageLinks()
285:     {
286:         $config = ConfigProvider::getInstance();
287: 
288:         $params = $this->request->getParams();
289: 
290:         $body = '';
291: 
292:         $end = ($this->startPoint + $config->get('app.list.page.amount'));
293: 
294:         if ($end > $this->resultCount) {
295:             $end = $this->resultCount;
296:         }
297: 
298:         if ($this->resultCount > 0) {
299:             $body .= '<p align="center">Displaying '.($this->startPoint + 1).' to '.$end.' of <strong>'.$this->resultCount.'</strong>.&nbsp;&nbsp;';
300:         } else {
301:             if (!empty($this->query)) {
302:                 $body .= View::displayUpdateMessage('There were no search results for your query.');
303:             }
304:         }
305: 
306:         $body .= '<ul class="pagination">';
307: 
308:         if ($this->startPoint > 0) {
309:             // handle secure URLs
310:             if (isset($params['tk'])) {
311:                 $body .= '<li><a href="'.FrontController::generateSecureURL('act=Search&q='.$this->query.'&start='.($this->startPoint - $config->get('app.list.page.amount'))).'">&laquo;</a></li>';
312:             } else {
313:                 $body .= '<li><a href="'.$config->get('app.url').'/search/'.$this->query.'/'.($this->startPoint - $config->get('app.list.page.amount')).'">&laquo;</a></li>';
314:             }
315:         } elseif ($this->resultCount > $config->get('app.list.page.amount')) {
316:             $body .= '<li class="disabled"><a href="#">&laquo;</a></li>';
317:         }
318: 
319:         $page = 1;
320: 
321:         for ($i = 0; $i < $this->resultCount; $i += $config->get('app.list.page.amount')) {
322:             if ($i != $this->startPoint) {
323:                 // handle secure URLs
324:                 if (isset($params['tk'])) {
325:                     $body .= '<li><a href="'.FrontController::generateSecureURL('act=Search&q='.$this->query.'&start='.$i).'">'.$page.'</a></li>';
326:                 } else {
327:                     $body .= '<li><a href="'.$config->get('app.url').'/search/'.$this->query.'/'.$i.'">'.$page.'</a></li>';
328:                 }
329:             } elseif ($this->resultCount > $config->get('app.list.page.amount')) {
330:                 $body .= '<li class="active"><a href="#">'.$page.'</a></li>';
331:             }
332: 
333:             ++$page;
334:         }
335: 
336:         if ($this->resultCount > $end) {
337:             // handle secure URLs
338:             if (isset($params['tk'])) {
339:                 $body .= '<li><a href="'.FrontController::generateSecureURL('act=Search&q='.$this->query.'&start='.($this->startPoint + $config->get('app.list.page.amount'))).'">Next-&gt;&gt;</a></li>';
340:             } else {
341:                 $body .= '<li><a href="'.$config->get('app.url').'/search/'.$this->query.'/'.($this->startPoint + $config->get('app.list.page.amount')).'">&raquo;</a></li>';
342:             }
343:         } elseif ($this->resultCount > $config->get('app.list.page.amount')) {
344:             $body .= '<li class="disabled"><a href="#">&raquo;</a></li>';
345:         }
346: 
347:         $body .= '</ul>';
348:         $body .= '</p>';
349: 
350:         return $body;
351:     }
352: 
353:     /**
354:      * Get the search result count.
355:      *
356:      * @return int
357:      *
358:      * @since 1.2.4
359:      */
360:     public function getResultCount()
361:     {
362:         return $this->resultCount;
363:     }
364: 
365:     /**
366:      * Set the search result count.
367:      *
368:      * @param int $resultCount
369:      *
370:      * @since 1.2.4
371:      */
372:     protected function setResultCount($resultCount)
373:     {
374:         $this->resultCount = $resultCount;
375:     }
376: 
377:     /**
378:      * Get the search query.
379:      *
380:      * @return string
381:      *
382:      * @since 1.2.4
383:      */
384:     public function getSearchQuery()
385:     {
386:         return $this->query;
387:     }
388: 
389:     /**
390:      * Set the search query.
391:      *
392:      * @param string $query
393:      *
394:      * @since 1.2.4
395:      */
396:     protected function setSearchQuery($query)
397:     {
398:         $this->query = $query;
399:     }
400: }
401: 
Alpha Framework 2.0.4 API Documentation API documentation generated by ApiGen 2.8.0