600 lines
23 KiB
Markdown
600 lines
23 KiB
Markdown
# 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*
|