Yii 为什么重复条目不显示错误?

Yii 为什么重复条目不显示错误?,yii,Yii,当我试图在表格输入表单上保存重复条目时。。Yii不会通知用户存在重复条目错误,并且重复条目未存储在数据库中 售票员 <?php class BookingController extends Controller { /** * @var string the default layout for the views. Defaults to '//layouts/column2', meaning * using two-column layout. See 'protected/

当我试图在表格输入表单上保存重复条目时。。Yii不会通知用户存在重复条目错误,并且重复条目未存储在数据库中

售票员

<?php

class BookingController 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', 'display'),
            '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),
    ));
}


    public function getItemsToUpdate($id){
        // create an empty list of records
        $items = array();

            // Iterate over each item from the submitted form                        
            if (isset($_POST['BookingRoom']) && is_array($_POST['BookingRoom'])) {  

                foreach ($_POST['BookingRoom'] as $item) {                        


                     // If item id is available, read the record from database 
                    if ((  array_key_exists('roomId', $item) ) && ( array_key_exists('startDate', $item) && array_key_exists('endDate', $item) )){

                        //$items[] = BookingRoom::model()->findByPk($item['bookingId']);
                    //$items[] = BookingRoom::model()->find('bookingId=:bookingId', array(':bookingId'=>$id));                            
                      if ((($item['roomId'] != NULL)  && ($item['roomId'] > 0 )) && (($item['startDate'] != NULL) && ($item['startDate'] > 0)) && 
                          (($item['endDate'] != NULL) && ($item['endDate'] > 0))){                                   


                          $item['bookingId'] = $id;



                            $BookingRoom = BookingRoom::model()->findByAttributes(array('roomId' => $item['roomId'], 'bookingId' => $id, 'startDate' => $item['startDate'], 'endDate' => $item['endDate']));



                            if (is_object($BookingRoom)){
                            $items[] = BookingRoom::model()->findByAttributes(array('roomId' => $item['roomId'], 'bookingId' => $id, 'startDate' => $item['startDate'], 'endDate' => $item['endDate']));
                            } else if (array_key_exists('bookingId', $item)){
                              $itemNew = new BookingRoom();
                              $itemNew->attributes = $item;
                              $items[] = $itemNew;
                            } else {
                              // delete requires command
                              //$whosloggedin=Whosloggedin::model()->find('username=:username',array(':username'=>$users->username) ); 
                              //$whosloggedin->delete();

                            }



                      } else {
                        $itemNew = new BookingRoom();
                        $itemNew->attributes = $item;
                        $items[] = $itemNew;
                    }
                    // Otherwise create a new record
                    } else {

                        //$items[] = new BookingRoom();
                    }
            }

                    } 
             else {

                $items = BookingRoom::model()->findAll('bookingId=:bookingId', array(':bookingId'=>$id));

            } 
            return $items;                     
    }



    public function sayHello(){
        //$model=new Page;

          echo "Hello World!";
        //Yii::app()->end();

    }
// Rest of the action.


/**
 * Creates a new model.
 * If creation is successful, the browser will be redirected to the 'view' page.
 */
public function actionCreate()
{

    $model=new Booking;
            //$BookingRoom=new BookingRoom;
            //$items=$this->getItemsToUpdate();

            if (isset($_POST['Booking'])){
            $model->attributes=$_POST['Booking'];
            }
            //var_dump($items);
    // Uncomment the following line if AJAX validation is needed
     //$this->performAjaxValidation($model,$items);                                                                              


            if(isset($_POST['BookingRoom']))
              {

                $valid=true;
                foreach($items as $i=>$item)
                {
                    if(isset($_POST['BookingRoom'][$i]))
                    $item->attributes=$_POST['BookingRoom'][$i];
                    $valid=$item->validate() && $valid;
                }

                $valid=$model->validate() && $valid;


                if($valid){

                }                                                                          
              }


    $this->render('create',
                    array('items'=>$items, '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)
{
    $baseUrl = Yii::app()->baseUrl; 
            $cs = Yii::app()->getClientScript();
            $cs->registerScriptFile($baseUrl.'/js/functions.js');

// first time round
        if (!isset($_POST['Booking'])) {
            $model=$this->loadModel($id);
        } else {

          $model = $this->loadModel($id);
          $model->attributes=$_POST['Booking'];              
          //$model->update();
        }



            $items = array();

    // Uncomment the following line if AJAX validation is needed
     //$this->performAjaxValidation($model, $items);                                                                              

             $items=$this->getItemsToUpdate($id);


            if(isset($_POST['BookingRoom']))
              {

                $valid=true;

                foreach($items as $i=>$item)
                {                         

                    if(isset($_POST['BookingRoom'][$i]))
                    $item->attributes=$_POST['BookingRoom'][$i];
                    //var_dump($item->attributes);
                    $valid=$item->validate() && $valid;


                }                    

                $valid=$model->validate() && $valid;


                if($valid){                                                    
                    $model->save(false);
                    foreach($items as $i=>$item)
                    {          
                          //$valid=$item->validate() && $valid;
                        if ($item->attributes){

                            try {
                            if($item->save(false)){}
// $this->redirect(array('view','id'=>$model->ID));
                            }
                            catch(CDbException $e) {
                                    $model->addError(null, $e->getMessage());
                            }

                        }
                    }                            
                }                                                                         
              }

    $this->render('update', array('model'=>$model, 'items'=>$items));

}

/**
 * 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'));
}

    public function actionDisplay()
{
    $dataProvider=new CActiveDataProvider('Booking');
    $this->render('index',array(
        'dataProvider'=>$dataProvider,
    ));
}

/**
  * Lists all models.
 */
public function actionIndex()
{
    $dataProvider=new CActiveDataProvider('Booking');
    $this->render('index',array(
        'dataProvider'=>$dataProvider,
    ));
}

/**
 * Manages all models.
 */
public function actionAdmin()
{
    $model=new Booking('search');
    $model->unsetAttributes();  // clear any default values
    if(isset($_GET['Booking']))
        $model->attributes=$_GET['Booking'];

    $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 Booking the loaded model
 * @throws CHttpException
 */
public function loadModel($id)
{                        
    $model=Booking::model()->findByPk($id);
            /*
            $criteria=new CDbCriteria;
            $criteria->condition='bookingId=:bookingId';
            $criteria->select = 'roomId';
            $criteria->params=array(':bookingId'=>$_GET['id']);
            $bookingRooms = BookingRoom::model()->findAll($criteria);

            $rooms = array();
            foreach ($bookingRooms as $room) {
                $rooms[] = $room->roomId;
            }

            $model->rooms = $rooms;
            */
    if($model===null) {
        throw new CHttpException(404,'The requested page does not exist.');
            }
    return $model;




}

/**
 * Performs the AJAX validation.
 * @param Booking $model the model to be validated
 */
protected function performAjaxValidation($model)
{
    if(isset($_POST['ajax']) && $_POST['ajax']==='booking-form')
    {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
}


}
房间模型

/**
 * This is the model class for table "bookingRoom".
 *
 * The followings are the available columns in table 'bookingRoom':
 * @property integer $roomId
 * @property integer $bookingId
 * @property string $startDate
 * @property string $endDate
 * @property integer $adults
 * @property integer $children
 */
class BookingRoom extends CActiveRecord
{
/**
 * @return string the associated database table name
 */
public function tableName()
{
    return 'bookingRoom';
}

/**
 * @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('roomId, bookingId, startDate, endDate, adults', 'required'),
        array('roomId, bookingId, adults, children', 'numerical', 'integerOnly'=>true),
        // The following rule is used by search().
        // @todo Please remove those attributes that should not be searched.
        array('roomId, bookingId, startDate, endDate, adults', 'safe', 'on'=>'search'),
                array('startDate, endDate', 'type', 'type' => 'date', 'message' => '{attribute}: is not a date!', 'dateFormat' => 'yyyy-MM-dd')
    );
}

/**
 * @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(   
                //'booking' => array(self::BELONGS_TO, 'Booking', 'bookingId'),
                //'room' => array(self::BELONGS_TO, 'Room', 'roomId'),
    );
}

/**
 * @return array customized attribute labels (name=>label)
 */
public function attributeLabels()
{
    return array(
        'roomId' => 'Room No',
        'bookingId' => 'Booking',
        'startDate' => 'Start Date',
        'endDate' => 'End Date',
        'adults' => 'Adults',
        'children' => 'Children',
    );
}

/**
 * Retrieves a list of models based on the current search/filter conditions.
 *
 * Typical usecase:
 * - Initialize the model fields with values from filter form.
 * - Execute this method to get CActiveDataProvider instance which will filter
 * models according to data in model fields.
 * - Pass data provider to CGridView, CListView or any similar widget.
 *
 * @return CActiveDataProvider the data provider that can return the models
 * based on the search/filter conditions.
 */
public function search()
{
    // @todo Please modify the following code to remove attributes that should not be searched.

    $criteria=new CDbCriteria;

    $criteria->compare('roomId',$this->roomId);
    $criteria->compare('bookingId',$this->bookingId);
    $criteria->compare('startDate',$this->startDate,true);
    $criteria->compare('endDate',$this->endDate,true);
    $criteria->compare('adults',$this->adults);
    $criteria->compare('children',$this->children);

    return new CActiveDataProvider($this, array(
        'criteria'=>$criteria,
    ));
}

/**
 * Returns the static model of the specified AR class.
 * Please note that you should have this exact method in all your CActiveRecord descendants!
 * @param string $className active record class name.
 * @return BookingRoom the static model class
 */
public static function model($className=__CLASS__)
{
    return parent::model($className);
}
/*
public function primaryKey()
{
    return array('roomId', 'bookingId', 'startDate', 'endDate');
}*/
}
<?php

/**
 * This is the model class for table "room".
 *
 * The followings are the available columns in table 'room':
 * @property integer $id
 * @property integer $beds
 */
class Room extends CActiveRecord
{
/**
 * @return string the associated database table name
 */
public function tableName()
{
    return 'room';
}

/**
 * @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('id, beds', 'required'),
        array('id, beds', 'numerical', 'integerOnly'=>true),
        // The following rule is used by search().
        // @todo Please remove those attributes that should not be searched.
        array('id, beds', '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(
               //'bookingrooms' => array(self::HAS_MANY, 'BookingRoom', 'roomId'),
                'bookings' => array(self::MANY_MANY, 'Booking','bookingroom(roomId, bookingId, startDate, endDate)'),
    );
}

/**
 * @return array customized attribute labels (name=>label)
 */
public function attributeLabels()
{
    return array(
        'id' => 'ID',
        'beds' => 'Beds',
    );
}

/**
 * Retrieves a list of models based on the current search/filter conditions.
 *
 * Typical usecase:
 * - Initialize the model fields with values from filter form.
 * - Execute this method to get CActiveDataProvider instance which will filter
 * models according to data in model fields.
 * - Pass data provider to CGridView, CListView or any similar widget.
 *
 * @return CActiveDataProvider the data provider that can return the models
 * based on the search/filter conditions.
 */
public function search()
{
    // @todo Please modify the following code to remove attributes that should not be searched.

    $criteria=new CDbCriteria;

    $criteria->compare('id',$this->id);
    $criteria->compare('beds',$this->beds);

    return new CActiveDataProvider($this, array(
        'criteria'=>$criteria,
    ));
}

/**
 * Returns the static model of the specified AR class.
 * Please note that you should have this exact method in all your CActiveRecord descendants!
 * @param string $className active record class name.
 * @return Room the static model class
 */
public static function model($className=__CLASS__)
{
    return parent::model($className);
}
}
问题在于:

try {
    if($item->save(false)){}
    // $this->redirect(array('view','id'=>$model->ID));
}
catch(CDbException $e) {
    $model->addError(null, $e->getMessage());
}
您需要在视图中显示错误

// Controller
$model->addError('unknownError', $e->getMessage());

// View
CHtml::error($model, 'unknownError');

你确定吗?你能把控制器和模型放在一起吗;我已经上传了控制器和模型。
// Controller
$model->addError('unknownError', $e->getMessage());

// View
CHtml::error($model, 'unknownError');