Accessing _related objects from CDbCriteria result model

Greetings everyone.

I’ve been working with Yii for quite some time now (since 1.0.4 I believe) and needless to say it has been great working with the framework. However, I’ve hit a wall and I’m not quite sure how to surpass it. I wonder if there is a way to accomplish what I’m trying to do or even if there is a better solution… I’m currently running Yii version 1.1.1.

Short Version:

Is it possible to dynamically access the "_related" array from a given model from the result of a CDbCriteria?

Long Version:

My goal is to create an end user query builder that is accessible and easy to maintain. What I’ve created is a user interface in which the user can pick and choose which tables/columns they would like to query and the ability to add conditions to each column and export the results to a table. Here is an example of the structure I’m working with for reference.

[center][/center]

So, a given user can target their search towards Tenant’s (for example) and return all related records including information about the house, the rooms and its corresponding doors, windows, etc.

Currently, I’m using CDbCriteria to generate the criteria using the With property to access related records.

Note: The following code is merely example code, so its not 100% but I hope it conveys the idea I am using to accomplish my goal. Example if querying Tenants and returning related records:


$table_id="T"

$tableColumn="TABLE_COL";

$value="COL_VALUE";

$selectColumns=[array of User selected columns];


$criteria = new CDBCriteria;

$criteria->alias=$table_id;

$criteria->addColumnCondition(array($tableColumn=>$value));

$criteria->select=$selectColumns; 

For the relations, I’m using Yii’s approach. The relations are all setup in their corresponding models:


$relationArray["rel_clothes"]->$relationCriteria->toArray();

$relationArray["rel_house.rel_room"]->$relationCriteria->toArray();

$relationArray["rel_house.rel_room.rel_doors"]->$relationCriteria->toArray();

Each $realtionCriteria has its own set of CDbCriteria such as select, condition, params, with, etc. I simply add each of the $relationCriteria’s to the main $criteria as one big ‘with’.


$criteria->with=($relationArray);

And then I perform the search using findAll


$models=tenants::model()->findAll($criteria);

So far, so good. All of this appears to be working just fine. I can see the model with its chosen select column(s) and all applied condition criteria. My problem arises when I attempt to loop through the related array from the model ‘_related’ property.

Accessing the model attributes is fine.


foreach($models as $model)

  {

   $modelData=$model['attributes'];

    foreach($modelData as $data)

       {

          //write table code: works just fine.

       }

  }

The next line is where I am scratching my head:

PROBLEM:


$relations=$model['related'];

The idea here is to loop through all relations, and corresponding relations dynamically and to get its attributes and write information to the export table but I’m just not having any luck. Within the debugger, I can see the model structure as the following:


model

  _md

  _new

  _attributes  <-- accessing this works just fine.


  _related  <-- this is what I want to access (and all potential corresponding relations).

     [+][rel_house]  <-- object (want)

           _related

              [+][rel_room] <-- object? (want)

     [+][clothes]    <--array (want)


  _pk

  _errors

  _scenario

  _e

  _m

Things I’ve tried:


$relations=$model['related'];

RESULT: Missing argument 1 for CActiveRecord::getRelated(), called in \framework\base\CComponent.php on line 112 and defined</p>


$relations=$model['_related'];

RESULT: Property &quot;tenants._related&quot; is not defined.</p>


$relations=$model->getRelated('rel_house');

Works. Returns a model object and only works if I hard code the name of the object…


$relations=$model->getRelated('rel_clothes');

Also works. Again, I must hard code the name of the object. Reason unknown, but the ‘clothes’ relation returns as an array [0] with and object in the array and not just the object.

I hope this all makes sense and if there is some answer to this or even a better way to approach the original problem, I would be more than grateful for the insight.

Again, is it possible to access and loop the "_related" array dynamically from a given model from the result of a CDbCriteria?

Hi quess,

Have you tried?


$model->relations()

or


$model->metaData->relations

http://www.yiiframework.com/doc/api/CActiveRecord

Best regards,

schmunk

Hi schmunk,

Thanks for your suggestions, unfortunately I could not get it to return exactly what I was hoping for. I tried both solutions and here are the results.


$model->relations()

Returns string array of relationship information from the ‘relations’ section of the model class (I believe):


[-]rel_house

  [0] string - CBelongsToRelation

  [1] string - <table name>

  [2] string - <foreign_key>

[+]rel_room  


$model->metaData->relations

Returns an object array consisting of the following components. Again, it appears to be retrieving the information from the model class and not the related models already loaded into _related.


[-]rel_house

  [0] joinType => LEFT OUTER JOIN

  [1] on => 

  [2] with =>

  [3] name => rel_house

  [4] className => House

  [5] foreignKey => <key>

  [6] select => *

  [7] condition =>

  [8] params => 

  [9] group =>

  [10] having =>

  [11] order =>

[+]rel_room



Any other ideas I may have missed?

Best regards,

quess

What you may try is: Looping through the relations of the loaded model and check every relation.

Every relation which is not "NULL" should be there and accessible, but this is an untested solution.

It is likely the best solution at this point as it should work using $model->getRelated(). For some reason, I thought it would be possible to simply loop “_related” directly since its already loaded, but ah well that’s programming. Many thanks schmunk.

I also need to loop through the _related array, without hardcoding the relation name (even that didn’t work for me). What I did may be a dirty hack but it works exactly the way I want it to:

I went into CActiveRecord and changed the visibility of _related to public so now I can loop the array where I need to. It’s probably better practice so add a simple myGetRelations() to CActiveRecord to return the whole array so now did that instead. I hop you’re proud of me :D