type field that will define the class that inherits this record. Car |- SportCar |- HeavyCar `car` has the following structure: 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'); Car model can be generated with Gii.CarQuery , which will automatically substitute the type of 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); } } Car . In them, we define the TYPE constant that will store the type of car for writing in the type field of the model, and override the ActiveRecord methods of init , find and beforeSave , in which this type will be automatically inserted into the model and into the CarQuery query. TYPE does not have to be a string (it is wiser to use an unsigned int), and not even necessarily a constant, but for simplicity, let's do this. This will be SportCar : namespace app\models; class SportCar extends Car { const TYPE = 'sport'; public function init() { $this->type = self::TYPE; parent::init(); } 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 : namespace app\models; class HeavyCar extends Car { const TYPE = 'heavy'; public function init() { $this->type = self::TYPE; parent::init(); } 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 class and using the Car::getType method instead of the protected constant, but now I will not dwell on this for simplicity.Car:instantiate: method to automatically create the model of the desired class, depending on the type: public static function instantiate($row) { switch ($row['type']) { case SportCar::TYPE: return new SportCar(); case HeavyCar::TYPE: return new HeavyCar(); default: return new self; } } switch case in the code of the parent model is actually not a very good solution, but, again, this is done only for ease of understanding the approach and it is easy to get rid of it by slightly complicating the code.single table inheritance everything is ready. Here is a simple example of its transparent use in the controller: // 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\HeavyCar 2 Ferrari app\models\SportCar 3 BMW app\models\Car 2 Ferrari app\models\SportCar UniqueValidator skip them from different classes, you can use such a pleasant Yii chip as the targetClass : public function rules() { return [ [['MyUniqueColumnName'], 'unique', 'targetClass' => Car::classname()], ]; } Source: https://habr.com/ru/post/274925/
All Articles