I am new to Yii, now trying to use ActiveRecord to do my projects. Below is the 2 model generated by Yii shell from to MySQL linked table, Package and PackageDetail :
class Package extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'Package';
}
public function relations()
{
return array(
'packageDetails' => array(self::HAS_MANY, 'PackageDetail', 'packageId'),
);
}
..
..
}
class PackageDetail extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'PackageDetail';
}
public function relations()
{
return array(
'package' => array(self::BELONGS_TO, 'Package', 'packageId'),
);
}
..
..
}
I can find the record with package id 1, and want to read the colume data in the packageDetail
It works! Thank you for your kind advice. My ActiveRecord concept still bad, trying to make use to it… Previously use query directly… lots of dirty works when update and maintaining.
Can I ask you another question, related to the above situation.
When come to add new record, I am using the /protected/views/package/_form.php generated by Yii shell. I would like to allow user to add a new record (in my case a new Package), together with the package details (HAS_MANY).
Can you brief me what is the steps I need to take to make the modification?
Here is my steps (not yet try, just thinkning):
Modify the /protected/views/package/_form.php to add some html form elements for the pakcage details.
Modify the /protected/models/Package.php, but don’t what to do.
Modify the /protected/controllers/PackageController.php actionCreate(), actionUpdate() method, also has no idea…
other steps…
Can you please advice? I actually migrating my old php apps to yii, and time is rush…
Reference: (actually, 100% generated by Yii shell)
/protected/controllers/PackageController.php
public function actionCreate()
{
$model=new Package;
if(isset($_POST['Package']))
{
$model->attributes=$_POST['Package'];
if($model->save())
$this->redirect(array('show','id'=>$model->id));
}
$this->render('create',array('model'=>$model));
}
public function actionUpdate()
{
$model=$this->loadPackage();
if(isset($_POST['Package']))
{
$model->attributes=$_POST['Package'];
if($model->save())
$this->redirect(array('show','id'=>$model->id));
}
$this->render('update',array('model'=>$model));
}
If PackageDetail has proper safeAttributes, you probably don’t have to touch the models for this scenario.
Make sure that form displays all the details by iterating through them. Provide a way to add new detail at the end of the page (it is done by javascript most of the time).
In your create and update actions, process all the details creating a new model each time. (Don’t forget to set the foreign key unless you set it via hidden field.)
Yii give me error. Property "Package.detailName" is not defined.
Can you please advice? I guess I am asking to much question already… but I have not much time to figure out my self… find not enough documentation about all this…
public function actionCreate()
{
$model = new Package;
$modelPackageDetail = new PackageDetail; # Added by me
if(isset($_POST['Package']))
{
$model->attributes=$_POST['Package'];
# If the new package saved successfully, then save the package details
if($model->save()) {
$modelPackageDetail->attributes=$_POST['PackageDetail']; # Added by me
$modelPackageDetail->packageId = $model->id; # Added by me, get the autoincrement value
if($modelPackageDetail->save()) # Added by me
$this->redirect(array('show','id'=>$model->id));
}
}
# Modified, add the modelPackageDetail to pass to render
$this->render('create',array('model'=>$model, 'modelPackageDetail'=>$modelPackageDetail));
}
Now the package + packageDetail has been saved to db properly, going to add some transaction commit/rollback handling.
Is this the normal way to perform this kind of logic? Do you have any advice on this?
You may want to call validate() instead of save() on package, because if the details cannot be saved, then you have to rollback the changes you made to package. Of course, don’t forget to save all models, once you make sure they are valid.
detailName is probably a column of packageDetail, so you cannot reach it via Package. You should try as following:
foreach($model->packageDetails as $packageDetail)
This way you can pass $packageDetails and ‘detailName’ to CHtml to generate all details. Please reread my previous post if this is clear now.
Yes you are right, I not using the validate() which is need to, get many data inconsistency error if the input got problem, will update it!
Thank you for your kind comment and advice. I will try to digest all the advice that you given. This is the first time I move to Framework, has no framework concept before, Yii is my choice after reading around the net.
Currently found Yii really help a lots in the application development time. I do believe I help also in the application maintainance efforts.
You help me a lots, I am moving further now in my coding. I will post again in this forum if I really cannot found the solutions.
You are very welcome. I know it is hard to pick up the idea to use someone else’s work to speed up your own development time, but this is really worth it, and will eventually make you a better programmer, especially if you are self taught, like many others here.
My question is on massive assignment for dynamic generated html form elements.
The number of packageDetail for different package is different. At the add new package page, my application setup will need to define the number of packageDetail to show for every new package.
Let said I define 5 packageDetails for a new package.
When come to the "add new pacakge" view page, I should display 5 packageDetail html form to allow user to input.
Yes, I can hardcode the 5 set of packageDetails in the html form view. But the problem is, the value 5 is changeable by the user, the particular user might change the 5 to different value.
How can I dynamically solve this problem, by using ActiveRecord and massive assignment? I know it can be done by not using massive assignment (by reading the number of details and generate number of html form elements for each packageDetails), but there should have a better way…