diff --git a/.gitignore b/.gitignore
index 613fd50..6f33216 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,5 @@ _deploy
dump.sql
.idea
.DS_Store
-**/.DS_Store
+**/.
+.cursor
diff --git a/app/Containers/Search/Actions/ClearStaticSearchCacheAction.php b/app/Containers/Search/Actions/ClearStaticSearchCacheAction.php
new file mode 100644
index 0000000..c699b14
--- /dev/null
+++ b/app/Containers/Search/Actions/ClearStaticSearchCacheAction.php
@@ -0,0 +1,22 @@
+getMessage());
+ return false;
+ }
+ }
+}
diff --git a/app/Containers/Search/Actions/PerformCrossEloquentSearchAction.php b/app/Containers/Search/Actions/PerformCrossEloquentSearchAction.php
new file mode 100644
index 0000000..b2bf2a5
--- /dev/null
+++ b/app/Containers/Search/Actions/PerformCrossEloquentSearchAction.php
@@ -0,0 +1,64 @@
+ 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;
+ }
+}
diff --git a/app/Containers/Search/Actions/RebuildStaticSearchIndexAction.php b/app/Containers/Search/Actions/RebuildStaticSearchIndexAction.php
new file mode 100644
index 0000000..2797e78
--- /dev/null
+++ b/app/Containers/Search/Actions/RebuildStaticSearchIndexAction.php
@@ -0,0 +1,16 @@
+run();
+
+ return app(BuildStaticFileIndexTask::class)->run();
+ }
+}
diff --git a/app/Containers/Search/Actions/SearchStaticFilesAction.php b/app/Containers/Search/Actions/SearchStaticFilesAction.php
new file mode 100644
index 0000000..8e8a867
--- /dev/null
+++ b/app/Containers/Search/Actions/SearchStaticFilesAction.php
@@ -0,0 +1,84 @@
+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>/is', $content, $matches)) {
+ return $this->normalizeText($matches[1]);
+ }
+
+ return null;
+ } catch (\Exception $e) {
+ Log::error('Failed to get H1: ' . $e->getMessage());
+ return null;
+ }
+ }
+}
diff --git a/app/Containers/Search/Services/CategoryFinderService.php b/app/Containers/Search/Services/CategoryFinderService.php
deleted file mode 100644
index 73d962d..0000000
--- a/app/Containers/Search/Services/CategoryFinderService.php
+++ /dev/null
@@ -1,36 +0,0 @@
-first('ul.dropdown-menu');
- $links = $dropdownMenu->find('a');
- $categories = [];
-
- foreach ($links as $link) {
- $category = trim($link->text());
- $categories[] = $category;
- }
-
- return $categories;
- }
-
-
-}
\ No newline at end of file
diff --git a/app/Containers/Search/Services/HtmlContentExtractorService.php b/app/Containers/Search/Services/HtmlContentExtractorService.php
deleted file mode 100644
index 4b72212..0000000
--- a/app/Containers/Search/Services/HtmlContentExtractorService.php
+++ /dev/null
@@ -1,20 +0,0 @@
-first('.vikon-content');
- $breadcrumb = $content->first('.row');
- $content->firstInDocument('.row')->remove();
-
- return [$content->html(), $breadcrumb->html()] ?? null;
- }
-
-
-}
\ No newline at end of file
diff --git a/app/Containers/Search/Services/StaticFileSearch.php b/app/Containers/Search/Services/StaticFileSearch.php
deleted file mode 100644
index 643f20b..0000000
--- a/app/Containers/Search/Services/StaticFileSearch.php
+++ /dev/null
@@ -1,218 +0,0 @@
-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>/is', $content, $matches)) {
- return $this->normalizeText($matches[1]);
- }
-
- return null;
- } catch (\Exception $e) {
- Log::error('Failed to get H1: ' . $e->getMessage());
- return null;
- }
- }
-}
\ No newline at end of file
diff --git a/app/Containers/Search/Tasks/BuildStaticFileIndexTask.php b/app/Containers/Search/Tasks/BuildStaticFileIndexTask.php
new file mode 100644
index 0000000..d8e7e05
--- /dev/null
+++ b/app/Containers/Search/Tasks/BuildStaticFileIndexTask.php
@@ -0,0 +1,87 @@
+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>/is', $content, $matches)) {
+ return $this->normalizeText($matches[1]);
+ }
+
+ return null;
+ } catch (\Exception $e) {
+ Log::error('Failed to get H1: ' . $e->getMessage());
+ return null;
+ }
+ }
+}
diff --git a/app/Containers/Search/Tasks/ExtractHtmlContentTask.php b/app/Containers/Search/Tasks/ExtractHtmlContentTask.php
new file mode 100644
index 0000000..ba77856
--- /dev/null
+++ b/app/Containers/Search/Tasks/ExtractHtmlContentTask.php
@@ -0,0 +1,24 @@
+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];
+ }
+}
diff --git a/app/Containers/Search/Tasks/FilterSearchResultsByCategoryTask.php b/app/Containers/Search/Tasks/FilterSearchResultsByCategoryTask.php
new file mode 100644
index 0000000..d4f5702
--- /dev/null
+++ b/app/Containers/Search/Tasks/FilterSearchResultsByCategoryTask.php
@@ -0,0 +1,17 @@
+where('type', $category);
+ }
+ }
+}
diff --git a/app/Containers/Search/Tasks/GetAvailableSearchCategoriesTask.php b/app/Containers/Search/Tasks/GetAvailableSearchCategoriesTask.php
new file mode 100644
index 0000000..55c3336
--- /dev/null
+++ b/app/Containers/Search/Tasks/GetAvailableSearchCategoriesTask.php
@@ -0,0 +1,13 @@
+pluck('type')->unique()->values()->all();
+ }
+}
diff --git a/app/Containers/Search/Services/BreadcrumbFinderService.php b/app/Containers/Search/Tasks/GetBreadcrumbFromHtmlTask.php
similarity index 54%
rename from app/Containers/Search/Services/BreadcrumbFinderService.php
rename to app/Containers/Search/Tasks/GetBreadcrumbFromHtmlTask.php
index b03bec7..af8d72a 100644
--- a/app/Containers/Search/Services/BreadcrumbFinderService.php
+++ b/app/Containers/Search/Tasks/GetBreadcrumbFromHtmlTask.php
@@ -1,31 +1,22 @@
getBreadcrumb($html);
- }
-
- private function getBreadcrumb(string $html): ?string
+ public function run(string $html): ?string
{
$document = new Document($html);
$breadcrumbs = $document->first('ol.breadcrumb')?->find('li') ?? [];
foreach ($breadcrumbs as $index => $breadcrumb) {
if ($index === 2) { // Индексация с 0 → третий элемент = 2
- return $breadcrumb->text();
+ return trim($breadcrumb->text());
}
}
return null;
}
-
-
-}
\ No newline at end of file
+}
diff --git a/app/Containers/Search/Tasks/GetStaticFileCategoriesTask.php b/app/Containers/Search/Tasks/GetStaticFileCategoriesTask.php
new file mode 100644
index 0000000..6524249
--- /dev/null
+++ b/app/Containers/Search/Tasks/GetStaticFileCategoriesTask.php
@@ -0,0 +1,45 @@
+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 [];
+ }
+ }
+}
diff --git a/app/Containers/Search/Tasks/GetStaticSearchCacheStatusTask.php b/app/Containers/Search/Tasks/GetStaticSearchCacheStatusTask.php
new file mode 100644
index 0000000..995ee35
--- /dev/null
+++ b/app/Containers/Search/Tasks/GetStaticSearchCacheStatusTask.php
@@ -0,0 +1,22 @@
+ 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))
+ ];
+ }
+}
diff --git a/app/Containers/Search/Tasks/PaginateCollectionTask.php b/app/Containers/Search/Tasks/PaginateCollectionTask.php
new file mode 100644
index 0000000..289110f
--- /dev/null
+++ b/app/Containers/Search/Tasks/PaginateCollectionTask.php
@@ -0,0 +1,33 @@
+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
+ ];
+ }
+}
diff --git a/app/Containers/Search/Tasks/PaginateSearchResultsTask.php b/app/Containers/Search/Tasks/PaginateSearchResultsTask.php
new file mode 100644
index 0000000..1849012
--- /dev/null
+++ b/app/Containers/Search/Tasks/PaginateSearchResultsTask.php
@@ -0,0 +1,27 @@
+ $paginatedResults,
+ 'meta' => [
+ 'current_page' => $page,
+ 'total' => $total,
+ 'per_page' => $perPage,
+ 'last_page' => $lastPage
+ ],
+ 'categories' => $categories
+ ];
+ }
+}
diff --git a/app/Containers/Search/Tasks/SortAndHighlightSearchResultsTask.php b/app/Containers/Search/Tasks/SortAndHighlightSearchResultsTask.php
new file mode 100644
index 0000000..0938984
--- /dev/null
+++ b/app/Containers/Search/Tasks/SortAndHighlightSearchResultsTask.php
@@ -0,0 +1,42 @@
+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;
+ }
+}
diff --git a/app/Containers/Search/UI/API/Controllers/SearchController.php b/app/Containers/Search/UI/API/Controllers/SearchController.php
index 3a0188c..a49cb1f 100644
--- a/app/Containers/Search/UI/API/Controllers/SearchController.php
+++ b/app/Containers/Search/UI/API/Controllers/SearchController.php
@@ -2,175 +2,46 @@
namespace App\Containers\Search\UI\API\Controllers;
-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 App\Containers\Search\Actions\PerformCrossEloquentSearchAction;
+use App\Containers\Search\Tasks\FilterSearchResultsByCategoryTask;
+use App\Containers\Search\Tasks\GetAvailableSearchCategoriesTask;
+use App\Containers\Search\Tasks\PaginateCollectionTask;
+use App\Containers\Search\Tasks\SortAndHighlightSearchResultsTask;
use App\Ship\Controllers\Controller;
use Illuminate\Http\Request;
-use Illuminate\Pagination\LengthAwarePaginator;
-use Illuminate\Support\Collection;
-use Illuminate\Support\Facades\Date;
use Illuminate\Support\Str;
-use ProtoneMedia\LaravelCrossEloquentSearch\Search;
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)
{
- $req = Str::lower($request->query('search'));
- if (!$req) {
+ $searchQuery = Str::lower($request->query('search'));
+ if (!$searchQuery) {
return response()->json([
'searchRes' => null,
]);
}
+ $allResources = app(PerformCrossEloquentSearchAction::class)->run($searchQuery);
+ $result_type = app(GetAvailableSearchCategoriesTask::class)->run($allResources);
- $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()
-// ->orderByRelevance()
- ->includeModelType()
- ->ignoreCase(true)
- ->search("$req");
+ $filteredResources = app(FilterSearchResultsByCategoryTask::class)->run($allResources, $request->query('category'));
+ $paginateData = app(PaginateCollectionTask::class)->run($filteredResources, $request, 7);
- $resourceMap = $this->resourceMap;
- $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);
+ $sortedData = app(SortAndHighlightSearchResultsTask::class)->run($paginateData['paginator']->getCollection(), $searchQuery);
return response()->json([
'searchRes' => $sortedData,
'result_type' => $result_type,
'selectedCategory' => ($request->query('category') !== null) ? $request->query('category') : null,
'paginate' => [
- 'current_page' => $paginate_data['paginator']->currentPage(),
- 'last_page' => $paginate_data['paginator']->lastPage(),
- 'total' => $paginate_data['paginator']->total(),
- 'next_page' => $paginate_data['next_page'],
- 'prev_page' => $paginate_data['prev_page'],
+ 'current_page' => $paginateData['paginator']->currentPage(),
+ 'last_page' => $paginateData['paginator']->lastPage(),
+ 'total' => $paginateData['paginator']->total(),
+ 'next_page' => $paginateData['next_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
- ];
- }
}
diff --git a/app/Containers/Search/UI/API/Controllers/StaticSearchController.php b/app/Containers/Search/UI/API/Controllers/StaticSearchController.php
index b712e87..9827cec 100644
--- a/app/Containers/Search/UI/API/Controllers/StaticSearchController.php
+++ b/app/Containers/Search/UI/API/Controllers/StaticSearchController.php
@@ -2,8 +2,8 @@
namespace App\Containers\Search\UI\API\Controllers;
-use App\Containers\Search\Services\CategoryFinderService;
-use App\Containers\Search\Services\StaticFileSearch;
+use App\Containers\Search\Actions\SearchStaticFilesAction;
+use App\Containers\Search\Tasks\GetStaticFileCategoriesTask;
use App\Ship\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
@@ -12,14 +12,14 @@ class StaticSearchController extends Controller
{
public function search(Request $request)
{
- return app(StaticFileSearch::class)
- ->search($request);
+ return app(SearchStaticFilesAction::class)
+ ->run($request);
}
public function getCategories()
{
return Cache::remember('page_static_categories', now()->addWeek(), function () {
- return app(CategoryFinderService::class)->getCategories();
+ return app(GetStaticFileCategoriesTask::class)->run();
});
}
}