* @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]); } }