5, 'B'=>45, 'C'=>50) * An array like this means that "A" has a 5% chance of being selected, "B" 45%, and "C" 50%. * The return value is the array key, A, B, or C in this case. Note that the values assigned * do not have to be percentages. The values are simply relative to each other. If one value * weight was 2, and the other weight of 1, the value with the weight of 2 has about a 66% * chance of being selected. Also note that weights should be integers. * * @param array $weightedValues * @return int The winning key * * @url https://stackoverflow.com/a/11872928/4355295 */ protected function getRandomWeightedElementIndex(array $weightedValues): int { mt_srand(time()); $rand = mt_rand(1, max((int) collect($weightedValues)->sum('percentage'), 1)); foreach ($weightedValues as $key => $value) { $rand -= $value->percentage; if ($rand <= 0) { return $key; } } return $rand; } /** * Gives the redirection path for FO Auth controllers */ protected function authLoggedRedirectPath(): string { return response()->redirectToRoute('fo.homepage')->getTargetUrl(); } /** * Build Search query on specified fields * splitting search into words or using whole sentence * * @param 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. */ 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 (\Illuminate\Contracts\Database\Query\Builder $query) use ($searchQuery, $words, $search, $fields): void { 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 */ 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(fn ($q): string => "`$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 (\Illuminate\Contracts\Database\Query\Builder $queryRelation) use ($field, $search): void { 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). */ protected function getSearchValue(Builder $query, string $search, string $field): string | array { $cast = $query->getModel()->getCasts()[$field] ?? null; if ( count($query->getModel()->getCasts()) && $cast && enum_exists($cast) // Check if the cast is an enum. ) { // @phpstan-ignore-next-line $cases = collect($cast::toArray()); $enum = $cases->filter(fn ($item): int | false => preg_match('/' . Str::lower($search) . '/', Str::lower($item->label))); return $enum->toArray(); } return $search; } /** * Sort columns with a query. */ protected function sortQuery(Builder $query, array $ignore = []): Builder { $rName = request()->route()->getName(); $table = $query->getModel()->getTable(); if (request()->sort_col) { Session::put("$rName.sort_col", request()->sort_col); Session::put("$rName.sorted", true); } if (request()->sort_way) { Session::put("$rName.sort_way", request()->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()->sort_col && request()->sort_way && Schema::hasColumn($table, request()->sort_col)) { if (! in_array(request()->sort_col, $ignore)) { $query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->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->latest('updated_at'); Session::put("$rName.sort_col", 'updated_at'); Session::put("$rName.sort_way", 'desc'); } elseif (Schema::hasColumn($table, 'created_at')) { $query = $query->latest(); Session::put("$rName.sort_col", 'created_at'); Session::put("$rName.sort_way", 'desc'); } return $query; } /** * Customize pagination with cache or config (default). */ protected function paginate( Builder $query, ?ItemsPerPaginationEnum $pagination = null ): LengthAwarePaginator { $currentRoutePath = Str::slug(request()->route()->getName()); $cacheKey = "pagination.{$currentRoutePath}"; $pagination ??= ItemsPerPaginationEnum::twelve; $pagination = ToolboxHelper::getValidatedEnum( Cache::get($cacheKey, $pagination->value()), 'pagination', ItemsPerPaginationEnum::class, ); if (Cache::get($cacheKey) !== $pagination) { Cache::put($cacheKey, $pagination); } $query = $query->paginate($pagination); return $query; } /** * Set the bootstrap theme or light (default). */ protected function setTheme(Request $request): 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 back()->with('success', __('crud.messages.theme_updated')); } }