Browse Source

Merge branch 'master' of github.com:yiisoft/yii2

tags/2.0.0-beta
Qiang Xue 12 years ago
parent
commit
194ff131ab
  1. 2
      docs/guide/database-basics.md
  2. 235
      docs/guide/query-builder.md
  3. 28
      docs/guide/validation.md
  4. 27
      extensions/mutex/composer.json
  5. 41
      extensions/mutex/yii/mutex/DbMutex.php
  6. 86
      extensions/mutex/yii/mutex/FileMutex.php
  7. 95
      extensions/mutex/yii/mutex/Mutex.php
  8. 57
      extensions/mutex/yii/mutex/MysqlMutex.php
  9. 2
      framework/yii/helpers/base/SecurityHelper.php
  10. 13
      framework/yii/web/Response.php

2
docs/guide/database-basics.md

@ -25,7 +25,7 @@ return array(
//'dsn' => 'sqlsrv:Server=localhost;Database=mydatabase', // MS SQL Server, sqlsrv driver
//'dsn' => 'dblib:host=localhost;dbname=mydatabase', // MS SQL Server, dblib driver
//'dsn' => 'mssql:host=localhost;dbname=mydatabase', // MS SQL Server, mssql driver
//'dsn' => 'oci:dbname=//localhost:1521/testdb', // Oracle
//'dsn' => 'oci:dbname=//localhost:1521/mydatabase', // Oracle
'username' => 'root',
'password' => '',
'charset' => 'utf8',

235
docs/guide/query-builder.md

@ -0,0 +1,235 @@
Query Builder and Query
=======================
Yii provides a basic database access layer as was described in [Database basics](database-basics.md) section. Still it's
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:
```php
$query = new Query;
// Define query
$query->select('id, name')
->from('tbl_user')
->limit(10);
// Create a command. You can get the actual SQL using $command->sql
$command = $query->createCommand();
// Execute command
$rows = $command->queryAll();
```
Basic selects and joins
-----------------------
In order to form a `SELECT` query you need to specify what to select and where to select it from.
```php
$query->select('id, name')
->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:
```php
$query->select('user_id')->distinct()->from('tbl_post');
```
Select options can be specified as array. It's especially useful when these are formed dynamically.
```php
$query->select(array('tbl_user.name AS author', 'tbl_post.title as title')) // <-- specified as array
->from('tbl_user')
->leftJoin('tbl_post', 'tbl_post.user_id = tbl_user.id'); // <-- join with another table
```
In the code above we've used `leftJoin` method to select from two related tables at the same time. Firsrt parameter
specifies table name and the second is the join condition. Query builder has the following methods to join tables:
- `innerJoin`
- `leftJoin`
- `rightJoin`
If your data storage supports more types you can use generic `join` method:
```php
$query->join('FULL OUTER JOIN', 'tbl_post', 'tbl_post.user_id = tbl_user.id');
```
Specifying conditions
---------------------
Usually you need data that matches some conditions. There are some useful methods to specify these and the most powerful
is `where`. There are multiple ways to use it.
The simplest is to specify condition in a string:
```php
$query->where('status=:status', array(
':status' => $status,
));
```
When using this format make sure you're binding parameters and not creating a query by string concatenation.
Instead of binding status value immediately you can do it using `params` or `addParams`:
```php
$query->where('status=:status');
$query->addParams(array(
':status' => $status,
));
```
There is another convenient way to use the method called hash format:
```php
$query->where(array(
'status' => 10,
'type' => 2,
'id' => array(4, 8, 15, 16, 23, 42),
));
```
It will generate the following SQL:
```sql
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:
```php
$query->where(array(
'status' => null,
));
```
SQL generated will be:
```sql
WHERE (`status` IS NULL)
```
Another way to use the method is the operand format which is `array(operator, operand1, operand2, ...)`.
Operator can be one of the following:
- `and`: the operands should be concatenated together using `AND`. For example,
`array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array,
it will be converted into a string using the rules described here. For example,
`array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`.
The method will NOT do any quoting or escaping.
- `or`: similar to the `and` operator except that the operands are concatenated using `OR`.
- `between`: operand 1 should be the column name, and operand 2 and 3 should be the
starting and ending values of the range that the column is in.
For example, `array('between', 'id', 1, 10)` will generate `id BETWEEN 1 AND 10`.
- `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN`
in the generated condition.
- `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing
the range of the values that the column or DB expression should be in. For example,
`array('in', 'id', array(1, 2, 3))` will generate `id IN (1, 2, 3)`.
The method will properly quote the column name and escape values in the range.
- `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition.
- `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing
the values that the column or DB expression should be like.
For example, `array('like', 'name', '%tester%')` will generate `name LIKE '%tester%'`.
When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated
using `AND`. For example, `array('like', 'name', array('%test%', '%sample%'))` will generate
`name LIKE '%test%' AND name LIKE '%sample%'`.
The method will properly quote the column name and escape values in the range.
- `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE`
predicates when operand 2 is an array.
- `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE`
in the generated condition.
- `or not like`: similar to the `not like` operator except that `OR` is used to concatenate
the `NOT LIKE` predicates.
If you are building parts of condition dynamically it's very convenient to use `andWhere` and `orWhere`:
```php
$status = 10;
$search = 'yii';
$query->where(array('status' => $status));
if (!empty($search)) {
$query->addWhere('like', 'title', $search);
}
```
In case `$search` isn't empty the following SQL will be generated:
```sql
WHERE (`status` = 10) AND (`title` LIKE '%yii%')
```
Order
-----
For odering results `orderBy` and `addOrderBy` could be used:
```php
$query->orderBy(array(
'id' => Query::SORT_ASC,
'name' => Query::SORT_DESC,
));
```
Here we are ordering by `id` ascending and then by `name` descending.
Group and Having
----------------
In order to add `GROUP BY` to generated SQL you can use the following:
```php
$query->groupBy('id, status');
```
If you want to add another field after using `groupBy`:
```php
$query->addGroupBy(array('created_at', 'updated_at'));
```
To add a `HAVING` condition the corresponding `having` method and its `andHaving` and `orHaving` can be used. Parameters
for these are similar to the ones for `where` methods group:
```php
$query->having(array('status' => $status));
```
Limit and offset
----------------
To limit result to 10 rows `limit` can be used:
```php
$query->limit(10);
```
To skip 100 fist rows use:
```php
$query->offset(100);
```
Union
-----
`UNION` in SQL adds results of one query to results of another query. Columns returned by both queries should match.
In Yii in order to build it you can first form two query objects and then use `union` method:
```php
$query = new Query;
$query->select("id, 'post' as type, name")->from('tbl_post')->limit(10);
$anotherQuery = new Query;
$query->select('id, 'user' as type, name')->from('tbl_user')->limit(10);
$query->union($anotherQuery);
```

28
docs/guide/validation.md

@ -0,0 +1,28 @@
Model validation reference
==========================
This guide section doesn't describe how validation works but instead describes all Yii validators and their parameters.
In order to learn model validation basics please refer to [Model, Validation subsection](model.md#Validation).
Standard Yii validators
-----------------------
- `boolean`: [[BooleanValidator]]
- `captcha`: [[CaptchaValidator]]
- `compare`: [[CompareValidator]]
- `date`: [[DateValidator]]
- `default`: [[DefaultValueValidator]]
- `double`: [[NumberValidator]]
- `email`: [[EmailValidator]]
- `exist`: [[ExistValidator]]
- `file`: [[FileValidator]]
- `filter`: [[FilterValidator]]
- `in`: [[RangeValidator]]
- `integer`: [[NumberValidator]]
- `match`: [[RegularExpressionValidator]]
- `required`: [[RequiredValidator]]
- `string`: [[StringValidator]]
- `unique`: [[UniqueValidator]]
- `url`: [[UrlValidator]]
TBD: refer to http://www.yiiframework.com/wiki/56/ for the format

27
extensions/mutex/composer.json

@ -0,0 +1,27 @@
{
"name": "yiisoft/yii2-mutex",
"description": "Mutual exclusion extension for the Yii framework",
"keywords": ["yii", "mutex"],
"type": "library",
"license": "BSD-3-Clause",
"support": {
"issues": "https://github.com/yiisoft/yii2/issues?state=open",
"forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"authors": [
{
"name": "resurtm",
"email": "resurtm@gmail.com"
}
],
"minimum-stability": "dev",
"require": {
"yiisoft/yii2": "*"
},
"autoload": {
"psr-0": { "yii\\mutex": "" }
}
}

41
extensions/mutex/yii/mutex/DbMutex.php

@ -0,0 +1,41 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\mutex;
use Yii;
use yii\db\Connection;
use yii\base\InvalidConfigException;
/**
* @author resurtm <resurtm@gmail.com>
* @since 2.0
*/
abstract class DbMutex extends Mutex
{
/**
* @var Connection|string the DB connection object or the application component ID of the DB connection.
* After the Mutex object is created, if you want to change this property, you should only assign
* it with a DB connection object.
*/
public $db = 'db';
/**
* Initializes generic database table based mutex implementation.
* @throws InvalidConfigException if [[db]] is invalid.
*/
public function init()
{
parent::init();
if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.');
}
}
}

86
extensions/mutex/yii/mutex/FileMutex.php

@ -0,0 +1,86 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\mutex;
use Yii;
use yii\base\InvalidConfigException;
/**
* @author resurtm <resurtm@gmail.com>
* @since 2.0
*/
class FileMutex extends Mutex
{
/**
* @var string the directory to store mutex files. You may use path alias here.
* If not set, it will use the "mutex" subdirectory under the application runtime path.
*/
public $mutexPath = '@runtime/mutex';
/**
* @var resource[] stores all opened lock files. Keys are lock names and values are file handles.
*/
private $_files = array();
/**
* Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like
* operating systems.
* @throws InvalidConfigException
*/
public function init()
{
if (stripos(php_uname('s'), 'win') === 0) {
throw new InvalidConfigException('FileMutex does not have MS Windows operating system support.');
}
$this->mutexPath = Yii::getAlias($this->mutexPath);
if (!is_dir($this->mutexPath)) {
mkdir($this->mutexPath, 0777, true);
}
}
/**
* This method should be extended by concrete mutex implementations. Acquires lock by given name.
* @param string $name of the lock to be acquired.
* @param integer $timeout to wait for lock to become released.
* @return boolean acquiring result.
*/
protected function acquireLock($name, $timeout = 0)
{
$file = fopen($this->mutexPath . '/' . md5($name) . '.lock', 'w+');
if ($file === false) {
return false;
}
$waitTime = 0;
while (!flock($file, LOCK_EX | LOCK_NB)) {
$waitTime++;
if ($waitTime > $timeout) {
fclose($file);
return false;
}
sleep(1);
}
$this->_files[$name] = $file;
return true;
}
/**
* This method should be extended by concrete mutex implementations. Releases lock by given name.
* @param string $name of the lock to be released.
* @return boolean release result.
*/
protected function releaseLock($name)
{
if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) {
return false;
} else {
fclose($this->_files[$name]);
unset($this->_files[$name]);
return true;
}
}
}

95
extensions/mutex/yii/mutex/Mutex.php

@ -0,0 +1,95 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\mutex;
use Yii;
use yii\base\Component;
/**
* @author resurtm <resurtm@gmail.com>
* @since 2.0
*/
abstract class Mutex extends Component
{
/**
* @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically
* before finishing script execution. Defaults to true. Setting this property to true means that all locks
* acquire in this process must be released in any case (regardless any kind of errors or exceptions).
*/
public $autoRelease = true;
/**
* @var string[] names of the locks acquired in the current PHP process.
*/
private $_locks = array();
/**
* Initializes the mutex component.
*/
public function init()
{
if ($this->autoRelease) {
$mutex = $this;
$locks = &$this->_locks;
register_shutdown_function(function () use ($mutex, &$locks) {
foreach ($locks as $lock) {
$mutex->release($lock);
}
});
}
}
/**
* @param string $name of the lock to be acquired. Must be unique.
* @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return
* false immediately in case lock was already acquired.
* @return boolean lock acquiring result.
*/
public function acquire($name, $timeout = 0)
{
if ($this->acquireLock($name, $timeout)) {
$this->_locks[] = $name;
return true;
} else {
return false;
}
}
/**
* Release acquired lock. This method will return false in case named lock was not found.
* @param string $name of the lock to be released. This lock must be already created.
* @return boolean lock release result: false in case named lock was not found..
*/
public function release($name)
{
if ($this->releaseLock($name)) {
$index = array_search($name, $this->_locks);
if ($index !== false) {
unset($this->_locks[$index]);
}
return true;
} else {
return false;
}
}
/**
* This method should be extended by concrete mutex implementations. Acquires lock by given name.
* @param string $name of the lock to be acquired.
* @param integer $timeout to wait for lock to become released.
* @return boolean acquiring result.
*/
abstract protected function acquireLock($name, $timeout = 0);
/**
* This method should be extended by concrete mutex implementations. Releases lock by given name.
* @param string $name of the lock to be released.
* @return boolean release result.
*/
abstract protected function releaseLock($name);
}

57
extensions/mutex/yii/mutex/MysqlMutex.php

@ -0,0 +1,57 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\mutex;
use Yii;
use yii\base\InvalidConfigException;
/**
* @author resurtm <resurtm@gmail.com>
* @since 2.0
*/
class MysqlMutex extends Mutex
{
/**
* Initializes MySQL specific mutex component implementation.
* @throws InvalidConfigException if [[db]] is not MySQL connection.
*/
public function init()
{
parent::init();
if ($this->db->driverName !== 'mysql') {
throw new InvalidConfigException('In order to use MysqlMutex connection must be configured to use MySQL database.');
}
}
/**
* This method should be extended by concrete mutex implementations. Acquires lock by given name.
* @param string $name of the lock to be acquired.
* @param integer $timeout to wait for lock to become released.
* @return boolean acquiring result.
* @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock
*/
protected function acquireLock($name, $timeout = 0)
{
return (boolean)$this->db
->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout))
->queryScalar();
}
/**
* This method should be extended by concrete mutex implementations. Releases lock by given name.
* @param string $name of the lock to be released.
* @return boolean release result.
* @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock
*/
protected function releaseLock($name)
{
return (boolean)$this->db
->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name))
->queryScalar();
}
}

2
framework/yii/helpers/base/SecurityHelper.php

@ -186,7 +186,7 @@ class SecurityHelper
* // ...save $hash in database...
*
* // during login, validate if the password entered is correct using $hash fetched from database
* if (SecurityHelper::verifyPassword($password, $hash) {
* if (SecurityHelper::validatePassword($password, $hash) {
* // password is good
* } else {
* // password is bad

13
framework/yii/web/Response.php

@ -557,6 +557,12 @@ class Response extends \yii\base\Response
* });
* ~~~
*
* In a controller action you may use this method like this:
*
* ~~~
* return Yii::$app->getResponse()->redirect($url);
* ~~~
*
* @param array|string $url the URL to be redirected to. [[\yii\helpers\Html::url()]]
* will be used to normalize the URL. If the resulting URL is still a relative URL
* (one without host info), the current request host info will be used.
@ -584,6 +590,13 @@ class Response extends \yii\base\Response
* Refreshes the current page.
* The effect of this method call is the same as the user pressing the refresh button of his browser
* (without re-posting data).
*
* In a controller action you may use this method like this:
*
* ~~~
* return Yii::$app->getResponse()->refresh();
* ~~~
*
* @param string $anchor the anchor that should be appended to the redirection URL.
* Defaults to empty. Make sure the anchor starts with '#' if you want to specify it.
* @return Response the response object itself

Loading…
Cancel
Save