この記事では、Yii のマルチテーブル結合クエリを要約して説明します。具体的な内容は次のとおりです。
1. 複数テーブル結合クエリの実装方法
方法は 2 つあります 1 つは、DAO を使用して SQL ステートメントを記述して を実装する方法です。ただし、SQL ステートメントが間違って書かれています。欠点も明らかであり、それらは散在しており、YII の推奨フレームワークに準拠していません。最も重要な欠点は間違いを犯しやすいことです。
もあります。1 つは、YII に付属の CActiveRecord を使用して、複数テーブルの結合クエリ
を実装する方法です。2.全体の枠組み
ユーザーの友人関係を見つける必要があります。ユーザーの情報はユーザー テーブルに配置され、ユーザー間の関係は関係テーブルに配置され、関係の内容は関係タイプ テーブルに配置されます。明らかに、他の 2 つのテーブルをクエリするためのメイン テーブルとしてリレーショナル テーブルを使用するだけで済みます。主に実装プロセスをコードの観点から分析します。
3. CActiveRecord
まず、3 つのテーブルに対応するモデルを確立する必要があります。以下はリレーショナル テーブルのコードです。
SocialRelation.php
<?php /** * This is the model class for table "{{social_relation}}". * * The followings are the available columns in table '{{social_relation}}': * @property integer $relation_id * @property integer $relation_type_id * @property integer $user_id * @property integer $another_user_id * * The followings are the available model relations: * @property SocialRelationType $relationType * @property AccessUser $user * @property AccessUser $anotherUser */ class SocialRelation extends CActiveRecord { /** * Returns the static model of the specified AR class. * @param string $className active record class name. * @return SocialRelation the static model class */ public static function model($className=__CLASS__) { return parent::model($className); } /** * @return string the associated database table name */ public function tableName() { return '{{social_relation}}'; } /** * @return array validation rules for model attributes. */ public function rules() { // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( array('relation_type_id, user_id, another_user_id', 'numerical', 'integerOnly'=>true), // The following rule is used by search(). // Please remove those attributes that should not be searched. array('relation_id, relation_type_id, user_id, another_user_id', 'safe', 'on'=>'search'), ); } /** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'relationType' => array(self::BELONGS_TO, 'SocialRelationType', 'relation_type_id'), 'user' => array(self::BELONGS_TO, 'AccessUser', 'user_id'), 'anotherUser' => array(self::BELONGS_TO, 'AccessUser', 'another_user_id'), ); } /** * @return array customized attribute labels (name=>label) */ public function attributeLabels() { return array( 'relation_id' => 'Relation', 'relation_type_id' => 'Relation Type', 'relation_type_name' => 'Relation Name', 'user_id' => 'User ID', 'user_name' => 'User Name', 'another_user_id' => 'Another User', 'another_user_name' => 'Another User Name', ); } /** * Retrieves a list of models based on the current search/filter conditions. * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions. */ public function search() { // Warning: Please modify the following code to remove attributes that // should not be searched. $criteria=new CDbCriteria; $criteria->compare('relation_id',$this->relation_id); $criteria->compare('relation_type_id',$this->relation_type_id); $criteria->compare('user_id',$this->user_id); $criteria->compare('another_user_id',$this->another_user_id); $criteria->with=array( 'relationType', ); return new CActiveDataProvider($this, array( 'criteria'=>$criteria, )); } }
説明の便宜上、主テーブルはテーブル A (クエリが実行されるテーブル)、参照テーブルはテーブル B (外部キーによって参照されるテーブル) であることに同意します
Gii を使用してモデルを自動的に生成することをお勧めします。これにより、テストの便宜上、追加、削除、変更、およびクエリ ページであるメイン テーブルに対して CRUD を生成できます。テーブルの場合は、モデルを生成するだけです。
1. このモデルとデータベーステーブルの基本情報を取得するには、モデル関数 と tablename 関数を使用します。変更せずに自動生成
2. ルール関数 。この関数は主にパラメーターの検証方法を指定するために使用されます。一部のパラメーターは検証を必要としない場合でも、ルールに含める必要があることに注意してください。そうしないと、モデルはパラメータを取得できなくなります
3. 関係関数 、この関数は非常に重要であり、テーブル間の関係を定義するために使用されます。その意味については、以下で詳しく説明します。
'relationType' => array(self::BELONGS_TO, 'SocialRelationType', 'relation_type_id')
このコードの構造は次のとおりです
'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...追加オプション)
VarName はリレーションシップの名前です。今後、この名前を使用して外部キー参照テーブルのフィールドにアクセスします。
RelationType は関係のタイプであり、設定が間違っている場合、Yii は合計 4 種類の関係を提供します。
BELONGS_TO (所属): テーブル A と B の関係が 1 対多の場合、テーブル B はテーブル A に属します
HAS_MANY (複数あり): テーブル A と B の関係が 1 対多の場合、A には複数の B があります
HAS_ONE (1 つあります): これは HAS_MANY の特殊なケースであり、A には B
が最大 1 つあります。
MANY_MANY: これはデータベース内の多対多の関係に対応します
ClassName は参照テーブル名であり、外部キーによって参照されるテーブルの名前であり、テーブル B
ForeignKey は外部キーの名前です。ここで主に入力するのは、メイン テーブルの外部キーの名前です。これは、テーブル A の外部キーのテーブル名です。間違った名前
テーブル B に二重の主キーがある場合、次の方法で実装できます。このアプローチは、各テーブルに独立した意味のない主キーを使用することが最善であり、そうしないとさまざまな問題が発生します。発生しやすく管理が不便になります
'categories'=>array(self::MANY_MANY, 'Category', 'tbl_post_category(post_id, category_id)'),
追加オプション 追加オプション、ほとんど使用されません
4 つのattributeLabels 関数 、これはテーブル属性の表示名で、powerdesigner のコードと名前の関係に少し似ています。最初の部分はデータベース フィールド名で、後者はデータベース フィールド名です。部分は表示名です
5 検索関数 は、テーブル クエリの結果を生成するために使用される関数です。ここでは、具体的な使用方法については説明しません。 API 。 Gii を使用して生成された場合、変更は必要ありません。
同様に、残りの 2 つの参照テーブルを生成します
関係タイプ テーブル: SocialRelationType.php
<?php /** * This is the model class for table "{{social_relation_type}}". * * The followings are the available columns in table '{{social_relation_type}}': * @property integer $relation_type_id * @property string $relation_type_name * * The followings are the available model relations: * @property SocialRelation[] $socialRelations */ class SocialRelationType extends CActiveRecord { /** * Returns the static model of the specified AR class. * @param string $className active record class name. * @return SocialRelationType the static model class */ public static function model($className=__CLASS__) { return parent::model($className); } /** * @return string the associated database table name */ public function tableName() { return '{{social_relation_type}}'; } /** * @return array validation rules for model attributes. */ public function rules() { // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( array('relation_type_name', 'length', 'max'=>10), // The following rule is used by search(). // Please remove those attributes that should not be searched. array('relation_type_id, relation_type_name', 'safe', 'on'=>'search'), ); } /** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'socialRelations' => array(self::HAS_MANY, 'SocialRelation', 'relation_type_id'), ); } /** * @return array customized attribute labels (name=>label) */ public function attributeLabels() { return array( 'relation_type_id' => 'Relation Type', 'relation_type_name' => 'Relation Type Name', ); } /** * Retrieves a list of models based on the current search/filter conditions. * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions. */ public function search() { // Warning: Please modify the following code to remove attributes that // should not be searched. $criteria=new CDbCriteria; $criteria->compare('relation_type_id',$this->relation_type_id); $criteria->compare('relation_type_name',$this->relation_type_name,true); return new CActiveDataProvider($this, array( 'criteria'=>$criteria, )); } }
ユーザーテーブル: AccessUser.php
<?php /** * This is the model class for table "{{access_user}}". * * The followings are the available columns in table '{{access_user}}': * @property integer $id * @property string $name * @property string $password * @property string $lastlogin * @property string $salt * @property string $email * @property integer $status * * The followings are the available model relations: * @property SocialRelation[] $socialRelations * @property SocialRelation[] $socialRelations1 */ class AccessUser extends CActiveRecord { /** * Returns the static model of the specified AR class. * @param string $className active record class name. * @return AccessUser the static model class */ public static function model($className=__CLASS__) { return parent::model($className); } /** * @return string the associated database table name */ public function tableName() { return '{{access_user}}'; } /** * @return array validation rules for model attributes. */ public function rules() { // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( array('status', 'numerical', 'integerOnly'=>true), array('name, password, salt, email', 'length', 'max'=>255), array('lastlogin', 'safe'), // The following rule is used by search(). // Please remove those attributes that should not be searched. array('id, name, password, lastlogin, salt, email, status', 'safe', 'on'=>'search'), ); } /** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'user_name' => array(self::HAS_MANY, 'SocialRelation', 'user_id'), 'anotherUser_name' => array(self::HAS_MANY, 'SocialRelation', 'another_user_id'), ); } /** * @return array customized attribute labels (name=>label) */ public function attributeLabels() { return array( 'id' => 'ID', 'name' => 'Name', 'password' => 'Password', 'lastlogin' => 'Lastlogin', 'salt' => 'Salt', 'email' => 'Email', 'status' => 'Status', ); } /** * Retrieves a list of models based on the current search/filter conditions. * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions. */ public function search() { // Warning: Please modify the following code to remove attributes that // should not be searched. $criteria=new CDbCriteria; $criteria->compare('id',$this->id); $criteria->compare('name',$this->name,true); $criteria->compare('password',$this->password,true); $criteria->compare('lastlogin',$this->lastlogin,true); $criteria->compare('salt',$this->salt,true); $criteria->compare('email',$this->email,true); $criteria->compare('status',$this->status); return new CActiveDataProvider($this, array( 'criteria'=>$criteria, )); } }
4. コントローラー
3 つのテーブルを導入した後、同様に、Gii を使用してメイン テーブル (テーブル A) の CRUD を生成し、コードにいくつかの変更を加えるだけです。以下の通り
SocialRelationController.php
<?php class SocialRelationController extends Controller { /** * @var string the default layout for the views. Defaults to '//layouts/column2', meaning * using two-column layout. See 'protected/views/layouts/column2.php'. */ public $layout='//layouts/column2'; /** * @return array action filters */ public function filters() { return array( 'accessControl', // perform access control for CRUD operations 'postOnly + delete', // we only allow deletion via POST request ); } /** * Specifies the access control rules. * This method is used by the 'accessControl' filter. * @return array access control rules */ public function accessRules() { return array( array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('index','view'), 'users'=>array('*'), ), array('allow', // allow authenticated user to perform 'create' and 'update' actions 'actions'=>array('create','update'), 'users'=>array('@'), ), array('allow', // allow admin user to perform 'admin' and 'delete' actions 'actions'=>array('admin','delete'), 'users'=>array('admin'), ), array('deny', // deny all users 'users'=>array('*'), ), ); } /** * Displays a particular model. * @param integer $id the ID of the model to be displayed */ public function actionView($id) { $this->render('view',array( 'model'=>$this->loadModel($id), )); } /** * Creates a new model. * If creation is successful, the browser will be redirected to the 'view' page. */ public function actionCreate() { $model=new SocialRelation; // Uncomment the following line if AJAX validation is needed // $this->performAjaxValidation($model); if(isset($_POST['SocialRelation'])) { $model->attributes=$_POST['SocialRelation']; if($model->save()) $this->redirect(array('view','id'=>$model->relation_id)); } $this->render('create',array( 'model'=>$model, )); } /** * Updates a particular model. * If update is successful, the browser will be redirected to the 'view' page. * @param integer $id the ID of the model to be updated */ public function actionUpdate($id) { $model=$this->loadModel($id); // Uncomment the following line if AJAX validation is needed // $this->performAjaxValidation($model); if(isset($_POST['SocialRelation'])) { $model->attributes=$_POST['SocialRelation']; if($model->save()) $this->redirect(array('view','id'=>$model->relation_id)); } $this->render('update',array( 'model'=>$model, )); } /** * Deletes a particular model. * If deletion is successful, the browser will be redirected to the 'admin' page. * @param integer $id the ID of the model to be deleted */ public function actionDelete($id) { $this->loadModel($id)->delete(); // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser if(!isset($_GET['ajax'])) $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin')); } /** * Lists all models. */ public function actionIndex() { if(Yii::app()->user->id != null){ $dataProvider=new CActiveDataProvider( 'SocialRelation', array('criteria'=>array('condition'=>'user_id='.Yii::app()->user->id, )) ); $this->render('index',array( 'dataProvider'=>$dataProvider, )); } } /** * Manages all models. */ public function actionAdmin() { $model=new SocialRelation('search'); $model->unsetAttributes(); // clear any default values if(isset($_GET['SocialRelation'])) $model->attributes=$_GET['SocialRelation']; $this->render('admin',array( 'model'=>$model, )); } /** * Returns the data model based on the primary key given in the GET variable. * If the data model is not found, an HTTP exception will be raised. * @param integer $id the ID of the model to be loaded * @return SocialRelation the loaded model * @throws CHttpException */ public function loadModel($id) { $model=SocialRelation::model()->findByPk($id); if($model===null) throw new CHttpException(404,'The requested page does not exist.'); return $model; } /** * Performs the AJAX validation. * @param SocialRelation $model the model to be validated */ protected function performAjaxValidation($model) { if(isset($_POST['ajax']) && $_POST['ajax']==='social-relation-form') { echo CActiveForm::validate($model); Yii::app()->end(); } } }
各関数と変数の簡単な紹介
$layout はレイアウト ファイルの場所です。レイアウト ファイルの使用方法についてはここでは説明しません
フィルターはフィルターを定義します、ここは水が深いです
accessRules アクセス メソッドは、これらのユーザーがこのモジュールにアクセスできることを意味します
array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('index','view'), 'users'=>array('*'), ),
allow 表示允许访问的规则如下,deny表示拒绝访问的规则如下。
action表示规定规则使用的动作
user表示规则适用的用户群组,*表示所有用户,@表示登录后的用户,admin表示管理员用户
actionXXX 各个action函数
这里值得注意的是 这个函数
public function actionIndex() { if(Yii::app()->user->id != null){ $dataProvider=new CActiveDataProvider( 'SocialRelation', array('criteria'=>array('condition'=>'user_id='.Yii::app()->user->id, )) ); $this->render('index',array( 'dataProvider'=>$dataProvider, )); } }
其中我们可以在dataProvider中设置相应的查询条件,注意这里设置是对于主表(A表)进行的,用的字段名也是主表中的,因为我们要显示的是当前用户的好友,于是,这里我们使用Yii::app()->user->id取得当前用户的id 。
loadModel 用于装载模型,这里我们可以看到findByPk查询了数据库。
performAjaxValidation 用于Ajax验证。
5、视图View
index.php
<?php /* @var $this SocialRelationController */ /* @var $dataProvider CActiveDataProvider */ $this->breadcrumbs=array( 'Social Relations', ); ?> <h1>Social Relations</h1> <?php $this->widget('zii.widgets.CListView', array( 'dataProvider'=>$dataProvider, 'itemView'=>'_view', )); ?>
我们使用一个 CListView控件进行显示,其中itemView为内容显示的具体表单,dataProvider这个是内容源,我们在controller中已经设定了。
_view.php
<?php /* @var $this SocialRelationController */ /* @var $data SocialRelation */ ?> <div class="view"> <b><?php echo CHtml::encode($data->getAttributeLabel('relation_id')); ?>:</b> <?php echo CHtml::link(CHtml::encode($data->relation_id), array('view', 'id'=>$data->relation_id)); ?> <br /> <b><?php echo CHtml::encode($data->getAttributeLabel('relation_type_id')); ?>:</b> <?php echo CHtml::encode($data->relation_type_id); ?> <br /> <b><?php echo CHtml::encode($data->getAttributeLabel('relation_type_name')); ?>:</b> <?php echo $data->relationType->relation_type_name; ?> <br /> <b><?php echo CHtml::encode($data->getAttributeLabel('user_id')); ?>:</b> <?php echo CHtml::encode($data->user_id); ?> <br /> <b><?php echo CHtml::encode($data->getAttributeLabel('user_name')); ?>:</b> <?php echo $data->user->name; ?> <br /> <b><?php echo CHtml::encode($data->getAttributeLabel('another_user_id')); ?>:</b> <?php echo CHtml::encode($data->another_user_id); ?> <br /> <b><?php echo CHtml::encode($data->getAttributeLabel('another_user_name')); ?>:</b> <?php echo $data->anotherUser->name; ?> <br /> </div>
主要都是类似的,我们看其中的一条
6、总结
通过上面的步骤,我们就实现了整个联合查询功能,效果图如下所示:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。