Anton Qcl Posted July 8, 2020 Report Posted July 8, 2020 Hi, Is there a way to extend custom search the way I need? For example, in some plugins I have additional information attached to client and I want to be able to find clients thru Smart Search using only this information. Quote
0 Paul Posted July 8, 2020 Report Posted July 8, 2020 The smart search can't be modified other than selecting which standard criteria is used for the smart search. Your best bet is to create a plugin that implements its own search, then you can configure it to search however you want. The plugin would create a new search option. Quote
0 Anton Qcl Posted July 8, 2020 Author Report Posted July 8, 2020 Paul, thank you for answer. I also think I can implement much more dirty but convinient for customers solution: add some js on the page which intercept smart search form submitting, then do necessary search thru ajax. I'll share the code here if somebody will face the same requirement Quote
0 Anton Qcl Posted July 23, 2020 Author Report Posted July 23, 2020 Paul, I actually tried to implement your idea. Action I took: 1. Added row into config/routes.php Router::route('^' . $admin_loc . '/search/?$', 'atn_smartsearch/atn_admin_search'); 2. Created plugin atn_smartsearch with controller atn_admin_search.php. Code of the AtnAdminSearch Controller: <?php class AtnAdminSearch extends AdminSearch { public function preAction() { // do nothing } public function index() { die('cathced index'); } } Please, take a look at this code. I expected that I can extend AdminSearch and redefine function index() to implement my own algo of search. This code works but, as you can see, I also redefined function preAction(). I did not want to do it but without it system just redirect me to the main admin page. I'm little bit confused because I did not find any errors in the logs which would indicate what I have done wrong. Can you, please, give me some advises? PS I've also added a video 2020-07-23 19-09-30.mp4 Quote
0 Abdy Posted July 24, 2020 Report Posted July 24, 2020 I think the best way to implement your own custom search is by using events and not a route. To implement it using events you need to register the event in the *_plugin.php file as in the following example: In this example we register the search() function from the AdminMain controller. class SearchPlugin extends Plugin { // ... public function customSearch($event) { $params = $event->getParams(); if (isset($params['options'])) { $params['options'] += [ $params['base_uri'] . 'plugin/search/admin_main/search/' => 'Custom Search' ]; } $event->setParams($params); } public function getEvents() { return [ [ 'event' => 'Navigation.getSearchOptions', 'callback' => ['this', 'customSearch'] ] ]; } } Now we need to create the AdminMain controller and implement the search() method, which will perform the search: <?php class AdminMain extends AppController { public function preAction() { parent::preAction(); $this->requireLogin(); // Load the languages, models, components // and helpers needed by this controller. } public function index() { // There is nothing to see here $this->redirect($this->base_uri); } public function search() { // Restore structure view location of the admin portal $this->structure->setDefaultView(APPDIR); $this->structure->setView(null, $this->orig_structure_view); // Set page title $this->structure->set('page_title', 'My Custom Search'); // Implement your amazing code here to do the search! if ($this->isAjax()) { return $this->renderAjaxWidgetIfAsync( isset($this->post['search']) ? null : isset($this->get['search']) ); } } } Quote
0 Anton Qcl Posted July 27, 2020 Author Report Posted July 27, 2020 @Abdy, good idea but in this case client need to do two additional actions every time he wants to use custom search. It is not acceptable. Probably I could've try to go this way if there was an option to change default search. Right now it is 'Smart Search' and I did not find the way to change it. Is it possible? However, I like the idea of using events, so I did it. Following code monitor event Appcontroller.preAction and fire custom search function if detect that url is /admin/search. If clients are found, function will redirect user to the first client's page. It is crutchy but, unfortunately, I did not find the way to get the controller in my function interceptAdminSearch - I could possible use only var $event which does not contain any useful information. <?php class AtnSmartsearchPlugin extends Plugin { public function __construct() { $this->loadConfig(dirname(__FILE__) . DS . "config.json"); } public function getEvents() { return [ [ 'event' => "Appcontroller.preAction", 'callback' => ["this", "interceptAdminSearch"] ] ]; } public function interceptAdminSearch() { if ( strpos($_SERVER['REQUEST_URI'], "/admin/search") === 0 && $_SERVER['REQUEST_METHOD'] === "POST" ) { $this->searchClients(); } } public function searchClients() { $this->requireLogin(); $value = htmlentities(strip_tags($_POST['search'])); $clients = $this->myFunctionToSearchClients($value); if (!empty($clients)) { $client = array_pop($clients); $this->redirect($client->url); } } // Just an example, not a real function private function myFunctionToSearchClients($value) { if ($value == "example") { return [ (object)['url'=>"/admin/clients/view/1/", 'name'=>"Test Client1"], (object)['url'=>"/admin/clients/view/2/", 'name'=>" TestClient2"], ]; } } private function requireLogin() { if (empty($_SESSION['blesta_staff_id'])) { $this->redirect("/admin/login"); } } private function redirect($url) { header("Location: {$url}"); die(); } } Technically, this approach solves my problem but I would like to show information about other found clients somehow. It would be ok if I could add it in a flash message, but method flashMessage() is protected and defined in AppController.I tried to create custom controller inside my plugin but it did not work - no errors, but no flash messages after using it: <?php class CustomSearch extends AppController { public function setFlashMessage($message) { $this->flashMessage("message", $message, ['preserve_tags'=>true], false); } } <?php class AtnSmartsearchPlugin extends Plugin { public function searchClients() { ... if (!empty($clients)) { $client = array_pop($clients); if (count($clients) > 0) { $this->addClientsInfoToFlashMessages($clients,); } ... } } private function addClientsInfoToFlashMessages($clients,) { $clientsInfo = array_map(function($client) { return "<a href='{$client->url}'>{$client->name}</a>"; }, $clients); $clientsInfo = implode(nl2br(PHP_EOL), $clientsInfo); $message = "Also found clients:<br>{$clientsInfo}"; $controller = $this->loadCustomSearchController(); $controller->setFlashMessage($message); } private function loadCustomSearchController() { require __DIR__ . "/controllers/custom_search.php"; $controller = new \CustomSearch(null, null, false); return $controller; } } Quote
0 Anton Qcl Posted July 30, 2020 Author Report Posted July 30, 2020 @Abdy, @Paul, I also found crutchy way to handle the case if we found few clients: Store results in session Handle event AppController.strucrure: Encode results and publish them as JS var inject JS script for handling result And then in JS script: Check if we are on the search results page Check if we have additional results Create html for row and append rows to the table. Create table if table does not exist. I can publish the code if you or somebody else need it. Quote
0 Paul Posted July 31, 2020 Report Posted July 31, 2020 18 hours ago, Anton Qcl said: @Abdy, @Paul, I also found crutchy way to handle the case if we found few clients: Store results in session Handle event AppController.strucrure: Encode results and publish them as JS var inject JS script for handling result And then in JS script: Check if we are on the search results page Check if we have additional results Create html for row and append rows to the table. Create table if table does not exist. I can publish the code if you or somebody else need it. You are welcome to publish the code if it may be helpful to others. I can imagine someone stumbling on this thread later and wishing it was included. Quote
0 Abdy Posted July 31, 2020 Report Posted July 31, 2020 On 7/27/2020 at 3:31 PM, Anton Qcl said: @Abdy, good idea but in this case client need to do two additional actions every time he wants to use custom search. It is not acceptable. Probably I could've try to go this way if there was an option to change default search. Right now it is 'Smart Search' and I did not find the way to change it. Is it possible? However, I like the idea of using events, so I did it. Following code monitor event Appcontroller.preAction and fire custom search function if detect that url is /admin/search. If clients are found, function will redirect user to the first client's page. It is crutchy but, unfortunately, I did not find the way to get the controller in my function interceptAdminSearch - I could possible use only var $event which does not contain any useful information. <?php class AtnSmartsearchPlugin extends Plugin { public function __construct() { $this->loadConfig(dirname(__FILE__) . DS . "config.json"); } public function getEvents() { return [ [ 'event' => "Appcontroller.preAction", 'callback' => ["this", "interceptAdminSearch"] ] ]; } public function interceptAdminSearch() { if ( strpos($_SERVER['REQUEST_URI'], "/admin/search") === 0 && $_SERVER['REQUEST_METHOD'] === "POST" ) { $this->searchClients(); } } public function searchClients() { $this->requireLogin(); $value = htmlentities(strip_tags($_POST['search'])); $clients = $this->myFunctionToSearchClients($value); if (!empty($clients)) { $client = array_pop($clients); $this->redirect($client->url); } } // Just an example, not a real function private function myFunctionToSearchClients($value) { if ($value == "example") { return [ (object)['url'=>"/admin/clients/view/1/", 'name'=>"Test Client1"], (object)['url'=>"/admin/clients/view/2/", 'name'=>" TestClient2"], ]; } } private function requireLogin() { if (empty($_SESSION['blesta_staff_id'])) { $this->redirect("/admin/login"); } } private function redirect($url) { header("Location: {$url}"); die(); } } Technically, this approach solves my problem but I would like to show information about other found clients somehow. It would be ok if I could add it in a flash message, but method flashMessage() is protected and defined in AppController.I tried to create custom controller inside my plugin but it did not work - no errors, but no flash messages after using it: <?php class CustomSearch extends AppController { public function setFlashMessage($message) { $this->flashMessage("message", $message, ['preserve_tags'=>true], false); } } <?php class AtnSmartsearchPlugin extends Plugin { public function searchClients() { ... if (!empty($clients)) { $client = array_pop($clients); if (count($clients) > 0) { $this->addClientsInfoToFlashMessages($clients,); } ... } } private function addClientsInfoToFlashMessages($clients,) { $clientsInfo = array_map(function($client) { return "<a href='{$client->url}'>{$client->name}</a>"; }, $clients); $clientsInfo = implode(nl2br(PHP_EOL), $clientsInfo); $message = "Also found clients:<br>{$clientsInfo}"; $controller = $this->loadCustomSearchController(); $controller->setFlashMessage($message); } private function loadCustomSearchController() { require __DIR__ . "/controllers/custom_search.php"; $controller = new \CustomSearch(null, null, false); return $controller; } } You can change Smart Search to another one, clicking on the magnifying glass icon. Quote
0 Anton Qcl Posted August 4, 2020 Author Report Posted August 4, 2020 @Abdy, like I said earlier, this option is completely unacceptable by my client: * He needs to do two additional actions every search (click to open menu, another click to change the search) * If custom search was unsuccessful, system will not automatically use Smart Search after that. Both of these problems are solved in my solution. @Paul, ok, I'll publish the code after I finish the tests Quote
0 Anton Qcl Posted January 5, 2022 Author Report Posted January 5, 2022 Forgot to share the code but I actually did it Note: this code is extremely dirty and should not be used in production. I hope, Smart Search will be really customizable some day ssbp-20210730.zip Paul 1 Quote
Question
Anton Qcl
Hi,
Is there a way to extend custom search the way I need?
For example, in some plugins I have additional information attached to client and I want to be able to find clients thru Smart Search using only this information.
10 answers to this question
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.