1
This commit is contained in:
@@ -0,0 +1,599 @@
|
||||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** 2026-04-21
|
||||
|
||||
## Naming Patterns
|
||||
|
||||
**Files:**
|
||||
- Controllers: PascalCase, directory structure mirrors URL path. Example: `application/admin/controller/user/User.php` -> `/admin/user/user`
|
||||
- Models: PascalCase in parallel directory structure. Example: `application/admin/model/User.php`
|
||||
- Validates: PascalCase. Example: `application/admin/validate/User.php`
|
||||
- Libraries: PascalCase. Example: `application/admin/library/Auth.php`, `application/common/library/Upload.php`
|
||||
- Traits: PascalCase. Example: `application/admin/library/traits/Backend.php`
|
||||
- Behaviors: PascalCase. Example: `application/admin/behavior/AdminLog.php`
|
||||
- Language files: lowercase `zh-cn.php`, mirroring controller directory structure
|
||||
- View templates: lowercase `.html`, matching action names. Example: `application/admin/view/user/user/index.html`
|
||||
- JS files: lowercase, mirroring controller path. Example: `public/assets/js/backend/user/user.js`
|
||||
- CSS: lowercase `.css` with `.min.css` variants
|
||||
- Less: lowercase `.less` (source files in `public/assets/less/`)
|
||||
- Common helper functions: snake_case. Example: `build_select()`, `cdnurl()`, `datetime()`, `letter_avatar()`
|
||||
|
||||
**Functions/Methods:**
|
||||
- Controller action methods: lowercase with underscores. Examples: `index()`, `add()`, `edit()`, `del()`, `recyclebin()`, `get_field_list()`, `get_controller_list()`
|
||||
- Controller protected methods: camelCase. Examples: `buildparams()`, `selectpage()`, `getDataLimitAdminIds()`, `loadlang()`, `assignconfig()`
|
||||
- Model accessors/mutators: ThinkPHP convention `get{FieldName}Attr()` / `set{FieldName}Attr()`. Example: `getPrevtimeTextAttr()`, `setJointimeAttr()`, `getAvatarAttr()`, `setBirthdayAttr()`
|
||||
- Model list methods: PascalCase `getStatusList()`, `getGenderList()`
|
||||
- Model static methods: camelCase. Example: `User::money()`, `User::score()`, `User::nextlevel()`
|
||||
- Library methods: camelCase. Example: `Auth::login()`, `Auth::getUserinfo()`, `Upload::init()`
|
||||
- Global functions: snake_case, wrapped in `if (!function_exists('...'))`. Example: `__()`, `format_bytes()`, `check_cors_request()`, `xss_clean()`
|
||||
- Addon methods: camelCase following ThinkPHP convention
|
||||
|
||||
**Variables:**
|
||||
- Controller properties: camelCase. Examples: `$noNeedLogin`, `$model`, `$searchFields`, `$relationSearch`, `$dataLimit`
|
||||
- Library private properties: underscore prefix + camelCase. Examples: `$_error`, `$_logined`, `$_user`, `$_token` (in `application/common/library/Auth.php`)
|
||||
- Library protected properties: camelCase, no prefix. Examples: `$keeptime`, `$requestUri`, `$allowFields`
|
||||
- Local variables: camelCase. Examples: `$tableList`, `$fieldlist`, `$insert_data`, `$changedata`
|
||||
- Database fields: lowercase with underscores. Examples: `createtime`, `updatetime`, `group_id`, `loginip`
|
||||
- Request input: via `$this->request->post('row/a')` (array), `$this->request->request('keyField')` (single)
|
||||
|
||||
**Types/Namespaces:**
|
||||
- Namespace convention: lowercase `app\admin\controller`, `app\common\model`, `app\api\library`
|
||||
- Class names: PascalCase. Example: `class User extends Backend`
|
||||
- Addon namespace: `addons\{name}\` mapped via PSR-4 in `composer.json`
|
||||
- Fast tools namespace: `fast\` maps to `extend/fast/` directory
|
||||
|
||||
## Code Style
|
||||
|
||||
**Formatting:**
|
||||
- 4-space indentation throughout (no tabs)
|
||||
- Opening brace on same line for classes/functions: `class User extends Backend\n{`
|
||||
- Opening brace on next line for control structures in some files, same line in others (inconsistent)
|
||||
- Closing PHP tag `?>` omitted at end of files
|
||||
- Files start with `<?php` followed by a blank line
|
||||
- Blank line after namespace declaration
|
||||
- Blank line after last `use` statement before class declaration
|
||||
|
||||
**PHP Version:** PHP >= 7.4.0 (per `composer.json`)
|
||||
- Union types in catch blocks: `catch (ValidateException|PDOException|Exception $e)`
|
||||
- Null coalescing: `$value ?? ''`
|
||||
- Match expressions: Not used
|
||||
- Arrow functions: Not used
|
||||
- Typed properties: Not used
|
||||
|
||||
**Linting/Formatting Tools:**
|
||||
- No project-level `.php-cs-fixer.php`, `phpcs.xml`, `.editorconfig`, or `biome.json`
|
||||
- No ESLint or stylelint configured
|
||||
- PhpStorm `.idea/` directory present with PHP 7.4 language level configured
|
||||
- Static analysis tools (PHPStan, PHPCS, MessDetector) configured in IDE but not activated (`transferred=true`)
|
||||
|
||||
## Import Organization
|
||||
|
||||
**Order in PHP files:**
|
||||
1. `namespace app\admin\controller;`
|
||||
2. `use` statements for app classes: `use app\common\controller\Backend;`
|
||||
3. `use` statements for ThinkPHP classes: `use think\Db;`, `use think\Config;`, `use think\Exception;`
|
||||
4. `use` statements for vendor/third-party classes: `use fast\Tree;`
|
||||
5. No grouping separators between use statement categories
|
||||
|
||||
**Example from `application/admin/controller/user/User.php`:**
|
||||
```php
|
||||
namespace app\admin\controller\user;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
use app\common\library\Auth;
|
||||
```
|
||||
|
||||
**Example from `application/common/controller/Backend.php`:**
|
||||
```php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\admin\library\Auth;
|
||||
use think\Config;
|
||||
use think\Controller;
|
||||
use think\Hook;
|
||||
use think\Lang;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
use think\Session;
|
||||
use fast\Tree;
|
||||
use think\Validate;
|
||||
```
|
||||
|
||||
**Path Aliases:**
|
||||
- No PSR-4 path aliases configured beyond `addons\\` -> `addons/` in `composer.json`
|
||||
- ThinkPHP autoload handles `app\` namespace mapping automatically
|
||||
- `fast\` namespace handled by ThinkPHP custom autoloader -> `extend/fast/`
|
||||
|
||||
## ThinkPHP Conventions
|
||||
|
||||
**Model Table Naming:**
|
||||
- `$name` property defines the table name without prefix. Example: `protected $name = 'user';` maps to `{prefix}user`
|
||||
- Table prefix configured in `application/config.php` database section
|
||||
- All models extend `think\Model`
|
||||
|
||||
**Timestamp Convention:**
|
||||
- Auto timestamp type: `protected $autoWriteTimestamp = 'int';` (Unix integer timestamps)
|
||||
- Create field name: `protected $createTime = 'createtime';`
|
||||
- Update field name: `protected $updateTime = 'updatetime';`
|
||||
|
||||
**Controller Initialization:**
|
||||
- `_initialize()` method called by ThinkPHP before each action
|
||||
- Always calls `parent::_initialize()` first
|
||||
- Sets `$this->model` instance in `_initialize()`
|
||||
- Assigns view data: `$this->view->assign("statusList", ...)`
|
||||
|
||||
**Magic Model Methods:**
|
||||
- Dynamic finders via `@method` PHPDoc annotations
|
||||
- `getBy{Field}()` auto-generated by ThinkPHP for any column
|
||||
- Example: `@method static mixed getByUsername($str)` in `application/common/model/User.php`
|
||||
- Usage: `\app\common\model\User::getByMobile($mobile)`
|
||||
|
||||
**AJAX Detection Pattern:**
|
||||
```php
|
||||
if ($this->request->isAjax()) {
|
||||
// Return JSON response
|
||||
return json(['total' => $list->total(), 'rows' => $list->items()]);
|
||||
}
|
||||
return $this->view->fetch();
|
||||
```
|
||||
|
||||
## FastAdmin Patterns
|
||||
|
||||
**Backend Base Class (`app\common\controller\Backend`):**
|
||||
- All admin controllers extend this class
|
||||
- Provides via trait `app\admin\library\traits\Backend`:
|
||||
- `index()` - List with pagination and filtering
|
||||
- `add()` - Create record
|
||||
- `edit($ids)` - Update record
|
||||
- `del($ids)` - Soft delete
|
||||
- `destroy($ids)` - Hard delete (from recycle bin)
|
||||
- `restore($ids)` - Restore from recycle bin
|
||||
- `multi($ids)` - Batch update
|
||||
- `recyclebin()` - Recycle bin list
|
||||
- `import()` - Excel/CSV import
|
||||
- `selectpage()` - SelectPage dropdown data
|
||||
- Key configurable properties:
|
||||
- `$noNeedLogin = []` - Methods skipping authentication entirely
|
||||
- `$noNeedRight = []` - Methods skipping permission check (still need login)
|
||||
- `$model = null` - Associated model instance
|
||||
- `$searchFields = 'id'` - Fields for quick search
|
||||
- `$relationSearch = false` - Whether to use table alias in queries
|
||||
- `$dataLimit = false` - Data scope: `auth`/`personal`/`false`
|
||||
- `$dataLimitField = 'admin_id'` - Field for data restriction
|
||||
- `$dataLimitFieldAutoFill = true` - Auto-fill restriction field
|
||||
- `$modelValidate = false` - Enable model-level validation
|
||||
- `$modelSceneValidate = false` - Enable scene-based validation
|
||||
- `$multiFields = 'status'` - Fields allowed in batch operations
|
||||
- `$selectpageFields = '*'` - Fields shown in SelectPage
|
||||
- `$excludeFields = ""` - Fields to exclude from form submission
|
||||
- `$importHeadType = 'comment'` - Import header type: `comment`/`name`
|
||||
- `$layout = 'default'` - Template layout name
|
||||
|
||||
**Standard CRUD Controller Pattern:**
|
||||
```php
|
||||
/**
|
||||
* 会员管理
|
||||
*
|
||||
* @icon fa fa-user
|
||||
*/
|
||||
class User extends Backend
|
||||
{
|
||||
protected $relationSearch = true;
|
||||
protected $searchFields = 'id,username,nickname';
|
||||
|
||||
/**
|
||||
* @var \app\admin\model\User
|
||||
*/
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = new \app\admin\model\User;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**CRUD Generation:**
|
||||
- Via `php think crud` command
|
||||
- Flags: `--table`, `--controller`, `--model`, `--fields`, `--force`, `--delete`, `--menu`
|
||||
- Extended flags: `--setcheckboxsuffix`, `--enumradiosuffix`, `--imagefield`, `--filefield`, etc.
|
||||
|
||||
**Auth Patterns:**
|
||||
- Admin auth: `app\admin\library\Auth` - backend admin user authentication
|
||||
- User auth: `app\common\library\Auth` - frontend/member user authentication
|
||||
- Both use singleton: `Auth::instance()`
|
||||
- Permission check: `$this->auth->check($path)` where `$path = 'controller/action'`
|
||||
- Login check: `$this->auth->isLogin()`
|
||||
- Super admin check: `$this->auth->isSuperAdmin()`
|
||||
|
||||
**API Controller Pattern (`app\common\controller\Api`):**
|
||||
- API controllers extend this (NOT `think\Controller`)
|
||||
- Does NOT extend `think\Controller` - standalone class with `__construct()`
|
||||
- Response format: `{'code': 1|0, 'msg': '', 'time': <timestamp>, 'data': ...}`
|
||||
- Success: `$this->success($msg, $data)` (code=1, HTTP 200)
|
||||
- Error: `$this->error($msg, $data, $httpCode)` (code=0)
|
||||
- HTTP status codes: 401 for unauth, 403 for forbidden
|
||||
- API annotations for doc generation: `@ApiMethod(POST)`, `@ApiParams(name="...", type="string", required=true, description="...")`
|
||||
- Default request filter: `trim,strip_tags,htmlspecialchars`
|
||||
|
||||
**Frontend Controller Pattern (`app\common\controller\Frontend`):**
|
||||
- Index module controllers extend this
|
||||
- Similar to Backend but for public-facing pages
|
||||
- Uses `app\common\library\Auth` for member auth
|
||||
- Layout can be empty string for no layout: `protected $layout = '';`
|
||||
|
||||
## Language File Structure
|
||||
|
||||
**Directory Layout:**
|
||||
```
|
||||
application/{module}/lang/zh-cn.php # Module-level translations
|
||||
application/{module}/lang/zh-cn/controller.php # Controller translations
|
||||
application/{module}/lang/zh-cn/sub/controller.php # Nested controller translations
|
||||
application/{module}/lang/{locale}/controller.php # Other locales
|
||||
```
|
||||
|
||||
**Observed locales:**
|
||||
- `zh-cn` (Simplified Chinese) - primary language for all modules
|
||||
- `en` - only exists for `application/index/lang/en/index.php`
|
||||
|
||||
**File Format:**
|
||||
```php
|
||||
return [
|
||||
'Id' => 'ID',
|
||||
'Group_id' => '组别ID',
|
||||
'Username' => '用户名',
|
||||
'Leave password blank if dont want to change' => '不修改密码请留空',
|
||||
];
|
||||
```
|
||||
|
||||
**Usage Pattern:**
|
||||
- `__('Key')` - Simple translation
|
||||
- `__('Key %s', $value)` - Parameterized translation
|
||||
- Keys use PascalCase for field names (matching DB column names)
|
||||
- Keys use sentence case for messages
|
||||
- Language auto-loaded by controller in `loadlang()` method
|
||||
- Language detection: `$this->request->langset()` with regex validation, defaults to `zh-cn`
|
||||
|
||||
## Template Syntax
|
||||
|
||||
**Template Engine:** ThinkPHP built-in template engine
|
||||
**File Extension:** `.html`
|
||||
|
||||
**Template Tags Used:**
|
||||
|
||||
| Tag | Example |
|
||||
|-----|---------|
|
||||
| Output | `{$variable}`, `{$var\|htmlentities}`, `{$var\|default='default'}` |
|
||||
| Function | `{:__('Dashboard')}`, `{:build_heading()}`, `{:build_toolbar('refresh,edit,del')}` |
|
||||
| Condition | `{if condition="$auth->check('dashboard')"}`, `{if !IS_DIALOG}`, `{/if}` |
|
||||
| If-else shorthand | `{:defined('IS_DIALOG') && IS_DIALOG ? 'is-dialog' : ''}` |
|
||||
| Loop | `{foreach $breadcrumb as $vo}`, `{/foreach}` |
|
||||
| Include | `{include file="common/meta" /}` |
|
||||
| Layout placeholder | `{__CONTENT__}` |
|
||||
| ThinkPHP config | `{$Think.config.fastadmin.breadcrumb}` |
|
||||
| Inline PHP | `{:$auth->check('user/user/multi')?'':'hide'}` |
|
||||
|
||||
**Layout Structure:**
|
||||
```
|
||||
application/{module}/view/layout/default.html # Layout wrapper with {__CONTENT__}
|
||||
application/{module}/view/{controller}/index.html # Page content
|
||||
application/{module}/view/common/meta.html # Shared <head> section
|
||||
application/{module}/view/common/script.html # Shared JS loading
|
||||
application/{module}/view/common/header.html # Header fragment
|
||||
application/{module}/view/common/menu.html # Sidebar menu
|
||||
application/{module}/view/common/control.html # Control bar fragment
|
||||
```
|
||||
|
||||
**CSS Framework:** Bootstrap 3 with AdminLTE theme
|
||||
**Common Classes:**
|
||||
- Layout: `.panel`, `.panel-default`, `.panel-intro`, `.panel-heading`, `.panel-body`
|
||||
- Table: `.table`, `.table-striped`, `.table-bordered`, `.table-hover`, `.table-nowrap`
|
||||
- Buttons: `.btn`, `.btn-primary`, `.btn-success`, `.btn-danger`, `.btn-info`, `.btn-xs`
|
||||
- Form: `.form-control`, `.selectpicker`, `.form-group`, `.control-label`
|
||||
- FastAdmin custom: `.btn-dialog`, `.btn-addtabs`, `.btn-ajax`, `.btn-click`, `.searchit`
|
||||
|
||||
## JS AMD Module Pattern (RequireJS)
|
||||
|
||||
**Module Definition Pattern:**
|
||||
```javascript
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
var Controller = {
|
||||
index: function () {
|
||||
Table.api.init({
|
||||
extend: {
|
||||
index_url: 'user/user/index',
|
||||
add_url: 'user/user/add',
|
||||
edit_url: 'user/user/edit',
|
||||
del_url: 'user/user/del',
|
||||
multi_url: 'user/user/multi',
|
||||
table: 'user',
|
||||
}
|
||||
});
|
||||
var table = $("#table");
|
||||
table.bootstrapTable({
|
||||
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||
pk: 'id',
|
||||
sortName: 'user.id',
|
||||
columns: [[
|
||||
{checkbox: true},
|
||||
{field: 'id', title: __('Id'), sortable: true},
|
||||
{field: 'operate', title: __('Operate'), table: table,
|
||||
events: Table.api.events.operate,
|
||||
formatter: Table.api.formatter.operate}
|
||||
]]
|
||||
});
|
||||
Table.api.bindevent(table);
|
||||
},
|
||||
add: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
edit: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
api: {
|
||||
bindevent: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
}
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
```
|
||||
|
||||
**RequireJS Configuration Files:**
|
||||
- `public/assets/js/require-backend.js` - Backend module config (minified as `require-backend.min.js`)
|
||||
- `public/assets/js/require-frontend.js` - Frontend module config (minified)
|
||||
- `public/assets/js/require-table.js` - Bootstrap-table wrapper module
|
||||
- `public/assets/js/require-form.js` - Form handling module
|
||||
- `public/assets/js/require-upload.js` - Upload module
|
||||
|
||||
**Core JS Modules:**
|
||||
- `Fast` / `Fast.api` - Core API: `ajax()`, `open()`, `cdnurl()`, `fixurl()`, `selectedids()`
|
||||
- `Backend` - Admin: sidebar badges, tab management, dialog/_ajax handlers
|
||||
- `Frontend` - Frontend: captcha sending, touch swipe for sidebar
|
||||
- `Table` - Bootstrap-table wrapper: `api.init()`, `api.bindevent()`, formatters, events
|
||||
- `Form` - Form validation and submission: `api.bindevent()`
|
||||
- `Template` - art-template JS template engine
|
||||
- `Moment` - Date/time formatting (with `moment/locale/zh-cn`)
|
||||
|
||||
**Global Objects (set on `window`):**
|
||||
- `window.Backend` - Backend namespace
|
||||
- `window.Frontend` - Frontend namespace
|
||||
- `window.Config` - Server-rendered config object
|
||||
- `window.Toastr` - Toastr notification library
|
||||
- `window.Layer` - Layer popup library (layui-based)
|
||||
- `window.Table` - (via require) Table module
|
||||
- `window.Form` - (via require) Form module
|
||||
- `window.Template` - Template engine
|
||||
- `window.Moment` - Moment.js
|
||||
|
||||
**Controller JS File Convention:**
|
||||
- Location: `public/assets/js/backend/{controller_path}.js`
|
||||
- Standard methods: `Controller.index()`, `Controller.add()`, `Controller.edit()`
|
||||
- Sub-controller: `public/assets/js/backend/auth/admin.js`
|
||||
- Each controller JS is loaded dynamically based on `Config.jsname`
|
||||
|
||||
**Button/Action Patterns in JS:**
|
||||
- `.btn-dialog` / `.dialogit` - Opens URL in Layer dialog
|
||||
- `.btn-addtabs` / `.addtabsit` - Opens URL in new tab
|
||||
- `.btn-ajax` / `.ajaxit` - Sends AJAX request
|
||||
- `.btn-click` / `.clickit` - Custom click handler
|
||||
- `.searchit` - Triggers table search with field/value
|
||||
|
||||
**Table Formatter Patterns:**
|
||||
- `Table.api.formatter.image` / `.images` - Image display
|
||||
- `Table.api.formatter.datetime` - Date formatting
|
||||
- `Table.api.formatter.status` - Status badge
|
||||
- `Table.api.formatter.normal` - Generic label with color
|
||||
- `Table.api.formatter.search` - Clickable search link
|
||||
- `Table.api.formatter.operate` - Action buttons (edit/del)
|
||||
- `Table.api.formatter.toggle` - Toggle switch
|
||||
- `Table.api.formatter.flag` / `.label` - Multi-value flags
|
||||
|
||||
## CSS Class Naming
|
||||
|
||||
**Convention:** Bootstrap 3 + AdminLTE + FastAdmin extensions
|
||||
**CSS Source:** Less files compiled to CSS
|
||||
- `public/assets/less/backend.less` -> `public/assets/css/backend.css`
|
||||
- `public/assets/less/frontend.less` -> `public/assets/css/frontend.css`
|
||||
- `public/assets/less/bootstrap.less` -> `public/assets/css/bootstrap.css`
|
||||
- `public/assets/css/fastadmin.css` - FastAdmin base overrides
|
||||
- `public/assets/css/index.css` - Index page styles
|
||||
- `public/assets/css/user.css` - User center styles
|
||||
|
||||
**Common Panel Pattern:**
|
||||
```html
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
<div class="panel-body">
|
||||
<div id="toolbar" class="toolbar">
|
||||
{:build_toolbar('refresh,edit,del')}
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
|
||||
data-operate-edit="{:$auth->check('user/user/edit')}"
|
||||
data-operate-del="{:$auth->check('user/user/del')}"
|
||||
width="100%">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Controller Layer:**
|
||||
- `$this->error($message)` - Returns error, terminates execution
|
||||
- `$this->success($message, $data)` - Returns success response
|
||||
- Backend: throws `HttpResponseException` internally
|
||||
- API: sets HTTP status codes (401/403) via header
|
||||
|
||||
**Transaction Pattern:**
|
||||
```php
|
||||
Db::startTrans();
|
||||
try {
|
||||
// database operations
|
||||
Db::commit();
|
||||
} catch (ValidateException|PDOException|Exception $e) {
|
||||
Db::rollback();
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
if ($result === false) {
|
||||
$this->error(__('No rows were inserted'));
|
||||
}
|
||||
$this->success();
|
||||
```
|
||||
|
||||
**Model Event Hooks:**
|
||||
```php
|
||||
protected static function init()
|
||||
{
|
||||
self::beforeWrite(function ($row) {
|
||||
$changed = $row->getChangedData();
|
||||
if (isset($changed['password'])) {
|
||||
$salt = \fast\Random::alnum();
|
||||
$row->password = \app\common\library\Auth::instance()->getEncryptPassword($changed['password'], $salt);
|
||||
$row->salt = $salt;
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
**Framework:** ThinkPHP built-in logging
|
||||
- Configurable driver (file, etc.) in `application/config.php`
|
||||
- Custom log library: `application/common/library/Log.php`
|
||||
- Admin log behavior: `application/admin/behavior/AdminLog.php` - auto-logs admin actions to database
|
||||
|
||||
## Comments
|
||||
|
||||
**JSDoc/TSDoc Pattern:**
|
||||
- All public/protected methods have PHPDoc with Chinese descriptions
|
||||
- Controller methods: brief action description
|
||||
- API methods: `@ApiMethod` + `@ApiParams` annotations for API doc generation
|
||||
|
||||
**Controller Class Doc:**
|
||||
```php
|
||||
/**
|
||||
* 会员管理
|
||||
*
|
||||
* @icon fa fa-user
|
||||
*/
|
||||
class User extends Backend
|
||||
```
|
||||
|
||||
**Method Doc:**
|
||||
```php
|
||||
/**
|
||||
* 会员登录
|
||||
*
|
||||
* @ApiMethod (POST)
|
||||
* @ApiParams (name="account", type="string", required=true, description="账号")
|
||||
* @ApiParams (name="password", type="string", required=true, description="密码")
|
||||
*/
|
||||
public function login()
|
||||
```
|
||||
|
||||
**Model Doc:**
|
||||
```php
|
||||
/**
|
||||
* 会员模型
|
||||
* @method static mixed getByUsername($str) 通过用户名查询用户
|
||||
* @method static mixed getByNickname($str) 通过昵称查询用户
|
||||
*/
|
||||
class User extends Model
|
||||
```
|
||||
|
||||
**Function Doc:**
|
||||
```php
|
||||
/**
|
||||
* 将字节转换为可读文本
|
||||
* @param int $size 大小
|
||||
* @param string $delimiter 分隔符
|
||||
* @param int $precision 小数位数
|
||||
* @return string
|
||||
*/
|
||||
function format_bytes($size, $delimiter = '', $precision = 2)
|
||||
```
|
||||
|
||||
## Function Design
|
||||
|
||||
**Size:**
|
||||
- Controller action methods: 10-30 lines (when extending Backend, most logic is in trait)
|
||||
- Backend trait methods: 30-80 lines (`index`, `add`, `edit`, `del`)
|
||||
- Import method: ~130 lines (`application/admin/library/traits/Backend.php`)
|
||||
- Library methods: 10-50 lines
|
||||
- Global functions: 5-30 lines
|
||||
|
||||
**Parameters:**
|
||||
- Primary key as method parameter: `edit($ids = null)`, `del($ids = "")`
|
||||
- POST form data: `$this->request->post('row/a')` (returns associative array)
|
||||
- Query params: `$this->request->request('key')`, `$this->request->get('filter')`
|
||||
|
||||
**Return Values:**
|
||||
- AJAX: `json(['total' => N, 'rows' => [...]])`
|
||||
- Non-AJAX: `$this->view->fetch()`
|
||||
- API: Always JSON via `$this->success()` / `$this->error()`
|
||||
|
||||
## Module Design
|
||||
|
||||
**PHP Exports:**
|
||||
- No explicit exports; PSR-4 autoloading handles class loading
|
||||
- Language files: `return [...]` array
|
||||
- Config files: `return [...]` array
|
||||
|
||||
**JS Exports:**
|
||||
- AMD `define()` with `return Controller;` pattern
|
||||
- No ES modules, no CommonJS
|
||||
|
||||
**No Barrel Files:** Direct imports throughout, no index/re-export files
|
||||
|
||||
**Addon Structure:**
|
||||
```
|
||||
addons/{addon_name}/
|
||||
├── config.php # Addon configuration (returns array)
|
||||
├── Command.php # Main addon class (extends \fast\Addons)
|
||||
├── controller/Index.php # Addon controller
|
||||
├── library/Output.php # Addon library
|
||||
└── info.ini # Addon metadata
|
||||
```
|
||||
|
||||
## Where to Add New Code
|
||||
|
||||
**New Admin Feature (CRUD):**
|
||||
- Controller: `application/admin/controller/{module}/{Name}.php`
|
||||
- Model: `application/admin/model/{Name}.php`
|
||||
- Validate: `application/admin/validate/{Name}.php`
|
||||
- Language: `application/admin/lang/zh-cn/{module}/{name}.php`
|
||||
- View: `application/admin/view/{module}/{name}/index.html`, `add.html`, `edit.html`
|
||||
- JS: `public/assets/js/backend/{module}/{name}.js`
|
||||
- Or auto-generate: `php think crud --table={table} --controller={name}`
|
||||
|
||||
**New API Endpoint:**
|
||||
- Controller: `application/api/controller/{Name}.php` (extends `app\common\controller\Api`)
|
||||
- Response via `$this->success()` / `$this->error()`
|
||||
- Add `@ApiMethod` and `@ApiParams` annotations for doc generation
|
||||
|
||||
**New Common Library:**
|
||||
- Location: `application/common/library/{Name}.php`
|
||||
- Use singleton `instance()` pattern if needed
|
||||
|
||||
**New Global Function:**
|
||||
- Location: `application/common.php`
|
||||
- Wrap in `if (!function_exists('name')) { ... }`
|
||||
|
||||
**New Module-Level Function:**
|
||||
- Location: `application/{module}/common.php`
|
||||
|
||||
**New Model:**
|
||||
- Shared model: `application/common/model/{Name}.php`
|
||||
- Admin-only model: `application/admin/model/{Name}.php`
|
||||
- Extend `think\Model`, set `$name`, `$autoWriteTimestamp`, `$createTime`, `$updateTime`
|
||||
|
||||
**New Validate:**
|
||||
- Location: `application/admin/validate/{Name}.php`
|
||||
- Extend `think\Validate`, define `$rule`, `$field`, `$scene`
|
||||
|
||||
---
|
||||
|
||||
*Convention analysis: 2026-04-21*
|
||||
Reference in New Issue
Block a user