调用百度翻译,加入seo
This commit is contained in:
parent
7db8c91e69
commit
2a5996e6c1
|
@ -28,8 +28,11 @@ class TopicsController extends Controller
|
||||||
return view('topics.index', compact('topics'));
|
return view('topics.index', compact('topics'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show(Topic $topic)
|
public function show(Topic $topic, Request $request)
|
||||||
{
|
{
|
||||||
|
if (!empty($topic->slug) && $topic->slug != $request->slug) {
|
||||||
|
return redirect($topic->link(), 301);
|
||||||
|
}
|
||||||
return view('topics.show', compact('topic'));
|
return view('topics.show', compact('topic'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +41,7 @@ class TopicsController extends Controller
|
||||||
$topic->fill($request->all());
|
$topic->fill($request->all());
|
||||||
$topic->user_id = Auth::id();
|
$topic->user_id = Auth::id();
|
||||||
$topic->save();
|
$topic->save();
|
||||||
return redirect()->route('topics.show', $topic->id)->with('success', '添加成功!.');
|
return redirect()->to($topic->link())->with('success', '添加成功!.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit(Topic $topic)
|
public function edit(Topic $topic)
|
||||||
|
@ -75,7 +78,7 @@ class TopicsController extends Controller
|
||||||
$this->authorize('update', $topic);
|
$this->authorize('update', $topic);
|
||||||
$topic->update($request->all());
|
$topic->update($request->all());
|
||||||
|
|
||||||
return redirect()->route('topics.show', $topic->id)->with('success', '编辑成功!.');
|
return redirect()->route('topics.show', [$topic->id, $topic->slug])->with('success', '编辑成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(Topic $topic)
|
public function destroy(Topic $topic)
|
||||||
|
@ -83,6 +86,6 @@ class TopicsController extends Controller
|
||||||
$this->authorize('destroy', $topic);
|
$this->authorize('destroy', $topic);
|
||||||
$topic->delete();
|
$topic->delete();
|
||||||
|
|
||||||
return redirect()->route('topics.index')->with('message', 'Deleted successfully.');
|
return redirect()->route('topics.index')->with('message', '删除成功.');
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,11 @@ class Topic extends Model
|
||||||
protected $fillable = ['title', 'category_id', 'body', 'excerpt', 'slug'];
|
protected $fillable = ['title', 'category_id', 'body', 'excerpt', 'slug'];
|
||||||
|
|
||||||
|
|
||||||
|
public function link($params = [])
|
||||||
|
{
|
||||||
|
return route('topics.show', array_merge([$this->id, $this->slug], $params));
|
||||||
|
}
|
||||||
|
|
||||||
public function scopeWithOrder($query, $order)
|
public function scopeWithOrder($query, $order)
|
||||||
{
|
{
|
||||||
// 不同的排序,使用不同的数据读取逻辑
|
// 不同的排序,使用不同的数据读取逻辑
|
||||||
|
|
|
@ -32,6 +32,11 @@ class User extends Authenticatable
|
||||||
return asset($this->avatar);
|
return asset($this->avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isAuthorOf($model)
|
||||||
|
{
|
||||||
|
return $this->id == $model->user_id;
|
||||||
|
}
|
||||||
|
|
||||||
public function topics()
|
public function topics()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Topic::class);
|
return $this->hasMany(Topic::class);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Observers;
|
namespace App\Observers;
|
||||||
|
|
||||||
use App\Models\Topic;
|
use App\Models\Topic;
|
||||||
|
use App\Tools\SlugTranslateHandler;
|
||||||
|
|
||||||
// creating, created, updating, updated, saving,
|
// creating, created, updating, updated, saving,
|
||||||
// saved, deleting, deleted, restoring, restored
|
// saved, deleting, deleted, restoring, restored
|
||||||
|
@ -18,6 +19,10 @@ class TopicObserver
|
||||||
{
|
{
|
||||||
$topic->body = clean($topic->body, 'user_topic_body');
|
$topic->body = clean($topic->body, 'user_topic_body');
|
||||||
$topic->excerpt = make_excerpt($topic->body);
|
$topic->excerpt = make_excerpt($topic->body);
|
||||||
|
// 如 slug 字段无内容,即使用翻译器对 title 进行翻译
|
||||||
|
if (!$topic->slug) {
|
||||||
|
$topic->slug = app(SlugTranslateHandler::class)->translate($topic->title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updating(Topic $topic)
|
public function updating(Topic $topic)
|
||||||
|
|
|
@ -9,11 +9,11 @@ class TopicPolicy extends Policy
|
||||||
{
|
{
|
||||||
public function update(User $user, Topic $topic)
|
public function update(User $user, Topic $topic)
|
||||||
{
|
{
|
||||||
return $topic->user_id == $user->id;
|
return $user->isAuthorOf($topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(User $user, Topic $topic)
|
public function destroy(User $user, Topic $topic)
|
||||||
{
|
{
|
||||||
return true;
|
return $user->isAuthorOf($topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
app/Tools/SlugTranslateHandler.php
Normal file
81
app/Tools/SlugTranslateHandler.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Created by PhpStorm.
|
||||||
|
* User: xing
|
||||||
|
* Date: 2018/1/1
|
||||||
|
* Time: 20:51
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Tools;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use Overtrue\Pinyin\Pinyin;
|
||||||
|
|
||||||
|
|
||||||
|
class SlugTranslateHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
public function translate($text)
|
||||||
|
{
|
||||||
|
// 实例化 HTTP 客户端
|
||||||
|
$http = new Client;
|
||||||
|
|
||||||
|
// 初始化配置信息
|
||||||
|
$api = 'http://api.fanyi.baidu.com/api/trans/vip/translate?';
|
||||||
|
$appid = config('services.baidu_translate.appid');
|
||||||
|
$key = config('services.baidu_translate.key');
|
||||||
|
$salt = time();
|
||||||
|
// 如果没有配置百度翻译,自动使用兼容的拼音方案
|
||||||
|
if (empty($appid) || empty($key)) {
|
||||||
|
return $this->pinyin($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据文档,生成 sign
|
||||||
|
// http://api.fanyi.baidu.com/api/trans/product/apidoc
|
||||||
|
// appid+q+salt+密钥 的MD5值
|
||||||
|
$sign = md5($appid . $text . $salt . $key);
|
||||||
|
|
||||||
|
// 构建请求参数
|
||||||
|
$query = http_build_query([
|
||||||
|
"q" => $text,
|
||||||
|
"from" => "zh",
|
||||||
|
"to" => "en",
|
||||||
|
"appid" => $appid,
|
||||||
|
"salt" => $salt,
|
||||||
|
"sign" => $sign,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 发送 HTTP Get 请求
|
||||||
|
$response = $http->get($api . $query);
|
||||||
|
|
||||||
|
$result = json_decode($response->getBody(), true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取结果,如果请求成功,dd($result) 结果如下:
|
||||||
|
*
|
||||||
|
* array:3 [▼
|
||||||
|
* "from" => "zh"
|
||||||
|
* "to" => "en"
|
||||||
|
* "trans_result" => array:1 [▼
|
||||||
|
* 0 => array:2 [▼
|
||||||
|
* "src" => "XSS 安全漏洞"
|
||||||
|
* "dst" => "XSS security vulnerability"
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
**/
|
||||||
|
|
||||||
|
// 尝试获取获取翻译结果
|
||||||
|
if (isset($result['trans_result'][0]['dst'])) {
|
||||||
|
return str_slug($result['trans_result'][0]['dst']);
|
||||||
|
} else {
|
||||||
|
// 如果百度翻译没有结果,使用拼音作为后备计划。
|
||||||
|
return $this->pinyin($text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pinyin($text)
|
||||||
|
{
|
||||||
|
return str_slug(app(Pinyin::class)->permalink($text));
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,13 +11,15 @@
|
||||||
"php": ">=7.0.0",
|
"php": ">=7.0.0",
|
||||||
"doctrine/dbal": "^2.6",
|
"doctrine/dbal": "^2.6",
|
||||||
"fideloper/proxy": "~3.3",
|
"fideloper/proxy": "~3.3",
|
||||||
|
"guzzlehttp/guzzle": "~6.3",
|
||||||
"hieu-le/active": "~3.5",
|
"hieu-le/active": "~3.5",
|
||||||
"intervention/image": "^2.4",
|
"intervention/image": "^2.4",
|
||||||
"laravel/framework": "5.5.*",
|
"laravel/framework": "5.5.*",
|
||||||
"laravel/tinker": "~1.0",
|
"laravel/tinker": "~1.0",
|
||||||
"mews/captcha": "~2.0",
|
"mews/captcha": "~2.0",
|
||||||
"mews/purifier": "~2.0",
|
"mews/purifier": "~2.0",
|
||||||
"overtrue/laravel-lang": "^3.0"
|
"overtrue/laravel-lang": "^3.0",
|
||||||
|
"overtrue/pinyin": "~3.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"barryvdh/laravel-debugbar": "^3.1",
|
"barryvdh/laravel-debugbar": "^3.1",
|
||||||
|
|
163
composer.lock
generated
163
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "0623f829dd1042d2c133664fd6525faa",
|
"content-hash": "8d5baf0bc06734b3359648bb624b4f3c",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "caouecs/laravel-lang",
|
"name": "caouecs/laravel-lang",
|
||||||
|
@ -763,6 +763,122 @@
|
||||||
],
|
],
|
||||||
"time": "2017-06-15T17:19:42+00:00"
|
"time": "2017-06-15T17:19:42+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "guzzlehttp/guzzle",
|
||||||
|
"version": "6.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/guzzle/guzzle.git",
|
||||||
|
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
|
||||||
|
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"guzzlehttp/promises": "^1.0",
|
||||||
|
"guzzlehttp/psr7": "^1.4",
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-curl": "*",
|
||||||
|
"phpunit/phpunit": "^4.0 || ^5.0",
|
||||||
|
"psr/log": "^1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"psr/log": "Required for using the Log middleware"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "6.2-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/functions_include.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"GuzzleHttp\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Michael Dowling",
|
||||||
|
"email": "mtdowling@gmail.com",
|
||||||
|
"homepage": "https://github.com/mtdowling"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Guzzle is a PHP HTTP client library",
|
||||||
|
"homepage": "http://guzzlephp.org/",
|
||||||
|
"keywords": [
|
||||||
|
"client",
|
||||||
|
"curl",
|
||||||
|
"framework",
|
||||||
|
"http",
|
||||||
|
"http client",
|
||||||
|
"rest",
|
||||||
|
"web service"
|
||||||
|
],
|
||||||
|
"time": "2017-06-22T18:50:49+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "guzzlehttp/promises",
|
||||||
|
"version": "v1.3.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/guzzle/promises.git",
|
||||||
|
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
|
||||||
|
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.5.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.4-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"GuzzleHttp\\Promise\\": "src/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/functions_include.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Michael Dowling",
|
||||||
|
"email": "mtdowling@gmail.com",
|
||||||
|
"homepage": "https://github.com/mtdowling"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Guzzle promises library",
|
||||||
|
"keywords": [
|
||||||
|
"promise"
|
||||||
|
],
|
||||||
|
"time": "2016-12-20T10:07:11+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/psr7",
|
"name": "guzzlehttp/psr7",
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
|
@ -1747,6 +1863,51 @@
|
||||||
],
|
],
|
||||||
"time": "2017-10-28T12:10:43+00:00"
|
"time": "2017-10-28T12:10:43+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "overtrue/pinyin",
|
||||||
|
"version": "3.0.6",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/overtrue/pinyin.git",
|
||||||
|
"reference": "3b781d267197b74752daa32814d3a2cf5d140779"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/overtrue/pinyin/zipball/3b781d267197b74752daa32814d3a2cf5d140779",
|
||||||
|
"reference": "3b781d267197b74752daa32814d3a2cf5d140779",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "~4.8"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Overtrue\\Pinyin\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Carlos",
|
||||||
|
"homepage": "http://github.com/overtrue"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Chinese to pinyin translator.",
|
||||||
|
"homepage": "https://github.com/overtrue/pinyin",
|
||||||
|
"keywords": [
|
||||||
|
"Chinese",
|
||||||
|
"Pinyin",
|
||||||
|
"cn2pinyin"
|
||||||
|
],
|
||||||
|
"time": "2017-07-10T07:20:01+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "paragonie/random_compat",
|
"name": "paragonie/random_compat",
|
||||||
"version": "v2.0.11",
|
"version": "v2.0.11",
|
||||||
|
|
|
@ -14,6 +14,11 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
'baidu_translate' => [
|
||||||
|
'appid' => env('BAIDU_TRANSLATE_APPID'),
|
||||||
|
'key' => env('BAIDU_TRANSLATE_KEY'),
|
||||||
|
],
|
||||||
|
|
||||||
'mailgun' => [
|
'mailgun' => [
|
||||||
'domain' => env('MAILGUN_DOMAIN'),
|
'domain' => env('MAILGUN_DOMAIN'),
|
||||||
'secret' => env('MAILGUN_SECRET'),
|
'secret' => env('MAILGUN_SECRET'),
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
<select class="form-control" name="category_id" required>
|
<select class="form-control" name="category_id" required>
|
||||||
<option value="" hidden disabled selected>请选择分类</option>
|
<option value="" hidden disabled selected>请选择分类</option>
|
||||||
@foreach ($categories as $value)
|
@foreach ($categories as $value)
|
||||||
<option value="{{ $value->id }}">{{ $value->name }}</option>
|
<option value="{{ $value->id }}" {{ $topic->category_id == $value->id ? 'selected' : '' }}>{{ $value->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -42,15 +42,24 @@
|
||||||
{!! $topic->body !!}
|
{!! $topic->body !!}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@can('update', $topic)
|
||||||
<div class="operate">
|
<div class="operate">
|
||||||
<hr>
|
<hr>
|
||||||
<a href="{{ route('topics.edit', $topic->id) }}" class="btn btn-default btn-xs" role="button">
|
<a href="{{ route('topics.edit', $topic->id) }}" class="btn btn-default btn-xs pull-left"
|
||||||
|
role="button">
|
||||||
<i class="glyphicon glyphicon-edit"></i> 编辑
|
<i class="glyphicon glyphicon-edit"></i> 编辑
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="btn btn-default btn-xs" role="button">
|
|
||||||
<i class="glyphicon glyphicon-trash"></i> 删除
|
<form action="{{ route('topics.destroy', $topic->id) }}" method="post">
|
||||||
</a>
|
{{ csrf_field() }}
|
||||||
|
{{ method_field('DELETE') }}
|
||||||
|
<button type="submit" class="btn btn-default btn-xs pull-left" style="margin-left: 6px">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i>
|
||||||
|
删除
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@endcan
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
@foreach ($topics as $topic)
|
@foreach ($topics as $topic)
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<a href="{{ route('topics.show', $topic->id) }}">
|
<a href="{{ route('topics.show', [$topic->id,$topic->slug]) }}">
|
||||||
{{ $topic->title }}
|
{{ $topic->title }}
|
||||||
</a>
|
</a>
|
||||||
<span class="meta pull-right">
|
<span class="meta pull-right">
|
||||||
|
|
|
@ -30,7 +30,9 @@ Route::get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm'
|
||||||
Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
|
Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
|
||||||
Route::get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
|
Route::get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
|
||||||
Route::post('password/reset', 'Auth\ResetPasswordController@reset');
|
Route::post('password/reset', 'Auth\ResetPasswordController@reset');
|
||||||
Route::resource('topics', 'TopicsController', ['only' => ['index', 'show', 'create', 'store', 'update', 'edit', 'destroy']]);
|
Route::resource('topics', 'TopicsController', ['only' => ['index', 'create', 'store', 'update', 'edit', 'destroy']]);
|
||||||
|
|
||||||
|
Route::get('topics/{topic}/{slug?}', 'TopicsController@show')->name('topics.show');
|
||||||
|
|
||||||
Route::resource('categories', 'CategoriesController', ['only' => ['show']]);
|
Route::resource('categories', 'CategoriesController', ['only' => ['show']]);
|
||||||
Route::post('upload_image', 'TopicsController@uploadImage')->name('topics.upload_image');
|
Route::post('upload_image', 'TopicsController@uploadImage')->name('topics.upload_image');
|
||||||
|
|
Loading…
Reference in New Issue
Block a user