I’ve been digging through the Wiki, but can’t figure this out. Hopefully it’s simple and I’m just missing it!
Let’s say I have an ActiveRecord model that has the column $tenant_id. I create a relation like so:
public function getTenant()
{
return $this->hasOne(\common\models\User::className(), ['id' => 'tenant_id']);
}
Easy enough. But in some other code I want to be able to look at any random ActiveRecord model and say “is this property represented by a relation?” Basically, I want to know if I can call a method for the property, but I don’t know the method name.
So for the example above, I may have other code that gets the model and sees $model->tenant_id. If it can determine if tenant_id can be grabbed using $model->getTenant(), it should do that (basically, to grab $model->tenant->name), but otherwise it would just print $model->tenant_id.
How do I know if tenant_id is accessible via a relation and, if so, the method name for that without knowing the details of the class itself?
I’m a little curious why you want to know it. I never have wondered if a certain ActiveRecord model has a related ActiveRecord model in terms of a relation (tenant in your example), or just a foreign key (tenant_id) to it. Because I usually use Gii’s model generator to get the skeletons of the ActiveRecord models, they usually have all the relations already defined.
softark, to generalize some debug code I use on the console basically. I have a console app that I use to print out models and relations. So let’s say I tell the app “show --model Abc”. Without knowing more, it will print out each property, e.g., location_id. But I’d like it so the app can say "wait, location_id is represented by a hasOne() and I can instead show $abc->location->name instead of $abc->location_id.
Hi fabriziocaldarelli, that’s not really where I was trying to go as that assumes there is a tenant. The property may be location, gate, sandwich, anything. The idea is my console app won’t know anything about the model it is looking at – it just knows it’s a model that has properties and many of those properties (e.g., location_id, gate_id, sandwich_id) are related to other models via hasOne() or hasMany() relationships.
I see. It makes sense.
You can access BaseActiveRecord::relatedRecords, but I think it is not available until you use the relations. But there must be some way to enumerate the relation names, I hope.
I’m not sure if this is a proper way of doing it, but I found a way to enumerate the attributes and the relations.
The following code snippet is inserted into an “actionView” method of a controller:
public function actionView($id)
{
$model = $this->findModel($id);
// get the reflection class of the model
$ref = new \ReflectionClass($model);
$className = $ref->getName();
$docComment = $ref->getDocComment();
// parse the doc comment and get the properties
$pattern = '/@property\s+([a-zA-Z0-9]+)(\[\])?\s+\$([a-zA-Z0-9_]+)/';
preg_match_all($pattern, $docComment, $properties, PREG_SET_ORDER);
// output the information
echo "<pre>\n";
echo "className:\n";
foreach($properties as $prop) {
echo " $prop[1]$prop[2] $prop[3]\n";
}
echo "</pre>\n";
exit;
return $this->render('view', [
'model' => $model,
]);
}
In the above, $prop[1] represents the type of the property. It can be an integer, a string, a boolean, etc. and also can be a model class. $prop[2] is whether '' (blank) or '[]', meaning a scholar or an array respectively. $prop[3] is the name of the property.
Please note that this code expects the doc comment of the model file is properly written and maintained in a standard format like the following:
/**
* This is the model class for table "slip".
*
* @property integer $id
* @property integer $book_id
* @property integer $in_out
* @property string $date
* @property integer $ser_no
* @property integer $item_id
* @property string $abstract
* @property string $amount
* @property string $comment
* @property integer $deleted
* @property string $created_at
* @property integer $created_by
*
* @property Audit[] $audits
* @property Book $book
* @property Item $item
* @property User $createdBy
* @property Voucher[] $vouchers
*/
class Slip extends \yii\db\ActiveRecord
{
...
Gii’s model generator is nice enough to automatically generate those doc comments including relations.