wyyl/beike/Plugin/Plugin.php

362 lines
8.3 KiB
PHP

<?php
/**
* Plugin.php
*
* @copyright 2022 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2022-06-29 20:27:21
* @modified 2022-06-29 20:27:21
*/
namespace Beike\Plugin;
use Beike\Repositories\PluginRepo;
use Beike\Repositories\SettingRepo;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class Plugin implements Arrayable, \ArrayAccess
{
public const TYPES = [
'payment', // 支付方式
'shipping', // 配送方式
'theme', // 主题模板
'feature', // 功能模块
'total', // 订单金额
'social', // 社交网络
'language', // 语言翻译
];
protected $type;
protected $path;
protected $name;
protected $description;
protected $packageInfo;
protected $dirName;
protected $installed;
protected $enabled;
protected $version;
protected $columns;
public function __construct(string $path, array $packageInfo)
{
$this->path = $path;
$this->packageInfo = $packageInfo;
}
public function __get($name)
{
return $this->packageInfoAttribute(Str::snake($name, '-'));
}
public function __isset($name)
{
return isset($this->{$name}) || $this->packageInfoAttribute(Str::snake($name, '-'));
}
public function packageInfoAttribute($name)
{
return Arr::get($this->packageInfo, $name);
}
/**
* Set plugin Type
*
* @throws \Exception
*/
public function setType(string $type): self
{
if (! in_array($type, self::TYPES)) {
throw new \Exception('Invalid plugin type, must be one of ' . implode(',', self::TYPES));
}
$this->type = $type;
return $this;
}
public function setDirname(string $dirName): self
{
$this->dirName = $dirName;
return $this;
}
public function setName(string|array $name): self
{
$this->name = $name;
return $this;
}
public function setDescription(string|array $description): self
{
$this->description = $description;
return $this;
}
public function setInstalled(bool $installed): self
{
$this->installed = $installed;
return $this;
}
public function setEnabled(bool $enabled): self
{
$this->enabled = $enabled;
return $this;
}
public function setVersion(string $version): self
{
$this->version = $version;
return $this;
}
public function setColumns(): self
{
$columnsPath = $this->path . DIRECTORY_SEPARATOR . 'columns.php';
if (! file_exists($columnsPath)) {
return $this;
}
$this->columns = require_once $columnsPath;
return $this;
}
/**
* 处理插件后台设置字段多语言 优先级: label > label_key
* 有label字段则直接返回, label_key 则翻译
*/
public function handleLabel()
{
$this->columns = collect($this->columns)->map(function ($item) {
$item = $this->transLabel($item);
if (isset($item['options'])) {
$item['options'] = collect($item['options'])->map(function ($option) {
return $this->transLabel($option);
})->toArray();
}
return $item;
})->toArray();
}
/**
* 翻译 label
* @param $item
* @return mixed
*/
private function transLabel($item)
{
$labelKey = $item['label_key'] ?? '';
$label = $item['label'] ?? '';
if (empty($label) && $labelKey) {
$languageKey = "{$this->dirName}::{$labelKey}";
$item['label'] = trans($languageKey);
}
$descriptionKey = $item['description_key'] ?? '';
$description = $item['description'] ?? '';
if (empty($description) && $descriptionKey) {
$languageKey = "{$this->dirName}::{$descriptionKey}";
$item['description'] = trans($languageKey);
}
return $item;
}
public function getName()
{
return $this->name;
}
public function getLocaleName(): string
{
$currentLocale = admin_locale();
if (is_array($this->name)) {
if ($this->name[$currentLocale] ?? '') {
return $this->name[$currentLocale];
}
return array_values($this->name)[0];
}
return (string) $this->name;
}
public function getDescription()
{
return $this->description;
}
public function getLocaleDescription(): string
{
$currentLocale = admin_locale();
if (is_array($this->description)) {
if ($this->description[$currentLocale] ?? '') {
return $this->description[$currentLocale];
}
return array_values($this->description)[0];
}
return (string) $this->description;
}
public function getType(): string
{
return $this->type;
}
public function getDirname(): string
{
return $this->dirName;
}
public function getPath(): string
{
return $this->path;
}
public function getVersion(): string
{
return $this->version;
}
public function getEditUrl(): string
{
return admin_route('plugins.edit', ['code' => $this->code]);
}
public function getStatus(): bool
{
return SettingRepo::getPluginStatus($this->code);
}
public function getInstalled(): bool
{
return PluginRepo::installed($this->code);
}
public function getEnabled(): bool
{
return $this->enabled;
}
public function getSetting($name = '')
{
if ($name) {
return plugin_setting("{$this->code}.{$name}");
}
return plugin_setting($this->code);
}
/**
* 获取插件对应的设置字段, 并获取已存储在DB的字段值
*
* @return array
*/
public function getColumns(): array
{
$this->columns[] = SettingRepo::getPluginStatusColumn();
$existValues = SettingRepo::getPluginColumns($this->code);
foreach ($this->columns as $index => $column) {
$dbColumn = $existValues[$column['name']] ?? null;
$value = $dbColumn ? $dbColumn->value : null;
if ($column['name'] == 'status') {
$value = (int) $value;
}
$this->columns[$index]['value'] = $value;
}
return $this->columns;
}
/**
* 字段验证
* @param $requestData
* @return \Illuminate\Contracts\Validation\Validator
*/
public function validate($requestData): \Illuminate\Contracts\Validation\Validator
{
$rules = array_column($this->columns, 'rules', 'name');
return Validator::make($requestData, $rules);
}
/**
* 获取插件自定义编辑模板
* @return string
*/
public function getColumnView(): string
{
$viewFile = $this->getPath() . '/Views/admin/config.blade.php';
if (file_exists($viewFile)) {
return "{$this->dirName}::admin.config";
}
return '';
}
/**
* 获取插件启动文件路径
*
* @return string
*/
public function getBootFile(): string
{
return $this->getPath() . '/Bootstrap.php';
}
public function toArray(): array
{
return (array) array_merge([
'name' => $this->name,
'version' => $this->getVersion(),
'path' => $this->path,
], $this->packageInfo);
}
public function offsetExists($key): bool
{
return Arr::has($this->packageInfo, $key);
}
#[\ReturnTypeWillChange]
public function offsetGet($key)
{
return $this->packageInfoAttribute($key);
}
#[\ReturnTypeWillChange]
public function offsetSet($key, $value)
{
return Arr::set($this->packageInfo, $key, $value);
}
#[\ReturnTypeWillChange]
public function offsetUnset($key)
{
unset($this->packageInfo[$key]);
}
}