Merge pull request #450 from shikorism/feature/312-tag-normalize
正規化したタグ名で検索
This commit is contained in:
commit
43ed36ccb7
@ -5,8 +5,8 @@ FROM php:7.3-apache
|
||||
ENV APACHE_DOCUMENT_ROOT /var/www/html/public
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y git libpq-dev unzip \
|
||||
&& docker-php-ext-install pdo_pgsql \
|
||||
&& apt-get install -y git libpq-dev unzip libicu-dev \
|
||||
&& docker-php-ext-install pdo_pgsql intl \
|
||||
&& pecl install xdebug \
|
||||
&& curl -sS https://getcomposer.org/installer | php \
|
||||
&& mv composer.phar /usr/local/bin/composer \
|
||||
|
61
app/Console/Commands/NormalizeTags.php
Normal file
61
app/Console/Commands/NormalizeTags.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Tag;
|
||||
use App\Utilities\Formatter;
|
||||
use DB;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class NormalizeTags extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'tissue:tag:normalize';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Normalize tags';
|
||||
|
||||
private $formatter;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Formatter $formatter)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$start = hrtime(true);
|
||||
|
||||
DB::transaction(function () {
|
||||
/** @var Tag $tag */
|
||||
foreach (Tag::query()->cursor() as $tag) {
|
||||
$normalizedName = $this->formatter->normalizeTagName($tag->name);
|
||||
$this->line("{$tag->name} : {$normalizedName}");
|
||||
$tag->normalized_name = $normalizedName;
|
||||
$tag->save();
|
||||
}
|
||||
});
|
||||
|
||||
$elapsed = (hrtime(true) - $start) / 1e+9;
|
||||
$this->info("Done! ({$elapsed} sec)");
|
||||
}
|
||||
}
|
@ -4,20 +4,30 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Ejaculation;
|
||||
use App\Tag;
|
||||
use App\Utilities\Formatter;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
/** @var Formatter */
|
||||
private $formatter;
|
||||
|
||||
public function __construct(Formatter $formatter)
|
||||
{
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$inputs = $request->validate([
|
||||
'q' => 'required'
|
||||
]);
|
||||
|
||||
$q = $this->normalizeQuery($inputs['q']);
|
||||
$results = Ejaculation::query()
|
||||
->whereHas('tags', function ($query) use ($inputs) {
|
||||
$query->where('name', 'like', "%{$inputs['q']}%");
|
||||
->whereHas('tags', function ($query) use ($q) {
|
||||
$query->where('normalized_name', 'like', "%{$q}%");
|
||||
})
|
||||
->whereHas('user', function ($query) {
|
||||
$query->where('is_protected', false);
|
||||
@ -41,11 +51,17 @@ class SearchController extends Controller
|
||||
'q' => 'required'
|
||||
]);
|
||||
|
||||
$q = $this->normalizeQuery($inputs['q']);
|
||||
$results = Tag::query()
|
||||
->where('name', 'like', "%{$inputs['q']}%")
|
||||
->where('normalized_name', 'like', "%{$q}%")
|
||||
->paginate(50)
|
||||
->appends($inputs);
|
||||
|
||||
return view('search.relatedTag')->with(compact('inputs', 'results'));
|
||||
}
|
||||
|
||||
private function normalizeQuery(string $query): string
|
||||
{
|
||||
return $this->formatter->normalizeTagName($query);
|
||||
}
|
||||
}
|
||||
|
10
app/Tag.php
10
app/Tag.php
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Utilities\Formatter;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Tag extends Model
|
||||
@ -15,6 +16,15 @@ class Tag extends Model
|
||||
'name'
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::creating(function (Tag $tag) {
|
||||
$tag->normalized_name = app(Formatter::class)->normalizeTagName($tag->name);
|
||||
});
|
||||
}
|
||||
|
||||
public function ejaculations()
|
||||
{
|
||||
return $this->belongsToMany('App\Ejaculation')->withTimestamps();
|
||||
|
@ -132,4 +132,12 @@ class Formatter
|
||||
|
||||
return $bytes . 'B';
|
||||
}
|
||||
|
||||
public function normalizeTagName(string $name)
|
||||
{
|
||||
$name = \Normalizer::normalize($name, \Normalizer::FORM_KC);
|
||||
$name = mb_strtolower($name);
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,12 @@
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.2",
|
||||
"ext-dom": "*",
|
||||
"ext-intl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-pdo": "*",
|
||||
"anhskohbo/no-captcha": "^3.0",
|
||||
"doctrine/dbal": "^2.9",
|
||||
"erusev/parsedown": "^1.7",
|
||||
|
104
composer.lock
generated
104
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": "2c0bd951a595d4856079c5a13a72e651",
|
||||
"content-hash": "1bba68b609be6a0dcdaf05d72e8eb759",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anhskohbo/no-captcha",
|
||||
@ -394,20 +394,6 @@
|
||||
"sqlserver",
|
||||
"sqlsrv"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-04-20T17:19:26+00:00"
|
||||
},
|
||||
{
|
||||
@ -1617,12 +1603,6 @@
|
||||
"transform",
|
||||
"write"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/nyamsprod",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-03-17T15:15:35+00:00"
|
||||
},
|
||||
{
|
||||
@ -1707,12 +1687,6 @@
|
||||
"sftp",
|
||||
"storage"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://offset.earth/frankdejonge",
|
||||
"type": "other"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-18T15:13:39+00:00"
|
||||
},
|
||||
{
|
||||
@ -1839,16 +1813,6 @@
|
||||
"logging",
|
||||
"psr-3"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Seldaek",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-22T08:12:19+00:00"
|
||||
},
|
||||
{
|
||||
@ -5875,12 +5839,6 @@
|
||||
"profiler",
|
||||
"webprofiler"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/barryvdh",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-05T10:53:32+00:00"
|
||||
},
|
||||
{
|
||||
@ -5952,12 +5910,6 @@
|
||||
"phpstorm",
|
||||
"sublime"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/barryvdh",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-04-22T09:57:26+00:00"
|
||||
},
|
||||
{
|
||||
@ -6063,16 +6015,6 @@
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-04-08T08:27:21+00:00"
|
||||
},
|
||||
{
|
||||
@ -6154,16 +6096,6 @@
|
||||
"dependency",
|
||||
"package"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-06T08:28:10+00:00"
|
||||
},
|
||||
{
|
||||
@ -6536,12 +6468,6 @@
|
||||
"flare",
|
||||
"reporting"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.patreon.com/spatie",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2020-03-02T15:52:04+00:00"
|
||||
},
|
||||
{
|
||||
@ -8088,12 +8014,6 @@
|
||||
"highlight.php",
|
||||
"syntax"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/allejo",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-03-02T05:59:21+00:00"
|
||||
},
|
||||
{
|
||||
@ -8758,16 +8678,6 @@
|
||||
"parser",
|
||||
"validator"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Seldaek",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/seld/jsonlint",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-04-30T19:05:18+00:00"
|
||||
},
|
||||
{
|
||||
@ -9032,8 +8942,8 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Arne Blankerts",
|
||||
"email": "arne@blankerts.de",
|
||||
"role": "Developer"
|
||||
"role": "Developer",
|
||||
"email": "arne@blankerts.de"
|
||||
}
|
||||
],
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
@ -9097,7 +9007,13 @@
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^7.2"
|
||||
"php": "^7.2",
|
||||
"ext-dom": "*",
|
||||
"ext-intl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "1.1.0"
|
||||
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddNormalizedNameToTags extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('tags', function (Blueprint $table) {
|
||||
$table->string('normalized_name')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('tags', function (Blueprint $table) {
|
||||
$table->dropColumn('normalized_name');
|
||||
});
|
||||
}
|
||||
}
|
@ -70,4 +70,30 @@ class FormatterTest extends TestCase
|
||||
$formatter->profileImageSrcSet($profileImageProvider, 128, 2)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideNormalizeTagName
|
||||
*/
|
||||
public function testNormalizeTagName($input, $expected)
|
||||
{
|
||||
$formatter = new Formatter();
|
||||
|
||||
$normalized = $formatter->normalizeTagName($input);
|
||||
$this->assertSame($expected, $normalized);
|
||||
$this->assertSame($expected, $formatter->normalizeTagName($normalized));
|
||||
}
|
||||
|
||||
public function provideNormalizeTagName()
|
||||
{
|
||||
return [
|
||||
'LowerCase' => ['example', 'example'],
|
||||
'UpperCase' => ['EXAMPLE', 'example'],
|
||||
'HalfWidthKana' => ['ティッシュ', 'ティッシュ'],
|
||||
'FullWidthAlphabet' => ['Tissue', 'tissue'],
|
||||
'組み文字1' => ['13㎝', '13cm'],
|
||||
'組み文字2' => ['13㌢㍍', '13センチメートル'],
|
||||
'Script' => ['ℬ𝒶𝒷𝓊𝓂𝒾', 'babumi'],
|
||||
'NFD' => ['オカズ', 'オカズ'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user