.example.env
文件。把.example
删掉即可开启调试模式。.env
中设置APP_DEBUG = true
.env
用于本地开发测试;config用于部署上线。.env
优先于config
。部署上线时,.env
会被自动忽略。public function config() {
echo "env配置:" . env("database.hostname");
echo "
";
echo "config配置:" . config("database.connections.mysql.hostname");
}
class Test {
// 控制器默认操作, http://localhost:8000/test
public function index() {
return "index";
}
// http://localhost:8000/test/hello
public function hello() {
return "hello";
}
// http://localhost:8000/test/hello1?value=world
public function hello1($value = "") {
return "hello, ". $value;
}
}
use think\facade\Db;
class DataTest {
public function index() {
$dbs = Db::table('member')->select();
return json($dbs);
}
}
public function index2() {
// 查询id为1
$dbs = Db::table('member')->where('id',1)->find();
// 查看sql语句
return Db::getLastSql();
return json($dbs);
}
public function index3() {
$data = [
"name" => "k",
"age" => 12,
"email" => "@@@"
];
return $this->memberTable->insert($data);
}
use think\Model;
class Member extends Model {
}
use think\Model;
class MemberModel extends Model {
protected $name = 'member';
}
use think\Model;
class MemberModel extends Model {
protected $pk = 'uid';
}
use think\Model;
class MemberModel extends Model {
protected $table= 'member';
}
use think\Model;
class MemberModel extends Model {
protected static function init(){
parent::init();
}
}
控制器中引入模型
use \app\model\Member as MemberModel;
use \app\model\Member as MemberModel;
class Member {
public function index() {
$member = MemberModel::select();
$member = MemberModel::find(1);
return $member;
}
}
public function index() {
$member = MemberModel::find(1);
return $member;
}
普通新增
public function insert() {
// 新增方式1
$member = new MemberModel();
$member->name = "李白";
$member->age = 18;
$member->email = "@";
$member->save();
// 新增方式2
$member = new MemberModel();
$member->save([
'name' => "李黑",
'age' => 19,
'email' => "@"
]);
}
验证新增,设置允许写入的字段
$member->allowField(['name', 'age'])->save([
'name' => "李黑",
'age' => 19,
'email' => "@"
]);
replace新增
$member->replace()->save();
新增成功后,获取自增的ID
$member->id;
批量新增
$member = new MemberModel();
$dataAll = [
[
'name' => "黑李",
'age' => 22,
'email' => "@"
],
[
'name' => "白李",
'age' => 24,
'email' => "@"
],
];
dump($member->saveAll($dataAll));
使用静态方法 create(新增数组, 允许写入的字段, 是否replace)
,创建要新增的数据。
$member = MemberModel::create([
'name' => "白李",
'age' => 24,
'email' => "@"
], ['name', 'age'], true);
echo $member->id;
删除单个,默认根据主键删除。
public function delete() {
// 成员方法删除
$member = MemberModel::find(1);
$member->delete();
// 静态方法删除
MemberModel::destroy(2);
}
批量删除
MemberModel::destroy([3, 4, 5]);
通过闭包删除
MemberModel::destroy(function ($query){
$query->where("age", "<", 10);
});
普通更新
public function update() {
$member = MemberModel::find(8);
$member->name = "李四";
$member->age = 120;
$member->save();
}
强制更新
$member->force()->save();
Db::raw()
执行SQL函数
$member->age = Db::raw("age + 1");
allowField()
限制更新的字段(限制不了raw)。
saveAll()
批量更新,只能根据主键更新,返回被修改的数据集。
静态方法update(数据数组, 限定记录, 限定字段)
MemberModel::update([
'name' => "占山",
'age' => 15
], ['id' => 10], ['name']);
模型的数据字段对应表字段,默认严格区分大小写。
class Member extends Model {
// 是否严格区分大小写
protected $strict = false;
// 设置字段
protected $schema = [
"id" => 'int',
'name' => "string",
"age" => "int",
"email" => "string"
];
}
$schema属性只对模型有效。如果需要Db类也有效,config/database.php 开启字段缓存。
'fields_cache' => true,
在模型中处理数据
class Member extends Model {
public function getMemberName($id) {
$data = $this->find($id);
return $data->getAttr('name');
}
}
一个获取器对应模型中的一个特殊方法,该方法是public,方法名格式固定getXxxAttr()
。
获取器的作用是对模型实例的数据做出自动处理。
class Member extends Model {
// 获取器,获取数据时自动执行
public function getAgeAttr($value) {
if ($value < 18) {
return "未成年";
}else{
return "已成年";
}
}
}
如果定义了获取器,并且需要获取原始值,使用getData()
。
动态获取器withAttr()
public function index6() {
$var = MemberModel::select()->withAttr("email", function ($value) {
return strtoupper($value);
});
return json($var);
}
修改器的作用是在新增、修改数据时对数据进行格式化、过滤等处理,方法名格式固定setXxxAttr()
。
修改器只对模型操作有效,对Db类无效。
class Member extends Model {
public function setEmailAttr($value) {
return strtoupper($value);
}
}
在模型中封装一个查询或写入的方法,方便控制器调用。方法名格式scopeXxx
。
class Member extends Model {
public function scopeAdult($query) {
$query->where("age", ">=", 18)
->field("id, name, age")
->limit(3);
}
}
调用只需要后缀,查询范围只支持find和select。
use \app\model\Member as MemberModel;
class Member {
public function index7() {
$select = MemberModel::adult()->select();
return json($select);
}
}
全局查询范围,任何查询都需要加上这个范围。
class Member extends Model {
// 定义全局查询范围
protected $globalScope = ['status'];
public function scopeStatus($query) {
$query->where("status", 1);
}
}
hidden()
,显示某个字段 visible()
,添加获取器字段 append()
,对字段进行函数处理 withAttr()
。自动时间戳会自动写入create_time和update_time两个字段。默认值是int。
全局开启自动时间戳,在config/database.php中设置
'auto_timestamp' => true,
只想设置一个模型开启,在模型中设置
protected $autoWriteTimestamp = true;
自定义新增和修改的时间戳
protected $createTime = "create_at";
protected $updateTime = "update_at";
不需要update_time
protected $updateTime = false;
只读字段只支持模型,不支持数据库方式。
只读字段在修改时无法被修改。
protected $readonly = ['name','email'];
动态设置只读字段。
$member->readonly(['name','email'])->save();
类型转换会调用属性里的获取器等操作。
设置类型转换可以在获取数据前将类型转换成需要的类型。
protected $type = [
'name' => 'string',
'price' => 'float',
"create_time" => "datetime:Y-m-d"
];
当字段不再使用时,可以设置为废弃字段。
protected $disuse = ['status', 'uid'];
软删除不会物理删除记录,相当于全局查询范围。
在模型中设置软删除的功能。
use think\model\concern\SoftDelete;
class Member extends Model {
use SoftDelete;
protected $deleteTime = "delete_time";
}
取消屏蔽软删除
UserModel::withTrashed()->select();
显示被软删除的记录
UserModel::onlyTrashed()->select();
还原软删除 restore()
$user = UserModel::onlyTrashed()->find(300);
$user->restore();
物理删除
UserModel::onlyTrashed()->find(298)->force()->delete();
关联模型是将表与表之间进行关联和具象化,更高效的操作数据。
主表关联附表(正向关联),hasOne(附表模型, 外键, 主键)
一对一关联,外键默认为主表名_id
。
class profile extends Model {
}
class Member extends Model {
public function profile() {
return $this->hasOne(Profile::class);
}
}
附表关联主表(反向关联),belongsTo()
class Profile extends Model {
public function member() {
return $this->belongsTo(Member::class, "user_id");
}
}
调用模型
use app\model\Member as MemberModel;
class Grade {
public function index() {
$member = MemberModel::find(1);
return $member->profile->hobby;
}
}
关联方式
函数 | 说明 |
---|---|
hasOne | 一对一 |
belongsTo | 一对一 |
hasMany | 一对多 |
hasOneThrough | 远程一对一 |
hasManyThrough | 远程一对多 |
belongsToMany | 多对多 |
morphMany | 多态一对多 |
morphTo | 多态 |
正反向关联
说明 | 正向关联 | 反向关联 |
---|---|---|
一对一 | hasOne | belongsTo |
一对多 | hasMany | belongsTo |
多对多 | belongsToMany | belongsToMany |
远程一对多 | hasManyThrough | \ |
多态一对一 | morphOne | morphTo |
多态一对多 | morphMany | morphTo |
一对一关联修改
$member = MemberModel::find(1);
$member ->profile->save(['hobby' => '吃饭']);
一对一关联新增
$member = MemberModel::find(1);
$member ->profile()->save(['hobby' => '吃饭']);
正向关联反向操作
$member = MemberModel::hasWhere("prefile", ["id" => 2])->find();
has()
方法查询关联附表的主表内容。
MemberModel::has("profile", ">=", 2)->select();
together()
可以在删除主表内容时,同时删除附表关联的内容。
$member = MemberModel::with('profile')->find(2);
$member->together(['profile'])->delete();
新增和一对一关联新增相同。
关联预载入可以减少查询次数提高性能,但不支持多次调用。
$list = MemberModel::with(['profile'])->select([19, 20, 21]);
foreach ($list as $member) {
dump($member->profile);
}
如果主表关联多个附表。
$list = MemberModel::with(['profile', 'book'])->select([19, 20, 21]);
foreach ($list as $member) {
dump($member->profile.$member->book);
}
延迟预载入
$list = MemberModel::select([19, 20, 21]);
$list->load(['profile']);
foreach ($list as $member) {
dump($member->profile);
}
统计主表在附表中有多少条记录,包括 withMax、withMin、withCount、withAvg等。
public function index3() {
$list = MemberModel::withCount(['profile'])->select([1,2,3]);
foreach ($list as $member) {
echo $member->profile_count . '
';
}
}
关联统计输出采用 关联方法_统计方法
。
hidden
和visible
控制隐藏和显示的字段,append
添加额外字段。
$list = MemberModel::withCount(['profile'])->select([1,2,3]);
$list->hidden(['password', 'gender', 'profile.status']);
多对多中间表模型类 Pivot。
在模型类中设置多对多关联,belongsToMany(关联模型, 中间表, 外键, 关联键)
public function roles(){
return $this->belongsToMany(Role::class, Access::class);
}
使用
// 获取用户
$member = MemberModel::find(2);
// 获取用户权限
$roles = $member->roles;
新增,需要通过用户表新增到中间表关联。
$member = MemberModel::find(2);
$member->roles->save(Role::find(5));
$member->roles->saveAll([1, 2, 3]);
$member->roles->attach(5, ["detail" => "测试"]);
删除中间表数据
$member = MemberModel::find(2);
$member->detach(5);
在数据库中写入JSON,使用数组方式。用json()
指定JSON字段。
public function insert(){
$data = [
"name" => "张三",
"list" => ["nikeName" => "zs", "gender" => "女"]
];
return Db::name("user")->json(["list"])->insert($data);
}
查询数据,需要转换JSON,也需要设置json()
Db::name('user')->json(["list"])->find(15);
修改JSON字段
$data["list"] = ["nikeName" => "zs", "gender" => "女"];
Db::name("user")->json(['list']->where('id', 1)->update($data);
$data["list->gender"] = "男";
Db::name("user")->json(["lsit"])->where('id', 1)->update($data);
在模型中设置JSON字段
protected $json = ["list"];
模型中通过JSON的数据查询
UserModel::where('list->name', "小红")->find();
更新数据
$user = UserModel::find(1);
$user->list->name = "小黑";
$user->save();
Db::event('事件名', '执行函数')
事件名 | 说明 |
---|---|
before_select | select查询前回调 |
before_find | find查询前回调 |
after_insert | insert操作成功后回调 |
after_update | update操作成功后回调 |
after_delete | dalete操作成功后回调 |
在控制器端,事件一般写在初始化方法里(继承于 BaseController)。
use app\BaseController;
use think\facade\Db;
class Member extends BaseController {
public function initialize() {
Db::event("before_select", function ($query) {
echo "执行了批量查询";
});
Db::event("after_update", function ($query) {
echo "修改被执行";
});
}
}
class Member extends Model {
protected static function onAfterRead($query){
echo "一条数据被查询";
}
protected static function onBeforeUpdate(Model $model) {
parent::onBeforeUpdate($model); // TODO: Change the autogenerated stub
}
}