218 lines
6.0 KiB
PHP
218 lines
6.0 KiB
PHP
<?php
|
|
|
|
namespace OFFLINE\SiteSearch\Classes\Providers;
|
|
|
|
use Carbon\Carbon;
|
|
use Cms\Classes\Controller;
|
|
use DB;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use OFFLINE\SiteSearch\Classes\Result;
|
|
use OFFLINE\SiteSearch\Models\Settings;
|
|
use RainLab\Blog\Models\Post;
|
|
use Throwable;
|
|
|
|
/**
|
|
* Searches the contents generated by the
|
|
* Rainlab.Blog plugin
|
|
*
|
|
* @package OFFLINE\SiteSearch\Classes\Providers
|
|
*/
|
|
class RainlabBlogResultsProvider extends ResultsProvider
|
|
{
|
|
/**
|
|
* @var Controller to be used to form urls to search results
|
|
*/
|
|
protected $controller;
|
|
|
|
/**
|
|
* ResultsProvider constructor.
|
|
*
|
|
* @param $query
|
|
* @param \Cms\Classes\Controller $controller
|
|
*/
|
|
public function __construct($query, Controller $controller)
|
|
{
|
|
parent::__construct($query);
|
|
$this->controller = $controller;
|
|
}
|
|
|
|
/**
|
|
* Runs the search for this provider.
|
|
*
|
|
* @return ResultsProvider
|
|
*/
|
|
public function search()
|
|
{
|
|
if ( ! $this->isInstalledAndEnabled()) {
|
|
return $this;
|
|
}
|
|
|
|
foreach ($this->posts() as $post) {
|
|
// Make this result more relevant, if the query is found in the title
|
|
$relevance = mb_stripos($post->title, $this->query) === false ? 1 : 2;
|
|
|
|
if ($relevance > 1 && $post->published_at) {
|
|
// Make sure that `published_at` is a Carbon object
|
|
$publishedAt = $post->published_at;
|
|
if (is_string($publishedAt)) {
|
|
try {
|
|
$publishedAt = Carbon::parse($publishedAt);
|
|
} catch (Throwable $e) {
|
|
// If parsing fails use the current date.
|
|
$publishedAt = Carbon::now();
|
|
}
|
|
}
|
|
$relevance -= $this->getAgePenalty($publishedAt->diffInDays(Carbon::now()));
|
|
}
|
|
|
|
$result = new Result($this->query, $relevance);
|
|
$result->title = $post->title;
|
|
$result->text = $post->summary;
|
|
$result->meta = $post->created_at;
|
|
$result->model = $post;
|
|
|
|
// Maintain compatibility with old setting
|
|
if (Settings::get('rainlab_blog_page') !== null) {
|
|
$result->url = $post->setUrl(Settings::get('rainlab_blog_page', ''), $this->controller);
|
|
} else {
|
|
$result->url = $this->getUrl($post);
|
|
}
|
|
|
|
$result->thumb = $this->getThumb($post->featured_images);
|
|
|
|
$this->addResult($result);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get all posts with matching title or content.
|
|
*
|
|
* @return Collection
|
|
*/
|
|
protected function posts()
|
|
{
|
|
// If Rainlab.Translate is not installed or we are currently,
|
|
// using the default locale we simply query the default table.
|
|
$translator = $this->translator();
|
|
if ( ! $translator || $translator->getDefaultLocale() === $translator->getLocale()) {
|
|
return $this->postsFromDefaultLocale();
|
|
}
|
|
|
|
// If Rainlab.Translate is available we also have to
|
|
// query the rainlab_translate_attributes table for translated
|
|
// contents since the title and content attributes on the Post
|
|
// model are not indexed.
|
|
return $this->postsFromCurrentLocale();
|
|
}
|
|
|
|
/**
|
|
* Returns all matching posts from the default locale.
|
|
* Translated attributes are ignored.
|
|
*
|
|
* @return Collection
|
|
*/
|
|
protected function postsFromDefaultLocale()
|
|
{
|
|
return $this->defaultModelQuery()
|
|
->where(function ($query) {
|
|
$query->where('title', 'like', "%{$this->query}%")
|
|
->orWhere('content', 'like', "%{$this->query}%")
|
|
->orWhere('excerpt', 'like', "%{$this->query}%");
|
|
})
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Returns all matching posts with translated contents.
|
|
*
|
|
* @return Collection
|
|
*/
|
|
protected function postsFromCurrentLocale()
|
|
{
|
|
// First fetch all model ids with maching contents.
|
|
$results = DB::table('rainlab_translate_attributes')
|
|
->where('locale', $this->currentLocale())
|
|
->where('model_type', Post::class)
|
|
->where('attribute_data', 'LIKE', "%{$this->query}%")
|
|
->get(['model_id']);
|
|
|
|
$ids = collect($results)->pluck('model_id');
|
|
|
|
// Then return all maching posts via Eloquent.
|
|
return $this->defaultModelQuery()->whereIn('id', $ids)->get();
|
|
}
|
|
|
|
/**
|
|
* This is the default "base query" for quering
|
|
* matching models.
|
|
*/
|
|
protected function defaultModelQuery()
|
|
{
|
|
return Post::isPublished()->with(['featured_images']);
|
|
}
|
|
|
|
/**
|
|
* Checks if the RainLab.Blog Plugin is installed and
|
|
* enabled in the config.
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function isInstalledAndEnabled()
|
|
{
|
|
return $this->isPluginAvailable($this->identifier)
|
|
&& Settings::get('rainlab_blog_enabled', true);
|
|
}
|
|
|
|
/**
|
|
* Generates the url to a blog post.
|
|
*
|
|
* @param $post
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function getUrl($post)
|
|
{
|
|
$url = trim(Settings::get('rainlab_blog_posturl', '/blog/post'), '/');
|
|
|
|
return implode('/', [$url, $post->slug]);
|
|
}
|
|
|
|
/**
|
|
* Display name for this provider.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function displayName()
|
|
{
|
|
return Settings::get('rainlab_blog_label', 'Blog');
|
|
}
|
|
|
|
/**
|
|
* Returns the plugin's identifier string.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function identifier()
|
|
{
|
|
return 'RainLab.Blog';
|
|
}
|
|
|
|
/**
|
|
* Return the current locale
|
|
*
|
|
* @return string|null
|
|
*/
|
|
protected function currentLocale()
|
|
{
|
|
$translator = $this->translator();
|
|
|
|
if ( ! $translator) {
|
|
return null;
|
|
}
|
|
|
|
return $translator->getLocale();
|
|
}
|
|
}
|