Merge pull request #770 from jonnybarnes/develop
MTM Re-add search functionality
This commit is contained in:
commit
2962675f9d
11 changed files with 298 additions and 20 deletions
|
@ -68,7 +68,8 @@ TWITTER_CONSUMER_SECRET=
|
|||
TWITTER_ACCESS_TOKEN=
|
||||
TWITTER_ACCESS_TOKEN_SECRET=
|
||||
|
||||
SCOUT_DRIVER=pgsql
|
||||
SCOUT_DRIVER=database
|
||||
SCOUT_QUEUE=false
|
||||
|
||||
PIWIK=false
|
||||
PIWIK_ID=1
|
||||
|
@ -79,7 +80,7 @@ FATHOM_ID=
|
|||
APP_TIMEZONE=UTC
|
||||
APP_LANG=en
|
||||
APP_LOG=daily
|
||||
SECURE_SESSION_COOKIE=true
|
||||
SESSION_SECURE_COOKIE=true
|
||||
|
||||
LOG_SLACK_WEBHOOK_URL=
|
||||
|
||||
|
|
|
@ -50,7 +50,8 @@ TWITTER_CONSUMER_SECRET=
|
|||
TWITTER_ACCESS_TOKEN=
|
||||
TWITTER_ACCESS_TOKEN_SECRET=
|
||||
|
||||
SCOUT_DRIVER=pgsql
|
||||
SCOUT_DRIVER=database
|
||||
SCOUT_QUEUE=false
|
||||
|
||||
PIWIK=false
|
||||
|
||||
|
|
25
app/Http/Controllers/SearchController.php
Normal file
25
app/Http/Controllers/SearchController.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Note;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
public function search(Request $request): View
|
||||
{
|
||||
$search = $request->input('q');
|
||||
|
||||
$notes = Note::search($search)
|
||||
->paginate();
|
||||
|
||||
/** @var Note $note */
|
||||
foreach ($notes as $note) {
|
||||
$note->load('place', 'media', 'client');
|
||||
}
|
||||
|
||||
return view('search', compact('search', 'notes'));
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
|
|||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Jonnybarnes\IndieWeb\Numbers;
|
||||
use Laravel\Scout\Searchable;
|
||||
use League\CommonMark\Environment\Environment;
|
||||
use League\CommonMark\Extension\Autolink\AutolinkExtension;
|
||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
||||
|
@ -34,6 +35,7 @@ use Spatie\CommonMarkHighlighter\IndentedCodeRenderer;
|
|||
class Note extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Searchable;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
|
@ -96,7 +98,7 @@ class Note extends Model
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toSearchableArray(): array
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"laravel/framework": "^10.0",
|
||||
"laravel/horizon": "^5.0",
|
||||
"laravel/sanctum": "^3.0",
|
||||
"laravel/scout": "^10.1",
|
||||
"laravel/tinker": "^2.0",
|
||||
"lcobucci/jwt": "^5.0",
|
||||
"league/commonmark": "^2.0",
|
||||
|
|
77
composer.lock
generated
77
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "5e3ba7f9ad88d53aa871be437f02a0c5",
|
||||
"content-hash": "617504ea1be00f742145197dbe3b5792",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-crt-php",
|
||||
|
@ -2165,6 +2165,81 @@
|
|||
},
|
||||
"time": "2023-01-13T15:41:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/scout",
|
||||
"version": "v10.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/scout.git",
|
||||
"reference": "ee57968e7ec6943316f6cc66190baf4de8fb3cef"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/scout/zipball/ee57968e7ec6943316f6cc66190baf4de8fb3cef",
|
||||
"reference": "ee57968e7ec6943316f6cc66190baf4de8fb3cef",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/bus": "^9.0|^10.0",
|
||||
"illuminate/contracts": "^9.0|^10.0",
|
||||
"illuminate/database": "^9.0|^10.0",
|
||||
"illuminate/http": "^9.0|^10.0",
|
||||
"illuminate/pagination": "^9.0|^10.0",
|
||||
"illuminate/queue": "^9.0|^10.0",
|
||||
"illuminate/support": "^9.0|^10.0",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"algolia/algoliasearch-client-php": "^3.2",
|
||||
"meilisearch/meilisearch-php": "^1.0",
|
||||
"mockery/mockery": "^1.0",
|
||||
"orchestra/testbench": "^7.0|^8.0",
|
||||
"php-http/guzzle7-adapter": "^1.0",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"suggest": {
|
||||
"algolia/algoliasearch-client-php": "Required to use the Algolia engine (^3.2).",
|
||||
"meilisearch/meilisearch-php": "Required to use the Meilisearch engine (^1.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "10.x-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Scout\\ScoutServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Scout\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Laravel Scout provides a driver based solution to searching your Eloquent models.",
|
||||
"keywords": [
|
||||
"algolia",
|
||||
"laravel",
|
||||
"search"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/scout/issues",
|
||||
"source": "https://github.com/laravel/scout"
|
||||
},
|
||||
"time": "2023-04-11T16:38:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
"version": "v1.3.0",
|
||||
|
|
142
config/scout.php
Normal file
142
config/scout.php
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Search Engine
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default search connection that gets used while
|
||||
| using Laravel Scout. This connection is used when syncing all models
|
||||
| to the search service. You should adjust this based on your needs.
|
||||
|
|
||||
| Supported: "algolia", "meilisearch", "database", "collection", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('SCOUT_DRIVER', 'algolia'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Index Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify a prefix that will be applied to all search index
|
||||
| names used by Scout. This prefix may be useful if you have multiple
|
||||
| "tenants" or applications sharing the same search infrastructure.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('SCOUT_PREFIX', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Data Syncing
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to control if the operations that sync your data
|
||||
| with your search engines are queued. When this is set to "true" then
|
||||
| all automatic data syncing will get queued for better performance.
|
||||
|
|
||||
*/
|
||||
|
||||
'queue' => env('SCOUT_QUEUE', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Database Transactions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration option determines if your data will only be synced
|
||||
| with your search indexes after every open database transaction has
|
||||
| been committed, thus preventing any discarded data from syncing.
|
||||
|
|
||||
*/
|
||||
|
||||
'after_commit' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Chunk Sizes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These options allow you to control the maximum chunk size when you are
|
||||
| mass importing data into the search engine. This allows you to fine
|
||||
| tune each of these chunk sizes based on the power of the servers.
|
||||
|
|
||||
*/
|
||||
|
||||
'chunk' => [
|
||||
'searchable' => 500,
|
||||
'unsearchable' => 500,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Soft Deletes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows to control whether to keep soft deleted records in
|
||||
| the search indexes. Maintaining soft deleted records can be useful
|
||||
| if your application still needs to search for the records later.
|
||||
|
|
||||
*/
|
||||
|
||||
'soft_delete' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Identify User
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to control whether to notify the search engine
|
||||
| of the user performing the search. This is sometimes useful if the
|
||||
| engine supports any analytics based on this application's users.
|
||||
|
|
||||
| Supported engines: "algolia"
|
||||
|
|
||||
*/
|
||||
|
||||
'identify' => env('SCOUT_IDENTIFY', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Algolia Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your Algolia settings. Algolia is a cloud hosted
|
||||
| search engine which works great with Scout out of the box. Just plug
|
||||
| in your application ID and admin API key to get started searching.
|
||||
|
|
||||
*/
|
||||
|
||||
'algolia' => [
|
||||
'id' => env('ALGOLIA_APP_ID', ''),
|
||||
'secret' => env('ALGOLIA_SECRET', ''),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Meilisearch Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your Meilisearch settings. Meilisearch is an open
|
||||
| source search engine with minimal configuration. Below, you can state
|
||||
| the host and key information for your own Meilisearch installation.
|
||||
|
|
||||
| See: https://docs.meilisearch.com/guides/advanced_guides/configuration.html
|
||||
|
|
||||
*/
|
||||
|
||||
'meilisearch' => [
|
||||
'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
|
||||
'key' => env('MEILISEARCH_KEY'),
|
||||
'index-settings' => [
|
||||
// 'users' => [
|
||||
// 'filterableAttributes'=> ['id', 'name', 'email'],
|
||||
// ],
|
||||
],
|
||||
],
|
||||
|
||||
];
|
|
@ -51,9 +51,9 @@
|
|||
</main>
|
||||
|
||||
<footer>
|
||||
{{-- <form action="search" method="get">--}}
|
||||
{{-- <input type="text" name="terms" title="Search"><button type="submit">Search</button>--}}
|
||||
{{-- </form>--}}
|
||||
<form action="/search" method="get">
|
||||
<input type="text" name="q" title="Search"><button type="submit">Search</button>
|
||||
</form>
|
||||
<p>Built with love: <a href="/colophon">Colophon</a></p>
|
||||
<a href="https://indieweb.org"><img src="/assets/img/iwc.svg" alt="Indie Web Camp logo" class="iwc-logo"></a>
|
||||
</footer>
|
||||
|
|
|
@ -4,16 +4,17 @@
|
|||
|
||||
@section('content')
|
||||
<h2>Search Results</h2>
|
||||
@foreach($notes as $note)
|
||||
<div class="h-entry">
|
||||
@include('templates.note', ['note' => $note])
|
||||
</div>
|
||||
@endforeach
|
||||
{{ $notes->links() }}
|
||||
@stop
|
||||
<p>Searching for “{{ $search }}”</p>
|
||||
|
||||
@section('scripts')
|
||||
@include('templates.mapbox-links')
|
||||
<script src="/assets/js/links.js"></script>
|
||||
<link rel="stylesheet" href="/assets/highlight/zenburn.css">
|
||||
<div class="h-feed">
|
||||
<!-- the following span stops microformat parses going haywire
|
||||
generating a name property for the h-feed -->
|
||||
<span class="p-name"></span>
|
||||
|
||||
@foreach ($notes as $note)
|
||||
@include('templates.note', ['note' => $note])
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{{ $notes->links() }}
|
||||
@stop
|
||||
|
|
|
@ -31,6 +31,7 @@ use App\Http\Controllers\MicropubController;
|
|||
use App\Http\Controllers\MicropubMediaController;
|
||||
use App\Http\Controllers\NotesController;
|
||||
use App\Http\Controllers\PlacesController;
|
||||
use App\Http\Controllers\SearchController;
|
||||
use App\Http\Controllers\ShortURLsController;
|
||||
use App\Http\Controllers\TokenEndpointController;
|
||||
use App\Http\Controllers\WebMentionsController;
|
||||
|
@ -205,6 +206,9 @@ Route::group(['domain' => config('url.longurl')], function () {
|
|||
|
||||
// Micropub
|
||||
Route::redirect('/micropub/create', '/notes/new');
|
||||
|
||||
// Search
|
||||
Route::get('search', [SearchController::class, 'search']);
|
||||
});
|
||||
|
||||
// Short URL
|
||||
|
|
26
tests/Feature/SearchTest.php
Normal file
26
tests/Feature/SearchTest.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Note;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SearchTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function searchEndpointReturnsResults(): void
|
||||
{
|
||||
Note::factory(10)->create();
|
||||
Note::Factory()->create(['note' => 'hello world']);
|
||||
|
||||
$response = $this->get('/search?q=hello');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertViewIs('search');
|
||||
$response->assertViewHas('search');
|
||||
$response->assertViewHas('notes');
|
||||
$response->assertSee('hello world');
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue