yii2-cookbook之单表继承[翻译]
来源:互联网 发布:淘宝刷流量有用么 编辑:程序博客网 时间:2024/04/30 05:28
以后会看心情不定时翻译github上的yii-cookbook(url: https://github.com/samdark/yii2-cookbook/tree/master/book)
英文水平有限,有错误请一定指出来.
原文地址: https://github.com/samdark/yii2-cookbook/blob/master/book/ar-single-table-inheritance.md
译文:
目前大多数的关系型数据库是不原生支持继承的,这就导致了我们必须手动实现继承的功能.其中一个解决办法就是单表继承(Single table inheritance),这在http://martinfowler.com/eaaCatalog/singleTableInheritance.html 里说的很详细(注: 简单的说单表继承就是用一个表表示父类,每行记录子类的信息,然后多加一个列type表示该子类的类型).
以下实现的是一个简单的car类型的继承关系结构:
Car|- SportCar|- HeavyCar
准备
首先我们要建张表,并添加点测试数据,SQL如下:
CREATE TABLE `car` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `type` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`));INSERT INTO car (id, NAME, TYPE) VALUES (1, 'Kamaz', 'heavy'), (2, 'Ferrari', 'sport'), (3, 'BMW', 'city');
然后用GII生成Car Model
实现
我们需要先建个简单的Car的ActiveQuery来实现Car类型的查询条件的添加.
namespace app\models;use yii\db\ActiveQuery;class CarQuery extends ActiveQuery{ public $type; public function prepare($builder) { if ($this->type !== null) { $this->andWhere(['type' => $this->type]); } return parent::prepare($builder); }}
然后我们需要为两个子类添加model文件,首先是SportCar.php:
namespace app\models;class SportCar extends Car{ const TYPE = 'sport'; public static function find() { return new CarQuery(get_called_class(), ['type' => self::TYPE]); } public function beforeSave($insert) { $this->type = self::TYPE; return parent::beforeSave($insert); }}
然后是HeavyCar.php:
namespace app\models;class HeavyCar extends Car{ const TYPE = 'heavy'; public static function find() { return new CarQuery(get_called_class(), ['type' => self::TYPE]); } public function beforeSave($insert) { $this->type = self::TYPE; return parent::beforeSave($insert); }}
最后需要在Car model中重写instantiate方法
public static function instantiate($row){ switch ($row['type']) { case SportCar::TYPE: return new SportCar(); case HeavyCar::TYPE: return new HeavyCar(); default: return new self; }}
好了,让我们在controller里添加个actionTest试试:
// finding all cars we have$cars = Car::find()->all();foreach ($cars as $car) { echo "$car->id $car->name " . get_class($car) . "<br />";}// finding any sport car$sportCar = SportCar::find()->limit(1)->one();echo "$sportCar->id $sportCar->name " . get_class($sportCar) . "<br />";
下面是输出:
1 Kamaz app\models\HeavyCar2 Ferrari app\models\SportCar3 BMW app\models\Car2 Ferrari app\models\SportCar
这说明model根据type列实例化了对应的子类.
工作原理:
SportCar 和 HeavyCar非常相像.他们都继承自Car类并且有两个方法被重写了.在find方法中,我们实例化了一个根据type定制的query class,这是通过重写prepare方法(此方法在生成SQL之前被调用)将”and type=xxxx”条件插入进去实现的.这样SportCar就对应type=sportCar的记录, heavyCar就对应type=heavyCar的记录.重写beforeSave方法则保证了在子类保存时type被正确的设定了.TYPE常量让代码更易懂.
Car model除了instantiate函数之外完全就是GII生成的.这个函数是在数据被从DB中查出后正要初始化类属性时被调用的.它的返回值是未初始化的对象,而它唯一的入参代表一行数据库里的数据(以数组形式).这个函数里是一个简单的switch用来根据type生成我们想要的对象.
- yii2-cookbook之单表继承[翻译]
- yii2-cookbook之定制response类型[翻译]
- yii2-cookbook之增强IDE自动补全[翻译]
- Hibernate 之单表继承映射策略
- C++之单继承
- 【Hibernate集锦】---继承映射之单表继承
- Rails Cookbook翻译(一)
- Rails Cookbook翻译(二)
- Flex CookBook翻译(1)
- Flex CookBook翻译(2)
- JavaScript之单继承与多继承
- C++之单继承与多继承
- 开始翻译Jakarta Commons Cookbook。
- Rails Cookbook翻译(三)
- Rails Cookbook翻译(四)
- Rails Cookbook翻译(五)
- Rails Cookbook翻译(六)
- Flex 3 Cookbook(翻译1)
- [Android学习]基于Android的Java学习路线图
- set RowCount 与 top n
- SimplyBrand Project Notes
- gtest参数化之Combine
- Android Drawable Resource学习(十二)、ShapeDrawable还是GradientDrawable?
- yii2-cookbook之单表继承[翻译]
- RecyclerView+Glide+PhotoView
- c++ # ## 区别
- 创建表和定义数据完整性
- iOS开发UI篇—Quartz2D简单使用(一)
- Linux信号、信号处理和信号处理函数
- IOS7.0 原生二维码扫描
- 安卓四大组件之——ContentProvider学习
- linux awk命令详解