This class is a master class for a Tabular input manager.
It has been tought to be used in scenarios where you have a one-to-many relationship.
The interface should present an interface for collect the data of the one, and zero, one or many rows for collect the many.
In the hypothesis that we have to insert a ClassRoom with many Students, we will create a StudentManager by extending Tabular input manager:
<?php
class StudentManager extends TabularInputManager
{
protected $class='Student';
public function getItems()
{
if (is_array($this->_items))
return ($this->_items);
else
return array(
'n0'=>new Student,
);
}
public function deleteOldItems($model, $itemsPk)
{
$criteria=new CDbCriteria;
$criteria->addNotInCondition('id', $itemsPk);
$criteria->addCondition("class_id= {$model->primaryKey}");
Student::model()->deleteAll($criteria);
}
public static function load($model)
{
$return= new StudentManager;
foreach ($model->students as $item)
$return->_items[$item->primaryKey]=$item;
return $return;
}
public function setUnsafeAttribute($item, $model)
{
$item->class_id=$model->primaryKey;
}
}
In this class we implement all methods needed for manage the primary keys of the students, for load the student of a class, for delete students.
The typical controller code for use this manager is:
[php]
/**
* Update a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model=new ClassRoom;
$studentManager=new studentManager();
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['ClassRoom']))
{
$model->attributes=$_POST['ClassR
Validate foreing key on Insert
Suppose the following relationship: a class has many students and a student belongs to a class.
The attribute "id classroom" (fk) in the student model is required and fails validation upon insertion.
How to work around this problem? Open a transaction and validate the student already knowing the id of the classroom?
vaildate fk
The foreign key field is not supposed to be validate.
You should remove this field from the required field list.
Before saving the students the function setUnsafeAttribute is called, in order to save the foreign key and other eventually values that are not collected from the user.
That's why the function save is called like that: $studentManager->save($model); we pass the main model to the manager for retrive the primary key value (and other eventually needed values)
deleteOldItems() before save()
To become more flexible, I suggest that the call to $ this->deleteOldItems($model, $itemOk) is made before calling the method $item->save()
As it is I can not let delete all records and then do the insert.
I'm having trouble programming the method deleteOldItems() with a table that has composite primary key. Has anyone done this and can help me, please?
re: deleteOldItems() before save()
This component has not been tought for work with composite primary key, you can simply add a foreign key autoincrement and solve all your problem.
The deleteOldItems has been created for avoid to delete and recreate the records each times. If you want to enhance, you should save all the composite primary keys in an array during the save(), then in the delete old items you should create a query that deletes all items but the just saved.
In a word: add the primary key autoincrement and solve all your problems... :)
I solved the problem with composite key
The table in question is a pivot for the relationship MANY_MANY. Therefore would not add a primary key autoincrement.
This issue was discussed this topic: http://www.yiiframework.com/forum/index.php?/topic/18275-relation-many-many-with-info-column-in-relation-table
With a small change in the code I solved the problem of working with composite primary keys.
(...) // if the code is like 'nxxx' is a new record if (substr($i, 0, 1)=='n') { // create of new record $item=new $classname(); // rember of the last one code $this->_lastNew=substr($i, 1); } else // load from db { $pk = $i; $model = CActiveRecord::model($this->class); if (is_array($model->primaryKey)) { $pk = array(); foreach(array_keys($model->primaryKey) as $key) { $pk[$key] = $item_post[$key]; } } $item=$model->findByPk($pk); } $this->_items[$i]=$item; if(isset($data[$i])) $item->attributes=$data[$i]; (...)
ztabularinputmanager doesn't work in php5.3
ztabularinputmanager doesn't work in php5.3,php error:"Static function TabularInputManager::load() should not be abstract".Anyone can help me,please?Thanks
Static function TabularInputManager::load() should not be abstract
In TabularInputManager class definition, last method is:
public abstract static function load($model);
I got the error:"Static function TabularInputManager::load() should not be abstract".
I took out "static" from load method definition and now it works perfectly. I left it like this:
public abstract function load($model);
I think that abstract static class methods are not allowed any more.
You can see an explanation in this link:
it can be more Helpful
Hi... First Of all thanks for g8 extension and tutorial... but i would like to say one thing here that it will be so much helpful to users if you add information like in which file u have to add this code or if u need to create new file then where...? it will be so much helpful to users who are bigginer and dont know much about yii classes... share the knowledge it can help others...
Where to place the file
@Zaccaria,
Can you please tell me where to place the tabularinputmanager.php?
Where to place the file
Hello Bianca,
I am just a user of ztabularinputmanager.php, but I think I can help you.
I have placed this file in the folowing path:
my_application\protected\extensions\
Then, in the main configuration file (my_application\protected\config\main.php), I have added the TabularInputManager extension to the 'import' array:
'import' => array( 'application.models.*', 'application.components.*', 'application.extensions.TabularInputManager', ),
Where to place the file
Blanca is right, you can place the file wherever you want, just include when you use it.
As it is supposed to be a masterclass, you can avoid to add it to the global imports and simplty include when needed:
<?php Yii::import('application.extensions.TabularInputManager'); class StudentManager extends TabularInputManager ...
Thanks fran1978 & Zaccaria
Thank you both fran1978 & Zaccaria.
Zaccaria, this is a marvellous extension. I have been digging my mind and tried several things which were not to my satisfaction.
Thank you very much. I tried it and it works when I create the primary model (classroom in the example that Zaccaria gave). I would like to do some additional operations and am trying with some difficulty because I am new to PHP and newer to Yii. I am trying to understand the code but there are some parts that are not too clear. If you can spare some time, could you please guide me to do the following:
I would really appreciate if you could help me. Thanks
Updated extension
I have updated the extension and added the enhancements described in http://www.yiiframework.com/extension/ztabularinputmanager#c3857, http://www.yiiframework.com/extension/ztabularinputmanager#c5287
I have also resurrected the code examples from above, and updated the documentation.
You can find it all on github: https://github.com/dastra/yii-ztabularinputmanager
Fatal Errore
Hi,
I tried to implement this solution as exact as you explained. But I am receiving the error;
//
Fatal error: Cannot make non static method TabularInputManager::load() static in class FamilyManager in ..............
//
re:Fatal Errore
@anilherath - there was an error in the documentation - it's now been corrected.
The StudentManager should have the following load function:
/** * Create a new TabularInputManager and loads the current child items * @param $model ClassRoom - the parent model * @return TabularInputManager the newly created TabularInputManager object */ public function load($model) { $return = new StudentManager; foreach($model->students as $item) $return->_items[$item->primaryKey]=$item; return $return; }
with no "static"
Re: Fatal Error
Dear Dastra,
Thanks for the reply. But I followed the provided codes in GITHUB which contain the loadmodel function.
In my scenario I have Children and their Families. And this is my family manager:
<?php yii::import('application.extensions.TabularInputManager'); class FamilyManager extends TabularInputManager { protected $class='Family'; /** * Retrieve the list of Familys * @return array of Family objects */ /** * Create a new TabularInputManager and loads the current child items * @param $model ClassRoom - the parent model * @return TabularInputManager the newly created TabularInputManager object */ public function load($model) { $return = new FamilyManager; foreach($model->families as $item) $return->_items[$item->primaryKey]=$item; return $return; } public function getItems() { if (is_array($this->_items)) return $this->_items; else { return array( 'n0' => new Family, ); } } /** * Deletes the uneeded Familys * @param $model ClassRoom - the parent model * @param $itemsPk array - an array of the primary keys of the child models which we want to keep */ public function deleteOldItems($model, $itemsPk) { $criteria = new CDbCriteria; $criteria->addNotInCondition('id', $itemsPk); //Family has a attribute classroom_id: indicates which classroom s/he is in. $criteria->addCondition("children_id = {$model->primaryKey}"); Family::model()->deleteAll($criteria); } /** * Create a new TabularInputManager and loads the current child items * @param $model ClassRoom - the parent model * @return TabularInputManager the newly created TabularInputManager object */ /** * Set the unsafe attributes for the child items, usually the primary key of the parent model * @param $item Family - the child item * @param $model ClassRoom - the parent model */ public function setUnsafeAttribute($item, $model) { $item->children_id = $model->primaryKey; } } ?>
My php version is 5.2 and I am using GIIx generated models and CRUD s.
Re: Fatal Error
Hi anilherath.
My php config didn't raise the exception you got, so I never experienced this error.
My suggestion is to make static the load function by adding "static":
public static function load($model)
In the example is now correct, I am pretty sure that you copied some old example without the static declaration.
Manager doesnt load or something
It seems to be an excellent extension, but sadly I cant get it ot work. I am having a problem just at the moment of creating the Manager
$students = new StudentManager();
Not a thing is showed (blank page).
And the last line of debugging doesnt show anything related (15:56:31.702699 profile system.db.CDbCommand.query
end:system.db.CDbCommand.query(SHOW CREATE TABLE
examen_caso
))Any idea?
Really need quickly help luis_alejandrop@hotmail.com thanks in advanced
Is there a git sample for this?
Is there a git sample for this?
I looked at https://github.com/dastra/yii-ztabularinputmanager and it seems partial. What is the contents of _formDetail?
I have created a sample
I have created a demo at
http://www.yiiframework.com/wiki/559/tabular-input-validating-and-saving-related-models/
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.