写作规范
标签(空格分隔): 未分类
1.控制器写作规范(controller)
当前主程序控制器写在application/index/controller中
admin文件夹下是后台管理控制器
同级文件或文件夹都是前台的控制器
规定控制器都写上后缀名:Controller
控制器命名规范为当前操作对象+Controller,例如针对用户操作的控制器可命名为UserController
控制前前缀相同的可以放在一个文件夹中
下面为一个简单的控制器
<?php
namespace app\index\controller\admin\user;
use app\common\model\RoleModel;
use app\common\model\user\UserProfileModel;
use app\index\common\ArrayToolkit;
use app\index\common\Paginator;
use app\index\controller\DefaultController;
use think\Request;
class UserController extends DefaultController
{
public function indexAction(Request $request)
{
$user = $this->getCurrentUser();
if (!$user->hasPermission('admin_user_manage')) {
return json([
'status' => false,
'message' => '对不起你没有权限访问当前页面',
'hasPermission' => false,
'redirect' => !empty($request->get('redirect')) ? $request->get('redirect') : '/'
]);
}
$conditions = array(
'keywordType' => '',
'keyword' => ''
);
$fields = $request->get();
$conditions = array_merge($conditions, $fields);
if (!empty($conditions['keywordType']) && !empty($conditions['keyword'])) {
$this->findByKeyword($conditions);
}
if (!empty($conditions['roles'])) {
$conditions['roleLike'] = "%{$conditions['roles']}%";
unset($conditions['roles']);
}
$countUsers = $this->getUserModel()->countUser($conditions);
$paginator = new Paginator(
$request,
$countUsers,
20
);
$users = $this->getUserModel()->searchUsers(
$conditions,
array('createdTime' => 'DESC'),
$paginator->getOffsetCount(),
$paginator->getPerPageCount()
);
$users = ArrayToolkit::index($users, 'id');
$allRoles = $this->getAllRoles();
return json([
'paginator' => $paginator,
'users' => $users,
'allRoles' => $allRoles,
'userCount' => $countUsers
]);
}
public function rolesAction(Request $request, $id)
{
$user = $this->getUserModel()->getUser($id);
$allRoles = $this->getRoleModel()->searchRoles([], [], 0, PHP_INT_MAX);
if ($request->isPost()) {
$roles = $request->post('roles/a');
$this->getUserModel()->changeUserRoles($user['id'], $roles);
}
return json([
'user' => $user,
'allRoles' => $allRoles
]);
}
public function showAction(Request $request, $id)
{
$user = $this->getUserModel()->getUser($id);
$profile = $this->getUserProfileModel()->getUserProfile($id);
$profile['title'] = $user['title'];
$allRoles = $this->getAllRoles();
return json([
'user' => $user,
'allRoles' => $allRoles,
'profiles' => $profile
]);
}
protected function getAllRoles()
{
$roles = $this->getRoleModel()->searchRoles([], [], 0, PHP_INT_MAX);
$roleDicts = array();
foreach ($roles as $role) {
$roleDicts[$role['code']] = $role['name'];
}
return $roleDicts;
}
protected function findByKeyword(&$conditions)
{
switch ($conditions['keywordType']) {
case 'nickname':
$conditions['nickname'] = "%{$conditions['keyword']}%";
break;
case 'emailLike':
$conditions['emailLike'] = "%{$conditions['keyword']}%";
break;
}
}
/**
* @return RoleModel
*/
protected function getRoleModel()
{
return model('common/RoleModel');
}
/**
* @return UserProfileModel
*/
protected function getUserProfileModel()
{
return model('common/user/UserProfileModel');
}
}
所有的action都应该为pubilc类型方法
控制器中其他不是Action的方法按实际情况分为protectd private类型
新建控制器应继承DefaultController 该控制中继承了相应的公共方法,
例如获取当前登录用户的信息getCurrentUser()(包含user表的信息,组织信息,访问许可表permissions,是否登录,是否超管等,详情请见CurrentUser.php)
$user = $this->getCurrentUser();//获取当前登录用户
if (!$user->hasPermission('admin_user_manage')) {//判断登录用户有无权限访问当前action,其中参数详解请见menus_admin.yml
return json([
'status' => false,
'message' => '对不起你没有权限访问当前页面',
'hasPermission' => false,
'redirect' => !empty($request->get('redirect')) ? $request->get('redirect') : '/'
]);
}
控制器复用性:
尽量用少量的控制器方法来实现多个行为操作,
例如上述例子中
public function rolesAction()//对用户进行角色授权
第一次访问时以get的方式获取到该用户当前的角色信息,填充到页面上,授权角色完后以post方式提交表单,任然是当前action,只需要在action判断当前的请求是不是post方式就行了。
获取model
/**
* @return UserProfileModel
*/
protected function getUserProfileModel()
{
return model('common/user/UserProfileModel');
}
控制器数据抛出
暂定,规范不是很清楚
模型代码规范
为了后续定制开发需求,当前主程序页面,模型,静态资源都放入application/common/ 中
一般来说,一个模型对应数据库中的一张表
例如:user用户表, UserModel.php,
org组织机构表, OrgModel.php
推荐,模型写上后缀名
模型没有前后台之分都放在common/model中,同样的前缀相同时可以放入一个文件夹中,
一般来说一个模型基本有增删改查,
getUser($id) //主键单条查询 单条都用get 多条find 复合条件查询 search
createUser($fields)
updateUser($id, $fields)
deleteUser($id)
countUsers($conditions) //复合条件查询条数
searchUsers($conditions, $orderBys, $start, $limit) //复合条件查询 支持排序 且或关系查询 分页
简单model示例:
<?php
namespace app\common\model\user;
use app\common\model\DefaultModel;
use app\index\common\ArrayToolkit;
use app\index\common\SimpleValidator;
use app\index\component\exception\ModelException;
use app\index\component\security\ReversibleEncryption;
use app\index\validate\UserValidate;
use think\Db;
use think\facade\Cookie;
use think\facade\Request;
class UserModel extends DefaultModel
{
protected $table = 'user';
protected $pk = 'id';
public function createUser($fields)
{
$validate = new UserValidate();
if (!empty($fields['__token__']) && !$validate->check($fields)) {
return new ModelException($validate->getError());
}
$fields['password'] = ReversibleEncryption::encrypt($fields['password']);
if (empty($fields['roles'])) {
$fields['roles'] = 'ROLE_USER';
}
$fields['createdTime'] = time();
unset($fields['__token__']);
Db::startTrans();
try {
$userId = db($this->table)->insertGetId($fields);
$this->getUserProfileModel()->createUserProfile(['id' => $userId]);
Db::commit();
} catch (ModelException $exception) {
Db::rollback();
return $exception->getMessage();
}
return $this->getUser($userId);
}
public function getUser($id)
{
$user = db($this->table)->find($id);
return $this->conversionData($user);
}
public function getUserByLoginSessionId($sessionId)
{
return db($this->table)->where('loginSessionId', $sessionId)->find();
}
public function updateUser($id, $fields)
{
$validate = new UserValidate();
if (!empty($fields['__token__']) && !$validate->check($fields)) {
return new ModelException($validate->getError());
}
if (!empty($fields['roles']) && is_array($fields['roles'])) {
$fields['roles'] = implode(',', $fields['roles']);
}
return db($this->table)->where('id', $id)->update($fields);
}
public function findUsersByIds($ids)
{
if (empty($ids)) {
return array();
}
return db($this->table)->where('id', 'IN', $ids)->select();
}
public function searchUsers($conditions, $orderBys, $start, $limit)
{
return $this->search($conditions, $orderBys, $start, $limit);
}
public function countUser($conditions)
{
$builder = $this->createQueryBuilder($conditions);
return $builder->count();
}
protected function conversionData(&$data)
{
$config = array(
'array' => array(
'roles'
)
);
if (empty($data)) {
return array();
}
//转化数据
foreach ($config as $key => $item) {
switch ($key) {
case 'array':
foreach ($config[$key] as $dataKey) {
if (in_array($dataKey, array_keys($data)) && is_string($data[$dataKey])) {
$data[$dataKey] = explode(',', $data[$dataKey]);
}
}
break;
}
}
return $data;
}
public function declares()// 用于构建多条件复合查询sql语句
{
return array(
'orderBys' => array(
'id',
'createdTime'
),
'conditions' => array(
'and' => array(
['id', 'in', 'ids'],
['nickname', 'like', 'nickname'],
['roles', 'like', 'roleLike'],
['email', 'like', 'emailLike']
),
'or' => array(
)
)
);
}
/**
* @return UserProfileModel
*/
protected function getUserProfileModel()
{
return model('common/user/UserProfileModel');
}
}
模型可继承DefaultModel.php 且都必须实现declares()方法,其中有构建复合条件查询sql的方法createQueryBuilder($conditions),
search($conditions, $orderBys, $start, $limit)
.配合declares()方法
public function declares()// 用于构建多条件复合查询sql语句
{
return array(
'orderBys' => array( //排序字段,使用search方法时,支持排序的字段必须写在这儿
'id',
'createdTime'
),
'conditions' => array(//createQueryBuilder, search中使用多条件构建复合查询
'and' => array(
['id', 'in', 'ids'],
['nickname', 'like', 'nickname'], 【字段名,匹配方式, 传递参数名】
['roles', 'like', 'roleLike'],
['email', 'like', 'emailLike'],
['age', '>', 'age_LT']
),
'or' => array(
)
)
);
}
其中conditions中分为 且条件and 类型的 或条件or类型, 使用方法:
例如:使用邮箱模糊查询且用户名模糊查询且年龄大于24的用户,创建时间降序排序,100个
public function searchUser($conditions, $orberBys, $start, $limit)
{
return $this->search(
array(
'nickname' => '%test%',
'eamilLike' => '%@163.com%',
'age_LT' => '24',
),
array('createdTime' => 'DESC'),//array('createdTime')默认为升序排序
0,
100,
)
}
由上述的searchUsers可以配合Paginator类实现分页查询
例:
$countUsers = $this->getUserModel()->countUser($conditions);
$paginator = new Paginator(
$request,
$countUsers,
20
);
$users = $this->getUserModel()->searchUsers(
$conditions,
array('createdTime' => 'DESC'),
$paginator->getOffsetCount(),
$paginator->getPerPageCount()
);
详情请见application/index/common/Paginator
关于模型中异常抛出
if (!$this->isNameAvailable($fields['name'])) {
throw new ModelException("机构名称<{$fields['name']}>不可用");
}
在application/index/component/expection中重写了一个Handle类实现抛出异常数据的格式为json,方便前端js中捕获异常
其他
关于安全,
csrf 令牌,在提交表单中都需要csrf令牌,到时候规范统一在后台生成csrf令牌,传给前端
xss,前端页面需要针对<>脚本语言过滤,防止xss攻击
其中表单的csrf令牌校验在验证器中进行,application/index/valicate