141 lines
5.6 KiB
PHP
141 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
|
use Illuminate\Routing\Controller as BaseController;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Support\Str;
|
|
|
|
class Controller extends BaseController
|
|
{
|
|
use AuthorizesRequests;
|
|
use DispatchesJobs;
|
|
use ValidatesRequests;
|
|
|
|
/**
|
|
* Build Search query on specified fields
|
|
* splitting search into words or using whole sentence
|
|
*
|
|
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
|
|
* @param string $search The query string.
|
|
* @param callable $searchQuery The query string.
|
|
* @param string ...$fields Either a simple array or a string
|
|
* in case of a string the two fields
|
|
* would be concatenate to make the search.
|
|
* @return \Illuminate\Database\Eloquent\Builder
|
|
*/
|
|
protected function searchQuery(
|
|
Builder $query,
|
|
string $search,
|
|
callable $searchQuery = null,
|
|
string ...$fields
|
|
): Builder {
|
|
if (count($fields)) {
|
|
// Search using words.
|
|
$words = explode(' ', $search);
|
|
$query->where(function ($query) use ($searchQuery, $words, $search, $fields) {
|
|
foreach ($words as $word) {
|
|
if (!strlen($word)) {
|
|
continue;
|
|
}
|
|
$this->searchOnFields($query, $word, $fields);
|
|
} //end foreach
|
|
// Search whole using whole sentence.
|
|
$this->searchOnFields($query, $search, $fields);
|
|
if ($searchQuery) {
|
|
$searchQuery($query);
|
|
}
|
|
});
|
|
} //end if
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* Build query search on all fields
|
|
*
|
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
* @param string $search
|
|
* @param array $fields
|
|
* @return \Illuminate\Database\Eloquent\Builder
|
|
*/
|
|
private function searchOnFields(
|
|
Builder $query,
|
|
string $search,
|
|
array $fields
|
|
): Builder {
|
|
$table = $query->getModel()->getTable();
|
|
foreach ($fields as $field) {
|
|
$field = str_replace('?', '\?', $field);
|
|
if (is_array($field)) {
|
|
$query->orWhereRaw(
|
|
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($field)->map(function ($q) use ($table) {
|
|
return "`$table`.`$q`";
|
|
})->implode(', \' \', ')),
|
|
['%' . htmlspecialchars($search) . '%']
|
|
);
|
|
return $query;
|
|
}
|
|
// Get models woth enum's label.
|
|
if (is_array($this->getSearchValue($query, $search, $field))) {
|
|
foreach ($this->getSearchValue($query, $search, $field) as $array) {
|
|
$query->orWhereRaw(
|
|
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
|
|
['%' . htmlspecialchars($array->value) . '%']
|
|
);
|
|
}
|
|
return $query;
|
|
}
|
|
// Get models with relation's name/label.
|
|
if (Str::endsWith($field, '_id')) {
|
|
$query->orWhereHas(Str::remove('_id', $field), function ($queryRelation) use ($field, $search) {
|
|
if (Schema::hasColumn(Str::remove('_id', $field) . 's', 'name')) {
|
|
$queryRelation->where('name', 'like', '%' . $search . '%');
|
|
} elseif (Schema::hasColumn(Str::remove('_id', $field) . 's', 'label')) {
|
|
$queryRelation->where('label', 'like', '%' . $search . '%');
|
|
}
|
|
});
|
|
return $query;
|
|
}
|
|
$query->orWhereRaw(
|
|
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
|
|
['%' . htmlspecialchars($this->getSearchValue($query, $search, $field)) . '%']
|
|
);
|
|
} //end foreach
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* Get the search value (on string or Enum).
|
|
*
|
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
* @param string $search
|
|
* @param string $field
|
|
* @return string|array
|
|
*/
|
|
protected function getSearchValue(Builder $query, string $search, string $field)
|
|
{
|
|
$cast = $query->getModel()->getCasts()[$field] ?? null;
|
|
if (
|
|
count($query->getModel()->getCasts()) and // Check if the model has casts.
|
|
// Check if there is cast about specific field.
|
|
is_string($cast) and
|
|
class_exists($cast) and
|
|
// Check if the cast is an enum.
|
|
in_array(\Kwaadpepper\Enum\BaseEnum::class, class_parents(\App\Enums\PriceShowingMode::class))
|
|
) {
|
|
/** @var \Kwaadpepper\Enum\BaseEnum $cast */
|
|
// @phpstan-ignore-next-line
|
|
$cases = collect($cast::toArray());
|
|
$enum = $cases->filter(function ($item) use ($search) {
|
|
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label));
|
|
});
|
|
return $enum->toArray();
|
|
} else {
|
|
return $search;
|
|
}
|
|
}
|
|
}
|