介绍
MVC模式中的Model模型,就是一个快速操作数据库(准确的说是对应的数据表,一个模型对应一个数据表)的方法,可以利用模型加上一些自己想要的操作对数据表进行快速操作。如查找特定的记录,增删查改都可。很多语言(Java、Go)都会提供Model的封装,Java有Hibernate,Go的Gin框架的Gorm等,这些封装的提供了接口方法来实现MVC程序逻辑。laravel框架提供的一套Model机制,很多方面值得学习,模型是laravel框架很重要的基础,Eloquent ORM组件提供了模型定义、CRUD、软删除、修改器等Api方法,还有模型事件。模型的封装好处是映射了底层数据库的数据结构、关联关系,提供给逻辑代码调用,并进行了一些优化,有时比直接调用数据库进行sql语句查询更加合理、结构化、性能优化;模型事件机制提取出事件处理、事件监听,使程序逻辑解耦,层次更加清晰。
参考
Laravel 使用artisan命令 创建数据库表,实体类和controller https://blog.csdn.net/chujianbi7142/article/details/100894653
实现
模型定义
# php artisan make:model Models/Test
use Illuminate\Database\Eloquent\Model;
class Test extends Model
{
//启用软删除
use SoftDeletes;
//表名的设置 不是必须 但是laravel会默认给模型相关表加复数s tests
protected $table = 'test';
//主键设置
protected $primaryKey = "u_id";
//主键的类型
protected $keyType = "string";
//主键是否自增
public $incrementing = true;
//自动时间戳
public $timestamps = false;
#定义属性字段的默认值
protected $attributes = ['password'=>'123456'];
#字段放行 允许对 name 和 email 字段操作
protected $fillable = ['name','email'];
#字段拦截 不允许对 update_time 字段操作
protected $guarded = ['update_time'];
//自定义时间戳字段名
const CREATED_AT = 'create_time';
const UPDATED_AT = 'update_time';
//时间戳格式设置
protected $dateFormat = 'U';
//自定义数据库连接
protected $connection = "yunyan";
}
上述模型参数给出了一些常用的,可以参考。
我们使用如下指令,生成建表语句(也可以自行创建)
# php artisan make:migration create_test_table --create=test
在database/migrations目录下自动生成建表语句xxx_create_test_table.php
class CreateTestTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('test', function (Blueprint $table) {
$table->id();
//这是我们自定义添加的字段
$table->string('name');
$table->string('email')->unique();
//上面是我们自定义添加的字段
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('test');
}
}
然后我们再执行指令,在数据库中创建表
# php artisan migrate
注:此指令会自动读取databse/*.php,根据定义的建表字段规则,创建新表,删除旧表,进行数据库迁移,这里要注意看看目录下的文件是否和数据库中已存在表。
执行成功后自动生成与建表语句对应的表。
CRUD功能
此处给出一个模型的新增表的一个简单调用例子,其他删除、修改功能不在赘述。
控制器
# php artisan make:controller ModelController
自动生成Models/ModelController.php文件
class ModelController extends Controller
{
public function add() {
$test = new Test([
'name' => '张三',
'email'=>'test@qq.com',
]);
$test->save();
return $test;
}
}
路由
routes/api.php
Route::get('/test/add', "ModelController@add");
浏览器访问:http://ip:port/api/test/add
软删除
此处需要在模型定义中加:use SoftDeletes;
控制器
class ModelController extends Controller
{
...
public function delete($id){
$test = Test::find($id);
$test->delete();
//$test->forceDelete(); //永久删除
return $test;
}
注:真删除就调用 forceDelete()即可。
路由
Route::get("/test/delete/{id}","ModelController@delete")->name("model.delete");
浏览器访问:http://{ip:port}/api/test/delete/4
查看表数据记录
发现删除操作记录打上了deleted_at的时间标记,并没有真正删除。
修改器
class Test extends Model
{
...
# 修改器
public function setPasswordAttribute($password) {
$password = md5($password);# encrypt 函数是 laravel 提供的一个加密函数
$this->attributes['password'] = $password; # 所有的字段保存在 $attributes 属性中
}
控制器
class ModelController extends Controller
{
...
//修改密码
public function modiPwd($id,$password){
$test = Test::find($id);
$test['password']=$password;
$test->save();
return $test;
}
路由
Route::get("/test/modiPwd/{id}/{password}","ModelController@modiPwd")->name("model.modiPwd"); # 修改密码
浏览器访问:http://{ip:port}/api/test/modiPwd/8/886644
查看数据表记录
发现密码已经修改为密文了
事件
普通事件
需求场景:我们模拟一个保存事件,观察事件监听、事件处理的情况。
1)建立事件,指令如下:
# php artisan make:event TestSaving
2)建立事件监听器,指令如下:
# php artisan make:listener TestListeners
class TestListeners
{
...
public function handle($event)
{
dump('测试事件监听到正在触发...');
}
3)生成事件及监听器
在事件服务提供者中注册事件及监听器,代码如下:
class EventServiceProvider extends ServiceProvider
{
...
protected $listen = [
...
//自定义事件
'App\Events\TestSaving' => [
'App\Listeners\TestListeners'
]
];
生成事件及监听器,指令如下:
# php artisan event:generate
4)事件分发
控制器
class ModelController extends Controller
{
...
//事件监听处理
public function savingEvent(){
// 用于触发事件
event(new TestSaving());
return "正在触发保存...";
}
路由
Route::get("/test/savingEvent","ModelController@savingEvent")->name("model.savingEvent");
浏览器访问:http://{ip:port}/api/test/savingEvent
模型事件
class Test extends Model
{
protected $dispatchesEvents = [
'saving' => TestSaving::class,
];
...
- retrieved:获取到模型实例后触发
- creating:插入到数据库前触发
- created:插入到数据库后触发
- updating:更新到数据库前触发
- updated:更新到数据库后触发
- saving:保存到数据库前触发(插入/更新之前,无论插入还是更新都会触发)
- saved:保存到数据库后触发(插入/更新之后,无论插入还是更新都会触发)
- deleting:从数据库删除记录前触发
- deleted:从数据库删除记录后触发
- restoring:恢复软删除记录前触发
- restored:恢复软删除记录后触发
我们再浏览器访问接口:http://ip:port/api/test/add
发现上图,在增加保存记录时,已经真正触发了保存事件saving。
模型关联
一对一
反向关联
一对多
多对多