mirror of
https://github.com/bs-community/blessing-skin-server.git
synced 2024-12-21 06:19:38 +08:00
enhance abstraction of Player model
This commit is contained in:
parent
1717095cef
commit
c09700ea57
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Player;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
|
||||
@ -16,7 +17,7 @@ class PlayerProfileUpdated extends Event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(\App\Models\Player $player)
|
||||
public function __construct(Player $player)
|
||||
{
|
||||
$this->player = $player;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\PlayerModel;
|
||||
use App\Models\Player;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
|
||||
@ -17,7 +17,7 @@ class PlayerWasAdded extends Event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(PlayerModel $player)
|
||||
public function __construct(Player $player)
|
||||
{
|
||||
$this->player = $player;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ use App\Models\User;
|
||||
use App\Models\Player;
|
||||
use App\Models\Texture;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\PlayerModel;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Exceptions\PrettyPageException;
|
||||
|
||||
@ -107,11 +106,11 @@ class AdminController extends Controller
|
||||
$q = $request->input('q', '');
|
||||
|
||||
if ($filter == "") {
|
||||
$players = PlayerModel::orderBy('uid');
|
||||
$players = Player::orderBy('uid');
|
||||
} elseif ($filter == "player_name") {
|
||||
$players = PlayerModel::like('player_name', $q)->orderBy('uid');
|
||||
$players = Player::like('player_name', $q)->orderBy('uid');
|
||||
} elseif ($filter == "uid") {
|
||||
$players = PlayerModel::where('uid', $q)->orderBy('uid');
|
||||
$players = Player::where('uid', $q)->orderBy('uid');
|
||||
}
|
||||
|
||||
$total_pages = ceil($players->count() / 30);
|
||||
@ -235,8 +234,10 @@ class AdminController extends Controller
|
||||
{
|
||||
$action = isset($_GET['action']) ? $_GET['action'] : "";
|
||||
|
||||
// exception will be throw by model if player is not existent
|
||||
$player = new Player($request->input('pid'));
|
||||
$player = Player::find($request->input('pid'));
|
||||
|
||||
if (!$player)
|
||||
abort(404, trans('general.unexistent-player'));
|
||||
|
||||
if ($action == "preference") {
|
||||
$this->validate($request, [
|
||||
@ -273,7 +274,7 @@ class AdminController extends Controller
|
||||
return json("角色 $player->player_name 已成功让渡至 ".$user->getNickName(), 0);
|
||||
|
||||
} elseif ($action == "delete") {
|
||||
if (PlayerModel::where('pid', $request->input('pid'))->delete())
|
||||
if ($player->delete())
|
||||
return json('角色已被成功删除', 0);
|
||||
} else {
|
||||
return json('非法参数', 1);
|
||||
|
@ -10,6 +10,8 @@ use App\Models\User;
|
||||
use App\Models\Player;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Events\PlayerWasAdded;
|
||||
use App\Events\PlayerWasDeleted;
|
||||
use App\Exceptions\PrettyPageException;
|
||||
|
||||
class PlayerController extends Controller
|
||||
@ -33,7 +35,7 @@ class PlayerController extends Controller
|
||||
$this->user = new User(session('uid'));
|
||||
|
||||
if ($request->has('pid'))
|
||||
$this->player = new Player($request->pid);
|
||||
$this->player = Player::find($request->pid);
|
||||
}
|
||||
|
||||
public function index()
|
||||
@ -47,9 +49,7 @@ class PlayerController extends Controller
|
||||
'player_name' => 'required|'.(Option::get('allow_chinese_playername') == "1") ? 'pname_chinese' : 'player_name'
|
||||
]);
|
||||
|
||||
$player = new Player(null, $request->input('player_name'));
|
||||
|
||||
if ($player->is_registered) {
|
||||
if (!Player::where('player_name', $request->input('player_name'))->get()->isEmpty()) {
|
||||
return json(trans('user.player.add.repeated'), 6);
|
||||
}
|
||||
|
||||
@ -57,7 +57,17 @@ class PlayerController extends Controller
|
||||
return json(trans('user.player.add.lack-score'), 7);
|
||||
}
|
||||
|
||||
$player->register($this->user);
|
||||
$player = new Player;
|
||||
|
||||
$player->uid = $this->user->uid;
|
||||
$player->player_name = $request->input('player_name');
|
||||
$player->preference = "default";
|
||||
$player->last_modified = Utils::getTimeFormatted();
|
||||
$player->save();
|
||||
|
||||
Event::fire(new PlayerWasAdded($player));
|
||||
|
||||
$this->user->setScore(option('score_per_player'), 'minus');
|
||||
|
||||
return json(trans('user.player.add.success', ['name' => $request->input('player_name')]), 0);
|
||||
}
|
||||
@ -69,13 +79,15 @@ class PlayerController extends Controller
|
||||
if ($this->player->delete()) {
|
||||
$this->user->setScore(Option::get('score_per_player'), 'plus');
|
||||
|
||||
// Event::fire(new PlayerWasDeleted($this));
|
||||
|
||||
return json(trans('user.player.delete.success', ['name' => $player_name]), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public function show()
|
||||
{
|
||||
return json_encode($this->player->model->toArray(), JSON_NUMERIC_CHECK);
|
||||
return json_encode($this->player->toArray(), JSON_NUMERIC_CHECK);
|
||||
}
|
||||
|
||||
public function rename(Request $request)
|
||||
@ -86,13 +98,14 @@ class PlayerController extends Controller
|
||||
|
||||
$new_name = $request->input('new_player_name');
|
||||
|
||||
if ((new Player(null, $new_name))->is_registered) {
|
||||
if (!Player::where('player_name', $new_name)->get()->isEmpty()) {
|
||||
return json(trans('user.player.rename.repeated'), 6);
|
||||
}
|
||||
|
||||
$old_name = $this->player->player_name;
|
||||
|
||||
$this->player->rename($new_name);
|
||||
$this->player->player_name = $new_name;
|
||||
$this->player->save();
|
||||
|
||||
return json(trans('user.player.rename.success', ['old' => $old_name, 'new' => $new_name]), 0);
|
||||
}
|
||||
|
@ -26,10 +26,7 @@ class TextureController extends Controller
|
||||
*/
|
||||
public function json($player_name, $api = "")
|
||||
{
|
||||
$player = new Player(0, $player_name);
|
||||
|
||||
if ($player->is_banned)
|
||||
abort(404, '该角色拥有者已被本站封禁。');
|
||||
$player = $this->getPlayerInstance($player_name);
|
||||
|
||||
if ($api == "csl") {
|
||||
return Response::rawJson($player->getJsonProfile(Player::CSL_API));
|
||||
@ -63,10 +60,7 @@ class TextureController extends Controller
|
||||
|
||||
public function skin($player_name, $model = "")
|
||||
{
|
||||
$player = new Player(0, $player_name);
|
||||
|
||||
if ($player->is_banned)
|
||||
abort(404, '该角色拥有者已被本站封禁。');
|
||||
$player = $this->getPlayerInstance($player_name);
|
||||
|
||||
$model_preference = ($player->getPreference() == "default") ? "steve" : "alex";
|
||||
$model = ($model == "") ? $model_preference : $model;
|
||||
@ -81,10 +75,7 @@ class TextureController extends Controller
|
||||
|
||||
public function cape($player_name)
|
||||
{
|
||||
$player = new Player(0, $player_name);
|
||||
|
||||
if ($player->is_banned)
|
||||
abort(404, '该角色拥有者已被本站封禁。');
|
||||
$player = $this->getPlayerInstance($player_name);
|
||||
|
||||
return $player->getBinaryTexture('cape');
|
||||
}
|
||||
@ -181,4 +172,17 @@ class TextureController extends Controller
|
||||
|
||||
}
|
||||
|
||||
private function getPlayerInstance($player_name)
|
||||
{
|
||||
$player = Player::where('player_name', $player_name)->first();
|
||||
|
||||
if (!$player)
|
||||
abort(404, '角色不存在');
|
||||
|
||||
if ($player->isBanned())
|
||||
abort(404, '该角色拥有者已被本站封禁。');
|
||||
|
||||
return $player;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\PlayerModel;
|
||||
use App\Models\Player;
|
||||
use App\Events\CheckPlayerExists;
|
||||
use Event;
|
||||
|
||||
@ -20,7 +20,7 @@ class CheckPlayerExistMiddleware
|
||||
|
||||
Event::fire(new CheckPlayerExists($player_name));
|
||||
|
||||
if (PlayerModel::where('player_name', $player_name)->get()->isEmpty()) {
|
||||
if (Player::where('player_name', $player_name)->get()->isEmpty()) {
|
||||
if (option('return_200_when_notfound') == "1") {
|
||||
return json([
|
||||
'player_name' => $player_name,
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace App\Listeners;
|
||||
|
||||
use Storage;
|
||||
use App\Models\PlayerModel;
|
||||
use App\Models\Player;
|
||||
use App\Events\CheckPlayerExists;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
@ -21,7 +21,7 @@ class CachePlayerExists
|
||||
$player_name = $event->player_name;
|
||||
|
||||
if ($player_name && !Storage::disk('cache')->has("notfound/$player_name")) {
|
||||
if (PlayerModel::where('player_name', $player_name)->get()->isEmpty()) {
|
||||
if (Player::where('player_name', $player_name)->get()->isEmpty()) {
|
||||
Storage::disk('cache')->put("notfound/$player_name", '');
|
||||
}
|
||||
} else {
|
||||
|
@ -8,106 +8,95 @@ use Utils;
|
||||
use Storage;
|
||||
use Response;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use App\Events\GetPlayerJson;
|
||||
use App\Events\PlayerWasAdded;
|
||||
use App\Events\PlayerWasDeleted;
|
||||
use App\Events\PlayerProfileUpdated;
|
||||
use App\Exceptions\PrettyPageException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class Player
|
||||
class Player extends \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
public $pid;
|
||||
public $player_name;
|
||||
public $primaryKey = 'pid';
|
||||
public $timestamps = false;
|
||||
|
||||
public $is_banned = false;
|
||||
protected $fillable = ['uid', 'player_name', 'preference', 'last_modified'];
|
||||
|
||||
public $is_registered = false;
|
||||
public $is_banned = false;
|
||||
|
||||
public $model;
|
||||
const CSL_API = 0;
|
||||
const USM_API = 1;
|
||||
const MODELS = ['steve', 'alex', 'cape'];
|
||||
|
||||
/**
|
||||
* User Instance.
|
||||
* Check if the player is banned.
|
||||
*
|
||||
* @var \App\Models\User
|
||||
* @return bool
|
||||
*/
|
||||
private $owner;
|
||||
|
||||
const CSL_API = 0;
|
||||
const USM_API = 1;
|
||||
|
||||
/**
|
||||
* Construct player with pid or playername
|
||||
*
|
||||
* @param int $pid
|
||||
* @param string $player_name
|
||||
*/
|
||||
public function __construct($pid, $player_name = "")
|
||||
public function isBanned()
|
||||
{
|
||||
if ($player_name == "") {
|
||||
$this->pid = $pid;
|
||||
$this->model = PlayerModel::find($pid);
|
||||
} else {
|
||||
$this->player_name = $player_name;
|
||||
$this->model = PlayerModel::where('player_name', $player_name)->first();
|
||||
}
|
||||
|
||||
if ($this->model) {
|
||||
$this->pid = $this->model->pid;
|
||||
|
||||
$this->player_name = $this->model->player_name;
|
||||
|
||||
$this->owner = new User($this->model->uid);
|
||||
|
||||
$this->is_registered = true;
|
||||
|
||||
$this->is_banned = ($this->owner->getPermission() == "-1");
|
||||
}
|
||||
return (new User($this->uid))->getPermission() == "-1";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get textures of player
|
||||
* Get specific texture of player.
|
||||
*
|
||||
* @param string $type steve|alex|cape, 'skin' for texture of preferred model
|
||||
* @return string sha256-hash of texture file
|
||||
* @param string $type steve|alex|cape
|
||||
* @return string sha256-hash of texture file
|
||||
*/
|
||||
public function getTexture($type)
|
||||
{
|
||||
if ($type == "skin")
|
||||
$type = ($this->getPreference() == "default") ? "steve" : "alex";
|
||||
if ($type == "steve" | $type == "alex" | $type == "cape") {
|
||||
$tid = $this->model['tid_'.$type];
|
||||
return Texture::find($tid)['hash'];
|
||||
|
||||
if (in_array($type, self::MODELS)) {
|
||||
return Texture::find($this["tid_$type"])['hash'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set textures for the player.
|
||||
*
|
||||
* @param array $tids
|
||||
* @return mixed
|
||||
*/
|
||||
public function setTexture(Array $tids)
|
||||
{
|
||||
$map = ['steve', 'alex', 'cape'];
|
||||
|
||||
foreach ($map as $model) {
|
||||
foreach (self::MODELS as $model) {
|
||||
$property = "tid_$model";
|
||||
|
||||
if (isset($tids[$property])) {
|
||||
$this->model->$property = $tids[$property];
|
||||
$this->$property = $tids[$property];
|
||||
}
|
||||
}
|
||||
|
||||
$this->model->last_modified = Utils::getTimeFormatted();
|
||||
$this->last_modified = Utils::getTimeFormatted();
|
||||
|
||||
$this->model->save();
|
||||
$this->save();
|
||||
|
||||
return Event::fire(new PlayerProfileUpdated($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the textures of player.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function clearTexture()
|
||||
{
|
||||
$this->setPreference('default');
|
||||
$this->setTexture(['tid_steve' => 0, 'tid_alex' => 0, 'tid_cape' => 0]);
|
||||
|
||||
return $this->setTexture([
|
||||
'tid_steve' => 0,
|
||||
'tid_alex' => 0,
|
||||
'tid_cape' => 0
|
||||
]);
|
||||
}
|
||||
|
||||
public function getBinaryTexture($type)
|
||||
{
|
||||
if ($this->getTexture($type) != "") {
|
||||
if ($this->getTexture($type)) {
|
||||
$hash = $this->getTexture($type);
|
||||
$path = BASE_DIR."/storage/textures/".$hash;
|
||||
|
||||
@ -119,21 +108,21 @@ class Player
|
||||
'Content-Length' => Storage::disk('textures')->size($hash),
|
||||
]);
|
||||
} else {
|
||||
abort(404, '请求的贴图已被删除。');
|
||||
throw new NotFoundHttpException(trans('general.texture-deleted'));
|
||||
}
|
||||
} else {
|
||||
abort(404, '该用户尚未上传请求的贴图类型 '.$type);
|
||||
throw new NotFoundHttpException(trans('general.texture-not-uploaded', ['type' => $type]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set preferred model.
|
||||
* Set preferred model for the player.
|
||||
*
|
||||
* @param string $type 'slim' or 'default'
|
||||
* @param string $type slim|default
|
||||
*/
|
||||
public function setPreference($type)
|
||||
{
|
||||
$this->model->update([
|
||||
$this->update([
|
||||
'preference' => $type,
|
||||
'last_modified' => Utils::getTimeFormatted()
|
||||
]);
|
||||
@ -143,30 +132,7 @@ class Player
|
||||
|
||||
public function getPreference()
|
||||
{
|
||||
return $this->model['preference'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new player.
|
||||
*
|
||||
* @param User $owner Owner of the player.
|
||||
* @return void
|
||||
*/
|
||||
public function register(User $owner)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
|
||||
$player = new PlayerModel();
|
||||
|
||||
$player->uid = $this->owner->uid;
|
||||
$player->player_name = $this->player_name;
|
||||
$player->preference = "default";
|
||||
$player->last_modified = Utils::getTimeFormatted();
|
||||
$player->save();
|
||||
|
||||
Event::fire(new PlayerWasAdded($player));
|
||||
|
||||
$this->owner->setScore(option('score_per_player'), 'minus');
|
||||
return $this['preference'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,7 +143,7 @@ class Player
|
||||
*/
|
||||
public function rename($new_name)
|
||||
{
|
||||
$this->model->update([
|
||||
$this->update([
|
||||
'player_name' => $new_name,
|
||||
'last_modified' => Utils::getTimeFormatted()
|
||||
]);
|
||||
@ -193,13 +159,13 @@ class Player
|
||||
* @param int $uid
|
||||
*/
|
||||
public function setOwner($uid) {
|
||||
$this->model->update(['uid' => $uid]);
|
||||
$this->update(['uid' => $uid]);
|
||||
|
||||
return Event::fire(new PlayerProfileUpdated($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON profile
|
||||
* Get Json profile of player.
|
||||
*
|
||||
* @param int $api_type Which API to use, 0 for CustomSkinAPI, 1 for UniSkinAPI
|
||||
* @return string User profile in json format
|
||||
@ -216,12 +182,12 @@ class Player
|
||||
return $this->generateJsonProfile($api_type);
|
||||
}
|
||||
} else {
|
||||
throw new PrettyPageException('不支持的 API_TYPE。', -1);
|
||||
throw new InvalidArgumentException('The given api type should be 0 or 1.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate player profile in json string
|
||||
* Generate player profile in json format.
|
||||
*
|
||||
* @param int $api_type
|
||||
* @return string
|
||||
@ -249,38 +215,28 @@ class Player
|
||||
return json_encode($json, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the date of last modified.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateLastModified()
|
||||
{
|
||||
// @see http://stackoverflow.com/questions/2215354/php-date-format-when-inserting-into-datetime-in-mysql
|
||||
$this->model->update(['last_modified' => Utils::getTimeFormatted()]);
|
||||
$this->update(['last_modified' => Utils::getTimeFormatted()]);
|
||||
return Event::fire(new PlayerProfileUpdated($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last modified time
|
||||
* Get time of last modified.
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
public function getLastModified()
|
||||
{
|
||||
return strtotime($this->model['last_modified']);
|
||||
return strtotime($this['last_modified']);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
// Event::fire(new PlayerWasDeleted($this));
|
||||
|
||||
return $this->model->delete();
|
||||
}
|
||||
}
|
||||
|
||||
class PlayerModel extends \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
public $primaryKey = 'pid';
|
||||
protected $table = 'players';
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['uid', 'player_name', 'preference', 'last_modified'];
|
||||
|
||||
public function scopeLike($query, $field, $value)
|
||||
{
|
||||
return $query->where($field, 'LIKE', "%$value%");
|
||||
|
@ -11,7 +11,7 @@ class Texture extends \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
$skin_type_map = ["steve", "alex", "cape"];
|
||||
for ($i = 0; $i <= 2; $i++) {
|
||||
if (PlayerModel::where('tid_'.$skin_type_map[$i], $tid)->count() > 0)
|
||||
if (Player::where('tid_'.$skin_type_map[$i], $tid)->count() > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -58,7 +58,7 @@ class User
|
||||
$this->email = e($info['email']);
|
||||
$this->model = UserModel::where('email', $this->email)->first();
|
||||
} elseif (isset($info['username'])) {
|
||||
$player = PlayerModel::where('player_name', $info['username'])->first();
|
||||
$player = Player::where('player_name', $info['username'])->first();
|
||||
$this->uid = $player ? $player['uid'] : 0;
|
||||
$this->model = UserModel::find($this->uid);
|
||||
} else {
|
||||
@ -242,7 +242,7 @@ class User
|
||||
|
||||
public function getPlayers()
|
||||
{
|
||||
return PlayerModel::where('uid', $this->uid)->get();
|
||||
return Player::where('uid', $this->uid)->get();
|
||||
}
|
||||
|
||||
public function getAvatarId()
|
||||
@ -258,7 +258,7 @@ class User
|
||||
|
||||
public function delete()
|
||||
{
|
||||
PlayerModel::where('uid', $this->uid)->delete();
|
||||
Player::where('uid', $this->uid)->delete();
|
||||
ClosetModel::where('uid', $this->uid)->delete();
|
||||
return $this->model->delete();
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
index: Homepage
|
||||
skinlib: Skin Library
|
||||
langs: Language
|
||||
user-center: User Center
|
||||
logout: Log Out
|
||||
login: Log In
|
||||
@ -45,3 +44,6 @@ public: Public
|
||||
|
||||
unexistent-user: Un-existent user
|
||||
unexistent-player: Un-existent player.
|
||||
|
||||
texture-deleted: The requested texture has been deleted.
|
||||
texture-not-uploaded: The user haven not uploaded the texture of :type model yet.
|
||||
|
@ -1,6 +1,5 @@
|
||||
index: 首页
|
||||
skinlib: 皮肤库
|
||||
langs: 语言
|
||||
user-center: 用户中心
|
||||
logout: 登出
|
||||
login: 登录
|
||||
@ -45,3 +44,6 @@ public: 公开
|
||||
|
||||
unexistent-user: 不存在的用户
|
||||
unexistent-player: 角色不存在
|
||||
|
||||
texture-deleted: 请求的材质已被删除
|
||||
texture-not-uploaded: 该用户尚未上传请求的材质类型 :type
|
||||
|
@ -37,7 +37,7 @@
|
||||
<a href="{{ url('admin/players') }}">
|
||||
<div class="info-box-content" style="margin-left: 0;">
|
||||
<span class="info-box-text">角色总数</span>
|
||||
<span class="info-box-number">{{ App\Models\PlayerModel::all()->count() }}</span>
|
||||
<span class="info-box-number">{{ App\Models\Player::all()->count() }}</span>
|
||||
</div><!-- /.info-box-content -->
|
||||
</a>
|
||||
</div><!-- /.info-box -->
|
||||
|
2
resources/views/vendor/language.tpl
vendored
2
resources/views/vendor/language.tpl
vendored
@ -1,7 +1,7 @@
|
||||
<!-- Language Menu -->
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-language" aria-hidden="true"></i> {{ trans('general.langs') }} <span class="caret"></span>
|
||||
<i class="fa fa-language" aria-hidden="true"></i> Language <span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
@foreach(config('locales') as $locale => $lang)
|
||||
|
Loading…
Reference in New Issue
Block a user