Skip to content

Commit 607d551

Browse files
committed
added elasticsearch integration + code reviews / fixes
1 parent ff276ba commit 607d551

File tree

16 files changed

+471
-20
lines changed

16 files changed

+471
-20
lines changed

.env.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ ENABLE_LOGGEDPAGES=0
2626
LOGGEDPAGES_GROUP=users
2727
DEBUG=1
2828
GTMID=GTM-XXXX
29+
ELASTICSEARCH=0
30+
ELASTICSEARCH_HOST=localhost
31+
ELASTICSEARCH_PORT=9200
2932

3033
#-- Smtp Info
3134
SMTP_HOST=smtp.mailtrap.io

app/base/abstracts/Controllers/BasePage.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
namespace App\Base\Abstracts\Controllers;
1313

14+
use App\Site\Routing\Web;
1415
use Degami\Basics\Exceptions\BasicException;
1516
use \Exception;
1617
use \Psr\Container\ContainerInterface;
@@ -54,12 +55,7 @@ public function __construct(ContainerInterface $container, Request $request)
5455
$this->request = $request ?: $this->getApp()->getRequest();
5556

5657
// dispatch "request_created" event
57-
$this->getApp()->event(
58-
'request_created',
59-
[
60-
'request' => $this->request
61-
]
62-
);
58+
$this->getApp()->event('request_created', ['request' => $this->request]);
6359
$this->response = $this->getContainer()->make(Response::class);
6460

6561
// let App know this is the controller object
@@ -202,9 +198,18 @@ public function getRouteName()
202198
*/
203199
public function getControllerUrl()
204200
{
201+
if ($this->getRouteInfo() instanceof RouteInfo) {
202+
return $this->getUrl($this->getRouteInfo()->getRouteName(), $this->getRouteInfo()->getVars());
203+
}
204+
205205
$path = str_replace("app/site/controllers/", "", str_replace("\\", "/", strtolower(get_class($this))));
206206
if (method_exists(static::class, 'getRoutePath')) {
207207
$path = call_user_func([static::class, 'getRoutePath']);
208+
if (is_string($path)) {
209+
$path = explode(",", $path);
210+
}
211+
$path = reset($path);
212+
208213
if (method_exists(static::class, 'getRouteGroup')) {
209214
$path = call_user_func([static::class, 'getRouteGroup']).'/'.$path;
210215
}
@@ -215,7 +220,8 @@ public function getControllerUrl()
215220
}
216221

217222
foreach ($route_vars as $varname => $value) {
218-
$path = preg_replace("/\{".$varname."(:.*?)?\}/", $value, $path);
223+
$regexp = "/\{".$varname.Web::REGEXP_ROUTEVAR_EXPRESSION."\}/i";
224+
$path = preg_replace($regexp, $value, $path);
219225
}
220226

221227
return $this->getRouting()->getBaseUrl().$path;

app/base/abstracts/Models/FrontendModel.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ abstract class FrontendModel extends BaseModel
2828
*/
2929
protected $rewriteObj = null;
3030

31+
/**
32+
* Field names to be exposed to indexer
33+
*
34+
* @return string[]
35+
*/
36+
public static function exposeToIndexer()
37+
{
38+
return ['title', 'content'];
39+
}
40+
3141
/**
3242
* gets object rewrite model
3343
*

app/base/tools/Plates/SiteBase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ public function renderFlashMessages(BasePage $controller)
255255
public function summarize($text, $max_words = 10)
256256
{
257257
$max_words = abs(intval($max_words));
258-
$words = preg_split("/\s+/", $text);
258+
$words = preg_split("/\s+/", strip_tags($text));
259259
if (count($words) < $max_words) {
260260
return $text;
261261
}

app/base/traits/ContainerAwareTrait.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,17 @@ public function getIcons()
282282
return $this->getService('icons');
283283
}
284284

285+
/**
286+
* gets elasticsearch service
287+
*
288+
* @return \ElasticSearch\Client
289+
* @throws BasicException
290+
*/
291+
public function getElasticsearch()
292+
{
293+
return $this->getService('elasticsearch');
294+
}
295+
285296
/**
286297
* gets env variable
287298
*

app/site/blocks/Search.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
/**
3+
* SiteBase
4+
* PHP Version 7.0
5+
*
6+
* @category CMS / Framework
7+
* @package Degami\Sitebase
8+
* @author Mirko De Grandis <degami@github.com>
9+
* @license MIT https://opensource.org/licenses/mit-license.php
10+
* @link https://github.com/degami/sitebase
11+
*/
12+
namespace App\Site\Blocks;
13+
14+
use \App\Base\Abstracts\Blocks\BaseCodeBlock;
15+
use \App\Base\Abstracts\Controllers\BasePage;
16+
use App\Site\Controllers\Frontend\Search as SearchController;
17+
use \Degami\Basics\Html\TagElement;
18+
use Exception;
19+
20+
/**
21+
* Search Block
22+
*/
23+
class Search extends BaseCodeBlock
24+
{
25+
/**
26+
* {@inheritdocs}
27+
*
28+
* @param BasePage|null $current_page
29+
* @return string
30+
*/
31+
public function renderHTML(BasePage $current_page = null)
32+
{
33+
if ($current_page instanceof SearchController) {
34+
return '';
35+
}
36+
37+
if (!$this->getEnv('ELASTICSEARCH')) {
38+
return '';
39+
}
40+
41+
try {
42+
$form_content = $this->getContainer()->make(TagElement::class , ['options' => [
43+
'tag' => 'div',
44+
'attributes' => [
45+
'class' => 'searchbar input-group',
46+
],
47+
]]);
48+
49+
$input = $this->getContainer()->make(TagElement::class , ['options' => [
50+
'tag' => 'input',
51+
'type' => 'text',
52+
'name' => 'q',
53+
'attributes' => [
54+
'class' => 'form-control',
55+
],
56+
]]);
57+
58+
$form_content->addChild($input);
59+
60+
$button = $this->getContainer()->make(TagElement::class , ['options' => [
61+
'tag' => 'input',
62+
'type' => 'submit',
63+
'value' => $this->getUtils()->translate('Search'),
64+
'attributes' => [
65+
'class' => 'btn searchbtn',
66+
],
67+
]]);
68+
69+
$div = $this->getContainer()->make(TagElement::class , ['options' => [
70+
'tag' => 'div',
71+
'attributes' => [
72+
'class' => 'input-group-append',
73+
],
74+
]]);
75+
76+
$div->addChild($button);
77+
78+
$form_content->addChild($div);
79+
80+
$action_url = $this->getRouting()->getUrl('frontend.search.withlang', ['lang' => $this->getApp()->getCurrentLocale()]);
81+
return '<form class="searchform-mini" action="'.$action_url.'" method="GET">' .
82+
$form_content .
83+
'</form>' ;
84+
} catch (Exception $e) {}
85+
return "";
86+
}
87+
}

app/site/commands/App/ModEnv.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class ModEnv extends BaseCommand
3131
'Database Info' => ['DATABASE_HOST','DATABASE_NAME','DATABASE_USER','DATABASE_PASS'],
3232
'Admin Info' => ['ADMINPAGES_GROUP','ADMIN_USER','ADMIN_PASS','ADMIN_EMAIL'],
3333
'Cache Info' => ['CACHE_LIFETIME','DISABLE_CACHE','ENABLE_FPC', 'PRELOAD_REWRITES'],
34-
'Other Info' => ['ENABLE_LOGGEDPAGES','LOGGEDPAGES_GROUP','DEBUG','GTMID'],
34+
'Other Info' => ['ENABLE_LOGGEDPAGES','LOGGEDPAGES_GROUP','DEBUG','GTMID','ELASTICSEARCH','ELASTICSEARCH_HOST', 'ELASTICSEARCH_PORT'],
3535
'Smtp Info' => ['SMTP_HOST','SMTP_PORT','SMTP_USER','SMTP_PASS'],
3636
'SES Info' => ['SES_REGION','SES_PROFILE'],
3737
];

app/site/commands/Search/Indexer.php

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
/**
3+
* SiteBase
4+
* PHP Version 7.0
5+
*
6+
* @category CMS / Framework
7+
* @package Degami\Sitebase
8+
* @author Mirko De Grandis <degami@github.com>
9+
* @license MIT https://opensource.org/licenses/mit-license.php
10+
* @link https://github.com/degami/sitebase
11+
*/
12+
namespace App\Site\Commands\Search;
13+
14+
use App\Base\Abstracts\Commands\BaseCommand;
15+
use App\Base\Abstracts\Models\FrontendModel;
16+
use App\Base\Tools\Plates\SiteBase;
17+
use App\Site\Controllers\Frontend\Search;
18+
use Degami\Basics\Exceptions\BasicException;
19+
use HaydenPierce\ClassFinder\ClassFinder;
20+
use Symfony\Component\Console\Input\InputInterface;
21+
use Symfony\Component\Console\Output\OutputInterface;
22+
23+
/**
24+
* Index data for search engine
25+
*/
26+
class Indexer extends BaseCommand
27+
{
28+
const SUMMARIZE_MAX_WORDS = 50;
29+
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
protected function configure()
34+
{
35+
$this->setDescription('Index data for search');
36+
}
37+
38+
/**
39+
* {@inheritdocs}
40+
*
41+
* @param InputInterface $input
42+
* @param OutputInterface $output
43+
* @return void
44+
* @throws BasicException
45+
*/
46+
protected function execute(InputInterface $input, OutputInterface $output)
47+
{
48+
$client = $this->getElasticsearch();
49+
50+
$classes = ClassFinder::getClassesInNamespace('App\Site\Models', ClassFinder::RECURSIVE_MODE);
51+
foreach($classes as $modelClass) {
52+
if (is_subclass_of($modelClass, FrontendModel::class)) {
53+
/** @var FrontendModel $object */
54+
$type = basename(str_replace("\\","/", strtolower($modelClass)));
55+
56+
$fields_to_index = ['title', 'content'];
57+
if (method_exists($modelClass, 'exposeToIndexer')) {
58+
$fields_to_index = $this->getContainer()->call([$modelClass, 'exposeToIndexer']);
59+
}
60+
61+
foreach ($this->getContainer()->call([$modelClass, 'all']) as $object) {
62+
$body = [];
63+
64+
foreach(array_merge(['id', 'website_id', 'locale', 'created_at', 'updated_at'], $fields_to_index) as $field_name) {
65+
$body[$field_name] = $object->getData($field_name);
66+
}
67+
68+
$body_additional = [
69+
'type' => $type,
70+
'frontend_url' => $object->getFrontendUrl()
71+
];
72+
73+
if (in_array('content', $fields_to_index)) {
74+
$body_additional['excerpt'] = $this->getContainer()->make(SiteBase::class)->summarize($object->getContent(), self::SUMMARIZE_MAX_WORDS);
75+
}
76+
77+
$params = [
78+
'index' => Search::INDEX_NAME,
79+
'id' => $type.'_'.$object->getId(),
80+
'body' => array_merge($body, $body_additional),
81+
];
82+
83+
$response = $client->index($params);
84+
}
85+
}
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)