[Solved] Get data from indirectly related model

Hey,

I try to populate a grid view, but do not manage to get data from an indirectly related table.

Table structure:

investment (top level data)

  • share (one module of my data structure and central access point for all data within this section)

    • shareSub (additional data e.g. the share’s name)

The table (in investment/admin):




$this->widget('zii.widgets.grid.CGridView', array(

	'dataProvider'=>$model->search(),

	'columns'=>array(

		'ID',

		array(

		    'value'=>'$data->share->name',

		),

	),

));



(the getter to attribute "trick" used above is implemented)

In the Share model I want to use a getter to return ‘name’ from a sub-table ShareSub.




public function getName()

{

   $this->_name="abc";

   return $this->_name;

}



So, “abc” works, but I have no clue how to get the appropriate ‘name’ value for the ‘investment’ from the ShareSub table.




$this->_name=Share::model()->sharesub->name;



… doesn’t work

To pass the investmentID and findAllByAttributes(array(‘share.investment.ID’=>’$investmentID’)) didn’t work either.

All necessary relations are defined in the models.

cheers

Steffen

Hey everyone,

sorry for bothering you again with this post, but I’m still struggeling with the getter.

Any hint is highly appreciated. (Also, if you would suggest a completely different approach)

Thank you very much in advance.

cheers

Steffen

Background info on the concept:

Besides Share there’re/will be hopefully many other investment types/data structures which I try to address in a unified way: <type> -> <field name> e.g. Share->name. So, I cannot hard code in the investment view investment->share->sharesub->name as I would do it with standard related ARs.

Can you describe how the models are related? Showing the relations() of each model would help.

thank you for having an eye on it.

the relations:

model/investment.php




'share'=>array(self::HAS_ONE, 'Share', 'investmentID'),



model/share.php




'investment'=>array(self::BELONGS_TO, 'Investment', 'investmentID'),

'sharesub'=>array(self::BELONGS_TO, 'ShareSub', 'shareSubID'),



Hmm, frankly speaking i don’t really understand the relation model. But from your relations, why can’t you do:




$data->share->sharesub->name;



Maybe this helps: Try to find out, which SQL you need to get the data for the datagrid. The SQL should create a compact result set where each row corresponds to a single row in the datagrid. If you can find this SQL, show it here, then we can maybe translate it back to AR.

yep, this was also my first approach until I recognized that the way how I access the var must be more generic.

central problem: there are different data structures for various types of shares, public pension, statutory pensions, …

I tried to explain it above:

put it the other way round, in a central investment overview using the suggested rAR I could not generate mixed type list. So, I would have to list one with a certain -> -> structure, then type 2 with its own -> -> rAR structure and so on.

Now, I wanted t get rid of this restriction by accessing any major attribute e.g. name of an investment by <function that gets the investmentID and returns the appropriate model> -> name (like share->name or pension->name). This way I could structure the data according to the specific needs of the investment type without having to think about its accessability.

Hope, I could somehow explain, what I’m trying to achieve.

Does that make any sense?

I guess i don’t get it. You want mixed types of data (or related data) somehow displayed in a single table? How should that be displayed? Not to mention how to handle e.g. sorting, paging, filtering…

ok, the view is pretty simple.

e.g.




ID | type      | name            | current value

1    share       BMW                   1000.00

2    insurance   Contract XYZ          1000.00



the same "under the hood"




ID   | type          | name                | current value

$id    getType($id)    getType($id)->name      getType($id)->currentValue



a unified way to access values which could also be written as

name

1: $data->share->sharesub->name

2: $data->insurance->name

current value

1: $data->share->currentValue (function which gives back the amount of shares x current value)

2: $data->insurance->insuranceOption->insuranceOptionCurrent->value (which is an amount accumulated over time)

So, simple view yet comprised of different investment types and data from completely different locations.

In my eyes, this results in a generic approach outlined above which relies on getter functions in the main models of each type.

Thank you very much for your effort!!

Like i said: If you want to do this, you’ll end up with (at least) one other subquery per rendered row in your grid, since the related types are not homogeneous and can’t be fetched with a single query. This will at least make problems with e.g. sorting by type.

Sorry that i can’t help you much further on this. Maybe someone else has an idea. My guess is, you’ll have to reconsider your DB layout, but i might be wrong since i had no time to think it through completely (which is your job after all ;) ).

Anyway, thank you for your input. At least I know it is for some serious reason that I was struggeling B)

I guess, I’ll continue with the modules first and postpone this issue until I (or someone else) get THE idea.

What do you mean about indirectly related table?

How do you get the data? What is the point in common? How do you specify the criteria to get the info from another model?




'sharesub'=>array(self::BELONGS_TO, 'ShareSub', 'shareSubID')



Means that share sub is also related to share right?

Then if investment is related to share and share related to subshare what is the big deal?

Please accept my apologies if I mistaken but I think is quite confusing.

:D So far, it looks like that the puzzle is solved.

Here is the code:

views/investment/admin.php




$this->widget('zii.widgets.grid.CGridView', array(

        'dataProvider'=>$model->search(),

        'columns'=>array(

                'ID',

                array(

                    'value'=>'eval("echo ".stripslashes($data->getName($data->typeID)).";")',

                ),

        ),

));



models/Investment.php




public function getName($_typeID)

	{

		$hInvestmentType=array('ID1'=>array('lcase'=>"share", 'ucase'=>"Share")); // will be moved to separate function and filled from db

		$this->_field=$hInvestmentType["ID".$_typeID]['ucase']::model()->name;

		return $this->_field;

	}



models/Share.php




	public function getName()

	{

		$this->_name="\$data->share->sharesub->name";

		return $this->_name;

	}




principle of operation:

View calls function in investment model and passes the typeID. There the request is routed to the appropriate model according to the investment type. Within the type-specific model the string is replaced by the actual location of the data. Back to the view the final rAR string is eval’d.

Performance is probably not ready for a real productive application (but for me it’s enough)

Thanks to everyone having thought about this issue.

Congrats… that solution is close to that provided in Yii cookbook creating blog (page 30 Lookup model) - maybe having a look at it could improve the performance :)

I didn’t understood your question before…

I have the same issue as you mentioned please tell me solution.