Yii provides a basic database access layer as was described in [Database basics](database-basics.md) section. Still it's
Yii provides a basic database access layer as described in the [Database basics](database-basics.md) section. The database access layer provides a low-level way to interact with the database. While useful in some situations, it can be tedious to rely too much upon direct SQL. An alternative approach that Yii provides is the Query Builder. The Query Builder provides an object-oriented vehicle for generating queries to be executed.
a bit too much to use SQL directly all the time. To solve the issue Yii provides a query builder that allows you to
work with the database in object-oriented style.
Basic query builder usage is the following:
Here's a basic example:
```php
```php
$query = new Query;
$query = new Query;
// Define query
// Define the query:
$query->select('id, name')
$query->select('id, name')
->from('tbl_user')
->from('tbl_user')
->limit(10);
->limit(10);
// Create a command. You can get the actual SQL using $command->sql
// Create a command.
$command = $query->createCommand();
$command = $query->createCommand();
// Execute command
// You can get the actual SQL using $command->sql
// Execute the command:
$rows = $command->queryAll();
$rows = $command->queryAll();
```
```
Basic selects and joins
Basic selects
-----------------------
-------------
In order to form a `SELECT` query you need to specify what to select and where to select it from.
In order to form a basic `SELECT` query, you need to specify what columns to select and from what table:
```php
```php
$query->select('id, name')
$query->select('id, name')
->from('tbl_user');
->from('tbl_user');
```
```
If you want to get IDs of all users with posts you can use `DISTINCT`. With query builder it will look like the following:
Select options can be specified as a comma-separated string, as in the above, or as an array. The array syntax is especially useful when forming the selection dynamically:
The first argument is the join type to perform. The second is the table to join to, and the third is the condition.
Specifying SELECT conditions
---------------------
---------------------
Usually you need data that matches some conditions. There are some useful methods to specify these and the most powerful
Usually data is selected based upon certain criteria. Query Builder has some useful methods to specify these, the most powerful of which being `where`. It can be used in multiple ways.
is `where`. There are multiple ways to use it.
The simplest is to specify condition in a string:
The simplest way to apply a condition is to use a string:
When using this format make sure you're binding parameters and not creating a query by string concatenation.
When using strings, make sure you're binding the query parameters, not creating a query by string concatenation. The above approach is safe to use, the following is not:
Instead of binding status value immediately you can do it using `params` or `addParams`:
```php
$query->where("status=$status"); // Dangerous!
```
Instead of binding the status value immediately, you can do so using `params` or `addParams`:
```php
```php
$query->where('status=:status');
$query->where('status=:status');
$query->addParams([':status' => $status]);
$query->addParams([':status' => $status]);
```
```
There is another convenient way to use the method called hash format:
Multiple conditions can simultaneously be set in `where` using the *hash format*:
```php
```php
$query->where([
$query->where([
@ -90,19 +102,19 @@ $query->where([
]);
]);
```
```
It will generate the following SQL:
That code will generate the following SQL:
```sql
```sql
WHERE (`status` = 10) AND (`type` = 2) AND (`id` IN (4, 8, 15, 16, 23, 42))
WHERE (`status` = 10) AND (`type` = 2) AND (`id` IN (4, 8, 15, 16, 23, 42))
```
```
If you'll specify value as `null` such as the following:
NULL is a special value in databases, and is handled smartly by the Query Builder. This code:
```php
```php
$query->where(['status' => null]);
$query->where(['status' => null]);
```
```
SQL generated will be:
results in this WHERE clause:
```sql
```sql
WHERE (`status` IS NULL)
WHERE (`status` IS NULL)
@ -174,6 +186,15 @@ $query->orderBy([
Here we are ordering by `id` ascending and then by `name` descending.
Here we are ordering by `id` ascending and then by `name` descending.
Distinct
--------
If you want to get IDs of all users with posts you can use `DISTINCT`. With query builder it will look like the following:
@ -67,9 +67,9 @@ Validates that the attribute value is a valid email address.
Validates that the attribute value exists in a table.
Validates that the attribute value exists in a table.
- `className` the ActiveRecord class name or alias of the class that should be used to look for the attribute value being
- `targetClass` the ActiveRecord class name or alias of the class that should be used to look for the attribute value being
validated. _(ActiveRecord class of the attribute being validated)_
validated. _(ActiveRecord class of the attribute being validated)_
- `attributeName` the ActiveRecord attribute name that should be used to look for the attribute value being validated.
- `targetAttribute` the ActiveRecord attribute name that should be used to look for the attribute value being validated.
_(name of the attribute being validated)_
_(name of the attribute being validated)_
### `file`: [[FileValidator]]
### `file`: [[FileValidator]]
@ -112,7 +112,9 @@ Validates that the attribute value is among a list of values.
### `inline`: [[InlineValidator]]
### `inline`: [[InlineValidator]]
Uses a custom function to validate the attribute. You need to define a public method in your model class which will evaluate the validity of the attribute. For example, if an attribute needs to be divisible by 10. In the rules you would define: `['attributeName', 'myValidationMethod'],`.
Uses a custom function to validate the attribute. You need to define a public method in your
model class which will evaluate the validity of the attribute. For example, if an attribute
needs to be divisible by 10. In the rules you would define: `['attributeName', 'myValidationMethod'],`.
Then, your own method could look like this:
Then, your own method could look like this:
```php
```php
@ -161,9 +163,9 @@ Validates that the attribute value is of certain length.
Validates that the attribute value is unique in the corresponding database table.
Validates that the attribute value is unique in the corresponding database table.
- `className` the ActiveRecord class name or alias of the class that should be used to look for the attribute value being
- `targetClass` the ActiveRecord class name or alias of the class that should be used to look for the attribute value being
validated. _(ActiveRecord class of the attribute being validated)_
validated. _(ActiveRecord class of the attribute being validated)_
- `attributeName` the ActiveRecord attribute name that should be used to look for the attribute value being validated.
- `targetAttribute` the ActiveRecord attribute name that should be used to look for the attribute value being validated.
3. Change `composer.json`. Instead of all stable requirements add just one `"yiisoft/yii2-dev": "*"`.
3. Change `composer.json`. Instead of all stable requirements add just one `"yiisoft/yii2-dev": "*"`.
4. Execute `composer install`.
4. Execute `composer create-project`.
5. Now you have working playground that uses latest code.
5. Now you have working playground that uses latest code.
Note that requirements of extensions that come with `yii2-dev` are not loaded automatically.
Note that requirements of extensions that come with `yii2-dev` are not loaded automatically.
@ -27,3 +27,5 @@ If you're not core developer or want to use your own fork for pull requests:
[remote "origin"]
[remote "origin"]
url = git://github.com/username/yii2.git
url = git://github.com/username/yii2.git
```
```
> Hint: The workflow of forking a package and pushing changes back into your fork and then sending a pull-request to the maintainer is the same for all extensions you require via composer.
B = Major version. Non-BC changes with upgrade instructions.
B = Major version. Non-BC changes with upgrade instructions.
C = BC changes and additions.
C = BC changes and additions.
A.B.CrcD
Release candidates
------------------
A.B.C-rc
A.B.C-rc2
This is when we want to do a release candidate. RC number increments till we're getting a stable release with no
critical bugs and backwards incompatibility reports.
Alphas and betas
----------------
A.B.C-alpha
A.B.C-alpha2
Alphas are unstable versions where significant bugs may and probably do exist. API isn't fixed yet and may be changed
significantly. `alpha2` etc. may or may not be released based on overall stability of code and API.
A.B.C-beta
A.B.C-beta2
This is when we want to release release candidate. D is the RC number. Starts with 1 and increments till we're getting a stable release with no critical bugs and BC incompatibility reports.
Beta is more or less stable with less bugs and API instability than alphas. There still could be changes in API but
throw new InvalidParamException('Relation names are case sensitive. ' . get_class($this) . " has a relation named \"$realName\" instead of \"$name\".");
throw new InvalidParamException('Relation names are case sensitive. ' . get_class($this) . " has a relation named \"$realName\" instead of \"$name\".");
}
}
return $relation;
}
}
/**
/**
@ -1217,11 +1234,10 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface