Skip to content

开发规范

版权声明

所有 PHP 文件必须包含标准版权头:

php
<?php
/**
 * Copyright (c) Since 2024 InnoShop - All Rights Reserved
 *
 * @link       https://www.innoshop.com
 * @author     InnoShop <team@innoshop.com>
 * @license    https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
 */

命名规范

目录与文件命名

类型规则示例
模块目录大驼峰 (PascalCase)Common/, FrontEnd/
控制器文件大驼峰 + ControllerProductController.php
模型文件大驼峰Product.php
视图目录小写front/, panel/
语言文件小写 + 下划线common.php, front.php
路由文件小写 + 下划线front.php, panel-api.php
配置文件小写 + 下划线config.json

命名空间

  • 后台相关:使用 Panel 命名空间
  • 前台相关:使用 Front 命名空间
  • 视图目录:panel/front/
  • 路由前缀:panel.front.

类与方法命名

php
// 控制器:大驼峰 + Controller
ProductController.php

// 模型:大驼峰
Product.php

// 方法命名
public function index()      // 列表页
public function show()       // 详情页
public function store()      // 保存
public function update()     // 更新
public function destroy()    // 删除

变量命名

php
// 模型变量:小驼峰
$product = Product::find(1);
$orderItem = OrderItem::first();

// 集合变量:复数形式
$products = Product::all();
$orderItems = OrderItem::get();

// 布尔变量:is/has/should 前缀
$isActive = true;
$hasStock = true;

路由使用

php
// 正确
front_route('product.index')   // 前台路由
panel_route('product.index')   // 后台路由

// 错误
route('product.index')         // 禁止使用

视图规范

布局继承

blade
{{-- 正确 --}}
@extends('panel::layouts.app')

{{-- 错误 --}}
@extends('admin::layouts.app')

缩进规范

Blade 文件必须使用两个空格缩进。项目根目录的 .editorconfig 文件已配置 [*.blade.php] 使用两个空格缩进。

blade
{{-- 正确 ✅ --}}
@section('content')
  <div class="container">
    <div class="row">
      @if($condition)
        <p>内容</p>
      @endif
    </div>
  </div>
@endsection

{{-- 错误 ❌ — 四个空格 --}}
@section('content')
    <div class="container">
        <p>内容</p>
    </div>
@endsection

空数据展示

blade
<x-common-no-data />

JavaScript 规范

代码位置

必须使用 @push('footer') 而不是 @push('scripts')

blade
{{-- 正确 --}}
@push('footer')
<script>
$(document).ready(function() {
    console.log('jQuery 正常工作');
});
</script>
@endpush

{{-- 错误 — 这样不会生效 --}}
@push('scripts')
<script>
// InnoShop 使用 @stack('footer') 渲染 JS
</script>
@endpush

Panel Axios 注意事项

后台(Panel)的 axios 经过拦截器处理,响应已被自动解包一层then 回调中 res 直接就是后端返回的 JSON 对象,不需要 再通过 res.data 访问。

javascript
// 错误 — 多了一层 .data
axios.post(url, params).then(function (res) {
    if (res.data && res.data.success) { ... }
});

// 正确 — res 已经是 response.data
axios.post(url, params).then(function (res) {
    if (res && res.success) { ... }
});

catch 中的 error 没有被解包

catch 中的 error 仍然是原始的 axios error 对象,需要通过 error.response.data 获取错误信息。

JavaScript 多语言

javascript
<script>
window.translations = {
    system: {
        submit: "{{ trans('common/button_submit') }}",
        cancel: "{{ trans('common/button_cancel') }}"
    },
    plugin: {
        save: "{{ trans('PluginName::common/message_save_success') }}"
    }
};
</script>

MVC 开发规范

控制器

php
class ProductController extends Controller
{
    public function store(ProductRequest $request): mixed
    {
        try {
            $product = $this->productService->create($request->validated());

            if ($request->ajax()) {
                return json_success('保存成功', $product);
            }

            return redirect()->panel_route('product.index')
                ->with('success', '保存成功');

        } catch (Throwable $e) {
            // 错误处理...
        }
    }
}

模型

php
class Product extends Model
{
    protected $fillable = ['name', 'price'];

    protected $casts = [
        'price' => 'decimal:2',
        'active' => 'boolean',
    ];
}

仓储层

php
class ProductRepo extends BaseRepo
{
    protected string $model = Product::class;

    public function builder(array $filters = []): Builder
    {
        $builder = $this->modelQuery();
        // 查询条件...
        return $builder;
    }
}

错误处理规范

控制器错误处理

  • 在 action 方法中使用 try-catch 包装服务实例化
  • 使用 session()->flash('error', $e->getMessage()) 显示错误
  • 始终返回视图,不要重定向到错误页面
php
public function index()
{
    try {
        $service = new PluginService;
        $data = $service->getData();

        return view('PluginName::index', compact('data'));
    } catch (Exception $e) {
        session()->flash('error', $e->getMessage());
        return view('PluginName::index', ['data' => collect()]);
    }
}

服务层错误处理

  • 服务类可以直接抛出异常
  • 使用具体的异常类型
  • 提供有意义的错误消息

最佳实践

  1. 使用 Service 层处理业务逻辑
  2. 使用 Repository 模式处理数据访问
  3. 使用 FormRequest 进行请求验证
  4. 保持 Controller 轻量,只负责请求处理
  5. 合理使用 Hook 机制扩展功能
  6. 遵循 Laravel 最佳实践
  7. 保持代码简洁和可维护性

帆连科技 · 基于 OSL 3.0 许可发布