Skip to content

Commit

Permalink
Merge pull request #3353 from ProcessMaker/feature/FOUR-1725
Browse files Browse the repository at this point in the history
Indexed Search
  • Loading branch information
velkymx committed Aug 20, 2020
2 parents 05912ab + ef3335a commit 4200342
Show file tree
Hide file tree
Showing 16 changed files with 669 additions and 83 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/public/js
/public/css
/storage/*.key
/storage/*.index
/vendor
/.idea
/.vscode
Expand Down
61 changes: 61 additions & 0 deletions ProcessMaker/Console/Commands/IndexedSearchDisable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace ProcessMaker\Console\Commands;

use Illuminate\Console\Command;
use ProcessMaker\Models\Setting;
use ProcessMaker\Traits\SupportsNonInteraction;

class IndexedSearchDisable extends Command
{
use SupportsNonInteraction;

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'indexed-search:disable';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Disable indexed search';

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}

/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if ($this->interactive()) {
$confirmed = $this->confirm("Are you sure you wish to disable indexed search?");
} else {
$confirmed = true;
}

if ($confirmed) {
$setting = Setting::updateOrCreate(
[ 'key' => 'indexed-search' ],
[ 'config' => [ 'enabled' => false ], ]
);

if ($setting->config['enabled'] === false) {
$this->line('Indexed search has been disabled.');
}
}
}
}
89 changes: 89 additions & 0 deletions ProcessMaker/Console/Commands/IndexedSearchEnable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace ProcessMaker\Console\Commands;

use App;
use Illuminate\Console\Command;
use ProcessMaker\Managers\IndexManager;
use ProcessMaker\Models\Setting;
use ProcessMaker\Traits\SupportsNonInteraction;

class IndexedSearchEnable extends Command
{
use SupportsNonInteraction;

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'indexed-search:enable';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Enable faster searches';

private $manager;

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
$this->manager = App::make(IndexManager::class);
$this->setCommandDescription();
parent::__construct();
}

private function setCommandDescription()
{
$items = $this->manager->list()->pluck('name')->implode(', ');
return $this->description = "{$this->description} of {$items}";
}

/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if ($this->interactive()) {
$confirmed = $this->confirm(
"Running this command will index data from Requests, Tasks, and packages that support indexed search. " .
"This may take a very long time and consume system resources on large datasets.\n\n " .
"Are you sure you wish to proceed?"
);
} else {
$confirmed = true;
}

if ($confirmed) {
$this->line("The indexer will occasionally display its status.");

foreach ($this->manager->list() as $index) {
$this->info("\nBeginning index of {$index->name}...");
if ($index->callback && is_callable($index->callback)) {
call_user_func($index->callback);
$this->info("All {$index->name} records have been imported.");
} else {
$this->call("scout:import", ['model' => $index->model]);
}
}

$setting = Setting::updateOrCreate(
[ 'key' => 'indexed-search' ],
[ 'config' => [ 'enabled' => true ], ]
);

if ($setting->config['enabled'] === true) {
$this->line("\nIndexed search has been enabled.");
}
}
}
}
21 changes: 16 additions & 5 deletions ProcessMaker/Http/Controllers/Api/ProcessRequestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use ProcessMaker\Models\Comment;
use ProcessMaker\Models\ProcessRequest;
use ProcessMaker\Models\ProcessRequestToken;
use ProcessMaker\Models\Setting;
use ProcessMaker\Nayra\Contracts\Bpmn\CatchEventInterface;
use ProcessMaker\Notifications\ProcessCanceledNotification;
use ProcessMaker\Query\SyntaxError;
Expand Down Expand Up @@ -120,11 +121,21 @@ public function index(Request $request)

$filter = $request->input('filter', '');
if (!empty($filter)) {
$filter = '%' . mb_strtolower($filter) . '%';
$query->where(function ($query) use ($filter) {
$query->where(DB::raw('LOWER(name)'), 'like', $filter)
->orWhere(DB::raw('LOWER(data)'), 'like', $filter);
});
$setting = Setting::byKey('indexed-search');
if ($setting && $setting->config['enabled'] === true) {
if (is_numeric($filter)) {
$query->whereIn('id', [$filter]);
} else {
$matches = ProcessRequest::search($filter)->get()->pluck('id');
$query->whereIn('id', $matches);
}
} else {
$filter = '%' . mb_strtolower($filter) . '%';
$query->where(function ($query) use ($filter) {
$query->where(DB::raw('LOWER(name)'), 'like', $filter)
->orWhere(DB::raw('LOWER(data)'), 'like', $filter);
});
}
}

$pmql = $request->input('pmql', '');
Expand Down
35 changes: 23 additions & 12 deletions ProcessMaker/Http/Controllers/Api/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Illuminate\Database\QueryException;
use ProcessMaker\Models\Process;
use ProcessMaker\Models\Screen;
use ProcessMaker\Models\Setting;
use ProcessMaker\Models\ProcessRequest;
use ProcessMaker\Models\ProcessRequestToken;
use ProcessMaker\Notifications\TaskReassignmentNotification;
Expand Down Expand Up @@ -106,25 +107,36 @@ public function index(Request $request)

$filter = $request->input('filter', '');
if (!empty($filter)) {
$filter = '%' . mb_strtolower($filter) . '%';
$query->where(function ($query) use ($filter) {
$query->where(DB::raw('LOWER(element_name)'), 'like', $filter)
->orWhere(DB::raw('LOWER(data)'), 'like', $filter);
});
$setting = Setting::byKey('indexed-search');
if ($setting && $setting->config['enabled'] === true) {
if (is_numeric($filter)) {
$query->whereIn('id', [$filter]);
} else {
$matches = ProcessRequestToken::search($filter)->get()->pluck('id');
$query->whereIn('id', $matches);
}
} else {
$filter = '%' . mb_strtolower($filter) . '%';
$query->where(function ($query) use ($filter) {
$query->where(DB::raw('LOWER(element_name)'), 'like', $filter)
->orWhere(DB::raw('LOWER(data)'), 'like', $filter);
});
}
}

$filterByFields = ['process_id', 'process_request_tokens.user_id' => 'user_id', 'process_request_tokens.status' => 'status', 'element_id', 'element_name', 'process_request_id'];
$parameters = $request->all();
foreach ($parameters as $column => $filter) {
foreach ($parameters as $column => $fieldFilter) {
if (in_array($column, $filterByFields)) {
if ($column === 'user_id') {
$key = array_search($column, $filterByFields);
$query->where(function($query) use ($key, $column, $filter){
$query->where(function($query) use ($key, $column, $fieldFilter){
$userColumn = is_string($key) ? $key : $column;
$query->where($userColumn, $filter);
$query->orWhere(function ($query) use($userColumn, $filter) {
$query->where($userColumn, $fieldFilter);
$query->orWhere(function ($query) use($userColumn, $fieldFilter) {
$query->whereNull($userColumn);
$query->where('process_request_tokens.is_self_service', 1);
$user = User::find($filter);
$user = User::find($fieldFilter);
$query->where(function ($query) use ($user) {
foreach($user->groups as $group) {
$query->orWhereJsonContains('process_request_tokens.self_service_groups', strval($group->getKey()));
Expand All @@ -134,7 +146,7 @@ public function index(Request $request)
});
} else {
$key = array_search($column, $filterByFields);
$query->where(is_string($key) ? $key : $column, 'like', $filter);
$query->where(is_string($key) ? $key : $column, 'like', $fieldFilter);
}
}
}
Expand Down Expand Up @@ -174,7 +186,6 @@ public function index(Request $request)
return response(['message' => __('Your PMQL contains invalid syntax.')], 400);
}
}

$response = $this->handleOrderByRequestName($request, $query->get());

$response = $response->filter(function($processRequestToken) {
Expand Down
51 changes: 51 additions & 0 deletions ProcessMaker/Managers/IndexManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace ProcessMaker\Managers;

use Illuminate\Support\Collection;

class IndexManager
{
private $indexes;

public function __construct()
{
$this->indexes = new Collection([]);
}

/**
* Register index
*
* @param $name string name of index
* @param $model string path of model
* @param $callback callback function to perform indexing
*/
public function add($name, $model, $callback = null)
{
$this->indexes->push((object) [
'name' => $name,
'model' => $model,
'callback' => $callback,
]);
}

/**
* Get an index by name
*
* @param $name string name of index
*/
public function get($name)
{
return $this->indexes->where('name', $name)->first();
}

/**
* List indexes
*
*/
public function list()
{
return $this->indexes;
}

}
16 changes: 16 additions & 0 deletions ProcessMaker/Models/ProcessRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\Rule;
use Laravel\Scout\Searchable;
use Log;
use ProcessMaker\Nayra\Contracts\Bpmn\FlowElementInterface;
use ProcessMaker\Nayra\Contracts\Bpmn\IntermediateCatchEventInterface;
Expand Down Expand Up @@ -74,6 +75,7 @@ class ProcessRequest extends Model implements ExecutionInstanceInterface, HasMed
use ExtendedPMQL;
use SqlsrvSupportTrait;
use HideSystemResources;
use Searchable;

protected $connection = 'data';

Expand Down Expand Up @@ -135,6 +137,20 @@ class ProcessRequest extends Model implements ExecutionInstanceInterface, HasMed
'participants',
];

/**
* Get the indexable data array for the model.
*
* @return array
*/
public function toSearchableArray()
{
return [
'id' => $this->id,
'name' => $this->name,
'data' => json_encode($this->data),
];
}

/**
* Boot the model as a process instance.
*
Expand Down
17 changes: 17 additions & 0 deletions ProcessMaker/Models/ProcessRequestToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Carbon\Carbon;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
use Log;
use ProcessMaker\Models\User;
use ProcessMaker\Nayra\Bpmn\TokenTrait;
Expand Down Expand Up @@ -69,6 +70,7 @@ class ProcessRequestToken extends Model implements TokenInterface
use ExtendedPMQL;
use TokenTrait;
use SerializeToIso8601;
use Searchable;

protected $connection = 'processmaker';

Expand Down Expand Up @@ -138,6 +140,21 @@ class ProcessRequestToken extends Model implements TokenInterface
'self_service_groups' => 'array',
];

/**
* Get the indexable data array for the model.
*
* @return array
*/
public function toSearchableArray()
{
return [
'id' => $this->id,
'element_name' => $this->element_name,
'request' => isset($this->processRequest->name) ? $this->processRequest->name : "",
'data' => json_encode($this->data),
];
}

/**
* Boot application as a process instance.
*
Expand Down

0 comments on commit 4200342

Please sign in to comment.