refactor search functionality; remove deprecated services and implement new action and task classes for improved structure and maintainability
This commit is contained in:
+2
-1
@@ -11,4 +11,5 @@ _deploy
|
|||||||
dump.sql
|
dump.sql
|
||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
**/.DS_Store
|
**/.
|
||||||
|
.cursor
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Actions;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class ClearStaticSearchCacheAction
|
||||||
|
{
|
||||||
|
const CACHE_KEY = 'static_html_index_v2';
|
||||||
|
|
||||||
|
public function run(): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Cache::forget(self::CACHE_KEY);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Cache clear error: ' . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Actions;
|
||||||
|
|
||||||
|
use App\Containers\AdditionalEducation\Models\AdditionalEducation;
|
||||||
|
use App\Containers\AppStructure\Models\Page;
|
||||||
|
use App\Containers\Article\Models\Post;
|
||||||
|
use App\Containers\Education\Models\EducationalProgram;
|
||||||
|
use App\Containers\Event\Models\Event;
|
||||||
|
use App\Containers\InstituteStructure\Models\Faculty;
|
||||||
|
use App\Containers\Schedule\Models\EducationalGroup;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\AdditionalEducationSearchResource;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\EducationalProgramSearchResource;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\EducationGroupSearchResource;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\EventSearchResource;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\FacultySearchResource;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\PageSearchResource;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\PostSearchResource;
|
||||||
|
use App\Containers\Search\UI\API\Transformers\UserSearchResource;
|
||||||
|
use App\Containers\User\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Date;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use ProtoneMedia\LaravelCrossEloquentSearch\Search;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class PerformCrossEloquentSearchAction
|
||||||
|
{
|
||||||
|
private array $resourceMap = [
|
||||||
|
Post::class => PostSearchResource::class,
|
||||||
|
Page::class => PageSearchResource::class,
|
||||||
|
EducationalGroup::class => EducationGroupSearchResource::class,
|
||||||
|
EducationalProgram::class => EducationalProgramSearchResource::class,
|
||||||
|
Event::class => EventSearchResource::class,
|
||||||
|
AdditionalEducation::class => AdditionalEducationSearchResource::class, //??
|
||||||
|
User::class => UserSearchResource::class, //??
|
||||||
|
Faculty::class => FacultySearchResource::class, //??
|
||||||
|
];
|
||||||
|
|
||||||
|
public function run(string $query): Collection
|
||||||
|
{
|
||||||
|
$results = Search::new()
|
||||||
|
->add(Post::where('status', '=', 'published'), ['title', 'search_data'], 'publish_at')
|
||||||
|
->add(Page::with('section')->where('searchable', '=', true), ['title', 'search_data'])
|
||||||
|
->add(Event::where('event_date_start', '>', Date::now()), 'title', 'created_at')
|
||||||
|
->add(AdditionalEducation::where('is_active', '=', true), 'title')
|
||||||
|
->add(EducationalGroup::with('schedules'), 'title')
|
||||||
|
->add(EducationalProgram::where('status', '=', true)->whereHas('admission_plans'), 'name')
|
||||||
|
->add(Faculty::where('is_active', '=', true), 'title')
|
||||||
|
->add(User::whereHas('userDetail'), 'name')
|
||||||
|
->orderByDesc()
|
||||||
|
->beginWithWildcard()
|
||||||
|
->includeModelType()
|
||||||
|
->ignoreCase(true)
|
||||||
|
->search("$query");
|
||||||
|
|
||||||
|
$resourceMap = $this->resourceMap;
|
||||||
|
$resources = collect($results)->map(function ($result) use ($resourceMap) {
|
||||||
|
$resourceClass = $resourceMap[get_class($result)] ?? null;
|
||||||
|
return $resourceClass ? new $resourceClass($result) : null;
|
||||||
|
})->filter(); // Filter out nulls from resources
|
||||||
|
|
||||||
|
return $resources;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Actions;
|
||||||
|
|
||||||
|
use App\Containers\Search\Tasks\BuildStaticFileIndexTask;
|
||||||
|
|
||||||
|
class RebuildStaticSearchIndexAction
|
||||||
|
{
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
// Clear existing cache (optional, depending on rebuild logic, but typical for full rebuilds)
|
||||||
|
// app(ClearStaticSearchCacheAction::class)->run();
|
||||||
|
|
||||||
|
return app(BuildStaticFileIndexTask::class)->run();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Actions;
|
||||||
|
|
||||||
|
use App\Containers\Search\Tasks\BuildStaticFileIndexTask;
|
||||||
|
use App\Containers\Search\Tasks\PaginateSearchResultsTask;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class SearchStaticFilesAction
|
||||||
|
{
|
||||||
|
const PER_PAGE = 10; // Количество результатов на страницу
|
||||||
|
|
||||||
|
public function run(Request $request): array
|
||||||
|
{
|
||||||
|
$query = $request->input('search');
|
||||||
|
$category = $request->input('category');
|
||||||
|
$page = $request->input('page', 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$index = app(BuildStaticFileIndexTask::class)->run();
|
||||||
|
$results = [];
|
||||||
|
$normalizedQuery = $this->normalizeText(Str::lower($query));
|
||||||
|
|
||||||
|
foreach ($index as $filePath => $content) {
|
||||||
|
if (stripos($content['content'], $normalizedQuery) !== false) {
|
||||||
|
$relativePath = str_replace(public_path() . '/', '', $filePath);
|
||||||
|
$results[] = [
|
||||||
|
'file' => $relativePath,
|
||||||
|
'content' => $content['title'],
|
||||||
|
'category' => trim($content['category']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$categories = array_values(array_unique(array_filter(array_column($results, 'category'))));
|
||||||
|
|
||||||
|
if ($category !== null) {
|
||||||
|
$results = array_filter($results, function($item) use ($category) {
|
||||||
|
return $item['category'] === $category;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Переиндексировать массив
|
||||||
|
$results = array_values($results);
|
||||||
|
}
|
||||||
|
|
||||||
|
return app(PaginateSearchResultsTask::class)->run($results, $page, self::PER_PAGE, $categories);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Search error: ' . $e->getMessage());
|
||||||
|
return [
|
||||||
|
'data' => [],
|
||||||
|
'meta' => [
|
||||||
|
'current_page' => 1,
|
||||||
|
'total' => 0,
|
||||||
|
'per_page' => self::PER_PAGE,
|
||||||
|
'last_page' => 1
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeText(string $text): string
|
||||||
|
{
|
||||||
|
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
$text = preg_replace('/\s+/u', ' ', $text);
|
||||||
|
$text = trim($text);
|
||||||
|
return Str::lower($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFirstH1Content(string $content): ?string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (preg_match('/<h1[^>]*>(.*?)<\/h1>/is', $content, $matches)) {
|
||||||
|
return $this->normalizeText($matches[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to get H1: ' . $e->getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Containers\Search\Services;
|
|
||||||
|
|
||||||
use DiDom\Document;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use RecursiveDirectoryIterator;
|
|
||||||
use RecursiveIteratorIterator;
|
|
||||||
|
|
||||||
class CategoryFinderService
|
|
||||||
{
|
|
||||||
const FILES_DIR = 'sveden';
|
|
||||||
|
|
||||||
public function getCategories()
|
|
||||||
{
|
|
||||||
$file = public_path(self::FILES_DIR . '/' . 'index.html');
|
|
||||||
$html = file_get_contents($file);
|
|
||||||
|
|
||||||
$document = new Document($html);
|
|
||||||
$dropdownMenu = $document->first('ul.dropdown-menu');
|
|
||||||
$links = $dropdownMenu->find('a');
|
|
||||||
$categories = [];
|
|
||||||
|
|
||||||
foreach ($links as $link) {
|
|
||||||
$category = trim($link->text());
|
|
||||||
$categories[] = $category;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Containers\Search\Services;
|
|
||||||
|
|
||||||
use DiDom\Document;
|
|
||||||
|
|
||||||
class HtmlContentExtractorService
|
|
||||||
{
|
|
||||||
public function getContent(string $html): ?array
|
|
||||||
{
|
|
||||||
$document = new Document($html);
|
|
||||||
$content = $document->first('.vikon-content');
|
|
||||||
$breadcrumb = $content->first('.row');
|
|
||||||
$content->firstInDocument('.row')->remove();
|
|
||||||
|
|
||||||
return [$content->html(), $breadcrumb->html()] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Containers\Search\Services;
|
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use RecursiveDirectoryIterator;
|
|
||||||
use RecursiveIteratorIterator;
|
|
||||||
|
|
||||||
class StaticFileSearch
|
|
||||||
{
|
|
||||||
const CACHE_KEY = 'static_html_index_v2';
|
|
||||||
const FILES_DIR = 'sveden';
|
|
||||||
const CACHE_TTL = 86400; // 24 часа
|
|
||||||
const PER_PAGE = 10; // Количество результатов на страницу
|
|
||||||
|
|
||||||
public function search(Request $request): array
|
|
||||||
{
|
|
||||||
$query = $request->input('search');
|
|
||||||
$category = $request->input('category');
|
|
||||||
$page = request()->input('page', 1);
|
|
||||||
|
|
||||||
|
|
||||||
if ($query === null) {
|
|
||||||
return [
|
|
||||||
'data' => []
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$index = $this->getIndex();
|
|
||||||
$results = [];
|
|
||||||
$normalizedQuery = $this->normalizeText(Str::lower($query));
|
|
||||||
|
|
||||||
foreach ($index as $filePath => $content) {
|
|
||||||
if (stripos($content['content'], $normalizedQuery) !== false) {
|
|
||||||
$relativePath = str_replace(public_path() . '/', '', $filePath);
|
|
||||||
$results[] = [
|
|
||||||
'file' => $relativePath,
|
|
||||||
'content' => $content['title'],
|
|
||||||
'category' => trim($content['category']),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$categories = array_values(array_unique(array_filter(array_column($results, 'category'))));
|
|
||||||
|
|
||||||
|
|
||||||
if ($category !== null) {
|
|
||||||
$results = array_filter($results, function($item) use ($category) {
|
|
||||||
return $item['category'] === $category;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Переиндексировать массив
|
|
||||||
$results = array_values($results);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return $this->paginateResults($results, $page, $categories);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::error('Search error: ' . $e->getMessage());
|
|
||||||
return [
|
|
||||||
'data' => [],
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => 1,
|
|
||||||
'total' => 0,
|
|
||||||
'per_page' => self::PER_PAGE,
|
|
||||||
'last_page' => 1
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function paginateResults(array $results, int $page, ?array $categories): array
|
|
||||||
{
|
|
||||||
$total = count($results);
|
|
||||||
$lastPage = max(1, ceil($total / self::PER_PAGE));
|
|
||||||
$page = max(1, min($page, $lastPage));
|
|
||||||
|
|
||||||
$offset = ($page - 1) * self::PER_PAGE;
|
|
||||||
$paginatedResults = array_slice($results, $offset, self::PER_PAGE);
|
|
||||||
|
|
||||||
return [
|
|
||||||
'data' => $paginatedResults,
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $page,
|
|
||||||
'total' => $total,
|
|
||||||
'per_page' => self::PER_PAGE,
|
|
||||||
'last_page' => $lastPage
|
|
||||||
],
|
|
||||||
'categories' => $categories
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getIndex(): array
|
|
||||||
{
|
|
||||||
return Cache::remember(self::CACHE_KEY, self::CACHE_TTL, function() {
|
|
||||||
try {
|
|
||||||
$index = [];
|
|
||||||
$directory = public_path(self::FILES_DIR);
|
|
||||||
|
|
||||||
if (!is_dir($directory)) {
|
|
||||||
Log::error("Directory not found: {$directory}");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$iterator = new RecursiveIteratorIterator(
|
|
||||||
new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
|
|
||||||
RecursiveIteratorIterator::SELF_FIRST
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($iterator as $file) {
|
|
||||||
if ($file->isFile() && $this->isHtmlFile($file)) {
|
|
||||||
$html = file_get_contents($file->getPathname());
|
|
||||||
[$content, $breadcrumb] = app(HtmlContentExtractorService::class)->getContent($html);
|
|
||||||
if ($content !== false) {
|
|
||||||
$breadcrumb = app(BreadcrumbFinderService::class)->isSameCategory($breadcrumb);
|
|
||||||
$text = $this->normalizeText(strip_tags($content));
|
|
||||||
$index[$file->getPathname()] = [
|
|
||||||
'title' => $this->getFirstH1Content($content),
|
|
||||||
'content' => $text,
|
|
||||||
'category' => $breadcrumb ?? null,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $index;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::error('Index creation error: ' . $e->getMessage());
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isHtmlFile(\SplFileInfo $file): bool
|
|
||||||
{
|
|
||||||
$extension = strtolower($file->getExtension());
|
|
||||||
return in_array($extension, ['html', 'htm']);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function normalizeText(string $text): string
|
|
||||||
{
|
|
||||||
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
|
||||||
$text = preg_replace('/\s+/u', ' ', $text);
|
|
||||||
$text = trim($text);
|
|
||||||
return Str::lower($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findMatches(string $content, string $query): array
|
|
||||||
{
|
|
||||||
$matches = [];
|
|
||||||
$offset = 0;
|
|
||||||
$query = Str::lower($query);
|
|
||||||
$content = Str::lower($content);
|
|
||||||
$queryLength = mb_strlen($query, 'UTF-8');
|
|
||||||
|
|
||||||
while (($offset = mb_strpos($content, $query, $offset, 'UTF-8')) !== false) {
|
|
||||||
$start = max(0, $offset - 50);
|
|
||||||
$length = min(150, mb_strlen($content) - $start);
|
|
||||||
$excerpt = mb_substr($content, $start, $length, 'UTF-8');
|
|
||||||
|
|
||||||
$matches[] = str_replace(
|
|
||||||
$query,
|
|
||||||
'[[HIGHLIGHT]]'.$query.'[[/HIGHLIGHT]]',
|
|
||||||
$excerpt
|
|
||||||
);
|
|
||||||
|
|
||||||
$offset += $queryLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clearCache(): bool
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
Cache::forget(self::CACHE_KEY);
|
|
||||||
return true;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::error('Cache clear error: ' . $e->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rebuildIndex(): array
|
|
||||||
{
|
|
||||||
$this->clearCache();
|
|
||||||
return $this->getIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheStatus(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'exists' => Cache::has(self::CACHE_KEY),
|
|
||||||
'ttl' => Cache::get(self::CACHE_KEY.'_ttl', null),
|
|
||||||
'driver' => config('cache.default'),
|
|
||||||
'path' => public_path(self::FILES_DIR),
|
|
||||||
'directory_exists' => is_dir(public_path(self::FILES_DIR))
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFirstH1Content(string $content): ?string
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (preg_match('/<h1[^>]*>(.*?)<\/h1>/is', $content, $matches)) {
|
|
||||||
return $this->normalizeText($matches[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::error('Failed to get H1: ' . $e->getMessage());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
use App\Containers\Search\Tasks\ExtractHtmlContentTask;
|
||||||
|
use App\Containers\Search\Tasks\GetBreadcrumbFromHtmlTask;
|
||||||
|
|
||||||
|
class BuildStaticFileIndexTask
|
||||||
|
{
|
||||||
|
const CACHE_KEY = 'static_html_index_v2';
|
||||||
|
const FILES_DIR = 'sveden';
|
||||||
|
const CACHE_TTL = 86400; // 24 часа
|
||||||
|
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
return Cache::remember(self::CACHE_KEY, self::CACHE_TTL, function() {
|
||||||
|
try {
|
||||||
|
$index = [];
|
||||||
|
$directory = public_path(self::FILES_DIR);
|
||||||
|
|
||||||
|
if (!is_dir($directory)) {
|
||||||
|
Log::error("Directory not found: {$directory}");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = new RecursiveIteratorIterator(
|
||||||
|
new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||||
|
RecursiveIteratorIterator::SELF_FIRST
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
if ($file->isFile() && $this->isHtmlFile($file)) {
|
||||||
|
$html = file_get_contents($file->getPathname());
|
||||||
|
[$content, $breadcrumb] = app(ExtractHtmlContentTask::class)->run($html);
|
||||||
|
if ($content !== false) {
|
||||||
|
$breadcrumb = app(GetBreadcrumbFromHtmlTask::class)->run($breadcrumb);
|
||||||
|
$text = $this->normalizeText(strip_tags($content));
|
||||||
|
$index[$file->getPathname()] = [
|
||||||
|
'title' => $this->getFirstH1Content($content),
|
||||||
|
'content' => $text,
|
||||||
|
'category' => $breadcrumb ?? null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $index;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Index creation error: ' . $e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isHtmlFile(\SplFileInfo $file): bool
|
||||||
|
{
|
||||||
|
$extension = strtolower($file->getExtension());
|
||||||
|
return in_array($extension, ['html', 'htm']);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeText(string $text): string
|
||||||
|
{
|
||||||
|
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
$text = preg_replace('/\s+/u', ' ', $text);
|
||||||
|
$text = trim($text);
|
||||||
|
return Str::lower($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFirstH1Content(string $content): ?string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (preg_match('/<h1[^>]*>(.*?)<\/h1>/is', $content, $matches)) {
|
||||||
|
return $this->normalizeText($matches[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to get H1: ' . $e->getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use DiDom\Document;
|
||||||
|
|
||||||
|
class ExtractHtmlContentTask
|
||||||
|
{
|
||||||
|
public function run(string $html): ?array
|
||||||
|
{
|
||||||
|
$document = new Document($html);
|
||||||
|
$content = $document->first('.vikon-content');
|
||||||
|
if ($content === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$breadcrumb = $content->first('.row');
|
||||||
|
if ($breadcrumb !== null) {
|
||||||
|
$content->firstInDocument('.row')->remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$content->html(), $breadcrumb->html() ?? null];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class FilterSearchResultsByCategoryTask
|
||||||
|
{
|
||||||
|
public function run(Collection $resources, ?string $category): Collection
|
||||||
|
{
|
||||||
|
if ($category === null || $category === "All") {
|
||||||
|
return $resources;
|
||||||
|
} else {
|
||||||
|
return $resources->where('type', $category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class GetAvailableSearchCategoriesTask
|
||||||
|
{
|
||||||
|
public function run(Collection $resources): array
|
||||||
|
{
|
||||||
|
return $resources->pluck('type')->unique()->values()->all();
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-14
@@ -1,31 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Containers\Search\Services;
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
use DiDom\Document;
|
use DiDom\Document;
|
||||||
|
|
||||||
class BreadcrumbFinderService
|
class GetBreadcrumbFromHtmlTask
|
||||||
{
|
{
|
||||||
const FILES_DIR = 'sveden';
|
public function run(string $html): ?string
|
||||||
|
|
||||||
public function isSameCategory($html)
|
|
||||||
{
|
|
||||||
return $this->getBreadcrumb($html);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getBreadcrumb(string $html): ?string
|
|
||||||
{
|
{
|
||||||
$document = new Document($html);
|
$document = new Document($html);
|
||||||
$breadcrumbs = $document->first('ol.breadcrumb')?->find('li') ?? [];
|
$breadcrumbs = $document->first('ol.breadcrumb')?->find('li') ?? [];
|
||||||
|
|
||||||
foreach ($breadcrumbs as $index => $breadcrumb) {
|
foreach ($breadcrumbs as $index => $breadcrumb) {
|
||||||
if ($index === 2) { // Индексация с 0 → третий элемент = 2
|
if ($index === 2) { // Индексация с 0 → третий элемент = 2
|
||||||
return $breadcrumb->text();
|
return trim($breadcrumb->text());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use DiDom\Document;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class GetStaticFileCategoriesTask
|
||||||
|
{
|
||||||
|
const FILES_DIR = 'sveden';
|
||||||
|
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$file = public_path(self::FILES_DIR . '/' . 'index.html');
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
Log::error("Category index file not found: {$file}");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = file_get_contents($file);
|
||||||
|
|
||||||
|
$document = new Document($html);
|
||||||
|
$dropdownMenu = $document->first('ul.dropdown-menu');
|
||||||
|
|
||||||
|
if ($dropdownMenu === null) {
|
||||||
|
Log::warning("Dropdown menu not found in category index file: {$file}");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$links = $dropdownMenu->find('a');
|
||||||
|
$categories = [];
|
||||||
|
|
||||||
|
foreach ($links as $link) {
|
||||||
|
$category = trim($link->text());
|
||||||
|
$categories[] = $category;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $categories;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error extracting categories: ' . $e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class GetStaticSearchCacheStatusTask
|
||||||
|
{
|
||||||
|
const CACHE_KEY = 'static_html_index_v2';
|
||||||
|
const FILES_DIR = 'sveden';
|
||||||
|
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'exists' => Cache::has(self::CACHE_KEY),
|
||||||
|
'ttl' => Cache::get(self::CACHE_KEY.'_ttl', null),
|
||||||
|
'driver' => config('cache.default'),
|
||||||
|
'path' => public_path(self::FILES_DIR),
|
||||||
|
'directory_exists' => is_dir(public_path(self::FILES_DIR))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class PaginateCollectionTask
|
||||||
|
{
|
||||||
|
public function run(Collection $resources, Request $request, int $perPage = 10): array
|
||||||
|
{
|
||||||
|
$currentPage = LengthAwarePaginator::resolveCurrentPage();
|
||||||
|
|
||||||
|
// Отрезаем нужные элементы для текущей страницы
|
||||||
|
$currentItems = $resources->slice(($currentPage - 1) * $perPage, $perPage)->all();
|
||||||
|
|
||||||
|
// Создаем экземпляр LengthAwarePaginator
|
||||||
|
$paginator = new LengthAwarePaginator($currentItems, count($resources), $perPage, $currentPage, [
|
||||||
|
'path' => $request->url(),
|
||||||
|
'query' => $request->query(), // Changed from $request->query to $request->query()
|
||||||
|
]);
|
||||||
|
|
||||||
|
$nextPage = $paginator->hasMorePages() ? $paginator->currentPage() + 1 : null;
|
||||||
|
$prevPage = $paginator->onFirstPage() ? null : $paginator->currentPage() - 1;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'paginator' => $paginator,
|
||||||
|
'next_page' => $nextPage,
|
||||||
|
'prev_page' => $prevPage
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
class PaginateSearchResultsTask
|
||||||
|
{
|
||||||
|
public function run(array $results, int $page, int $perPage, ?array $categories): array
|
||||||
|
{
|
||||||
|
$total = count($results);
|
||||||
|
$lastPage = max(1, ceil($total / $perPage));
|
||||||
|
$page = max(1, min($page, $lastPage));
|
||||||
|
|
||||||
|
$offset = ($page - 1) * $perPage;
|
||||||
|
$paginatedResults = array_slice($results, $offset, $perPage);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'data' => $paginatedResults,
|
||||||
|
'meta' => [
|
||||||
|
'current_page' => $page,
|
||||||
|
'total' => $total,
|
||||||
|
'per_page' => $perPage,
|
||||||
|
'last_page' => $lastPage
|
||||||
|
],
|
||||||
|
'categories' => $categories
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Containers\Search\Tasks;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class SortAndHighlightSearchResultsTask
|
||||||
|
{
|
||||||
|
public function run(Collection $data, string $searchRequest): array
|
||||||
|
{
|
||||||
|
$sortedData = [];
|
||||||
|
|
||||||
|
foreach ($data as $item) {
|
||||||
|
$searchData = $item['search_data'] ?? '';
|
||||||
|
$matches = $this->getMatches($searchData, $searchRequest);
|
||||||
|
$sortedData[$item['type']][] = [
|
||||||
|
'data' => $item,
|
||||||
|
'matches' => $matches,
|
||||||
|
'tag' => $item['type']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sortedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMatches(string $haystack, string $needle): array
|
||||||
|
{
|
||||||
|
$matches = [];
|
||||||
|
$offset = 0;
|
||||||
|
if (($offset = mb_strpos($haystack, $needle, $offset, 'UTF-8')) !== false) {
|
||||||
|
for ($i = 0; 1 > count($matches); $i++) {
|
||||||
|
$left = max(0, $offset - 50);
|
||||||
|
$right = min(mb_strlen($haystack, 'UTF-8'), $offset + 100);
|
||||||
|
$excerpt = mb_substr($haystack, $left, $right - $left, 'UTF-8');
|
||||||
|
$matches[] = $excerpt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,175 +2,46 @@
|
|||||||
|
|
||||||
namespace App\Containers\Search\UI\API\Controllers;
|
namespace App\Containers\Search\UI\API\Controllers;
|
||||||
|
|
||||||
use App\Containers\AdditionalEducation\Models\AdditionalEducation;
|
use App\Containers\Search\Actions\PerformCrossEloquentSearchAction;
|
||||||
use App\Containers\AppStructure\Models\Page;
|
use App\Containers\Search\Tasks\FilterSearchResultsByCategoryTask;
|
||||||
use App\Containers\Article\Models\Post;
|
use App\Containers\Search\Tasks\GetAvailableSearchCategoriesTask;
|
||||||
use App\Containers\Education\Models\EducationalProgram;
|
use App\Containers\Search\Tasks\PaginateCollectionTask;
|
||||||
use App\Containers\Event\Models\Event;
|
use App\Containers\Search\Tasks\SortAndHighlightSearchResultsTask;
|
||||||
use App\Containers\InstituteStructure\Models\Faculty;
|
|
||||||
use App\Containers\Schedule\Models\EducationalGroup;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\AdditionalEducationSearchResource;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\EducationalProgramSearchResource;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\EducationGroupSearchResource;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\EventSearchResource;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\FacultySearchResource;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\PageSearchResource;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\PostSearchResource;
|
|
||||||
use App\Containers\Search\UI\API\Transformers\UserSearchResource;
|
|
||||||
use App\Containers\User\Models\User;
|
|
||||||
use App\Ship\Controllers\Controller;
|
use App\Ship\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\Date;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use ProtoneMedia\LaravelCrossEloquentSearch\Search;
|
|
||||||
|
|
||||||
class SearchController extends Controller
|
class SearchController extends Controller
|
||||||
{
|
{
|
||||||
private array $resourceMap = [
|
|
||||||
Post::class => PostSearchResource::class,
|
|
||||||
Page::class => PageSearchResource::class,
|
|
||||||
EducationalGroup::class => EducationGroupSearchResource::class,
|
|
||||||
EducationalProgram::class => EducationalProgramSearchResource::class,
|
|
||||||
Event::class => EventSearchResource::class,
|
|
||||||
AdditionalEducation::class => AdditionalEducationSearchResource::class, //??
|
|
||||||
User::class => UserSearchResource::class, //??
|
|
||||||
Faculty::class => FacultySearchResource::class, //??
|
|
||||||
];
|
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$req = Str::lower($request->query('search'));
|
$searchQuery = Str::lower($request->query('search'));
|
||||||
if (!$req) {
|
if (!$searchQuery) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'searchRes' => null,
|
'searchRes' => null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$allResources = app(PerformCrossEloquentSearchAction::class)->run($searchQuery);
|
||||||
|
$result_type = app(GetAvailableSearchCategoriesTask::class)->run($allResources);
|
||||||
|
|
||||||
$results = Search::new()
|
$filteredResources = app(FilterSearchResultsByCategoryTask::class)->run($allResources, $request->query('category'));
|
||||||
->add(Post::where('status', '=', 'published'), ['title', 'search_data'], 'publish_at')
|
|
||||||
->add(Page::with('section')->where('searchable', '=', true), ['title', 'search_data'])
|
|
||||||
->add(Event::where('event_date_start', '>', Date::now()), 'title', 'created_at')
|
|
||||||
->add(AdditionalEducation::where('is_active', '=', true), 'title')
|
|
||||||
->add(EducationalGroup::with('schedules'), 'title')
|
|
||||||
->add(EducationalProgram::where('status', '=', true)->whereHas('admission_plans'), 'name')
|
|
||||||
->add(Faculty::where('is_active', '=', true), 'title')
|
|
||||||
->add(User::whereHas('userDetail'), 'name')
|
|
||||||
->orderByDesc()
|
|
||||||
->beginWithWildcard()
|
|
||||||
// ->orderByRelevance()
|
|
||||||
->includeModelType()
|
|
||||||
->ignoreCase(true)
|
|
||||||
->search("$req");
|
|
||||||
|
|
||||||
|
$paginateData = app(PaginateCollectionTask::class)->run($filteredResources, $request, 7);
|
||||||
|
|
||||||
$resourceMap = $this->resourceMap;
|
$sortedData = app(SortAndHighlightSearchResultsTask::class)->run($paginateData['paginator']->getCollection(), $searchQuery);
|
||||||
$resources = collect($results)->map(function ($result) use ($resourceMap) {
|
|
||||||
$resourceClass = $resourceMap[get_class($result)] ?? null;
|
|
||||||
return $resourceClass ? new $resourceClass($result) : null;
|
|
||||||
});
|
|
||||||
|
|
||||||
$result_type = $this->getCategoriesSearchResult($resources);
|
|
||||||
|
|
||||||
|
|
||||||
if ($request->query('category')) {
|
|
||||||
$resources = $this->sortResourcesByCategory($resources, $request->query('category'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$paginate_data = $this->createPaginate($resources, $request, 7);
|
|
||||||
|
|
||||||
$sortedData = $this->sortByType($paginate_data['paginator'], $req);
|
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'searchRes' => $sortedData,
|
'searchRes' => $sortedData,
|
||||||
'result_type' => $result_type,
|
'result_type' => $result_type,
|
||||||
'selectedCategory' => ($request->query('category') !== null) ? $request->query('category') : null,
|
'selectedCategory' => ($request->query('category') !== null) ? $request->query('category') : null,
|
||||||
'paginate' => [
|
'paginate' => [
|
||||||
'current_page' => $paginate_data['paginator']->currentPage(),
|
'current_page' => $paginateData['paginator']->currentPage(),
|
||||||
'last_page' => $paginate_data['paginator']->lastPage(),
|
'last_page' => $paginateData['paginator']->lastPage(),
|
||||||
'total' => $paginate_data['paginator']->total(),
|
'total' => $paginateData['paginator']->total(),
|
||||||
'next_page' => $paginate_data['next_page'],
|
'next_page' => $paginateData['next_page'],
|
||||||
'prev_page' => $paginate_data['prev_page'],
|
'prev_page' => $paginateData['prev_page'],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
private function sortByType(object $data, string $searchRequest): array
|
|
||||||
{
|
|
||||||
$sortedData = [];
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
|
||||||
$searchData = $item['search_data'] ?? '';
|
|
||||||
$matches = $this->getMatches($searchData, $searchRequest);
|
|
||||||
$sortedData[$item['type']][] = [
|
|
||||||
'data' => $item,
|
|
||||||
'matches' => $matches,
|
|
||||||
'tag' => $item['type']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sortedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getMatches(string $haystack, string $needle): array
|
|
||||||
{
|
|
||||||
$matches = [];
|
|
||||||
// while (($offset = mb_strpos($haystack, $needle, $offset, 'UTF-8')) !== false) {
|
|
||||||
// $left = max(0, $offset - 50);
|
|
||||||
// $right = min(mb_strlen($haystack, 'UTF-8'), $offset + 100);
|
|
||||||
// $excerpt = mb_substr($haystack, $left, $right - $left, 'UTF-8');
|
|
||||||
// $matches[] = $excerpt;
|
|
||||||
// $offset += mb_strlen($needle, 'UTF-8');
|
|
||||||
// }
|
|
||||||
|
|
||||||
$offset = 0;
|
|
||||||
if (($offset = mb_strpos($haystack, $needle, $offset, 'UTF-8')) !== false) {
|
|
||||||
for ($i = 0; 1 > count($matches); $i++) {
|
|
||||||
$left = max(0, $offset - 50);
|
|
||||||
$right = min(mb_strlen($haystack, 'UTF-8'), $offset + 100);
|
|
||||||
$excerpt = mb_substr($haystack, $left, $right - $left, 'UTF-8');
|
|
||||||
$matches[] = $excerpt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function sortResourcesByCategory(Collection $resources, string $category) : Collection
|
|
||||||
{
|
|
||||||
if ($category === "All") {
|
|
||||||
$data = $resources;
|
|
||||||
} else {
|
|
||||||
$data = $resources->where('type', $category);
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getCategoriesSearchResult(Collection $resources)
|
|
||||||
{
|
|
||||||
return $resources->pluck('type')->unique()->values()->all();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createPaginate($resources, $request, $perPage = 10) : array
|
|
||||||
{
|
|
||||||
$currentPage = LengthAwarePaginator::resolveCurrentPage();
|
|
||||||
|
|
||||||
// Отрезаем нужные элементы для текущей страницы
|
|
||||||
$currentItems = $resources->slice(($currentPage - 1) * $perPage, $perPage)->all();
|
|
||||||
|
|
||||||
// Создаем экземпляр LengthAwarePaginator
|
|
||||||
$paginator = new LengthAwarePaginator($currentItems, count($resources), $perPage, $currentPage, [
|
|
||||||
'path' => $request->url(),
|
|
||||||
'query' => $request->query,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$nextPage = $paginator->hasMorePages() ? $paginator->currentPage() + 1 : null;
|
|
||||||
$prevPage = $paginator->onFirstPage() ? null : $paginator->currentPage() - 1;
|
|
||||||
|
|
||||||
return [
|
|
||||||
'paginator' => $paginator,
|
|
||||||
'next_page' => $nextPage,
|
|
||||||
'prev_page' => $prevPage
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Containers\Search\UI\API\Controllers;
|
namespace App\Containers\Search\UI\API\Controllers;
|
||||||
|
|
||||||
use App\Containers\Search\Services\CategoryFinderService;
|
use App\Containers\Search\Actions\SearchStaticFilesAction;
|
||||||
use App\Containers\Search\Services\StaticFileSearch;
|
use App\Containers\Search\Tasks\GetStaticFileCategoriesTask;
|
||||||
use App\Ship\Controllers\Controller;
|
use App\Ship\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
@@ -12,14 +12,14 @@ class StaticSearchController extends Controller
|
|||||||
{
|
{
|
||||||
public function search(Request $request)
|
public function search(Request $request)
|
||||||
{
|
{
|
||||||
return app(StaticFileSearch::class)
|
return app(SearchStaticFilesAction::class)
|
||||||
->search($request);
|
->run($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategories()
|
public function getCategories()
|
||||||
{
|
{
|
||||||
return Cache::remember('page_static_categories', now()->addWeek(), function () {
|
return Cache::remember('page_static_categories', now()->addWeek(), function () {
|
||||||
return app(CategoryFinderService::class)->getCategories();
|
return app(GetStaticFileCategoriesTask::class)->run();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user