349 lines
14 KiB
PHP
349 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
|
use App\Enums\Theme\BootstrapThemeEnum;
|
|
use App\Lib\Helpers\ToolboxHelper;
|
|
use App\Models\Discount;
|
|
use App\Models\Message;
|
|
use App\Models\Notification;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Pagination\LengthAwarePaginator as LengthAwarePaginatorCustom;
|
|
use Illuminate\Routing\Controller as BaseController;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Support\Facades\Session;
|
|
use Illuminate\Support\Facades\View;
|
|
use Illuminate\Support\Str;
|
|
|
|
class Controller extends BaseController
|
|
{
|
|
use AuthorizesRequests;
|
|
use ValidatesRequests;
|
|
|
|
/**
|
|
* Summary of _construct.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->middleware(function (Request $request, callable $next) {
|
|
if (Auth::guard('club')->check()) {
|
|
/** @var \App\Models\Customer */
|
|
$customerModel = Auth::guard('club')->user();
|
|
$notificationModels = $customerModel->getAllNotifications();
|
|
View::share(
|
|
'notifications_count',
|
|
$notificationModels->count() - $customerModel->readNotifications()->count()
|
|
);
|
|
View::share('notifications_list', $notificationModels);
|
|
View::share('notifications_message_count', $notificationModels
|
|
// @phpstan-ignore-next-line
|
|
->filter(function (Notification $notificationModel) {
|
|
return $notificationModel->notifiable_type === Message::class and
|
|
!is_null($notificationModel->customer_id);
|
|
})
|
|
->count());
|
|
$discountCache = Cache::remember(
|
|
"discountsCustomerCount_{$customerModel->hashcode}",
|
|
86400,
|
|
function () use ($customerModel) {
|
|
return Discount::getCustomerDiscountsCount($customerModel->hashcode);
|
|
}
|
|
);
|
|
View::share('discountsCustomerCount', $discountCache);
|
|
} //end if
|
|
return $next($request);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gives the redirection path for FO Auth controllers.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function authLoggedRedirectPath(): string
|
|
{
|
|
return route('club.home.show');
|
|
}
|
|
|
|
/**
|
|
* 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|null $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|null $searchQuery = null,
|
|
string ...$fields
|
|
): \Illuminate\Database\Eloquent\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
|
|
): \Illuminate\Database\Eloquent\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): string|array
|
|
{
|
|
$cast = $query->getModel()->getCasts()[$field] ?? null;
|
|
if (
|
|
count($query->getModel()->getCasts()) and // Check if the model has casts.
|
|
$cast and // Check if there is cast about specific field.
|
|
enum_exists($cast) // Check if the cast is an enum.
|
|
) {
|
|
/** @var \App\Traits\Enums $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;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sort columns with a query.
|
|
*
|
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
* @param array $ignore
|
|
* @return \Illuminate\Database\Eloquent\Builder
|
|
*/
|
|
protected function sortQuery(Builder $query, array $ignore = []): \Illuminate\Database\Eloquent\Builder
|
|
{
|
|
$rName = request()->route()->getName();
|
|
$table = $query->getModel()->getTable();
|
|
if (request()->input('sort_col')) {
|
|
Session::put("$rName.sort_col", request()->input('sort_col'));
|
|
Session::put("$rName.sorted", true);
|
|
}
|
|
if (request()->input('sort_way')) {
|
|
Session::put("$rName.sort_way", request()->input('sort_way'));
|
|
Session::put("$rName.sorted", true);
|
|
}
|
|
if (request()->rst) {
|
|
Session::remove("$rName.sorted");
|
|
Session::remove("$rName.sort_col");
|
|
Session::remove("$rName.sort_way");
|
|
}
|
|
if (
|
|
request()->input('sort_col') and
|
|
request()->input('sort_way') and
|
|
Schema::hasColumn($table, request()->input('sort_col'))
|
|
) {
|
|
if (!in_array(request()->input('sort_col'), $ignore)) {
|
|
$query = $query->orderBy(
|
|
\sprintf("$table.%s", request()->input('sort_col')),
|
|
request()->input('sort_way')
|
|
);
|
|
}
|
|
} elseif (Schema::hasColumn($table, 'order')) {
|
|
$query = $query->orderBy('order', 'ASC');
|
|
Session::put("$rName.sort_col", 'order');
|
|
Session::put("$rName.sort_way", 'asc');
|
|
} elseif (Schema::hasColumn($table, 'updated_at')) {
|
|
$query = $query->orderBy('updated_at', 'DESC');
|
|
Session::put("$rName.sort_col", 'updated_at');
|
|
Session::put("$rName.sort_way", 'desc');
|
|
} elseif (Schema::hasColumn($table, 'created_at')) {
|
|
$query = $query->orderBy('created_at', 'DESC');
|
|
Session::put("$rName.sort_col", 'created_at');
|
|
Session::put("$rName.sort_way", 'desc');
|
|
}
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* Customize pagination with cache or config (default).
|
|
*
|
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
* @param \App\Enums\Pagination\ItemsPerPaginationEnum|null $pagination
|
|
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
|
*/
|
|
protected function paginate(
|
|
Builder $query,
|
|
ItemsPerPaginationEnum|null $pagination = null
|
|
): \Illuminate\Contracts\Pagination\LengthAwarePaginator {
|
|
$currentRoutePath = Str::slug(request()->route()->getName());
|
|
$cacheKey = "pagination.{$currentRoutePath}";
|
|
$pagination = $pagination ?? ItemsPerPaginationEnum::twelve;
|
|
$pagination = ToolboxHelper::getValidatedEnum(
|
|
Cache::get($cacheKey, $pagination->value()),
|
|
'pagination',
|
|
'\App\Enums\Pagination\ItemsPerPaginationEnum',
|
|
);
|
|
if (Cache::get($cacheKey) !== $pagination) {
|
|
Cache::put($cacheKey, $pagination);
|
|
}
|
|
$query = $query->paginate($pagination);
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* Get a paginate resource.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\Http\JsonResponse
|
|
*/
|
|
public function jsonPaginateModels(Request $request): \Illuminate\Http\JsonResponse
|
|
{
|
|
/** @var \Illuminate\Database\Eloquent\Model $models */
|
|
$models = $request->targetModel::query()
|
|
->where($request->input('fieldName') ?? 'name', 'like', "%{$request->input('search')}%")
|
|
->orderBy($request->input('fieldName') ?? 'name', 'ASC')
|
|
->paginate($request->input('paginate') ?? 10);
|
|
return \response()->json($models);
|
|
}
|
|
|
|
/**
|
|
* Set the bootstrap theme or light (default).
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
protected function setTheme(Request $request): \Illuminate\Http\RedirectResponse
|
|
{
|
|
$theme = ToolboxHelper::getValidatedEnum(
|
|
$request->theme ?: Cache::get('theme', BootstrapThemeEnum::light->value()),
|
|
'theme',
|
|
'\App\Http\Controllers\BootstrapThemeEnum',
|
|
);
|
|
if (Cache::get("theme") !== $theme) {
|
|
Cache::put("theme", $theme);
|
|
}
|
|
return redirect()->back()->with('success', trans('crud.messages.theme_updated'));
|
|
}
|
|
|
|
/**
|
|
* Get models titles for search input propositions.
|
|
*
|
|
* @param Builder $query
|
|
* @param string $searchField
|
|
* @param string|null $search
|
|
* @return \Illuminate\Pagination\LengthAwarePaginator
|
|
*/
|
|
public function getModelsTitles(
|
|
Builder $query,
|
|
string $searchField,
|
|
string|null $search = null
|
|
): \Illuminate\Pagination\LengthAwarePaginator {
|
|
$modelsTitles = [];
|
|
$searchLower = Str::lower($search);
|
|
$query->when(!is_null($search), function (Builder $q) use ($searchLower, $searchField) {
|
|
$q->where($searchField, 'like', "%{$searchLower}%");
|
|
})
|
|
->where('published', true)
|
|
->inRandomOrder()
|
|
->pluck($searchField)
|
|
->each(function (string $title) use (&$modelsTitles, $searchLower) {
|
|
if (count($modelsTitles) < 5) {
|
|
foreach (explode(" ", $title) as $word) {
|
|
$word = Str::lower($word);
|
|
if (
|
|
strlen($word) > 3
|
|
&& !in_array($word, $modelsTitles)
|
|
&& str_contains($word, $searchLower)
|
|
) {
|
|
$modelsTitles[] = $word;
|
|
}
|
|
}
|
|
return $modelsTitles;
|
|
}
|
|
})
|
|
->toArray();
|
|
\sort($modelsTitles);
|
|
$titles = array_slice($modelsTitles, 0, 5);
|
|
return new LengthAwarePaginatorCustom($titles, count($titles), (count($titles) <= 0) ? 1 : count($titles));
|
|
}
|
|
}
|