File: D:/HostingSpaces/SBogers10/blije-gasten.komma.pro/app/Komma/Shop/Search/SearchService.php
<?php
namespace App\Komma\Shop\Search;
use App\Komma\Base\Service;
use App\Komma\Kms\Core\AbstractTranslationModel;
use App\Komma\Shop\Categories\Models\CategoryTranslation;
use App\Komma\Shop\Products\Product\ProductTranslation;
use App\Komma\Shop\Search\Types\SearchResult;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
class SearchService extends Service
{
/**
* The models that can be searched trough. They are recognized because they use the Searchable trait
*
* @var array
*/
public static $searchableModelClasses = [
// Product::class,
// Category::class,
ProductTranslation::class,
CategoryTranslation::class
];
/**
* Get collection of models that match the given term
*
* @param string $term
* @return Collection
*/
public function searchByTerm(string $term): Collection
{
//Make a collection that will hold al found models
$foundModels = collect();
foreach (self::$searchableModelClasses as $searchableModelClass) {
//Check if the search method isset
if (!method_exists($searchableModelClass, 'search')) {
throw new \BadMethodCallException(self::class.': Search function not found within '. $searchableModelClass . '. Did you implement the SearchableTrait?');
}
// Create query for calling the search
$searchQuery = $searchableModelClass::search($term);
// Apply the language filter if AbstractTranslationModel
if(is_subclass_of($searchableModelClass, AbstractTranslationModel::class)) {
$searchQuery = $searchQuery->where('language_id', app()->getLanguage()->id);
}
// Get the models
// Note we use the paginate to be able to load relation on the search models
$searchModels = $searchQuery->paginate(25);
// Eager load the translatable on the model if AbstractTranslationModel
if(is_subclass_of($searchableModelClass, AbstractTranslationModel::class)) {
$searchModels->load('translatable', 'translatable.images');
// On productsTranslation we also want to load the categories
if(is_a($searchableModelClass, ProductTranslation::class, true)) {
$searchModels->load('translatable.categories', 'translatable.categories.translation');
}
}
// Append the search models to the found collection
$foundModels = $foundModels->merge($searchModels->items());
}
return $foundModels;
}
/**
* Convert models into search results
* We do this so we can easily loop in the blade instead of having complex if else constructions
*
* @param Collection $models
* @param $links
* @return Collection
*/
public function convertModelsIntoSearchResults(Collection $models, $links): Collection
{
$searchResults = collect();
foreach ($models as $model) {
$searchResult = null;
// Create the SearchResult for the given model
switch (get_class($model)) {
case ProductTranslation::class:
$searchResult = $this->simpleTranslationModelConversion($model, $links, 'products');
break;
case CategoryTranslation::class:
$searchResult = $this->simpleTranslationModelConversion($model, $links, 'categories');
break;
default:
throw new \InvalidArgumentException(self::class . ': Model (' . get_class($model) . ') has been defined for converting into a SearchResult');
}
// If search result ins't defined continue
if(!isset($searchResult)) continue;
//TODO: If it's possible to have double models (so Categories and CategoryTranslation are listed for searching) then create a check that prevent duplicated models
$searchResults->push($searchResult);
}
return $searchResults;
}
/**
* Simple conversion for an AbstractTranslationModel.
*
* Meaning that the model has a name and slug,
* has a translatable model that is active
* and is mapped by a page.
*
* @param AbstractTranslationModel $model
* @param $links
* @param string $linksName
* @return SearchResult|null
*/
private function simpleTranslationModelConversion(AbstractTranslationModel $model, $links, string $linksName): ? SearchResult
{
// Related page for mapping should be defined in links
if(!isset($links->{$linksName})) return null;
// Model should have a name and a slug
if(empty($model->name) && empty($model->slug)) return null;
// Model should have a translatable and it translatable should be active
if(!isset($model->translatable) && !$model->translatable->active) return null;
// Possibly add an image to the search result
$image = null;
if(isset($model->translatable->images) && $model->translatable->images->isNotEmpty()) {
$image = $model->translatable->images->first();
}
// Get only the translation model
$translationModel = clone $model;
$translationModel->unsetRelation('translatable');
// Recreate the model from the translatable to translation
$rootModel = $model->translatable;
$rootModel->setRelation('translation', $translationModel);
// Model is valid for creating the search result
return new SearchResult($rootModel, $translationModel->name, $links->{$linksName}->route . '/' . $translationModel->slug, $image);
}
}