Mvc Question For Complex Actions

Hi,

Pretty new to Yii and MVC so still trying to get my head around it. Have been using gii to generate CRUD so I can see whats happening and have models and controllers for all my tables. Now I have everything working but I really want to structure this properly so not sure how to go about it.

For example, the application I am writing is for sporting organizations to record match results in. A player in the system can be a member of many organizations at the same time so I have the following structure

Person - a persons record containing name, address etc. A person does not have a parent although it is "connected" to a single organization who is responsible for updating the information for the person.

OrgYearPerson - an unique instance of a person in a particular organisation in a particular year

CompPerson - an unique instance of a person in a particular Comp (a comp exists within an organization and year

CompTeamPerson - an unique instance of a person in a Team within a comp. a person can be on multiple teams (ie floating reserve player)

There is full database integrity (relationships) between all the above 4 tables.

This structure works perfectly so there are no issues there. I just need some clarity around a scenario:

So, when someone is adding a player to a team they select a player from the "person" table (via an autocomplete field), or if the person is not found a new one is created. Then the OrgYearPerson record needs to be either found or created, then the CompPerson record needs to be found or created, then finally, the CompTeamPerson record can be created.

In my Compteamperson controller, the actionAdmin displays a page where a user can select players existing in the application or enter names for new players to be created then added to the team.

From actionAdmin I call a protected function called "createCompteamperson" in the same Controller. This function then calls 3 more protected functions in the same controller called "createPerson", "createOrgyearPerson" and "createCompperson".

So as I stated, all works perfectly well, but now I need to call these any or all of "createPerson", "createOrgyearPerson" and "createCompperson" functions from another controller. I understand that its not ideal to be calling functions across controllers so I would like some advice on how I should be structuring these functions so that they are accessible from anywhere.

Is the logical place to put these in their own models? or should I have some sort of separate library? and if so, what would this look like and where does it sit?

Any advice would be greatly appreciated. Learning all the time and absolutely loving Yii.

Here is the code:




	public function actionAdmin($id = null)

	{

		$model=new XrefCompteamperson('search');

		$model->unsetAttributes();  // clear any default values

                

		if(isset($_POST['AddPerson']))

                { 

                    $this->createCompteamperson($_POST['AddPerson'], $id);

                    

                }   // end of save block

                else {

//                $model->attributes=$_GET['XrefCompteamperson'];


                }

                $model->compteamid = $id;

                

		$this->render('admin',array(

			'model'=>$model,

		));

                

        }

        

        protected function createCompteamperson($addp, $id) {

            

//                    $addp = $_POST['AddPerson'];

                    

            $compteam = XrefCompteam::model()->findByPK($id);


            $trans = $compteam->dbConnection->beginTransaction();


            try {


                // get the form values

                $personid = $addp['getpersonid'];

                $pname = $addp['getperson'];

                $orgid = $addp['ownerorgid'];

                $rank = $addp['ranking'];

                $float = (isset($addp['floating']) ? $float = $addp['floating'] : 0);


                // STEP 1: create the Person record

                $person = $this->createPerson($personid, $pname, $orgid);


                // STEP 2: create the Xref_Person record

                //need person id and xref_orgyear id

                $oyperson = $this->createOrgyearPerson($person->id, $compteam->comp->orgyear->id);

                

                // STEP 3: create the Xref_Compperson record

                $compperson = $this->createCompperson($oyperson->id, $compteam->compid, $rank);

                

                // STEP 4: create the Xref_Compteamperson record

                $ctperson = XrefCompteamperson::model()->find('compteamid=:id1 AND comppersonid=:id2', array(':id1'=>$id, ':id2'=>$compperson->id));

                        

                if(!$ctperson)

                {

                    $ctperson = new XrefCompteamperson();


                    $ctperson->compteamid = $id;

                    $ctperson->comppersonid = $compperson->id;

                    $ctperson->personid = $person->id;              // stored here to save trawling up the tree to get a persons details

                    $ctperson->floating = $float;


                    $ctperson->save();

                    

                }            

             

                $trans->commit();

                

                return true;

                

            } 

            catch (Exception $ex) {

                $trans->rollback();

                return false;

                

            }

                    

        }

        

        protected function createPerson($pid, $pname, $orgid) {

            

            $pparts = explode(' ', trim($pname));


            if($pid < 0)

            {

                //person is new

                $person = new Person();


                $person->firstname = $pparts[0];

                $sname = '';

                for($i=1; $i<count($pparts); $i++)

                {

                    $sname .= $pparts[$i].' ';

                }

                $person->surname = trim($sname);

                $person->ownerorgid = $orgid;


                $person->addressid = 0;

                $person->statusid = 1;


                $person->save();

            }

            else

            {

                $person = Person::model()->findByPK($pid);

            }

            

            return $person;

            

        }


        protected function createOrgyearPerson($personid, $oyid)

        {

            $oyperson = XrefPerson::model()->find('orgyearid=:id1 AND personid=:id2', array(':id1'=>$oyid, ':id2'=>$personid));


            if(!$oyperson)

            {

                $oyperson = new Xrefperson();


                $oyperson->personid = $personid;

                $oyperson->orgyearid = $oyid;

                $oyperson->default = 0;


                $oyperson->save();

            }

            

            return $oyperson;

        }

                

        protected function createCompPerson($oypersonid, $compid, $rank)

        {

            $compperson = XrefCompperson::model()->find('personorgyearid=:id1 AND compid=:id2', array(':id1'=>$oypersonid, ':id2'=>$compid));


            if(!$compperson)

            {

                $compperson = new XrefCompperson();


                $compperson->personorgyearid = $oypersonid;

                $compperson->ranking = $rank;

                $compperson->compid = $compid;


                $compperson->save();

            }            

            return $compperson;

        }



Cheers

Greg J

Just some random thoughts to maybe help out.

  1. you indicated that the various createXXX() function are protected. They can’t be used by other classes, unless inheritance is involved.

  2. For MVC: It is my belief that ALL interaction with the database should be in Model. The controller just instantiates the model classes, not talking to the database.

  3. Isn’t the same logic for creating the various records the same whether called directly throw the model or called from a different controller/model?

So I would make the various creates in there respective models, make them public, then call from wherever.

Hi jkofsky,

thanks for your input. I guess the issue with these particular functions are that at the point of calling them, its unknown whether the record exists or not. My initial thoughts were to put it in the actual model for each table so do I need to instantiate a new model then call the function from that?




$model = new XrefPerson();

$model->createOrgyearPerson($personid, $oyid);



If I do this, the model is set as ‘new’ when I am in the function.

or do I call it this way…




$model = XrefPerson::model();

$model->createOrgyearPerson($personid, $oyid);



So does this instantiate a new model too?

Someone else (a friend of mine) suggested creating a site-wide static function, like a Library, as a component so I would call it this way…




$model = LibPerson::createOrgyearPerson($personid, $oyid);



This last option seems pretty clean but Im wanting to structure the data properly in case I need to bring others onto the project, I want them to be able to work out what ive done.

cheers

Greg J

Since createOrgyearPerson() returns a model then this would work:


$model = LibPerson::model()->createOrgyearPerson($personid, $oyid);

Then $model->isNewRecord will be true/false depending on what is returned.