Here is a way to use the ‘autoScope’ feature now available in RelatedSearchBehavior.
AutoScope automagically adds scopes to your CActiveRecord for each field. If you have a field ‘author’ then you’ll get a scope like this for free:
public function author(mixed $value, boolean $partialMatch=false, string $operator='AND', boolean $escape=true)
Why do you need this: well, to speed up development and avoid writing ‘condition’.
Autoscope provides:
-
Automatic specification of the table alias for the field;
-
Same functionnality as provided by CDbCriteria::compare();
-
Runtime checking that the used field/scope exists (instead of getting a failed SQL command);
-
The opportunity to write less code.
How do I use this?
To understand, have a look at the "manual" scope definition below where I[size=2]select Devices with a given protocol.[/size]
[size=2]It requires that the CActiveRecord referenced in the relation ‘deviceType’ also has a scope called ‘device_type_protocol’:[/size]
class Device extends CActiveRecord {
/** Scope to select devices with specific protocol. */
public function protocol($protocol) {
$this->getDbCriteria()->mergeWith(
array(
'with'=>array(
'deviceType'=>array(
'scopes'=>array('device_type_protocol'=>$protocol),
),
),
)
);
return $this;
}
}
In the case where the scope ‘DeviceType::device_type_protocol’ does not exist, I’ld have to use ‘condition’ to filter on it:
class Device extends CActiveRecord {
/** Scope to select devices with specific protocol. */
public function protocol($protocol) {
$this->getDbCriteria()->mergeWith(
array(
'with'=>array(
'deviceType'=>array(
'condition'=>"deviceType.device_type_protocol=$protocol",
),[
),
)
);
return $this;
}
}
That is the code when I am ‘lazy’: no quoting for the alias, duplication of the alias name (‘deviceType’ is written twice), non escaping or parameter for ‘$protocol’. And to do better, I’ld have to create a lot of stupid scopes.
Too many things I do not like, so I developed ‘autoScope’ which provides the scope ‘device_type_protocol()’ automagically.
Unfortunately, I could not put everything in the extension, and you must extend the ‘__call’ method of the ActiveRecord. I’ve automated that by updating the ‘Gii’ generator template for the model.
class DeviceType extends CActiveRecord {
public function __call($name,$parameters) {
try {
return parent::__call($name,$parameters);
} catch (CException $e) {
if(preg_match('/ and its behaviors do not have a method or closure named /',$e->getMessage())) {
return $this->autoScope($name, $parameters);
} else {
throw $e;
}
}
}
}
If you look closer you’ll see that there is a call to ‘$this->autoScope()’. Yii will not find ‘autoScope’ in the model and will go look for it in the behaviors and should find it in the the RelatedSearchBehavior.
AutoScope checks if the attribute exists and if it does applies a scope on it using ‘compare’ as the method, here is the line of code to the call of ‘compare’ in autoScope:
[size=2] $owner->getDbCriteria()->compare($column, $value,$partialMatch,$operator,$escape);[/size]