|
|
@ -547,33 +547,61 @@ Finally when calling [[delete()]] to delete an ActiveRecord, we will have the fo |
|
|
|
3. [[afterDelete()]]: will trigger an [[EVENT_AFTER_DELETE]] event |
|
|
|
3. [[afterDelete()]]: will trigger an [[EVENT_AFTER_DELETE]] event |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Scopes |
|
|
|
Custom scopes |
|
|
|
------ |
|
|
|
------------- |
|
|
|
|
|
|
|
|
|
|
|
A scope is a method that customizes a given [[ActiveQuery]] object. Scope methods are static and are defined |
|
|
|
When [[find()]] or [[findBySql()]] Active Record method is being called without parameters it returns an [[ActiveQuery]] |
|
|
|
in the ActiveRecord classes. They can be invoked through the [[ActiveQuery]] object that is created |
|
|
|
instance. This object holds all the parameters and conditions for a future query and also allows you to customize these |
|
|
|
via [[find()]] or [[findBySql()]]. The following is an example: |
|
|
|
using a set of methods that are called scopes. By deafault there is a good set of such methods some of which we've |
|
|
|
|
|
|
|
already used above: `where`, `orderBy`, `limit` etc. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In many cases it is convenient to wrap extra conditions into custom scope methods. In order to do so you need two things. |
|
|
|
|
|
|
|
First is creating a custom query class for your model. For example, a `Comment` may have a `CommentQuery`: |
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
class Comment extends \yii\db\ActiveRecord |
|
|
|
namespace app\models; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import yii\db\ActiveQuery; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CommentQuery extends ActiveQuery |
|
|
|
{ |
|
|
|
{ |
|
|
|
// ... |
|
|
|
public function active($state = true) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$this->andWhere(['active' => $state]); |
|
|
|
|
|
|
|
return $this; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
Important points are: |
|
|
|
* @param ActiveQuery $query |
|
|
|
|
|
|
|
*/ |
|
|
|
1. Class should extend from `yii\db\ActiveQuery` (or another `ActiveQuery` such as `yii\mongodb\ActiveQuery`). |
|
|
|
public static function active($query) |
|
|
|
2. A method should be `public` and should return `$this` in order to allow method chaining. It may accept parameters. |
|
|
|
|
|
|
|
3. Check `ActiveQuery` methods that are very useful for modifying query conditions. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The second step is to use `CommentQuery` instead of regular `ActiveQuery` for `Comment` model: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
namespace app\models; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use yii\db\ActiveRecord; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Comment extends ActiveRecord |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
public static function createQuery() |
|
|
|
{ |
|
|
|
{ |
|
|
|
$query->andWhere('status = 1'); |
|
|
|
return new CommentQuery(['modelClass' => get_called_class()]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
That's it. Now you can use your custom scope methods: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
$comments = Comment::find()->active()->all(); |
|
|
|
$comments = Comment::find()->active()->all(); |
|
|
|
|
|
|
|
$inactiveComments = Comment::find()->active(false)->all(); |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
In the above, the `active()` method is defined in `Comment` while we are calling it |
|
|
|
|
|
|
|
through `ActiveQuery` returned by `Comment::find()`. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
You can also use scopes when defining relations. For example, |
|
|
|
You can also use scopes when defining relations. For example, |
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
@ -597,29 +625,32 @@ $posts = Post::find()->with([ |
|
|
|
])->all(); |
|
|
|
])->all(); |
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Scopes can be parameterized. For example, we can define and use the following `olderThan` scope: |
|
|
|
### Making it IDE-friendly |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In order to make most modern IDE autocomplete happy you need to override return types for some methods of both model |
|
|
|
|
|
|
|
and query like the following: |
|
|
|
|
|
|
|
|
|
|
|
```php |
|
|
|
```php |
|
|
|
class Customer extends \yii\db\ActiveRecord |
|
|
|
/** |
|
|
|
|
|
|
|
* @method \app\models\CommentQuery|static|null find($q = null) static |
|
|
|
|
|
|
|
* @method \app\models\CommentQuery findBySql($sql, $params = []) static |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
class Comment extends ActiveRecord |
|
|
|
{ |
|
|
|
{ |
|
|
|
// ... |
|
|
|
// ... |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* @param ActiveQuery $query |
|
|
|
|
|
|
|
* @param integer $age |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static function olderThan($query, $age = 30) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$query->andWhere('age > :age', [':age' => $age]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$customers = Customer::find()->olderThan(50)->all(); |
|
|
|
|
|
|
|
``` |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
The parameters should follow after the `$query` parameter when defining the scope method, and they |
|
|
|
```php |
|
|
|
can take default values like shown above. |
|
|
|
/** |
|
|
|
|
|
|
|
* @method \app\models\Comment|array|null one($db = null) |
|
|
|
|
|
|
|
* @method \app\models\Comment[]|array all($db = null) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
class CommentQuery extends ActiveQuery |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// ... |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
Transactional operations |
|
|
|
Transactional operations |
|
|
|
------------------------ |
|
|
|
------------------------ |
|
|
|