# 自动生成api和model 在执行上一步创建的user表 ```php php think migrate:run ``` 之后,我们来自动创建user的api和model等相关文件 ```php php think smart_init ``` 执行结果如下 ```php php think smart_init [Map]:create /webroot/thinkphp_test/application/index/map/UserMap.php ok [Model]:create /webroot/thinkphp_test/application/index/model/UserModel.php ok [ApiBaseController]:create /webroot/thinkphp_test/application/api/base/UserBaseApiController.php ok [ApiController]:create /webroot/thinkphp_test/application/api/controller/UserController.php ok ``` 此时看下application的目录结构 ``` . ├── api │   ├── base │   │   ├── BaseApiController.php │   │   └── UserBaseApiController.php │   └── controller │   ├── ApiController.php │   └── UserController.php ├── command.php ├── common │   └── behavior │   ├── BrowserSyncJsMerge.php │   └── MergeResource.php ├── common.php ├── config.php ├── console │   ├── ApiDoc.php │   ├── api_doc_templates │   │   ├── api.html │   │   ├── api_item.html │   │   └── api.md │   ├── BrowserSync.php │   ├── SmartInit.php │   ├── smart_init_templates │   │   ├── controller_base.tpl │   │   ├── controller.tpl │   │   ├── model_map.tpl │   │   └── model.tpl │   ├── task_run.ini │   └── TaskRun.php ├── database.php ├── extra │   └── queue.php ├── index │   ├── controller │   │   └── IndexController.php │   ├── map │   │   └── UserMap.php │   └── model │   ├── BaseModel.php │   └── UserModel.php ├── route.php └── tags.php ``` 看application/api目录结构 ``` ├── base │   ├── BaseApiController.php │   └── UserBaseApiController.php └── controller ├── ApiController.php └── UserController.php ``` 其中,base目录是依据数据库生成的base类,一个User表对应了,2个文件,分别是controller/UserController.php和base/UserBaseApiController.php。UserController.php的内容如下 ```php <?php /** * Created by PhpStorm. * User: SmartInit * Date: 2018/01/23 * Time: 10:13:26 */ namespace app\api\controller; use app\api\base\UserBaseApiController; /** * 用户表 * 如果有需要,请重写父类接口,不可直接修改父类函数,会被自动覆盖掉。 * Class UserController * @package app\api\controller */ class UserController extends UserBaseApiController { } ``` UserBaseController.php的内容如下 ```php <?php /** * Created by PhpStorm. * User: SmartInit */ namespace app\api\base; use app\api\controller\ApiController; use app\index\model\UserModel; use ClassLibrary\ClFieldVerify; use ClassLibrary\ClArray; /** * 用户表 Base * Class User Base Api * @package app\api\base */ class UserBaseApiController extends ApiController { /** * 列表 * @return \think\response\Json|\think\response\Jsonp * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getList() { $where = []; return $this->ar(1, $this->paging(UserModel::instance(), $where, function ($items) { //拼接额外字段 & 格式化相关字段 return UserModel::forShow($items); }), '{"status":"api-user-getlist-1","items":[{"id":"主键id","name":"名称","password":"密码"}]}'); } /** * 单个信息 * @return \think\response\Json|\think\response\Jsonp * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function get() { $id = get_param(UserModel::F_ID, ClFieldVerify::instance()->verifyIsRequire()->verifyNumber()->fetchVerifies(), '主键id或id数组'); $info = UserModel::getById($id); //拼接额外字段 & 格式化相关字段 $info = UserModel::forShow($info); return $this->ar(1, ['info' => $info], '{"status":"api-user-get-1","info":{"id":"主键id","name":"名称","password":"密码"}}'); } /** * 创建 * @return \think\response\Json|\think\response\Jsonp */ public function create() { $fields = ClArray::getByKeys(input(), UserModel::getAllFields()); //创建 UserModel::instance()->insert($fields); return $this->ar(1, ['id' => UserModel::instance()->getLastInsID()], '{"status":"api-user-create-1","id":"主键id"}'); } /** * 更新 * @return \think\response\Json|\think\response\Jsonp */ public function update() { $id = get_param(UserModel::F_ID, ClFieldVerify::instance()->verifyIsRequire()->verifyNumber()->fetchVerifies(), '主键id或id数组'); $fields = ClArray::getByKeys(input(), UserModel::getAllFields()); //更新 UserModel::instance()->where([ UserModel::F_ID => $id ])->setField($fields); return $this->ar(1, ['id' => $id], '{"status":"api-user-update-1","id":"主键id"}'); } /** * 删除 * @return \think\response\Json|\think\response\Jsonp * @throws \think\Exception * @throws \think\exception\PDOException */ public function delete() { $id = get_param(UserModel::F_ID, ClFieldVerify::instance()->verifyIsRequire()->verifyNumber()->fetchVerifies(), '主键id或id数组'); //删除 UserModel::instance()->where([ UserModel::F_ID => is_array($id) ? ['in', $id] : $id ])->delete(); return $this->ar(1, ['id' => $id], '{"status":"api-user-delete-1","id":"主键id"}'); } } ``` UserController继承自UserBaseController,且UserBaseController里自动生成了5个方法,具体请看代码。 ### 新增接口函数 比如,新增一个login登录接口 ```php <?php /** * Created by PhpStorm. * User: SmartInit * Date: 2018/01/23 * Time: 10:13:26 */ namespace app\api\controller; use app\api\base\UserBaseApiController; use app\index\model\UserModel; use ClassLibrary\ClFieldVerify; /** * 用户表 * 如果有需要,请重写父类接口,不可直接修改父类函数,会被自动覆盖掉。 * Class UserController * @package app\api\controller */ class UserController extends UserBaseApiController { /** * 登录 * @return \think\response\Json|\think\response\Jsonp * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function login(){ $name = get_param('name', ClFieldVerify::instance() ->verifyIsRequire() ->verifyChinese() ->fetchVerifies() ); $password = get_param('password', ClFieldVerify::instance() ->verifyIsRequire() ->verifyIsPassword() ->fetchVerifies() ); //获取用户信息 $user_info = UserModel::instance()->where([ UserModel::F_NAME => $name ])->find(); if(empty($user_info)){ return $this->ar(1, ['message' => '不存在当前账号']); }else{ if(UserModel::verifyPassword($user_info[UserModel::F_PASSWORD], $password)){ //拼接额外字段 & 格式化相关字段 $user_info = UserModel::forShow($user_info); return $this->ar(2, ['message' => '登录成功', 'user_info' => $user_info]); }else{ return $this->ar(3, ['message' => '密码错误']); } } } } ``` 其中函数 ```php get_param ``` 重新包装了,tp提供的 ```php input ``` 方法,用于提供字段校验功能。 ### api字段校验 主要依赖于ClFieldVerify类库,提供了如下校验函数 函数名 | 注释 ---|--- instance | 获取实例对象 fetch | 获取表Comment定义Json verifyIsRequire | 校验,必填字段 verifyIsPassword | 校验,密码格式 verifyInArray | 校验,在数组内 verifyIntInScope | 校验,在范围内 verifyIntMax | 校验,最大int值 verifyIntMin | 校验,最小int值 verifyStringLength | 校验,字符串长度 verifyStringLengthMax | 校验,最大字符串长度 verifyStringLengthMin | 校验,最小字符串长度 verifyEmail | 校验,email格式 verifyMobile | 校验,手机格式 verifyIp | 校验,ip verifyPostcode | 校验,邮编 verifyIdCard | 校验,身份证 verifyChinese | 校验,汉字 verifyChineseAlpha | 校验,汉字+字母 verifyChineseAlphaNum | 校验,汉字+字母+数字 verifyChineseAlphaNumDash | 校验,汉字+字母+数字+下划线_+破折号- verifyAlpha | 校验,字母 verifyAlphaNum | 校验,字母+数字 verifyAlphaNumDash | 校验,字母+数字+下划线_+破折号- verifyUrl | 校验,网址 verifyNumber | 校验,数字 verifyArray | 校验,数组 verifyTel | 校验,固话 verifyIsDate | 校验,时间格式 verifyUnique | 校验,唯一值,比如身份证号、手机号等 其中密码校验函数UserModel::verifyPassword是BaseModel中提供的。 ## model模块分析 开发规则,一个大的系统不管是1个模块还是多个模块,应当在业务层共用相同的逻辑,即,所有的模块,应当共用application/index/model中定义的model来实现共用和维护。最好是以静态方法暴露出来。 ### index 模块目录结构 ```php . ├── controller │   └── IndexController.php ├── map │   └── UserMap.php └── model ├── BaseModel.php └── UserModel.php ``` 用户User表自动创建了,index/map/UserMap.php和index/model/UserModel.php。map目录会自动被覆盖,不可写入新的逻辑。新增的逻辑应当在UserModel.php中撰写。 #### UserMap.php内容 ```php <?php <?php /** * Created by PhpStorm. * User: SmartInit */ namespace app\index\map; use app\index\model\BaseModel; use ClassLibrary\ClArray; use ClassLibrary\ClCache; /** * 用户表 Map * Class UserMap * @package app\index\map */ class UserMap extends BaseModel { /** * 当前数据表名称(含前缀) * @var string */ protected $table = 'user'; /** * 名称 * Type: varchar(255) * Default: '' */ const F_NAME = 'name'; /** * 密码 * Type: varchar(255) * Default: '' */ const F_PASSWORD = 'password'; /** * 字段校验,用于字段内容判断 * @var array */ public static $fields_verifies = [ self::F_NAME => ["is_required","chinese",["length_max",255]], self::F_PASSWORD => ["is_required",["password",6,18],["length_max",255]], ]; /** * 只读的字段,仅仅是创建的时候添加,其他地方均不可修改 * @var array */ protected static $fields_read_only = []; /** * 不可见字段,去掉view层或接口中的字段 * @var array */ protected static $fields_invisible = []; /** * 字段映射 * @var array */ protected static $fields_show_map_fields = []; /** * 字段格式化 * @var array */ protected static $fields_show_format = []; /** * 字段存储格式 * @var array */ protected static $fields_store_format = [ self::F_PASSWORD => ["password","aaa"] ]; /** * 获取所有的字段 * @param array $exclude_fields 不包含的字段 * @return array */ public static function getAllFields($exclude_fields = [self::F_ID]) { $fields = [self::F_ID, self::F_NAME, self::F_PASSWORD]; return array_diff($fields, $exclude_fields); } /** * 按id或id数组获取 * @param $id * @param array $exclude_fields 不包含的字段 * @param int $duration 缓存时间 * @return array|false|\PDOStatement|string|\think\Model * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function getById($id, $exclude_fields = [], $duration = 0) { if($duration == 0){ return static::instance()->where([ self::F_ID => is_array($id) ? ['in', $id] : $id ])->field(self::getAllFields($exclude_fields))->find(); }else{ if(is_array($id)){ $items = []; foreach($id as $each_id){ $info = self::getById($each_id, $exclude_fields, $duration); if(!empty($info)){ $items[] = $info; } } return $items; } $info = static::instance()->cache([$id], $duration)->where([ self::F_ID => $id ])->find(); if(empty($info)){ return []; }else{ return ClArray::getByKeys($info, self::getAllFields($exclude_fields)); } } } /** * 清除缓存 * @param $id * @return bool */ public static function getByIdRc($id){ return ClCache::remove($id); } /** * 获取某个字段值 * @param integer $id 主键 * @param string $field 字段 * @param string $default 默认值 * @param bool $is_convert_to_int 是否转换为int * @return int|mixed|string * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function getValueById($id, $field, $default = '', $is_convert_to_int = false) { if(0 > 0){ $info = self::getById($id); if(empty($info)){ return $default; }else{ if($is_convert_to_int){ return intval($info[$field]); }else{ return $info[$field]; } } }else{ return static::instance()->where([ self::F_ID => $id ])->value($field, $default, $is_convert_to_int); } } } ``` #### UserModel.php内容 ```php <?php /** * Created by PhpStorm. * User: SmartInit * Date: 2018/01/23 * Time: 10:05:54 */ namespace app\index\model; use app\index\map\UserMap; /** * Model */ class UserModel extends UserMap { /** * 实例对象存放数组 * @var array */ private static $instances_array = []; /** * 实例对象 * @param int $id -1/获取实例数量,-2/自动新增一个实例 * @return int|mixed|null|static */ public static function instance($id = 0) { if($id >= 0){ if (!isset(self::$instances_array[$id])) { self::$instances_array[$id] = new self(); } return self::$instances_array[$id]; }else if($id == -1){ return count(self::$instances_array); }else if($id == -2){ return self::instance(count(self::$instances_array)); } } /** * 缓存清除触发器 * @param $item */ protected function cacheRemoveTrigger($item) { if(isset($item[self::F_ID])){ self::getByIdRc($item[self::F_ID]); } } } ``` 默认提供了几个方法 函数名 | 注释 ---|--- getAllFields | 获取所有的字段 getById | 按id获取 getValueById | 按id获取某一个字段值 instance | 获取实例对象 cacheRemoveTrigger | 缓存清除触发器,此方法,会在后续文档中重点说明 我们来实现一个静态方法,比如,按用户名来获取账号信息。 ```php <?php /** * Created by PhpStorm. * User: SmartInit * Date: 2018/01/23 * Time: 10:05:54 */ namespace app\index\model; use app\index\map\UserMap; /** * Model */ class UserModel extends UserMap { /** * 实例对象存放数组 * @var array */ private static $instances_array = []; /** * 实例对象 * @param int $id -1/获取实例数量,-2/自动新增一个实例 * @return int|mixed|null|static */ public static function instance($id = 0) { if($id >= 0){ if (!isset(self::$instances_array[$id])) { self::$instances_array[$id] = new self(); } return self::$instances_array[$id]; }else if($id == -1){ return count(self::$instances_array); }else if($id == -2){ return self::instance(count(self::$instances_array)); } } /** * 缓存清除触发器 * @param $item */ protected function cacheRemoveTrigger($item) { if(isset($item[self::F_ID])){ self::getByIdRc($item[self::F_ID]); } } /** * 按用户名获取账号信息 * @param string $name * @return array|false|null|\PDOStatement|string|\think\Model * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function getByName($name){ return self::instance()->where([ self::F_NAME => $name ])->find(); } } ``` getByName是一个静态方法,在所有的模块中均可调取使用。