I’m working a lot with (default) scopes. Often when I try to get the table alias, it crashes - telling me, that the allowed memory size is exhausted. E.g.:
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 20 bytes) in /.../yii/framework/db/ar/CActiveRecord.php on line 1206
This is an example query in the controller:
Product::model()->with('prices')->findByPk(4);
This is my Product.php code:
...
public function defaultScope()
{
return array(
'condition' => sprintf('`%s`.`is_active` = 1', $this->getTableAlias()),
);
}
public function relations()
{
'prices' => array(self::HAS_MANY, 'Price', 'product_id'),
}
This is my Prices.php code:
...
public function defaultScope()
{
return array(
'condition' => sprintf('`%s`.`is_active` = 1', $this->getTableAlias()),
);
}
So the SQL query should look sth like this (pseudo code)
SELECT a.*, b.* FROM Product a, JOIN Price b WHERE a.id=4 AND a.active=1 AND b.active=1
Update: Seems that this method already causes the memory overflow:
$this->getDbCriteria(false)
I set the memory usage up to 1GB (in php.ini), but same effect: Memory usage is growing until 1GB, then the process get interrupted. Looks like an endless loop.
The method getTableAlias calls getDbCriteria that calls defaultScope, which is calling getDbCriteria.
So an endless loop
But what is the right approach to get the upper mentioned request done?
We have:
2 tables,
2 models,
2 same called columns,
2 defaultScopes.
The only solution I have in mind is to ensure that every column of my 92 tables has a unique name. But that’s not the way I want to spend the next 2 weeks.
I tried to find a work around: My idea was to override the default alias t whith the table name. So I created a parent model class which extends from CActiveRecord and contains only this method:
class ActiveRecord extends CActiveRecord
{
public function defaultScope()
{
$criteria = new CDbCriteria;
$criteria->alias = $this->tableName();
return $criteria;
}
}
Every model now extends from ActiveRecord. The defaultScope method is tweaked like this:
[...]
public function defaultScope()
{
// Only return actire records
$criteria = parent::defaultScope();
$criteria->condition = sprintf('`%s`.`is_active` = :active', $criteria->alias);
$criteria->params = array(':active' => true);
return $criteria;
}
This works - well - sometimes
After an extatic change of my models (I thought I had the solution), I figured out another problem:
Fatal error: Cannot use object of type CDbCriteria as array in /.../yii/framework/db/ar/CActiveRecord.php on line 1703
Is this another bug, or is a CDbCriteria object not allowed for scopes? Do you have an idea how to continue programming anyway?
an email address only can be used if verified via activation link
and a foto can be banned by the support team.
So the defaultScope often looks like "where is_active=1 and is_banned=0 and is_verified=1".
So I don’t want to create such a long pipe (…->active()->notBanned()->verified()) in every controller action. The possibility is too high to forget one scope.
But - I found an easier solution/work around:
public function defaultScope()
{
return array(
'alias' => $this->tableName(),
'condition' => sprintf('`%s`.`is_active` = 1', $this->tableName())
);
}