Yii 1.1: ztabularinputmanager

This class will help anyone that have to collect a tabular input
35 followers

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

Total 20 comments

#14614 report it
Xavier John at 2013/08/28 07:29pm
I have created a sample

I have created a demo at http://www.yiiframework.com/wiki/559/tabular-input-validating-and-saving-related-models/

#14596 report it
Xavier John at 2013/08/26 08:23pm
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?

#12765 report it
luisp88 at 2013/04/10 04:34pm
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

#11308 report it
zaccaria at 2013/01/05 04:00am
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.

#11306 report it
anilherath at 2013/01/05 12:33am
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.

#11303 report it
dastra at 2013/01/04 12:58pm
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"

#11287 report it
anilherath at 2013/01/03 02:19pm
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 ..............

//

#11179 report it
dastra at 2012/12/23 03:55pm
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

#8798 report it
Jimlam at 2012/06/27 09:26am
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:

  1. How to update the primary model (classroom) together with the students (actionUpdate of classroomcontroller)?
  2. How to delete the student records also when I delete the classroom?
  3. Students have a numeric attribute that I wish to add and retrieve in the view form (_form) of the classroom that is being edited/created.

I would really appreciate if you could help me. Thanks

#8797 report it
zaccaria at 2012/06/27 09:06am
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 
...
#8795 report it
Fran1978 at 2012/06/27 03:43am
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',
    ),
#8793 report it
Jimlam at 2012/06/27 02:14am
Where to place the file

@Zaccaria,

Can you please tell me where to place the tabularinputmanager.php?

#6853 report it
sagarneo11 at 2012/02/09 06:48am
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...

#5287 report it
Fran1978 at 2011/10/01 06:43am
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:

#4527 report it
business_hour at 2011/07/17 06:46am
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

#3857 report it
Athos at 2011/05/14 11:55am
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];
(...)
#3856 report it
zaccaria at 2011/05/14 11:05am
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... :)

#3851 report it
Athos at 2011/05/13 04:20pm
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?

#2826 report it
zaccaria at 2011/02/14 02:51pm
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)

#2824 report it
Athos at 2011/02/14 12:17pm
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?

Leave a comment

Please to leave your comment.

Create extension