加入後台選單建立機制,後台設定選項建立機制
This commit is contained in:
parent
568d481742
commit
51f9e57e6a
10
app/Exceptions/AdminMenuItemArgInvalidException.php
Normal file
10
app/Exceptions/AdminMenuItemArgInvalidException.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class AdminMenuItemArgInvalidException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
192
app/Http/Controllers/Admin/Menu/BaseMenuItemController.php
Normal file
192
app/Http/Controllers/Admin/Menu/BaseMenuItemController.php
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\Menu;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use View;
|
||||||
|
use Arr;
|
||||||
|
use Gate;
|
||||||
|
use Str;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BaseMenuItemController
|
||||||
|
* @package App\Http\Controllers\Admin\Menu
|
||||||
|
*/
|
||||||
|
abstract class BaseMenuItemController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 顯示名稱
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slug
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $slug;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所需權限,有一個符合即可
|
||||||
|
* 如沒有填入,代表不設限
|
||||||
|
* 子選單預設會沿用父選單的權限,如有填入,則再加上自己的權限
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $permissions = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 選單項目的Icon類別
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $iconClasses = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $badge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default route handler
|
||||||
|
*/
|
||||||
|
public function handle(Request $request)
|
||||||
|
{
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return trans($this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
|
public function setName($name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSlug()
|
||||||
|
{
|
||||||
|
return $this->slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $slug
|
||||||
|
*/
|
||||||
|
public function setSlug($slug): void
|
||||||
|
{
|
||||||
|
$this->slug = $slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPermissions(): array
|
||||||
|
{
|
||||||
|
return $this->permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $permissions
|
||||||
|
*/
|
||||||
|
public function setPermissions(array $permissions): void
|
||||||
|
{
|
||||||
|
$this->permissions = $permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get bootstrap badge arguments
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getBadge()
|
||||||
|
{
|
||||||
|
if(!empty($this->badge['label']) && !empty($this->badge['type'])) {
|
||||||
|
return Arr::add($this->badge, 'isPill', false);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set bootstrap badge arguments
|
||||||
|
*
|
||||||
|
* @param array $badge
|
||||||
|
*/
|
||||||
|
public function setBadge(array $badge): void
|
||||||
|
{
|
||||||
|
$this->badge = $badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|array
|
||||||
|
*/
|
||||||
|
public function getIconClass(): string
|
||||||
|
{
|
||||||
|
if(is_array($this->iconClasses)) {
|
||||||
|
return implode(' ', $this->iconClasses);
|
||||||
|
} else {
|
||||||
|
return $this->iconClasses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|string $iconClasses
|
||||||
|
*/
|
||||||
|
public function setIconClasses($iconClasses): void
|
||||||
|
{
|
||||||
|
$this->iconClasses = $iconClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasIcon()
|
||||||
|
{
|
||||||
|
return !empty($this->getIconClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasBadge()
|
||||||
|
{
|
||||||
|
return !empty($this->badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function userHasPermission()
|
||||||
|
{
|
||||||
|
$hasAnyPermission = false;
|
||||||
|
foreach ($this->permissions as $permission) {
|
||||||
|
$hasAnyPermission = $hasAnyPermission || Gate::allows('permission:' . Str::kebab($permission));
|
||||||
|
}
|
||||||
|
return Auth::check() &&
|
||||||
|
((!empty($this->permissions) && $hasAnyPermission) || empty($this->permissions));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valid if both name and slug are not empty
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isValid()
|
||||||
|
{
|
||||||
|
return $this->getName() && $this->getSlug();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\Menu\Options\Children;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\Menu\BaseMenuItemController;
|
||||||
|
use Gate;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class DevelopmentMenuItemController extends BaseMenuItemController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->name = 'adminMenu.items.options.development';
|
||||||
|
|
||||||
|
$this->slug = 'development';
|
||||||
|
|
||||||
|
$this->permissions = ['admin manage options development'];
|
||||||
|
|
||||||
|
$this->iconClasses = 'nav-icon icon-settings';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Request $request)
|
||||||
|
{
|
||||||
|
return view('admin.menu.options.development');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\Menu\Options\Children;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\Menu\BaseMenuItemController;
|
||||||
|
use Gate;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class GeneralMenuItemController extends BaseMenuItemController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->name = 'adminMenu.items.options.general';
|
||||||
|
|
||||||
|
$this->slug = 'general';
|
||||||
|
|
||||||
|
$this->permissions = ['admin manage options general'];
|
||||||
|
|
||||||
|
$this->iconClasses = 'nav-icon icon-settings';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Request $request)
|
||||||
|
{
|
||||||
|
return view('admin.menu.options.general');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\Menu\Options\Children;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\Menu\BaseMenuItemController;
|
||||||
|
use Gate;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class PlatformMenuItemController extends BaseMenuItemController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->name = 'adminMenu.items.options.platform';
|
||||||
|
|
||||||
|
$this->slug = 'platform';
|
||||||
|
|
||||||
|
$this->permissions = ['admin manage options platform'];
|
||||||
|
|
||||||
|
$this->iconClasses = 'nav-icon icon-settings';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Request $request)
|
||||||
|
{
|
||||||
|
return view('admin.menu.options.platform');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\Menu\Options;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\Menu\BaseMenuItemController;
|
||||||
|
|
||||||
|
class OptionsMenuItemController extends BaseMenuItemController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->name = 'adminMenu.items.options.options';
|
||||||
|
|
||||||
|
$this->slug = 'options';
|
||||||
|
|
||||||
|
$this->permissions = ['admin view options'];
|
||||||
|
|
||||||
|
$this->iconClasses = 'nav-icon icon-settings';
|
||||||
|
}
|
||||||
|
}
|
||||||
120
app/Http/Controllers/OptionsController.php
Normal file
120
app/Http/Controllers/OptionsController.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Exceptions\AdminOptionsInvalidException;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Gate;
|
||||||
|
use Arr;
|
||||||
|
use mysql_xdevapi\Exception;
|
||||||
|
use Str;
|
||||||
|
use Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 網站設定選項
|
||||||
|
* Class OptionsController
|
||||||
|
* @package App\Http\Controllers\Admin
|
||||||
|
*/
|
||||||
|
class OptionsController extends Controller
|
||||||
|
{
|
||||||
|
private $request;
|
||||||
|
|
||||||
|
public function __construct(Request $request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 檢查權限
|
||||||
|
*
|
||||||
|
* @param $gateName
|
||||||
|
*/
|
||||||
|
private function gate($gateName)
|
||||||
|
{
|
||||||
|
if(Gate::denies($gateName)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驗證欄位
|
||||||
|
*
|
||||||
|
* @param $options
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
private function validateOptions($options)
|
||||||
|
{
|
||||||
|
$rules = collect($options['fields'])
|
||||||
|
->filter(function($item, $key){
|
||||||
|
return isset($item['validator']);
|
||||||
|
})
|
||||||
|
->map(function($item, $key){
|
||||||
|
return $item['validator'];
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->validate($this->request, $rules->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新欄位資料
|
||||||
|
*
|
||||||
|
* @param $options
|
||||||
|
*/
|
||||||
|
private function update($options)
|
||||||
|
{
|
||||||
|
$fields = $this->request->only(array_keys($options['fields']));
|
||||||
|
|
||||||
|
$checkboxOptions = collect($options['fields'])
|
||||||
|
->filter(function($item, $key){
|
||||||
|
return isset($item['type']) && $item['type'] = 'checkbox';
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach ($fields as $key => $value) {
|
||||||
|
app('Option')->$key = $value;
|
||||||
|
}
|
||||||
|
foreach ($checkboxOptions as $key => $checkboxOption) {
|
||||||
|
if(!$this->request->has($key)) {
|
||||||
|
app('Option')->$key = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理更新選項的動作並回應
|
||||||
|
*
|
||||||
|
* @param $options
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
private function generateResponse($options)
|
||||||
|
{
|
||||||
|
$this->validateOptions($options);
|
||||||
|
|
||||||
|
$this->update($options);
|
||||||
|
return back()->with(['updated' => trans('message.success')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理更新選項的動作
|
||||||
|
*
|
||||||
|
* @param string $method
|
||||||
|
* @param array $args
|
||||||
|
* @return \Illuminate\Http\RedirectResponse|mixed
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function __call($method, $args = [])
|
||||||
|
{
|
||||||
|
$config = config('admin.options');
|
||||||
|
if(preg_match('/^update/', $method)) {
|
||||||
|
$page = strtolower(preg_replace('/^update/', '', $method));
|
||||||
|
if(in_array($page, array_keys($config))) {
|
||||||
|
if(!empty($config[$page]['permission'])) {
|
||||||
|
$this->gate('permission:' . Str::kebab($config[$page]['permission']));
|
||||||
|
}
|
||||||
|
return $this->generateResponse($config[$page]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \Exception("method: $method dos not exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -66,6 +66,7 @@ class Kernel extends HttpKernel
|
|||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
'admin.area' => \App\Http\Middleware\AdminAreaGuard::class,
|
'admin.area' => \App\Http\Middleware\AdminAreaGuard::class,
|
||||||
|
'admin.menu' => \App\Http\Middleware\CheckAdminMenuPagePermission::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
56
app/Http/Middleware/CheckAdminMenuPagePermission.php
Normal file
56
app/Http/Middleware/CheckAdminMenuPagePermission.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Route;
|
||||||
|
use Arr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 檢查Admin選單項目的route權限
|
||||||
|
*
|
||||||
|
* Class CheckAdminMenuPagePermission
|
||||||
|
* @package App\Http\Middleware
|
||||||
|
*/
|
||||||
|
class CheckAdminMenuPagePermission
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 處理並檢查Admin選單項目的route權限
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
//取得目前的Route
|
||||||
|
$currentRoute = Route::current();
|
||||||
|
//取得目前的Route Controller
|
||||||
|
$menuController = $currentRoute->controller;
|
||||||
|
//取得目前的Route Method
|
||||||
|
$method = $currentRoute->getActionMethod();
|
||||||
|
|
||||||
|
//如果Controller為選單項目的子類別
|
||||||
|
if(is_subclass_of($menuController, \App\Http\Controllers\Admin\Menu\BaseMenuItemController::class)) {
|
||||||
|
//如果方法為預設的route方法
|
||||||
|
if($method == 'handle') {
|
||||||
|
//取得slug組成的route name
|
||||||
|
$routeName = str_replace(config('admin.route_name_prefix') . config('admin.menu.route_name_prefix'), '', Route::currentRouteName());
|
||||||
|
//取得Admin選單項目
|
||||||
|
$adminMenu = app('AdminMenu')->getMenu();
|
||||||
|
//分解Slug
|
||||||
|
$slugs = explode('.', $routeName);
|
||||||
|
//如果slug數量大於1,則為子選單controller
|
||||||
|
if(sizeof($slugs) > 1) {
|
||||||
|
$permission = Arr::get($adminMenu, "{$slugs[0]}.children.{$slugs[1]}.userHasPermission");
|
||||||
|
} else {
|
||||||
|
$permission = Arr::get($adminMenu, "{$slugs[0]}.userHasPermission");
|
||||||
|
}
|
||||||
|
if(!$permission) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/Option.php
Normal file
15
app/Option.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Option extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['key', 'value'];
|
||||||
|
|
||||||
|
public function scopeKey($query, $key)
|
||||||
|
{
|
||||||
|
return $query->where('key', $key);
|
||||||
|
}
|
||||||
|
}
|
||||||
129
app/Presenters/Admin/MainMenuItemPresenter.php
Normal file
129
app/Presenters/Admin/MainMenuItemPresenter.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Presenters\Admin;
|
||||||
|
|
||||||
|
use App\Presenters\Html\HtmlPresenter;
|
||||||
|
|
||||||
|
class MainMenuItemPresenter
|
||||||
|
{
|
||||||
|
private $htmlPresenter;
|
||||||
|
|
||||||
|
public function __construct(HtmlPresenter $htmlPresenter)
|
||||||
|
{
|
||||||
|
$this->htmlPresenter = $htmlPresenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 檢查選單項目權限
|
||||||
|
*
|
||||||
|
* @param array $item
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function checkMenuItemPermission($item)
|
||||||
|
{
|
||||||
|
return !empty($item['userHasPermission']) && $item['userHasPermission'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if any child has permission
|
||||||
|
*
|
||||||
|
* @param $item
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkAnyChildPermission($item)
|
||||||
|
{
|
||||||
|
if(isset($item['children'])) {
|
||||||
|
$anyChildHasPermission = false;
|
||||||
|
foreach ($item['children'] as $childMenu) {
|
||||||
|
$anyChildHasPermission = $anyChildHasPermission || $childMenu['userHasPermission'];
|
||||||
|
}
|
||||||
|
return $anyChildHasPermission;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回傳選單項目Html
|
||||||
|
*
|
||||||
|
* return string
|
||||||
|
*/
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
$menu = app('AdminMenu')->getMenu();
|
||||||
|
|
||||||
|
$html = '';
|
||||||
|
$htmlPresenter = $this->htmlPresenter;
|
||||||
|
|
||||||
|
foreach ($menu as $parentKey => $item) {
|
||||||
|
switch($item['type']) {
|
||||||
|
case 'title':
|
||||||
|
$html .= $htmlPresenter->li([
|
||||||
|
'class' => 'nav-title',
|
||||||
|
'html' => trans('menu.titles.' . $item['name'])
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
case 'item':
|
||||||
|
if($this->checkMenuItemPermission($item) && $this->checkAnyChildPermission($item)) {
|
||||||
|
$hasChildren = !empty($item['children']);
|
||||||
|
$html .= $htmlPresenter->li([
|
||||||
|
'class' => [
|
||||||
|
'nav-item',
|
||||||
|
$hasChildren ? 'nav-dropdown has-children' : '',
|
||||||
|
"slug-{$item['slug']}"
|
||||||
|
],
|
||||||
|
'html' => [
|
||||||
|
$htmlPresenter->a([
|
||||||
|
'class' => [
|
||||||
|
'nav-link',
|
||||||
|
$hasChildren ? 'nav-dropdown-toggle' : '',
|
||||||
|
],
|
||||||
|
'href' => $item['link'],
|
||||||
|
'html' => [
|
||||||
|
!empty($item['iconClass']) ? $htmlPresenter->i(['class' => $item['iconClass']]) : '',
|
||||||
|
$item['name'],
|
||||||
|
!empty($item['badge']) ? $htmlPresenter->bs()->badge($item['badge']['label'], $item['badge']['type'], $item['badge']['isPill']) : ''
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
$hasChildren ? $htmlPresenter->ul([
|
||||||
|
'class' => 'nav-dropdown-items submenu',
|
||||||
|
'html' => function() use ($hasChildren, $item, $htmlPresenter) {
|
||||||
|
$html = '';
|
||||||
|
if($hasChildren) {
|
||||||
|
foreach ($item['children'] as $childItem) {
|
||||||
|
if($this->checkMenuItemPermission($childItem)) {
|
||||||
|
$html .= $htmlPresenter->li([
|
||||||
|
'class' => [
|
||||||
|
'nav-item',
|
||||||
|
"slug-{$childItem['slug']}",
|
||||||
|
],
|
||||||
|
'html' => $htmlPresenter->a([
|
||||||
|
'class' => 'nav-link',
|
||||||
|
'href' => $childItem['link'],
|
||||||
|
'html' => [
|
||||||
|
!empty($childItem['iconClass']) ? $htmlPresenter->i(['class' => $childItem['iconClass']]) : '',
|
||||||
|
$childItem['name'],
|
||||||
|
!empty($childItem['badge']) ? $htmlPresenter->bs()->badge($childItem['badge']['label'], $childItem['badge']['type'], $childItem['badge']['isPill']) : ''
|
||||||
|
]
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
]) : ''
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'divider':
|
||||||
|
$html .= $htmlPresenter->li([
|
||||||
|
'class' => 'nav-divider'
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo $html;
|
||||||
|
}
|
||||||
|
}
|
||||||
168
app/Presenters/Admin/OptionFormFieldsPresenter.php
Normal file
168
app/Presenters/Admin/OptionFormFieldsPresenter.php
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Presenters\Admin;
|
||||||
|
|
||||||
|
use Arr;
|
||||||
|
|
||||||
|
class OptionFormFieldsPresenter
|
||||||
|
{
|
||||||
|
public function render($page)
|
||||||
|
{
|
||||||
|
$options = config('admin.options.' . $page);
|
||||||
|
$presenter = app('Html');
|
||||||
|
$optionRepo = app('Option');
|
||||||
|
$html = '';
|
||||||
|
if(!empty($options['fields'])) {
|
||||||
|
foreach($options['fields'] as $key => $option) {
|
||||||
|
$type = !empty($option['type']) ? $option['type'] : 'text';
|
||||||
|
$required = !empty($option['required']) && $option['required'] ? true : false;
|
||||||
|
$label = !empty($option['label']) ? $option['label'] : $key;
|
||||||
|
$html .= $presenter->div([
|
||||||
|
'class' => 'form-group row',
|
||||||
|
'html' => [
|
||||||
|
$presenter->div([
|
||||||
|
'class' => 'col-12 col-md-6',
|
||||||
|
'html' => $presenter->label([
|
||||||
|
'for' => 'option-' . $key,
|
||||||
|
'html' => [
|
||||||
|
trans('adminOptionLabels.' . $label),
|
||||||
|
$required ? $presenter->span([
|
||||||
|
'class' => 'required',
|
||||||
|
'html' => '*'
|
||||||
|
]) : ''
|
||||||
|
]
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
$presenter->div([
|
||||||
|
'class' => 'col-12 col-md-6',
|
||||||
|
'html' => function() use ($key, $type, $required, $presenter, $optionRepo) {
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
$bastHtmlArgs = [
|
||||||
|
'name' => $key,
|
||||||
|
'id' => 'option-' . $key,
|
||||||
|
];
|
||||||
|
switch ($type) {
|
||||||
|
case 'text':
|
||||||
|
case 'password':
|
||||||
|
case 'email':
|
||||||
|
case 'number':
|
||||||
|
$htmlArgs = array_merge([
|
||||||
|
'type' => $type,
|
||||||
|
'value' => $optionRepo->$key,
|
||||||
|
'class' => 'form-control',
|
||||||
|
], $bastHtmlArgs);
|
||||||
|
|
||||||
|
if($required)
|
||||||
|
$htmlArgs['required'] = null;
|
||||||
|
|
||||||
|
$html .= $presenter->input($htmlArgs);
|
||||||
|
break;
|
||||||
|
case 'checkbox':
|
||||||
|
$htmlArgs = array_merge([
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'value' => 1,
|
||||||
|
], $bastHtmlArgs);
|
||||||
|
|
||||||
|
if($optionRepo->$key) {
|
||||||
|
$htmlArgs['checked'] = 'checked';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= $presenter->input($htmlArgs);
|
||||||
|
break;
|
||||||
|
case 'textarea':
|
||||||
|
$htmlArgs = array_merge([
|
||||||
|
'html' => $optionRepo->$key,
|
||||||
|
'class' => 'form-control',
|
||||||
|
], $bastHtmlArgs);
|
||||||
|
|
||||||
|
if($required)
|
||||||
|
$htmlArgs['required'] = null;
|
||||||
|
|
||||||
|
if(!empty($option['row']))
|
||||||
|
$htmlArgs['row'] = $option['row'];
|
||||||
|
|
||||||
|
$html .= $presenter->textarea($htmlArgs);
|
||||||
|
break;
|
||||||
|
case 'select':
|
||||||
|
$selectOptions = !empty($option['options']) ? $option['options'] : null;
|
||||||
|
$htmlArgs = array_merge([
|
||||||
|
'class' => 'form-control',
|
||||||
|
], $bastHtmlArgs);
|
||||||
|
$currentValue = $optionRepo->$key;
|
||||||
|
if(!empty($selectOptions)) {
|
||||||
|
$htmlArgs['html'] = function() use ($currentValue, $selectOptions, $presenter) {
|
||||||
|
$html = '';
|
||||||
|
foreach ($selectOptions as $value => $label) {
|
||||||
|
$htmlArgs = [
|
||||||
|
'value' => $value,
|
||||||
|
'html' => trans('form.options.' . $label),
|
||||||
|
];
|
||||||
|
if($currentValue == $value) {
|
||||||
|
$htmlArgs['selected'] = 'selected';
|
||||||
|
}
|
||||||
|
$html .= $presenter->option($htmlArgs);
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if($required)
|
||||||
|
$htmlArgs['required'] = null;
|
||||||
|
|
||||||
|
$html .= $presenter->select($htmlArgs);
|
||||||
|
break;
|
||||||
|
case 'radio':
|
||||||
|
$radioOptions = !empty($option['options']) ? $option['options'] : null;
|
||||||
|
$currentValue = $optionRepo->$key;
|
||||||
|
$defaultValue = !empty($option['default']) ? $option['default'] : null;
|
||||||
|
if(!empty($radioOptions)) {
|
||||||
|
foreach ($radioOptions as $value => $label) {
|
||||||
|
$html .= $presenter->div([
|
||||||
|
'class' => 'form-check',
|
||||||
|
'html' => function() use ($key, $currentValue, $defaultValue, $label, $value, $radioOptions, $presenter) {
|
||||||
|
$html = '';
|
||||||
|
$inputId = 'option-' . $key . '-' . $value;
|
||||||
|
|
||||||
|
$inputHtmlArgs = [
|
||||||
|
'type' => 'radio',
|
||||||
|
'class' => 'form-check-input',
|
||||||
|
'name' => $key,
|
||||||
|
'id' => $inputId,
|
||||||
|
'value' => $value
|
||||||
|
];
|
||||||
|
|
||||||
|
if($currentValue === null) {
|
||||||
|
if($defaultValue && $defaultValue == $value) {
|
||||||
|
$inputHtmlArgs['checked'] = 'checked';
|
||||||
|
} elseif(array_key_first($radioOptions) == $value) {
|
||||||
|
$inputHtmlArgs['checked'] = 'checked';
|
||||||
|
}
|
||||||
|
} elseif($currentValue == $value) {
|
||||||
|
$inputHtmlArgs['checked'] = 'checked';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= $presenter->input($inputHtmlArgs);
|
||||||
|
|
||||||
|
$html .= $presenter->label([
|
||||||
|
'class' => 'form-check-label',
|
||||||
|
'for' => $inputId,
|
||||||
|
'html' => $label
|
||||||
|
]);
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
||||||
128
app/Presenters/Html/BaseHtmlPresenter.php
Normal file
128
app/Presenters/Html/BaseHtmlPresenter.php
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Presenters\Html;
|
||||||
|
|
||||||
|
use Arr;
|
||||||
|
|
||||||
|
trait BaseHtmlPresenter
|
||||||
|
{
|
||||||
|
public function __call($name, $arguments)
|
||||||
|
{
|
||||||
|
return $this->tag($name, isset($arguments[0]) ? $arguments[0] : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAttribute($key, $value = null)
|
||||||
|
{
|
||||||
|
if($value === null) {
|
||||||
|
return "$key";
|
||||||
|
} else{
|
||||||
|
return "$key=\"{$value}\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAttributes($fieldArgs = [])
|
||||||
|
{
|
||||||
|
$attributes = [];
|
||||||
|
$multiValueAttributes = [
|
||||||
|
'class',
|
||||||
|
'style',
|
||||||
|
];
|
||||||
|
Arr::forget($fieldArgs, 'html');
|
||||||
|
foreach ($fieldArgs as $name => $value) {
|
||||||
|
if(in_array($name, $multiValueAttributes)) {
|
||||||
|
if(is_array($value)) {
|
||||||
|
$value = array_filter($value);
|
||||||
|
$values = trim(implode(' ', $value));
|
||||||
|
} else {
|
||||||
|
$values = $value;
|
||||||
|
}
|
||||||
|
array_push($attributes, $this->getAttribute($name, $values));
|
||||||
|
} else {
|
||||||
|
array_push($attributes, $this->getAttribute($name, $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trim(implode(' ', $attributes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tag($tag, $fieldArgs = [], $echo = false)
|
||||||
|
{
|
||||||
|
$selfClosingTags = array(
|
||||||
|
'area',
|
||||||
|
'base',
|
||||||
|
'br',
|
||||||
|
'col',
|
||||||
|
'command',
|
||||||
|
'embed',
|
||||||
|
'hr',
|
||||||
|
'img',
|
||||||
|
'input',
|
||||||
|
'keygen',
|
||||||
|
'link',
|
||||||
|
'menuitem',
|
||||||
|
'meta',
|
||||||
|
'param',
|
||||||
|
'source',
|
||||||
|
'track',
|
||||||
|
'wbr',
|
||||||
|
);
|
||||||
|
$htmlElements = !isset($fieldArgs['html']) ? '' : $fieldArgs['html'];
|
||||||
|
$htmlContent = '';
|
||||||
|
if(is_array($htmlElements)) {
|
||||||
|
foreach ($htmlElements as $htmlElement) {
|
||||||
|
if($htmlElement instanceof \Closure) {
|
||||||
|
$htmlContent .= call_user_func($htmlElement);
|
||||||
|
} else {
|
||||||
|
$htmlContent .= $htmlElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif($htmlElements instanceof \Closure) {
|
||||||
|
$htmlContent = call_user_func($htmlElements);
|
||||||
|
} else {
|
||||||
|
$htmlContent = $htmlElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isSelfClosing = in_array($tag, $selfClosingTags);
|
||||||
|
|
||||||
|
return '<' . trim(implode(' ', [$tag, $this->getAttributes($fieldArgs)])) . '>' .
|
||||||
|
(!$isSelfClosing ? $htmlContent . '</' . $tag . '>' : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readonly($readonly = true)
|
||||||
|
{
|
||||||
|
return $readonly ? $this->getAttribute('readonly') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disabled($disabled = true)
|
||||||
|
{
|
||||||
|
return $disabled ? $this->getAttribute('disabled', 'disabled') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function required($required = true)
|
||||||
|
{
|
||||||
|
return $required ? $this->getAttribute('required') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checked($checked = true)
|
||||||
|
{
|
||||||
|
return $checked ? $this->getAttribute('checked', 'checked') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkChecked($currentValue, $comparedValue)
|
||||||
|
{
|
||||||
|
if(is_array($comparedValue)) {
|
||||||
|
return in_array($currentValue, $comparedValue) ? $this->checked() : '';
|
||||||
|
} else {
|
||||||
|
return $currentValue == $comparedValue ? $this->checked() : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function selected($selected = true)
|
||||||
|
{
|
||||||
|
return $selected ? $this->getAttribute('selected', 'selected') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function selectSelected($currentValue, $comparedValue)
|
||||||
|
{
|
||||||
|
return $currentValue == $comparedValue ? $this->selected() : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
158
app/Presenters/Html/Bootstrap4HtmlPresenter.php
Normal file
158
app/Presenters/Html/Bootstrap4HtmlPresenter.php
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Presenters\Html;
|
||||||
|
|
||||||
|
class Bootstrap4HtmlPresenter
|
||||||
|
{
|
||||||
|
use BaseHtmlPresenter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回Badge元件的Html
|
||||||
|
*
|
||||||
|
* @param string $content 內容
|
||||||
|
* @param string $type 類型
|
||||||
|
* @param bool $isPill 膠囊型態
|
||||||
|
* @param bool $isLink 連結
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function badge(string $content = '', string $type = 'primary', $isPill = false, string $link = '')
|
||||||
|
{
|
||||||
|
$allowedTypes = [
|
||||||
|
'primary',
|
||||||
|
'secondary',
|
||||||
|
'success',
|
||||||
|
'danger',
|
||||||
|
'warning',
|
||||||
|
'info',
|
||||||
|
'light',
|
||||||
|
'dark',
|
||||||
|
];
|
||||||
|
if(in_array(strtolower($type), $allowedTypes)) {
|
||||||
|
$tag = $link ? 'a' : 'span';
|
||||||
|
$htmlArgs = [
|
||||||
|
'class' => [
|
||||||
|
'badge',
|
||||||
|
'badge-' . $type,
|
||||||
|
],
|
||||||
|
'role' => 'alert',
|
||||||
|
'html' => $content
|
||||||
|
];
|
||||||
|
if($isPill)
|
||||||
|
$htmlArgs['class'][] = 'badge-pill';
|
||||||
|
|
||||||
|
if($link)
|
||||||
|
$htmlArgs['href'] = $link;
|
||||||
|
|
||||||
|
return $this->tag($tag, $htmlArgs);
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回Alert元件的Html
|
||||||
|
*
|
||||||
|
* @param string $content 內容,可包含連結,連結格式為:key,再於alertLink參數使用陣列指定傳入網址
|
||||||
|
* @param $type string 類型
|
||||||
|
* @param bool $dismiss 是否有關閉的按鈕
|
||||||
|
* @param array $alertLinks 文字中連結,陣列格式為 key => url
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function alert(string $content = '', string $type = 'primary', $dismiss = true, array $alertLinks = [])
|
||||||
|
{
|
||||||
|
$allowedTypes = [
|
||||||
|
'primary',
|
||||||
|
'secondary',
|
||||||
|
'success',
|
||||||
|
'danger',
|
||||||
|
'warning',
|
||||||
|
'info',
|
||||||
|
'light',
|
||||||
|
'dark',
|
||||||
|
];
|
||||||
|
if(in_array(strtolower($type), $allowedTypes)) {
|
||||||
|
if(!empty($alertLinks)) {
|
||||||
|
foreach ($alertLinks as $key => $link) {
|
||||||
|
$linkHtmlArgs = [
|
||||||
|
'href' => $link['url'],
|
||||||
|
'class' => 'alert-link',
|
||||||
|
'html' => $link['content']
|
||||||
|
];
|
||||||
|
if(!empty($link['target'])) {
|
||||||
|
$linkHtmlArgs['target'] = $link['target'];
|
||||||
|
}
|
||||||
|
$linkHtml = $this->tag('a', $linkHtmlArgs);
|
||||||
|
$content = str_replace(":$key", $linkHtml, $content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$dismissButtonHtml = '';
|
||||||
|
if($dismiss) {
|
||||||
|
$dismissButtonHtml = $this->tag('button', [
|
||||||
|
'type' => 'button',
|
||||||
|
'class' => 'close',
|
||||||
|
'data-dismiss' => 'alert',
|
||||||
|
'aria-label' => 'Close',
|
||||||
|
'html' => $this->tag('span', [
|
||||||
|
'aria-hidden' => 'true',
|
||||||
|
'html' => '×'
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$htmlArgs = [
|
||||||
|
'class' => [
|
||||||
|
'alert',
|
||||||
|
'alert-' . $type,
|
||||||
|
],
|
||||||
|
'html' => $content . $dismissButtonHtml
|
||||||
|
];
|
||||||
|
|
||||||
|
if($dismiss) {
|
||||||
|
$htmlArgs['class'][] = 'alert-dismissible fade show';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->tag('div', $htmlArgs);
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回Breadcrumb元件的Html
|
||||||
|
*
|
||||||
|
* @param array $items
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function breadcrumb(array $items = [])
|
||||||
|
{
|
||||||
|
$html = $this->tag('nav', [
|
||||||
|
'aria-label' => 'breadcrumb',
|
||||||
|
'html' => $this->tag('ol', [
|
||||||
|
'class' => 'breadcrumb',
|
||||||
|
'html' => function() use ($items) {
|
||||||
|
$itemsHtml = '';
|
||||||
|
foreach ((array)$items as $item) {
|
||||||
|
$args = [
|
||||||
|
'class' => [
|
||||||
|
'breadcrumb-item'
|
||||||
|
],
|
||||||
|
'html' => !empty($item['content']) ? $item['content'] : ''
|
||||||
|
];
|
||||||
|
|
||||||
|
if(!empty($item['active'])) {
|
||||||
|
$args['class'][] = 'active';
|
||||||
|
$args['aria-current'] = 'page';
|
||||||
|
$args['html'] = $this->tag('a', [
|
||||||
|
'href' => !empty($item['href']) ? $item['href'] : '#',
|
||||||
|
'html' => !empty($item['content']) ? $item['content'] : ''
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$itemsHtml .= $this->tag('li', $args);
|
||||||
|
}
|
||||||
|
return $itemsHtml;
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/Presenters/Html/FontAwesomeHtmlPresenter.php
Normal file
18
app/Presenters/Html/FontAwesomeHtmlPresenter.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Presenters\Html;
|
||||||
|
|
||||||
|
class FontAwesomeHtmlPresenter
|
||||||
|
{
|
||||||
|
use BaseHtmlPresenter;
|
||||||
|
|
||||||
|
public function icon($name = '')
|
||||||
|
{
|
||||||
|
return $this->tag('i', [
|
||||||
|
'class' => [
|
||||||
|
'fa',
|
||||||
|
'fa-' . $name
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/Presenters/Html/HtmlPresenter.php
Normal file
47
app/Presenters/Html/HtmlPresenter.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Presenters\Html;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class HtmlPresenter
|
||||||
|
* @package App\Presenters\Html
|
||||||
|
*
|
||||||
|
* @property Bootstrap4HtmlPresenter $bootstrap
|
||||||
|
* @property FontAwesomeHtmlPresenter $fontawesome
|
||||||
|
*/
|
||||||
|
class HtmlPresenter
|
||||||
|
{
|
||||||
|
use BaseHtmlPresenter;
|
||||||
|
|
||||||
|
private $bootstrap;
|
||||||
|
|
||||||
|
private $fontawesome;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->bootstrap = app()->make(Bootstrap4HtmlPresenter::class);
|
||||||
|
$this->fontawesome = app()->make(FontAwesomeHtmlPresenter::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bootstrap()
|
||||||
|
{
|
||||||
|
return $this->bootstrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bs()
|
||||||
|
{
|
||||||
|
return $this->bootstrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fontawesome()
|
||||||
|
{
|
||||||
|
return $this->fontawesome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fa()
|
||||||
|
{
|
||||||
|
return $this->fontawesome();
|
||||||
|
}
|
||||||
|
}
|
||||||
113
app/Providers/AdminMenuServiceProvider.php
Normal file
113
app/Providers/AdminMenuServiceProvider.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Route;
|
||||||
|
use Auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 從Config檔案建立Menu Item,並註冊相關Route
|
||||||
|
*
|
||||||
|
* Class AdminMenuServiceProvider
|
||||||
|
* @package App\Providers
|
||||||
|
*/
|
||||||
|
class AdminMenuServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
protected $namespace = '\\';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
/** 從Config建Admin Menu物件內容 */
|
||||||
|
Route::group(['prefix' => config('admin.route') . '/main', 'middleware' => ['web', 'admin.area', 'admin.menu'], 'as' => config('admin.route_name_prefix')], function(){
|
||||||
|
|
||||||
|
//Config的Menu組態設定
|
||||||
|
$menuItems = config('admin.menuItems');
|
||||||
|
//Menu Route Name的前綴
|
||||||
|
$menuRouteNamePrefix = config('admin.menu.route_name_prefix');
|
||||||
|
//MenuItemContoller的Route處理函式
|
||||||
|
$menuItemControllerHandlingMethod = 'handle';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MenuItem的處理物件,為全域Singleton物件
|
||||||
|
* @var \App\Services\Admin\MainMenuItemService $adminMenu
|
||||||
|
*/
|
||||||
|
$adminMenu = app('AdminMenu');
|
||||||
|
|
||||||
|
foreach ($menuItems as $menuItem) {
|
||||||
|
if($menuItem['type'] == 'item') {
|
||||||
|
if(class_exists($menuItem['controller'])) {
|
||||||
|
/**
|
||||||
|
* @var \App\Http\Controllers\Admin\Menu\BaseMenuItemController $parentItem
|
||||||
|
*/
|
||||||
|
$parentItem = new $menuItem['controller'];
|
||||||
|
if(!$parentItem->isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$hasChildren = !empty($menuItem['children']);
|
||||||
|
$routeName = false;
|
||||||
|
$link = '#';
|
||||||
|
if(!$hasChildren) {
|
||||||
|
$routeName = "{$menuRouteNamePrefix}{$parentItem->getSlug()}";
|
||||||
|
$action = "{$menuItem['controller']}@$menuItemControllerHandlingMethod";
|
||||||
|
//註冊Route
|
||||||
|
Route::get($parentItem->getSlug(), $action)->name($routeName);
|
||||||
|
}
|
||||||
|
//註冊選單項目
|
||||||
|
$adminMenu->addItem([
|
||||||
|
'type' => 'item',
|
||||||
|
'parentSlug' => false,
|
||||||
|
'routeName' => $routeName,
|
||||||
|
], $parentItem);
|
||||||
|
if($hasChildren) {
|
||||||
|
foreach((array)$menuItem['children'] as $childMenuItem) {
|
||||||
|
if(class_exists($childMenuItem)) {
|
||||||
|
/**
|
||||||
|
* @var \App\Http\Controllers\Admin\Menu\BaseMenuItemController $childItem
|
||||||
|
*/
|
||||||
|
$childItem = new $childMenuItem;
|
||||||
|
if(!$childItem->isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$routeName = "{$menuRouteNamePrefix}{$parentItem->getSlug()}.{$childItem->getSlug()}";
|
||||||
|
$action = "$childMenuItem@$menuItemControllerHandlingMethod";
|
||||||
|
//註冊Route
|
||||||
|
Route::get("{$parentItem->getSlug()}/{$childItem->getSlug()}", $action)->name($routeName);
|
||||||
|
//註冊選單項目
|
||||||
|
$adminMenu->addItem([
|
||||||
|
'type' => 'item',
|
||||||
|
'parentSlug' => $parentItem->getSlug(),
|
||||||
|
'routeName' => $routeName,
|
||||||
|
], $childItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif($menuItem['type'] == 'title') {
|
||||||
|
$adminMenu->addItem([
|
||||||
|
'type' => 'title',
|
||||||
|
'name' => $menuItem['name']
|
||||||
|
]);
|
||||||
|
} elseif($menuItem['type'] == 'divider') {
|
||||||
|
$adminMenu->addItem([
|
||||||
|
'type' => 'divider',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,9 @@ namespace App\Providers;
|
|||||||
|
|
||||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Spatie\Permission\Models\Permission;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
use Str;
|
||||||
|
|
||||||
class AuthServiceProvider extends ServiceProvider
|
class AuthServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@ -25,6 +28,38 @@ class AuthServiceProvider extends ServiceProvider
|
|||||||
{
|
{
|
||||||
$this->registerPolicies();
|
$this->registerPolicies();
|
||||||
|
|
||||||
//
|
//administrator不受Gate限制
|
||||||
|
Gate::before(function($user, $ability) {
|
||||||
|
/** @var \App\User $user */
|
||||||
|
if($user->hasRole('administrator')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Register all permissions as gate ability
|
||||||
|
$allPermissions = Permission::all();
|
||||||
|
foreach ($allPermissions as $permission) {
|
||||||
|
/** @var Permission $permission */
|
||||||
|
$permissionName = $permission->name;
|
||||||
|
$gateName = 'permission:' . Str::kebab($permissionName);
|
||||||
|
Gate::define($gateName, function ($user) use ($permissionName) {
|
||||||
|
/** @var \App\User $user */
|
||||||
|
return $user->hasPermissionTo($permissionName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register all roles as gate ability
|
||||||
|
$allRoles = Role::all();
|
||||||
|
foreach ($allRoles as $role) {
|
||||||
|
/** @var Role $permission */
|
||||||
|
$roleName = $role->name;
|
||||||
|
$gateName = 'role:' . Str::kebab($roleName);
|
||||||
|
Gate::define($gateName, function ($user) use ($roleName) {
|
||||||
|
/** @var \App\User $user */
|
||||||
|
return $user->hasRole($roleName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
47
app/Providers/OptionRouteServiceProvider.php
Normal file
47
app/Providers/OptionRouteServiceProvider.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\OptionsController;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建立後台設定頁面的route
|
||||||
|
*
|
||||||
|
* Class OptionRouteServiceProvider
|
||||||
|
* @package App\Providers
|
||||||
|
*/
|
||||||
|
class OptionRouteServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
Route::group(['prefix' => config('admin.route'), 'middleware' => ['web', 'admin.area'], 'as' => config('admin.route_name_prefix')], function(){
|
||||||
|
$config = config('admin.options');
|
||||||
|
if(empty($config)) return;
|
||||||
|
$options = array_keys(config('admin.options'));
|
||||||
|
|
||||||
|
foreach ($options as $page) {
|
||||||
|
$action = OptionsController::class;
|
||||||
|
$action .= '@update' . ucfirst($page);
|
||||||
|
Route::match(['put', 'patch'], "/options/{$page}/update", $action)
|
||||||
|
->name("options.{$page}.update");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Option;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,6 +24,25 @@ class SingletonServiceProvider extends ServiceProvider
|
|||||||
$this->app->singleton(\App\Services\SiteStateService::class, function($app){
|
$this->app->singleton(\App\Services\SiteStateService::class, function($app){
|
||||||
return new \App\Services\SiteStateService;
|
return new \App\Services\SiteStateService;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->app->alias(\App\Services\Admin\MainMenuItemService::class, 'AdminMenu');
|
||||||
|
$this->app->singleton(\App\Services\Admin\MainMenuItemService::class, function($app){
|
||||||
|
return new \App\Services\Admin\MainMenuItemService;
|
||||||
|
});
|
||||||
|
|
||||||
|
//Repositories
|
||||||
|
$this->app->alias(\App\Repositories\OptionRepository::class, 'Option');
|
||||||
|
$this->app->singleton(\App\Repositories\OptionRepository::class, function($app){
|
||||||
|
return new \App\Repositories\OptionRepository($app->make(\App\Option::class));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Presenters
|
||||||
|
$this->app->alias(\App\Presenters\Html\HtmlPresenter::class, 'Html');
|
||||||
|
$this->app->singleton(\App\Presenters\Html\HtmlPresenter::class, function($app){
|
||||||
|
return new \App\Presenters\Html\HtmlPresenter;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
125
app/Reposotories/OptionRepository.php
Normal file
125
app/Reposotories/OptionRepository.php
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Option;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
/**
|
||||||
|
* Class OptionRepository
|
||||||
|
* @package App\Repositories
|
||||||
|
*
|
||||||
|
* @property \App\Option $model
|
||||||
|
* @method \App\Option getModel()
|
||||||
|
*/
|
||||||
|
class OptionRepository extends BaseRepository
|
||||||
|
{
|
||||||
|
private $cacheKeyPrefix = 'options_';
|
||||||
|
|
||||||
|
public function __construct(Option $option)
|
||||||
|
{
|
||||||
|
$this->setModel($option);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($key)
|
||||||
|
{
|
||||||
|
return $this->getOption($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set($key, $value)
|
||||||
|
{
|
||||||
|
$this->setOption($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增Option
|
||||||
|
*
|
||||||
|
* @param $key
|
||||||
|
* @param $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addOption($key, $value)
|
||||||
|
{
|
||||||
|
if(is_string($key) && $key) {
|
||||||
|
if(!is_string($value)) {
|
||||||
|
if(is_bool($value) || is_null($value)) {
|
||||||
|
$value = (string) $value;
|
||||||
|
} else {
|
||||||
|
$value = serialize($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->model->updateOrInsert(['key' => $key], ['value' => $value]);
|
||||||
|
Cache::forget($this->cacheKeyPrefix . $key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新Option
|
||||||
|
*
|
||||||
|
* @param $key
|
||||||
|
* @param $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setOption($key, $value)
|
||||||
|
{
|
||||||
|
$this->addOption($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得Option
|
||||||
|
*
|
||||||
|
* @param $key
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getOption($key)
|
||||||
|
{
|
||||||
|
if(Cache::has($this->cacheKeyPrefix . $key)) {
|
||||||
|
return Cache::get($this->cacheKeyPrefix . $key);
|
||||||
|
}
|
||||||
|
$value = null;
|
||||||
|
try {
|
||||||
|
$option = $this->model->where(['key' => $key])->first();
|
||||||
|
if($option) {
|
||||||
|
$value = @unserialize($option->value);
|
||||||
|
if($value === false) {
|
||||||
|
$value = $option->value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
|
Cache::put($this->cacheKeyPrefix . $key, $value);
|
||||||
|
} catch(\Exception $e) {}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刪除Option
|
||||||
|
*
|
||||||
|
* @param $key
|
||||||
|
* @throws \Exception
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function deleteOption($key)
|
||||||
|
{
|
||||||
|
$option = $this->model->where('key', $key)->first();
|
||||||
|
if($option) {
|
||||||
|
$option->delete();
|
||||||
|
Cache::forget($this->cacheKeyPrefix . $key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批次更新Options
|
||||||
|
*
|
||||||
|
* @param $options
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setOptions($options)
|
||||||
|
{
|
||||||
|
if(is_array($options)) {
|
||||||
|
foreach ($options as $key => $value) {
|
||||||
|
$this->setOption($key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
149
app/Services/Admin/MainMenuItemService.php
Normal file
149
app/Services/Admin/MainMenuItemService.php
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Admin;
|
||||||
|
|
||||||
|
use App\Exceptions\AdminMenuItemArgInvalidException;
|
||||||
|
use App\Http\Controllers\Admin\Menu\BaseMenuItemController;
|
||||||
|
use Composer\Util\Git;
|
||||||
|
use Validator;
|
||||||
|
use Arr;
|
||||||
|
use Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存放Admin主選單項目
|
||||||
|
*
|
||||||
|
* Class MainMenuItemHandler
|
||||||
|
* @package App\Handlers\Admin
|
||||||
|
*/
|
||||||
|
class MainMenuItemService
|
||||||
|
{
|
||||||
|
private $menu = [];
|
||||||
|
|
||||||
|
private $allowedItemTypes = [
|
||||||
|
'item',
|
||||||
|
'title',
|
||||||
|
'divider'
|
||||||
|
];
|
||||||
|
|
||||||
|
private $adminRouteNamePrefix;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->adminRouteNamePrefix = config('admin.route_name_prefix');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驗證新增選單項目方法參數
|
||||||
|
*
|
||||||
|
* @param $args
|
||||||
|
* @throws AdminMenuItemArgInvalidException
|
||||||
|
*/
|
||||||
|
private function validateItemArgs($args)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($args, [
|
||||||
|
'type' => 'required',
|
||||||
|
'name' => 'required_if:type,title',
|
||||||
|
'slug' => 'required_if:type,item',
|
||||||
|
'controller' => 'required_if:type,item',
|
||||||
|
'routeName' => 'required_if:type,item',
|
||||||
|
]);
|
||||||
|
if($validator->fails()) {
|
||||||
|
throw new AdminMenuItemArgInvalidException($validator->getMessageBag()->first());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增選單項目
|
||||||
|
*
|
||||||
|
* @param array $givenArgs
|
||||||
|
* @param BaseMenuItemController $menuItemController;
|
||||||
|
* @throws AdminMenuItemArgInvalidException
|
||||||
|
*/
|
||||||
|
public function addItem($givenArgs, BaseMenuItemController $menuItemController = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
$args = [
|
||||||
|
'slug' => null,
|
||||||
|
'routeName' => null,
|
||||||
|
'link' => null,
|
||||||
|
'iconClass' => null,
|
||||||
|
'badge' => null,
|
||||||
|
'controller' => null,
|
||||||
|
'parentSlug' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
if($givenArgs['type'] == 'item' && $menuItemController) {
|
||||||
|
$givenArgs['slug'] = $menuItemController->getSlug();
|
||||||
|
$givenArgs['iconClass'] = $menuItemController->getIconClass();
|
||||||
|
$givenArgs['badge'] = $menuItemController->getBadge();
|
||||||
|
$givenArgs['controller'] = $menuItemController;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->validateItemArgs($givenArgs);
|
||||||
|
|
||||||
|
foreach ($givenArgs as $key => $value) {
|
||||||
|
$args = Arr::add($args, $key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(in_array($args['type'], $this->allowedItemTypes)) {
|
||||||
|
if($args['parentSlug']) {
|
||||||
|
Arr::set($this->menu, "{$args['parentSlug']}.children.{$args['slug']}", $args);
|
||||||
|
} else {
|
||||||
|
if($args['type'] == 'item') {
|
||||||
|
$this->menu[$args['slug']] = $args;
|
||||||
|
} else {
|
||||||
|
$this->menu[] = $args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得選單項目
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getMenu()
|
||||||
|
{
|
||||||
|
foreach ($this->menu as $parentSlug => $parentItem) {
|
||||||
|
if($parentItem['controller']) {
|
||||||
|
$userHasParentPermission = $parentItem['controller']->userHasPermission();
|
||||||
|
Arr::set($this->menu, "$parentSlug.userHasPermission", $userHasParentPermission);
|
||||||
|
|
||||||
|
Arr::set($this->menu, "$parentSlug.name", $parentItem['controller']->getName());
|
||||||
|
|
||||||
|
$parentRouteName = $this->adminRouteNamePrefix . $parentItem['routeName'];
|
||||||
|
$link = Route::has($parentRouteName) ? route($parentRouteName) : '#';
|
||||||
|
Arr::set($this->menu, "$parentSlug.link", $link);
|
||||||
|
|
||||||
|
if(!empty($parentItem['children'])) {
|
||||||
|
foreach ($parentItem['children'] as $childSlug => $childItem) {
|
||||||
|
if($childItem['controller']) {
|
||||||
|
Arr::set($this->menu,
|
||||||
|
"$parentSlug.children.$childSlug.userHasPermission",
|
||||||
|
$userHasParentPermission && $childItem['controller']->userHasPermission());
|
||||||
|
|
||||||
|
Arr::set($this->menu, "$parentSlug.children.$childSlug.name", $childItem['controller']->getName());
|
||||||
|
|
||||||
|
$childRouteName = $this->adminRouteNamePrefix . $childItem['routeName'];
|
||||||
|
$link = Route::has($childRouteName) ? route($childRouteName) : '#';
|
||||||
|
Arr::set($this->menu, "$parentSlug.children.$childSlug.link", $link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設定選單項目
|
||||||
|
*
|
||||||
|
* @param $menu
|
||||||
|
*/
|
||||||
|
public function setMenu($menu)
|
||||||
|
{
|
||||||
|
$this->menu = $menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,4 +6,51 @@ return [
|
|||||||
'route' => 'adm',
|
'route' => 'adm',
|
||||||
// 後台的Route Name前綴
|
// 後台的Route Name前綴
|
||||||
'route_name_prefix' => 'admin.',
|
'route_name_prefix' => 'admin.',
|
||||||
|
// 後台選單項目
|
||||||
|
'menuItems' => [
|
||||||
|
[
|
||||||
|
'type' => 'item',
|
||||||
|
'controller' => Menu\Options\OptionsMenuItemController::class,
|
||||||
|
'children' => [
|
||||||
|
Menu\Options\Children\GeneralMenuItemController::class,
|
||||||
|
Menu\Options\Children\PlatformMenuItemController::class,
|
||||||
|
Menu\Options\Children\DevelopmentMenuItemController::class,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
// 設定的項目
|
||||||
|
'options' => [
|
||||||
|
'general' => [
|
||||||
|
'permission' => 'admin manage options general',
|
||||||
|
'fields' => [
|
||||||
|
'site_name' => [
|
||||||
|
'label' => 'siteName',
|
||||||
|
'validator' => 'required',
|
||||||
|
'required' => true
|
||||||
|
],
|
||||||
|
'site_description' => [
|
||||||
|
'label' => 'siteDescription'
|
||||||
|
],
|
||||||
|
'block_search_indexing' => [
|
||||||
|
'label' => 'blockSearchEngineIndexing',
|
||||||
|
'type' => 'checkbox'
|
||||||
|
],
|
||||||
|
'google_api_key' => [
|
||||||
|
'label' => 'googleApiKey',
|
||||||
|
],
|
||||||
|
'fb_app_id' => [
|
||||||
|
'label' => 'fbAppId'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'platform' => [
|
||||||
|
'permission' => 'admin manage options platform',
|
||||||
|
'fields' => [
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'development' => [
|
||||||
|
'permission' => 'admin manage options development'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@ -177,6 +177,8 @@ return [
|
|||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
App\Providers\RouteServiceProvider::class,
|
App\Providers\RouteServiceProvider::class,
|
||||||
App\Providers\SingletonServiceProvider::class,
|
App\Providers\SingletonServiceProvider::class,
|
||||||
|
App\Providers\AdminMenuServiceProvider::class,
|
||||||
|
App\Providers\OptionRouteServiceProvider::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -10,8 +10,37 @@ return [
|
|||||||
'name' => 'admin area',
|
'name' => 'admin area',
|
||||||
'displayName' => 'adminArea',
|
'displayName' => 'adminArea',
|
||||||
'assignTo' => [
|
'assignTo' => [
|
||||||
'administrator', 'editor'
|
'editor'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
]
|
[
|
||||||
|
//檢視設定頁面
|
||||||
|
'name' => 'admin view options',
|
||||||
|
'displayName' => 'adminViewOptions',
|
||||||
|
'assignTo' => []
|
||||||
|
],
|
||||||
|
[
|
||||||
|
//管理一般設定
|
||||||
|
'name' => 'admin manage options general',
|
||||||
|
'displayName' => 'adminManageOptionsGeneral',
|
||||||
|
'assignTo' => []
|
||||||
|
],
|
||||||
|
[
|
||||||
|
//管理平台設定
|
||||||
|
'name' => 'admin manage options platform',
|
||||||
|
'displayName' => 'adminManageOptionsPlatform',
|
||||||
|
'assignTo' => []
|
||||||
|
],
|
||||||
|
[
|
||||||
|
//管理開發設定的權限
|
||||||
|
'name' => 'admin manage options development',
|
||||||
|
'displayName' => 'adminManageOptionsDevelopment',
|
||||||
|
'assignTo' => []
|
||||||
|
],
|
||||||
|
],
|
||||||
|
// 預設的設定值
|
||||||
|
'options' => [
|
||||||
|
'site_name' => config('app.name'),
|
||||||
|
'block_search_indexing' => true
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateOptionsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('options', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->string('key')->unique()->comment('選項名稱');
|
||||||
|
$table->longText('value')->comment('選項值');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('options');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,5 +12,6 @@ class DatabaseSeeder extends Seeder
|
|||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$this->call(RolesAndPermissionsSeeder::class);
|
$this->call(RolesAndPermissionsSeeder::class);
|
||||||
|
$this->call(OptionsSeeder::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
database/seeds/Preset/OptionsSeeder.php
Normal file
21
database/seeds/Preset/OptionsSeeder.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use \App\Repositories\OptionRepository;
|
||||||
|
|
||||||
|
class OptionsSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$options = config('data-presets.options');
|
||||||
|
|
||||||
|
$optionRepo = app(OptionRepository::class);
|
||||||
|
|
||||||
|
$optionRepo->setOptions($options);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
resources/lang/en/adminMenu.php
Normal file
11
resources/lang/en/adminMenu.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
return array(
|
||||||
|
'items' => [
|
||||||
|
'options' => [
|
||||||
|
'options' => 'Options',
|
||||||
|
'general' => 'General',
|
||||||
|
'development' => 'Development',
|
||||||
|
'platform' => 'Platform',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
12
resources/lang/en/adminOptionLabels.php
Normal file
12
resources/lang/en/adminOptionLabels.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'siteName' => 'Site Name',
|
||||||
|
'siteDescription' => 'Site Description',
|
||||||
|
'blockSearchEngineIndexing' => 'Block Search Engine Indexing',
|
||||||
|
'googleApiKey' => 'Google API Key',
|
||||||
|
'fbAppId' => 'Facebook APP ID',
|
||||||
|
'categoryName' => 'Category Name',
|
||||||
|
'parentCategory' => 'Parent Category',
|
||||||
|
'featureImage' => 'Feature Image',
|
||||||
|
'showInFrontSearch' => 'Show In Searchbar List',
|
||||||
|
];
|
||||||
9
resources/lang/en/adminPageHeader.php
Normal file
9
resources/lang/en/adminPageHeader.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'options' => [
|
||||||
|
'general' => 'General Settings',
|
||||||
|
'development' => 'Development Settings',
|
||||||
|
'platform' => 'Platform Settings',
|
||||||
|
],
|
||||||
|
];
|
||||||
6
resources/lang/en/form.php
Normal file
6
resources/lang/en/form.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'buttons' => [
|
||||||
|
'update' => 'Update'
|
||||||
|
]
|
||||||
|
];
|
||||||
4
resources/lang/en/message.php
Normal file
4
resources/lang/en/message.php
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'success' => 'Success'
|
||||||
|
];
|
||||||
2
resources/views/admin/components/navItems.blade.php
Normal file
2
resources/views/admin/components/navItems.blade.php
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@inject('adminMenuItemPresenter', App\Presenters\Admin\MainMenuItemPresenter)
|
||||||
|
{{ $adminMenuItemPresenter->render() }}
|
||||||
@ -1,3 +1,9 @@
|
|||||||
@extends('admin.layouts.app')
|
@extends('admin.layouts.app')
|
||||||
|
|
||||||
@section('title', 'Admin Area')
|
@section('title', 'Admin Area')
|
||||||
|
|
||||||
|
@section('admin-page-content')
|
||||||
|
<pre>
|
||||||
|
{{ print_r(app('AdminMenu')->getMenu()) }}
|
||||||
|
</pre>
|
||||||
|
@endsection
|
||||||
|
|||||||
@ -51,6 +51,7 @@
|
|||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
|
@include('admin.components.navItems')
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<button class="sidebar-minimizer brand-minimizer" type="button"></button>
|
<button class="sidebar-minimizer brand-minimizer" type="button"></button>
|
||||||
|
|||||||
3
resources/views/admin/menu/options/development.blade.php
Normal file
3
resources/views/admin/menu/options/development.blade.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@include('admin.menu.options.layout', [
|
||||||
|
'slug' => 'development'
|
||||||
|
])
|
||||||
3
resources/views/admin/menu/options/general.blade.php
Normal file
3
resources/views/admin/menu/options/general.blade.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@include('admin.menu.options.layout', [
|
||||||
|
'slug' => 'general'
|
||||||
|
])
|
||||||
37
resources/views/admin/menu/options/layout.blade.php
Normal file
37
resources/views/admin/menu/options/layout.blade.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
@extends('admin.layouts.app')
|
||||||
|
@section('admin-page-content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<h1>@lang('adminPageHeader.options.' . $slug)</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if($errors->any())
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{!! app('Html')->bs()->alert($errors->first(), 'danger') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if(session()->has('updated'))
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{!! app('Html')->bs()->alert(session()->get('updated'), 'success') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<form action="{{ route('admin.options.' . $slug . '.update') }}" method="post">
|
||||||
|
@method('put')
|
||||||
|
@csrf
|
||||||
|
@inject('html', \App\Presenters\Admin\OptionFormFieldsPresenter)
|
||||||
|
{!! $html->render($slug) !!}
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col">
|
||||||
|
<button type="submit" class="btn btn-primary">@lang('form.buttons.update')</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
3
resources/views/admin/menu/options/platform.blade.php
Normal file
3
resources/views/admin/menu/options/platform.blade.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@include('admin.menu.options.layout', [
|
||||||
|
'slug' => 'platform'
|
||||||
|
])
|
||||||
Loading…
Reference in New Issue
Block a user