resurtm
12 years ago
538 changed files with 51288 additions and 44868 deletions
@ -0,0 +1,14 @@ |
|||||||
|
language: php |
||||||
|
|
||||||
|
php: |
||||||
|
- 5.3 |
||||||
|
- 5.4 |
||||||
|
- 5.5 |
||||||
|
|
||||||
|
env: |
||||||
|
- DB=mysql |
||||||
|
|
||||||
|
before_script: |
||||||
|
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS yiitest;'; fi" |
||||||
|
|
||||||
|
script: phpunit |
@ -1,9 +0,0 @@ |
|||||||
<?php |
|
||||||
|
|
||||||
defined('YII_DEBUG') or define('YII_DEBUG', true); |
|
||||||
|
|
||||||
require(__DIR__ . '/../framework/yii.php'); |
|
||||||
|
|
||||||
$config = require(__DIR__ . '/protected/config/main.php'); |
|
||||||
$application = new yii\web\Application($config); |
|
||||||
$application->run(); |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,14 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
// comment out the following line to disable debug mode |
||||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||||
|
|
||||||
|
$frameworkPath = __DIR__ . '/../../yii'; |
||||||
|
|
||||||
|
require($frameworkPath . '/Yii.php'); |
||||||
|
// Register Composer autoloader |
||||||
|
@include($frameworkPath . '/vendor/autoload.php'); |
||||||
|
|
||||||
|
$config = require(__DIR__ . '/protected/config/main.php'); |
||||||
|
$application = new yii\web\Application($config); |
||||||
|
$application->run(); |
@ -1,21 +1,24 @@ |
|||||||
<?php |
<?php |
||||||
use yii\helpers\Html; |
use yii\helpers\Html; |
||||||
|
use yii\widgets\ActiveForm; |
||||||
|
|
||||||
/** |
/** |
||||||
* @var yii\base\View $this |
* @var yii\base\View $this |
||||||
* @var yii\widgets\ActiveForm $form |
* @var yii\widgets\ActiveForm $form |
||||||
* @var app\models\LoginForm $model |
* @var app\models\LoginForm $model |
||||||
*/ |
*/ |
||||||
$this->title = 'Login'; |
$this->title = 'Login'; |
||||||
|
$this->params['breadcrumbs'][] = $this->title; |
||||||
?> |
?> |
||||||
<h1><?php echo Html::encode($this->title); ?></h1>
|
<h1><?php echo Html::encode($this->title); ?></h1>
|
||||||
|
|
||||||
<p>Please fill out the following fields to login:</p> |
<p>Please fill out the following fields to login:</p> |
||||||
|
|
||||||
<?php $form = $this->beginWidget('yii\widgets\ActiveForm', array('options' => array('class' => 'form-horizontal'))); ?> |
<?php $form = $this->beginWidget(ActiveForm::className(), array('options' => array('class' => 'form-horizontal'))); ?> |
||||||
<?php echo $form->field($model, 'username')->textInput(); ?> |
<?php echo $form->field($model, 'username')->textInput(); ?> |
||||||
<?php echo $form->field($model, 'password')->passwordInput(); ?> |
<?php echo $form->field($model, 'password')->passwordInput(); ?> |
||||||
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?> |
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?> |
||||||
<div class="form-actions"> |
<div class="form-actions"> |
||||||
<?php echo Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')); ?> |
<?php echo Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')); ?> |
||||||
</div> |
</div> |
||||||
<?php $this->endWidget(); ?> |
<?php $this->endWidget(); ?> |
@ -0,0 +1,79 @@ |
|||||||
|
{ |
||||||
|
"name": "yiisoft/yii2", |
||||||
|
"description": "Yii2 Web Programming Framework", |
||||||
|
"keywords": ["yii", "framework"], |
||||||
|
"homepage": "http://www.yiiframework.com/", |
||||||
|
"type": "library", |
||||||
|
"license": "BSD-3-Clause", |
||||||
|
"authors": [ |
||||||
|
{ |
||||||
|
"name": "Qiang Xue", |
||||||
|
"email": "qiang.xue@gmail.com", |
||||||
|
"homepage": "http://www.yiiframework.com/", |
||||||
|
"role": "Founder and project lead" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Alexander Makarov", |
||||||
|
"email": "sam@rmcreative.ru", |
||||||
|
"homepage": "http://rmcreative.ru/", |
||||||
|
"role": "Core framework development" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Maurizio Domba", |
||||||
|
"homepage": "http://mdomba.info/", |
||||||
|
"role": "Core framework development" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Carsten Brandt", |
||||||
|
"email": "mail@cebe.cc", |
||||||
|
"homepage": "http://cebe.cc/", |
||||||
|
"role": "Core framework development" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Timur Ruziev", |
||||||
|
"email": "resurtm@gmail.com", |
||||||
|
"homepage": "http://resurtm.com/", |
||||||
|
"role": "Core framework development" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Paul Klimov", |
||||||
|
"email": "klimov.paul@gmail.com", |
||||||
|
"role": "Core framework development" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Wei Zhuo", |
||||||
|
"email": "weizhuo@gmail.com", |
||||||
|
"role": "Project site maintenance and development" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Sebastián Thierer", |
||||||
|
"email": "sebas@artfos.com", |
||||||
|
"role": "Component development" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Jeffrey Winesett", |
||||||
|
"email": "jefftulsa@gmail.com", |
||||||
|
"role": "Documentation and marketing" |
||||||
|
} |
||||||
|
], |
||||||
|
"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" |
||||||
|
}, |
||||||
|
"config": { |
||||||
|
"vendor-dir": "yii/vendor" |
||||||
|
}, |
||||||
|
"bin": [ |
||||||
|
"yii/yiic" |
||||||
|
], |
||||||
|
"require": { |
||||||
|
"php": ">=5.3.0", |
||||||
|
"michelf/php-markdown": "1.3", |
||||||
|
"twig/twig": "1.12.*", |
||||||
|
"smarty/smarty": "3.1.*", |
||||||
|
"ezyang/htmlpurifier": "v4.5.0" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,212 @@ |
|||||||
|
{ |
||||||
|
"_readme": [ |
||||||
|
"This file locks the dependencies of your project to a known state", |
||||||
|
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" |
||||||
|
], |
||||||
|
"hash": "7d46ce9c4d8d5f4ecae1611ea8f0b49c", |
||||||
|
"packages": [ |
||||||
|
{ |
||||||
|
"name": "ezyang/htmlpurifier", |
||||||
|
"version": "v4.5.0", |
||||||
|
"source": { |
||||||
|
"type": "git", |
||||||
|
"url": "https://github.com/ezyang/htmlpurifier.git", |
||||||
|
"reference": "v4.5.0" |
||||||
|
}, |
||||||
|
"dist": { |
||||||
|
"type": "zip", |
||||||
|
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/v4.5.0", |
||||||
|
"reference": "v4.5.0", |
||||||
|
"shasum": "" |
||||||
|
}, |
||||||
|
"require": { |
||||||
|
"php": ">=5.2" |
||||||
|
}, |
||||||
|
"type": "library", |
||||||
|
"autoload": { |
||||||
|
"psr-0": { |
||||||
|
"HTMLPurifier": "library/" |
||||||
|
}, |
||||||
|
"files": [ |
||||||
|
"library/HTMLPurifier.composer.php" |
||||||
|
] |
||||||
|
}, |
||||||
|
"notification-url": "https://packagist.org/downloads/", |
||||||
|
"license": [ |
||||||
|
"LGPL" |
||||||
|
], |
||||||
|
"authors": [ |
||||||
|
{ |
||||||
|
"name": "Edward Z. Yang", |
||||||
|
"email": "admin@htmlpurifier.org", |
||||||
|
"homepage": "http://ezyang.com" |
||||||
|
} |
||||||
|
], |
||||||
|
"description": "Standards compliant HTML filter written in PHP", |
||||||
|
"homepage": "http://htmlpurifier.org/", |
||||||
|
"keywords": [ |
||||||
|
"html" |
||||||
|
], |
||||||
|
"time": "2013-02-18 00:04:08" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "michelf/php-markdown", |
||||||
|
"version": "1.3", |
||||||
|
"source": { |
||||||
|
"type": "git", |
||||||
|
"url": "https://github.com/michelf/php-markdown.git", |
||||||
|
"reference": "1.3" |
||||||
|
}, |
||||||
|
"dist": { |
||||||
|
"type": "zip", |
||||||
|
"url": "https://api.github.com/repos/michelf/php-markdown/zipball/1.3", |
||||||
|
"reference": "1.3", |
||||||
|
"shasum": "" |
||||||
|
}, |
||||||
|
"require": { |
||||||
|
"php": ">=5.3.0" |
||||||
|
}, |
||||||
|
"type": "library", |
||||||
|
"extra": { |
||||||
|
"branch-alias": { |
||||||
|
"dev-lib": "1.3.x-dev" |
||||||
|
} |
||||||
|
}, |
||||||
|
"autoload": { |
||||||
|
"psr-0": { |
||||||
|
"Michelf": "" |
||||||
|
} |
||||||
|
}, |
||||||
|
"notification-url": "https://packagist.org/downloads/", |
||||||
|
"license": [ |
||||||
|
"BSD-3-Clause" |
||||||
|
], |
||||||
|
"authors": [ |
||||||
|
{ |
||||||
|
"name": "Michel Fortin", |
||||||
|
"email": "michel.fortin@michelf.ca", |
||||||
|
"homepage": "http://michelf.ca/", |
||||||
|
"role": "Developer" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "John Gruber", |
||||||
|
"homepage": "http://daringfireball.net/" |
||||||
|
} |
||||||
|
], |
||||||
|
"description": "PHP Markdown", |
||||||
|
"homepage": "http://michelf.ca/projects/php-markdown/", |
||||||
|
"keywords": [ |
||||||
|
"markdown" |
||||||
|
], |
||||||
|
"time": "2013-04-11 18:53:11" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "smarty/smarty", |
||||||
|
"version": "v3.1.13", |
||||||
|
"source": { |
||||||
|
"type": "svn", |
||||||
|
"url": "http://smarty-php.googlecode.com/svn", |
||||||
|
"reference": "/tags/v3.1.13/@4699" |
||||||
|
}, |
||||||
|
"require": { |
||||||
|
"php": ">=5.2" |
||||||
|
}, |
||||||
|
"type": "library", |
||||||
|
"autoload": { |
||||||
|
"classmap": [ |
||||||
|
"distribution/libs/Smarty.class.php", |
||||||
|
"distribution/libs/SmartyBC.class.php" |
||||||
|
] |
||||||
|
}, |
||||||
|
"notification-url": "https://packagist.org/downloads/", |
||||||
|
"license": [ |
||||||
|
"LGPL-3.0" |
||||||
|
], |
||||||
|
"authors": [ |
||||||
|
{ |
||||||
|
"name": "Monte Ohrt", |
||||||
|
"email": "monte@ohrt.com" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Uwe Tews", |
||||||
|
"email": "uwe.tews@googlemail.com" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Rodney Rehm", |
||||||
|
"email": "rodney.rehm@medialize.de" |
||||||
|
} |
||||||
|
], |
||||||
|
"description": "Smarty - the compiling PHP template engine", |
||||||
|
"homepage": "http://www.smarty.net", |
||||||
|
"keywords": [ |
||||||
|
"templating" |
||||||
|
], |
||||||
|
"time": "2013-01-26 12:03:52" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "twig/twig", |
||||||
|
"version": "v1.12.3", |
||||||
|
"source": { |
||||||
|
"type": "git", |
||||||
|
"url": "https://github.com/fabpot/Twig.git", |
||||||
|
"reference": "v1.12.3" |
||||||
|
}, |
||||||
|
"dist": { |
||||||
|
"type": "zip", |
||||||
|
"url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.12.3", |
||||||
|
"reference": "v1.12.3", |
||||||
|
"shasum": "" |
||||||
|
}, |
||||||
|
"require": { |
||||||
|
"php": ">=5.2.4" |
||||||
|
}, |
||||||
|
"type": "library", |
||||||
|
"extra": { |
||||||
|
"branch-alias": { |
||||||
|
"dev-master": "1.12-dev" |
||||||
|
} |
||||||
|
}, |
||||||
|
"autoload": { |
||||||
|
"psr-0": { |
||||||
|
"Twig_": "lib/" |
||||||
|
} |
||||||
|
}, |
||||||
|
"notification-url": "https://packagist.org/downloads/", |
||||||
|
"license": [ |
||||||
|
"BSD-3" |
||||||
|
], |
||||||
|
"authors": [ |
||||||
|
{ |
||||||
|
"name": "Fabien Potencier", |
||||||
|
"email": "fabien@symfony.com" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "Armin Ronacher", |
||||||
|
"email": "armin.ronacher@active-4.com" |
||||||
|
} |
||||||
|
], |
||||||
|
"description": "Twig, the flexible, fast, and secure template language for PHP", |
||||||
|
"homepage": "http://twig.sensiolabs.org", |
||||||
|
"keywords": [ |
||||||
|
"templating" |
||||||
|
], |
||||||
|
"time": "2013-04-08 12:40:11" |
||||||
|
} |
||||||
|
], |
||||||
|
"packages-dev": [ |
||||||
|
|
||||||
|
], |
||||||
|
"aliases": [ |
||||||
|
|
||||||
|
], |
||||||
|
"minimum-stability": "stable", |
||||||
|
"stability-flags": [ |
||||||
|
|
||||||
|
], |
||||||
|
"platform": { |
||||||
|
"php": ">=5.3.0" |
||||||
|
}, |
||||||
|
"platform-dev": [ |
||||||
|
|
||||||
|
] |
||||||
|
} |
@ -0,0 +1,319 @@ |
|||||||
|
Database Migration |
||||||
|
================== |
||||||
|
|
||||||
|
Like source code, the structure of a database is evolving as we develop and maintain |
||||||
|
a database-driven application. For example, during development, we may want to |
||||||
|
add a new table; or after the application is put into production, we may realize |
||||||
|
the need of adding an index on a column. It is important to keep track of these |
||||||
|
structural database changes (called **migration**) like we do with our source |
||||||
|
code. If the source code and the database are out of sync, it is very likely |
||||||
|
the whole system may break. For this reason, Yii provides a database migration |
||||||
|
tool that can keep track of database migration history, apply new migrations, |
||||||
|
or revert existing ones. |
||||||
|
|
||||||
|
The following steps show how we can use database migration during development: |
||||||
|
|
||||||
|
1. Tim creates a new migration (e.g. create a new table) |
||||||
|
2. Tim commits the new migration into source control system (e.g. GIT, Mercurial) |
||||||
|
3. Doug updates from source control system and receives the new migration |
||||||
|
4. Doug applies the migration to his local development database |
||||||
|
|
||||||
|
|
||||||
|
Yii supports database migration via the `yiic migrate` command line tool. This |
||||||
|
tool supports creating new migrations, applying/reverting/redoing migrations, and |
||||||
|
showing migration history and new migrations. |
||||||
|
|
||||||
|
Creating Migrations |
||||||
|
------------------- |
||||||
|
|
||||||
|
To create a new migration (e.g. create a news table), we run the following command: |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/create <name> |
||||||
|
~~~ |
||||||
|
|
||||||
|
The required `name` parameter specifies a very brief description of the migration |
||||||
|
(e.g. `create_news_table`). As we will show in the following, the `name` parameter |
||||||
|
is used as part of a PHP class name. Therefore, it should only contain letters, |
||||||
|
digits and/or underscore characters. |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/create create_news_table |
||||||
|
~~~ |
||||||
|
|
||||||
|
The above command will create under the `protected/migrations` directory a new |
||||||
|
file named `m101129_185401_create_news_table.php` which contains the following |
||||||
|
initial code: |
||||||
|
|
||||||
|
~~~ |
||||||
|
[php] |
||||||
|
class m101129_185401_create_news_table extends \yii\db\Migration |
||||||
|
{ |
||||||
|
public function up() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public function down() |
||||||
|
{ |
||||||
|
echo "m101129_185401_create_news_table cannot be reverted.\n"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
~~~ |
||||||
|
|
||||||
|
Notice that the class name is the same as the file name which is of the pattern |
||||||
|
`m<timestamp>_<name>`, where `<timestamp>` refers to the UTC timestamp (in the |
||||||
|
format of `yymmdd_hhmmss`) when the migration is created, and `<name>` is taken |
||||||
|
from the command's `name` parameter. |
||||||
|
|
||||||
|
The `up()` method should contain the code implementing the actual database |
||||||
|
migration, while the `down()` method may contain the code reverting what is |
||||||
|
done in `up()`. |
||||||
|
|
||||||
|
Sometimes, it is impossible to implement `down()`. For example, if we delete |
||||||
|
table rows in `up()`, we will not be able to recover them in `down()`. In this |
||||||
|
case, the migration is called irreversible, meaning we cannot roll back to |
||||||
|
a previous state of the database. In the above generated code, the `down()` |
||||||
|
method returns `false` to indicate that the migration cannot be reverted. |
||||||
|
|
||||||
|
As an example, let's show the migration about creating a news table. |
||||||
|
|
||||||
|
~~~ |
||||||
|
[php] |
||||||
|
class m101129_185401_create_news_table extends \yii\db\Migration |
||||||
|
{ |
||||||
|
public function up() |
||||||
|
{ |
||||||
|
$this->db->createCommand()->createTable('tbl_news, array( |
||||||
|
'id' => 'pk', |
||||||
|
'title' => 'string NOT NULL', |
||||||
|
'content' => 'text', |
||||||
|
))->execute(); |
||||||
|
} |
||||||
|
|
||||||
|
public function down() |
||||||
|
{ |
||||||
|
$this->db->createCommand()->dropTable('tbl_news')->execute(); |
||||||
|
} |
||||||
|
} |
||||||
|
~~~ |
||||||
|
|
||||||
|
The base class [\yii\db\Migration] exposes a database connection via `db` |
||||||
|
property. You can use it for manipulating data and schema of a database. |
||||||
|
|
||||||
|
Transactional Migrations |
||||||
|
------------------------ |
||||||
|
|
||||||
|
While performing complex DB migrations, we usually want to make sure that each |
||||||
|
migration succeed or fail as a whole so that the database maintains the |
||||||
|
consistency and integrity. In order to achieve this goal, we can exploit |
||||||
|
DB transactions. |
||||||
|
|
||||||
|
We could explicitly start a DB transaction and enclose the rest of the DB-related |
||||||
|
code within the transaction, like the following: |
||||||
|
|
||||||
|
~~~ |
||||||
|
[php] |
||||||
|
class m101129_185401_create_news_table extends \yii\db\Migration |
||||||
|
{ |
||||||
|
public function up() |
||||||
|
{ |
||||||
|
$transaction=$this->getDbConnection()->beginTransaction(); |
||||||
|
try |
||||||
|
{ |
||||||
|
$this->db->createCommand()->createTable('tbl_news, array( |
||||||
|
'id' => 'pk', |
||||||
|
'title' => 'string NOT NULL', |
||||||
|
'content' => 'text', |
||||||
|
))->execute(); |
||||||
|
$transaction->commit(); |
||||||
|
} |
||||||
|
catch(Exception $e) |
||||||
|
{ |
||||||
|
echo "Exception: ".$e->getMessage()."\n"; |
||||||
|
$transaction->rollback(); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// ...similar code for down() |
||||||
|
} |
||||||
|
~~~ |
||||||
|
|
||||||
|
> Note: Not all DBMS support transactions. And some DB queries cannot be put |
||||||
|
> into a transaction. In this case, you will have to implement `up()` and |
||||||
|
> `down()`, instead. And for MySQL, some SQL statements may cause |
||||||
|
> [implicit commit](http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html). |
||||||
|
|
||||||
|
|
||||||
|
Applying Migrations |
||||||
|
------------------- |
||||||
|
|
||||||
|
To apply all available new migrations (i.e., make the local database up-to-date), |
||||||
|
run the following command: |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate |
||||||
|
~~~ |
||||||
|
|
||||||
|
The command will show the list of all new migrations. If you confirm to apply |
||||||
|
the migrations, it will run the `up()` method in every new migration class, one |
||||||
|
after another, in the order of the timestamp value in the class name. |
||||||
|
|
||||||
|
After applying a migration, the migration tool will keep a record in a database |
||||||
|
table named `tbl_migration`. This allows the tool to identify which migrations |
||||||
|
have been applied and which are not. If the `tbl_migration` table does not exist, |
||||||
|
the tool will automatically create it in the database specified by the `db` |
||||||
|
application component. |
||||||
|
|
||||||
|
Sometimes, we may only want to apply one or a few new migrations. We can use the |
||||||
|
following command: |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/up 3 |
||||||
|
~~~ |
||||||
|
|
||||||
|
This command will apply the 3 new migrations. Changing the value 3 will allow |
||||||
|
us to change the number of migrations to be applied. |
||||||
|
|
||||||
|
We can also migrate the database to a specific version with the following command: |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/to 101129_185401 |
||||||
|
~~~ |
||||||
|
|
||||||
|
That is, we use the timestamp part of a migration name to specify the version |
||||||
|
that we want to migrate the database to. If there are multiple migrations between |
||||||
|
the last applied migration and the specified migration, all these migrations |
||||||
|
will be applied. If the specified migration has been applied before, then all |
||||||
|
migrations applied after it will be reverted (to be described in the next section). |
||||||
|
|
||||||
|
|
||||||
|
Reverting Migrations |
||||||
|
-------------------- |
||||||
|
|
||||||
|
To revert the last one or several applied migrations, we can use the following |
||||||
|
command: |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/down [step] |
||||||
|
~~~ |
||||||
|
|
||||||
|
where the optional `step` parameter specifies how many migrations to be reverted |
||||||
|
back. It defaults to 1, meaning reverting back the last applied migration. |
||||||
|
|
||||||
|
As we described before, not all migrations can be reverted. Trying to revert |
||||||
|
such migrations will throw an exception and stop the whole reverting process. |
||||||
|
|
||||||
|
|
||||||
|
Redoing Migrations |
||||||
|
------------------ |
||||||
|
|
||||||
|
Redoing migrations means first reverting and then applying the specified migrations. |
||||||
|
This can be done with the following command: |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/redo [step] |
||||||
|
~~~ |
||||||
|
|
||||||
|
where the optional `step` parameter specifies how many migrations to be redone. |
||||||
|
It defaults to 1, meaning redoing the last migration. |
||||||
|
|
||||||
|
|
||||||
|
Showing Migration Information |
||||||
|
----------------------------- |
||||||
|
|
||||||
|
Besides applying and reverting migrations, the migration tool can also display |
||||||
|
the migration history and the new migrations to be applied. |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/history [limit] |
||||||
|
yiic migrate/new [limit] |
||||||
|
~~~ |
||||||
|
|
||||||
|
where the optional parameter `limit` specifies the number of migrations to be |
||||||
|
displayed. If `limit` is not specified, all available migrations will be displayed. |
||||||
|
|
||||||
|
The first command shows the migrations that have been applied, while the second |
||||||
|
command shows the migrations that have not been applied. |
||||||
|
|
||||||
|
|
||||||
|
Modifying Migration History |
||||||
|
--------------------------- |
||||||
|
|
||||||
|
Sometimes, we may want to modify the migration history to a specific migration |
||||||
|
version without actually applying or reverting the relevant migrations. This |
||||||
|
often happens when developing a new migration. We can use the following command |
||||||
|
to achieve this goal. |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/mark 101129_185401 |
||||||
|
~~~ |
||||||
|
|
||||||
|
This command is very similar to `yiic migrate/to` command, except that it only |
||||||
|
modifies the migration history table to the specified version without applying |
||||||
|
or reverting the migrations. |
||||||
|
|
||||||
|
|
||||||
|
Customizing Migration Command |
||||||
|
----------------------------- |
||||||
|
|
||||||
|
There are several ways to customize the migration command. |
||||||
|
|
||||||
|
### Use Command Line Options |
||||||
|
|
||||||
|
The migration command comes with four options that can be specified in command |
||||||
|
line: |
||||||
|
|
||||||
|
* `interactive`: boolean, specifies whether to perform migrations in an |
||||||
|
interactive mode. Defaults to true, meaning the user will be prompted when |
||||||
|
performing a specific migration. You may set this to false should the |
||||||
|
migrations be done in a background process. |
||||||
|
|
||||||
|
* `migrationPath`: string, specifies the directory storing all migration class |
||||||
|
files. This must be specified in terms of a path alias, and the corresponding |
||||||
|
directory must exist. If not specified, it will use the `migrations` |
||||||
|
sub-directory under the application base path. |
||||||
|
|
||||||
|
* `migrationTable`: string, specifies the name of the database table for storing |
||||||
|
migration history information. It defaults to `tbl_migration`. The table |
||||||
|
structure is `version varchar(255) primary key, apply_time integer`. |
||||||
|
|
||||||
|
* `connectionID`: string, specifies the ID of the database application component. |
||||||
|
Defaults to 'db'. |
||||||
|
|
||||||
|
* `templateFile`: string, specifies the path of the file to be served as the code |
||||||
|
template for generating the migration classes. This must be specified in terms |
||||||
|
of a path alias (e.g. `application.migrations.template`). If not set, an |
||||||
|
internal template will be used. Inside the template, the token `{ClassName}` |
||||||
|
will be replaced with the actual migration class name. |
||||||
|
|
||||||
|
To specify these options, execute the migrate command using the following format |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/up --option1=value1 --option2=value2 ... |
||||||
|
~~~ |
||||||
|
|
||||||
|
For example, if we want to migrate for a `forum` module whose migration files |
||||||
|
are located within the module's `migrations` directory, we can use the following |
||||||
|
command: |
||||||
|
|
||||||
|
~~~ |
||||||
|
yiic migrate/up --migrationPath=ext.forum.migrations |
||||||
|
~~~ |
||||||
|
|
||||||
|
|
||||||
|
### Configure Command Globally |
||||||
|
|
||||||
|
While command line options allow us to configure the migration command |
||||||
|
on-the-fly, sometimes we may want to configure the command once for all. |
||||||
|
For example, we may want to use a different table to store the migration history, |
||||||
|
or we may want to use a customized migration template. We can do so by modifying |
||||||
|
the console application's configuration file like the following, |
||||||
|
|
||||||
|
```php |
||||||
|
TBD |
||||||
|
``` |
||||||
|
|
||||||
|
Now if we run the `migrate` command, the above configurations will take effect |
||||||
|
without requiring us to enter the command line options every time. |
@ -0,0 +1,181 @@ |
|||||||
|
Performance Tuning |
||||||
|
================== |
||||||
|
|
||||||
|
Application performance consists of two parts. First is the framework performance |
||||||
|
and the second is the application itself. Yii has a pretty low performance impact |
||||||
|
on your application out of the box and can be fine-tuned further for production |
||||||
|
environment. As for the application, we'll provide some of the best practices |
||||||
|
along with examples on how to apply them to Yii. |
||||||
|
|
||||||
|
Preparing framework for production |
||||||
|
---------------------------------- |
||||||
|
|
||||||
|
### Disabling Debug Mode |
||||||
|
|
||||||
|
First thing you should do before deploying your application to production environment |
||||||
|
is to disable debug mode. A Yii application runs in debug mode if the constant |
||||||
|
`YII_DEBUG` is defined as `true` in `index.php` so to disable debug the following |
||||||
|
should be in your `index.php`: |
||||||
|
|
||||||
|
```php |
||||||
|
defined('YII_DEBUG') or define('YII_DEBUG', false); |
||||||
|
``` |
||||||
|
|
||||||
|
Debug mode is very useful during development stage, but it would impact performance |
||||||
|
because some components cause extra burden in debug mode. For example, the message |
||||||
|
logger may record additional debug information for every message being logged. |
||||||
|
|
||||||
|
### Enabling PHP opcode cache |
||||||
|
|
||||||
|
Enabling the PHP opcode cache improves any PHP application performance and lowers |
||||||
|
memory usage significantly. Yii is no exception. It was tested with |
||||||
|
[APC PHP extension](http://php.net/manual/en/book.apc.php) that caches |
||||||
|
and optimizes PHP intermediate code and avoids the time spent in parsing PHP |
||||||
|
scripts for every incoming request. |
||||||
|
|
||||||
|
### Turning on ActiveRecord database schema caching |
||||||
|
|
||||||
|
If the application is using Active Record, we should turn on the schema caching |
||||||
|
to save the time of parsing database schema. This can be done by setting the |
||||||
|
`Connection::enableSchemaCache` property to be `true` via application configuration |
||||||
|
`protected/config/main.php`: |
||||||
|
|
||||||
|
```php |
||||||
|
return array( |
||||||
|
// ... |
||||||
|
'components' => array( |
||||||
|
// ... |
||||||
|
'db' => array( |
||||||
|
'class' => 'yii\db\Connection', |
||||||
|
'dsn' => 'mysql:host=localhost;dbname=mydatabase', |
||||||
|
'username' => 'root', |
||||||
|
'password' => '', |
||||||
|
'enableSchemaCache' => true, |
||||||
|
|
||||||
|
// Duration of schema cache. |
||||||
|
// 'schemaCacheDuration' => 3600, |
||||||
|
|
||||||
|
// Name of the cache component used. Default is 'cache'. |
||||||
|
//'schemaCache' => 'cache', |
||||||
|
), |
||||||
|
'cache' => array( |
||||||
|
'class' => 'yii\caching\FileCache', |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
``` |
||||||
|
|
||||||
|
Note that `cache` application component should be configured. |
||||||
|
|
||||||
|
### Combining and Minimizing Assets |
||||||
|
|
||||||
|
TBD |
||||||
|
|
||||||
|
### Using better storage for sessions |
||||||
|
|
||||||
|
By default PHP uses files to handle sessions. It is OK for development and |
||||||
|
small projects but when it comes to handling concurrent requests it's better to |
||||||
|
switch to another storage such as database. You can do so by configuring your |
||||||
|
application via `protected/config/main.php`: |
||||||
|
|
||||||
|
```php |
||||||
|
return array( |
||||||
|
// ... |
||||||
|
'components' => array( |
||||||
|
'session' => array( |
||||||
|
'class' => 'yii\web\DbSession', |
||||||
|
|
||||||
|
// Set the following if want to use DB component other than |
||||||
|
// default 'db'. |
||||||
|
// 'db' => 'mydb', |
||||||
|
|
||||||
|
// To override default session table set the following |
||||||
|
// 'sessionTable' => 'my_session', |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
``` |
||||||
|
|
||||||
|
You can use `CacheSession` to store sessions using cache. Note that some |
||||||
|
cache storages such as memcached has no guaranteee that session data will not |
||||||
|
be lost leading to unexpected logouts. |
||||||
|
|
||||||
|
Improving application |
||||||
|
--------------------- |
||||||
|
|
||||||
|
### Using Serverside Caching Techniques |
||||||
|
|
||||||
|
As described in the Caching section, Yii provides several caching solutions that |
||||||
|
may improve the performance of a Web application significantly. If the generation |
||||||
|
of some data takes long time, we can use the data caching approach to reduce the |
||||||
|
data generation frequency; If a portion of page remains relatively static, we |
||||||
|
can use the fragment caching approach to reduce its rendering frequency; |
||||||
|
If a whole page remains relative static, we can use the page caching approach to |
||||||
|
save the rendering cost for the whole page. |
||||||
|
|
||||||
|
|
||||||
|
### Leveraging HTTP to save procesing time and bandwidth |
||||||
|
|
||||||
|
TBD |
||||||
|
|
||||||
|
### Database Optimization |
||||||
|
|
||||||
|
Fetching data from database is often the main performance bottleneck in |
||||||
|
a Web application. Although using caching may alleviate the performance hit, |
||||||
|
it does not fully solve the problem. When the database contains enormous data |
||||||
|
and the cached data is invalid, fetching the latest data could be prohibitively |
||||||
|
expensive without proper database and query design. |
||||||
|
|
||||||
|
Design index wisely in a database. Indexing can make SELECT queries much faster, |
||||||
|
but it may slow down INSERT, UPDATE or DELETE queries. |
||||||
|
|
||||||
|
For complex queries, it is recommended to create a database view for it instead |
||||||
|
of issuing the queries inside the PHP code and asking DBMS to parse them repetitively. |
||||||
|
|
||||||
|
Do not overuse Active Record. Although Active Record is good at modelling data |
||||||
|
in an OOP fashion, it actually degrades performance due to the fact that it needs |
||||||
|
to create one or several objects to represent each row of query result. For data |
||||||
|
intensive applications, using DAO or database APIs at lower level could be |
||||||
|
a better choice. |
||||||
|
|
||||||
|
Last but not least, use LIMIT in your SELECT queries. This avoids fetching |
||||||
|
overwhelming data from database and exhausting the memory allocated to PHP. |
||||||
|
|
||||||
|
### Using asArray |
||||||
|
|
||||||
|
A good way to save memory and processing time on read-only pages is to use |
||||||
|
ActiveRecord's `asArray` method. |
||||||
|
|
||||||
|
```php |
||||||
|
class PostController extends Controller |
||||||
|
{ |
||||||
|
public function actionIndex() |
||||||
|
{ |
||||||
|
$posts = Post::find()->orderBy('id DESC')->limit(100)->asArray()->all(); |
||||||
|
echo $this->render('index', array( |
||||||
|
'posts' => $posts, |
||||||
|
)); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
In the view you should access fields of each invidual record from `$posts` as array: |
||||||
|
|
||||||
|
```php |
||||||
|
foreach($posts as $post) { |
||||||
|
echo $post['title']."<br>"; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
Note that you can use array notation even if `asArray` wasn't specified and you're |
||||||
|
working with AR objects. |
||||||
|
|
||||||
|
### Processing data in background |
||||||
|
|
||||||
|
In order to respond to user requests faster you can process heavy parts of the |
||||||
|
request later if there's no need for immediate response. |
||||||
|
|
||||||
|
- Cron jobs + console. |
||||||
|
- queues + handlers. |
||||||
|
|
||||||
|
TBD |
@ -0,0 +1,459 @@ |
|||||||
|
Upgrading from Yii 1.1 |
||||||
|
====================== |
||||||
|
|
||||||
|
In this chapter, we list the major changes introduced in Yii 2.0 since version 1.1. |
||||||
|
We hope this list will make it easier for you to upgrade from Yii 1.1 and quickly |
||||||
|
master Yii 2.0 based on your existing Yii knowledge. |
||||||
|
|
||||||
|
|
||||||
|
Namespace |
||||||
|
--------- |
||||||
|
|
||||||
|
The most obvious change in Yii 2.0 is the use of namespaces. Almost every core class |
||||||
|
is namespaced, e.g., `yii\web\Request`. The "C" prefix is no longer used in class names. |
||||||
|
The naming of the namespaces follows the directory structure. For example, `yii\web\Request` |
||||||
|
indicates the corresponding class file is `web/Request.php` under the Yii framework folder. |
||||||
|
You can use any core class without explicitly include that class file, thanks to the Yii |
||||||
|
class loader. |
||||||
|
|
||||||
|
|
||||||
|
Component and Object |
||||||
|
-------------------- |
||||||
|
|
||||||
|
Yii 2.0 breaks the `CComponent` class in 1.1 into two classes: `Object` and `Component`. |
||||||
|
The `Object` class is a lightweight base class that allows defining class properties |
||||||
|
via getters and setters. The `Component` class extends from `Object` and supports |
||||||
|
the event feature and the behavior feature. |
||||||
|
|
||||||
|
If your class does not need the event or behavior feature, you should consider using |
||||||
|
`Object` as the base class. This is usually the case for classes that represent basic |
||||||
|
data structures. |
||||||
|
|
||||||
|
|
||||||
|
Object Configuration |
||||||
|
-------------------- |
||||||
|
|
||||||
|
The `Object` class introduces a uniform way of configuring objects. Any descendant class |
||||||
|
of `Object` should declare its constructor (if needed) in the following way so that |
||||||
|
it can be properly configured: |
||||||
|
|
||||||
|
```php |
||||||
|
class MyClass extends \yii\Object |
||||||
|
{ |
||||||
|
public function __construct($param1, $param2, $config = array()) |
||||||
|
{ |
||||||
|
// ... initialization before configuration is applied |
||||||
|
|
||||||
|
parent::__construct($config); |
||||||
|
} |
||||||
|
|
||||||
|
public function init() |
||||||
|
{ |
||||||
|
parent::init(); |
||||||
|
|
||||||
|
// ... initialization after configuration is applied |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
In the above, the last parameter of the constructor must take a configuration array |
||||||
|
which contains name-value pairs for initializing the properties at the end of the constructor. |
||||||
|
You can override the `init()` method to do initialization work that should be done after |
||||||
|
the configuration is applied. |
||||||
|
|
||||||
|
By following this convention, you will be able to create and configure a new object |
||||||
|
using a configuration array like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
$object = Yii::createObject(array( |
||||||
|
'class' => 'MyClass', |
||||||
|
'property1' => 'abc', |
||||||
|
'property2' => 'cde', |
||||||
|
), $param1, $param2); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Events |
||||||
|
------ |
||||||
|
|
||||||
|
There is no longer the need to define an `on`-method in order to define an event in Yii 2.0. |
||||||
|
Instead, you can use whatever event names. To attach a handler to an event, you should |
||||||
|
use the `on` method now: |
||||||
|
|
||||||
|
```php |
||||||
|
$component->on($eventName, $handler); |
||||||
|
// To detach the handler, use: |
||||||
|
// $component->off($eventName, $handler); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
When you attach a handler, you can now associate it with some parameters which can be later |
||||||
|
accessed via the event parameter by the handler: |
||||||
|
|
||||||
|
```php |
||||||
|
$component->on($eventName, $handler, $params); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
Because of this change, you can now use "global" events. Simply trigger and attach handlers to |
||||||
|
an event of the application instance: |
||||||
|
|
||||||
|
```php |
||||||
|
Yii::$app->on($eventName, $handler); |
||||||
|
.... |
||||||
|
// this will trigger the event and cause $handler to be invoked. |
||||||
|
Yii::$app->trigger($eventName); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
Path Alias |
||||||
|
---------- |
||||||
|
|
||||||
|
Yii 2.0 expands the usage of path aliases to both file/directory paths and URLs. An alias |
||||||
|
must start with a `@` character so that it can be differentiated from file/directory paths and URLs. |
||||||
|
For example, the alias `@yii` refers to the Yii installation directory. Path aliases are |
||||||
|
supported in most places in the Yii core code. For example, `FileCache::cachePath` can take |
||||||
|
both a path alias and a normal directory path. |
||||||
|
|
||||||
|
Path alias is also closely related with class namespaces. It is recommended that a path |
||||||
|
alias defined for each root namespace so that you can use Yii class autoloader without |
||||||
|
any further configuration. For example, because `@yii` refers to the Yii installation directory, |
||||||
|
a class like `yii\web\Request` can be autoloaded by Yii. If you use a third party library |
||||||
|
such as Zend Framework, you may define a path alias `@Zend` which refers to its installation directory. |
||||||
|
And Yii will be able to autoload any class in this library. |
||||||
|
|
||||||
|
|
||||||
|
View |
||||||
|
---- |
||||||
|
|
||||||
|
Yii 2.0 introduces a `View` class to represent the view part in the MVC pattern. |
||||||
|
It can be configured globally through the "view" application component. It is also |
||||||
|
accessible in any view file via `$this`. This is one of the biggest changes compared to 1.1: |
||||||
|
**`$this` in a view file no longer refers to the controller or widget object.** |
||||||
|
It refers to the view object that is used to render the view file. To access the controller |
||||||
|
or the widget object, you have to use `$this->context` now. |
||||||
|
|
||||||
|
Because you can access the view object through the "view" application component, |
||||||
|
you can now render a view file like the following anywhere in your code, not necessarily |
||||||
|
in controllers or widgets: |
||||||
|
|
||||||
|
```php |
||||||
|
$content = Yii::$app->view->renderFile($viewFile, $params); |
||||||
|
// You can also explicitly create a new View instance to do the rendering |
||||||
|
// $view = new View; |
||||||
|
// $view->renderFile($viewFile, $params); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
Also, there is no more `CClientScript` in Yii 2.0. The `View` class has taken over its role |
||||||
|
with significant improvements. For more details, please see the "assets" subsection. |
||||||
|
|
||||||
|
While Yii 2.0 continues to use PHP as its main template language, it comes with built-in |
||||||
|
support for two popular template engines: Smarty and Twig. The Prado template engine is |
||||||
|
no longer supported. To use these template engines, you just need to use `tpl` as the file |
||||||
|
extension for your Smarty views, or `twig` for Twig views. You may also configure the |
||||||
|
`View::renderers` property to use other template engines. |
||||||
|
|
||||||
|
|
||||||
|
Models |
||||||
|
------ |
||||||
|
|
||||||
|
A model is now associated with a form name returned its `formName()` method. This is |
||||||
|
mainly used when using HTML forms to collect user inputs for a model. Previously in 1.1, |
||||||
|
this is usually hardcoded as the class name of the model. |
||||||
|
|
||||||
|
|
||||||
|
Yii 2.0 introduces a new method called `scenarios()` to declare which attributes require |
||||||
|
validation under which scenario. Child classes should overwrite `scenarios()` to return |
||||||
|
a list of scenarios and the corresponding attributes that need to be validated when |
||||||
|
`validate()` is called. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
public function scenarios() |
||||||
|
{ |
||||||
|
return array( |
||||||
|
'backend' => array('email', 'role'), |
||||||
|
'frontend' => array('email', '!name'), |
||||||
|
); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
This method also determines which attributes are safe and which are not. In particular, |
||||||
|
given a scenario, if an attribute appears in the corresponding attribute list in `scenarios()` |
||||||
|
and the name is not prefixed with `!`, it is considered *safe*. |
||||||
|
|
||||||
|
Because of the above change, Yii 2.0 no longer has "safe" and "unsafe" validators. |
||||||
|
|
||||||
|
If your model only has one scenario (very common), you do not have to overwrite `scenarios()`, |
||||||
|
and everything will still work like the 1.1 way. |
||||||
|
|
||||||
|
|
||||||
|
Controllers |
||||||
|
----------- |
||||||
|
|
||||||
|
The `render()` and `renderPartial()` methods now return the rendering results instead of directly |
||||||
|
sending them out. You have to `echo` them explicitly, e.g., `echo $this->render(...);`. |
||||||
|
|
||||||
|
A new method called `populate()` is introduced to simplify the data population from user inputs |
||||||
|
to a model. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
$model = new Post; |
||||||
|
if ($this->populate($_POST, $model)) {...} |
||||||
|
// which is equivalent to: |
||||||
|
if (isset($_POST['Post'])) { |
||||||
|
$model->attributes = $_POST['Post']; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Themes |
||||||
|
------ |
||||||
|
|
||||||
|
Theme works completely different in 2.0. It is now based on a path map to "translate" a source |
||||||
|
view into a themed view. For example, if the path map for a theme is |
||||||
|
`array('/www/views' => '/www/themes/basic')`, then the themed version for a view file |
||||||
|
`/www/views/site/index.php` will be `/www/themes/basic/site/index.php`. |
||||||
|
|
||||||
|
For this reason, theme can now be applied to any view file, even if a view rendered outside |
||||||
|
of the context of a controller or a widget. |
||||||
|
|
||||||
|
There is no more `CThemeManager`. Instead, `theme` is a configurable property of the "view" |
||||||
|
application component. |
||||||
|
|
||||||
|
|
||||||
|
Console Applications |
||||||
|
-------------------- |
||||||
|
|
||||||
|
Console applications are now composed by controllers, too, like Web applications. In fact, |
||||||
|
console controllers and Web controllers share the same base controller class. |
||||||
|
|
||||||
|
Each console controller is like `CConsoleCommand` in 1.1. It consists of one or several |
||||||
|
actions. You use the `yiic <route>` command to execute a console command, where `<route>` |
||||||
|
stands for a controller route (e.g. `sitemap/index`). Additional anonymous arguments |
||||||
|
are passed as the parameters to the corresponding controller action method, and named arguments |
||||||
|
are treated as global options declared in `globalOptions()`. |
||||||
|
|
||||||
|
Yii 2.0 supports automatic generation of command help information from comment blocks. |
||||||
|
|
||||||
|
|
||||||
|
I18N |
||||||
|
---- |
||||||
|
|
||||||
|
Yii 2.0 removes date formatter and number formatter in favor of the PECL intl PHP module. |
||||||
|
|
||||||
|
Message translation is still supported, but managed via the "i18n" application component. |
||||||
|
The component manages a set of message sources, which allows you to use different message |
||||||
|
sources based on message categories. For more information, see the class documentation for `I18N`. |
||||||
|
|
||||||
|
The message translation method is changed by merging the message category into the message being |
||||||
|
translated. For example, `Yii::t('yii|message to be translated')`. |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Action Filters |
||||||
|
-------------- |
||||||
|
|
||||||
|
Action filters are implemented via behaviors now. You should extend from `ActionFilter` to |
||||||
|
define a new filter. To use a filter, you should attach the filter class to the controller |
||||||
|
as a behavior. For example, to use the `AccessControl` filter, you should have the following |
||||||
|
code in a controller: |
||||||
|
|
||||||
|
```php |
||||||
|
public function behaviors() |
||||||
|
{ |
||||||
|
return array( |
||||||
|
'access' => array( |
||||||
|
'class' => 'yii\web\AccessControl', |
||||||
|
'rules' => array( |
||||||
|
array('allow' => true, 'actions' => array('admin'), 'roles' => array('@')), |
||||||
|
array('allow' => false), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Assets |
||||||
|
------ |
||||||
|
|
||||||
|
Yii 2.0 introduces a new concept called *asset bundle*. It is a bit similar to script |
||||||
|
packages (managed by `CClientScript`) in 1.1, but with better support. |
||||||
|
|
||||||
|
An asset bundle is a collection of asset files (e.g. JavaScript files, CSS files, image files, etc.) |
||||||
|
under a directory. By registering an asset bundle via `View::registerAssetBundle()`, you |
||||||
|
will be able to make the assets in that bundle accessible via Web, and the current page |
||||||
|
will automatically contain references to the JavaScript and CSS files in that bundle. |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Static Helpers |
||||||
|
-------------- |
||||||
|
|
||||||
|
Yii 2.0 introduces many commonly used static helper classes, such as `Html`, `ArrayHelper`, |
||||||
|
`StringHelper`. These classes are designed to be easily extended. Note that static classes |
||||||
|
are usually hard to be extended because of the fixed class name references. But Yii 2.0 |
||||||
|
introduces the class map (via `Yii::$classMap`) to overcome this difficulty. |
||||||
|
|
||||||
|
|
||||||
|
`ActiveForm` |
||||||
|
------------ |
||||||
|
|
||||||
|
Yii 2.0 introduces the *field* concept for building a form using `ActiveForm`. A field |
||||||
|
is a container consisting of a label, an input, and an error message. It is represented |
||||||
|
as an `ActiveField` object. Using fields, you can build a form more cleanly than before: |
||||||
|
|
||||||
|
```php |
||||||
|
<?php $form = $this->beginWidget('yii\widgets\ActiveForm'); ?> |
||||||
|
<?php echo $form->field($model, 'username')->textInput(); ?> |
||||||
|
<?php echo $form->field($model, 'password')->passwordInput(); ?> |
||||||
|
<div class="form-actions"> |
||||||
|
<?php echo Html::submitButton('Login'); ?> |
||||||
|
</div> |
||||||
|
<?php $this->endWidget(); ?> |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Query Builder |
||||||
|
------------- |
||||||
|
|
||||||
|
In 1.1, query building is scattered among several classes, including `CDbCommand`, |
||||||
|
`CDbCriteria`, and `CDbCommandBuilder`. Yii 2.0 uses `Query` to represent a DB query |
||||||
|
and `QueryBuilder` to generate SQL statements from query objects. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
$query = new \yii\db\Query; |
||||||
|
$query->select('id, name') |
||||||
|
->from('tbl_user') |
||||||
|
->limit(10); |
||||||
|
|
||||||
|
$command = $query->createCommand(); |
||||||
|
$sql = $command->sql; |
||||||
|
$rows = $command->queryAll(); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
Best of all, such query building methods can be used together with `ActiveRecord`, |
||||||
|
as explained in the next sub-section. |
||||||
|
|
||||||
|
|
||||||
|
ActiveRecord |
||||||
|
------------ |
||||||
|
|
||||||
|
ActiveRecord has undergone significant changes in Yii 2.0. The most important one |
||||||
|
is about relational ActiveRecord query. In 1.1, you have to declare the relations |
||||||
|
in the `relations()` method. In 2.0, this is done via getter methods that return |
||||||
|
an `ActiveQuery` object. For example, the following method declares an "orders" relation: |
||||||
|
|
||||||
|
```php |
||||||
|
class Customer extends \yii\db\ActiveRecord |
||||||
|
{ |
||||||
|
public function getOrders() |
||||||
|
{ |
||||||
|
return $this->hasMany('Order', array('customer_id' => 'id')); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
You can use `$customer->orders` to access the customer's orders. You can also |
||||||
|
use `$customer->getOrders()->andWhere('status=1')->all()` to perform on-the-fly |
||||||
|
relational query with customized query conditions. |
||||||
|
|
||||||
|
When loading relational records in an eager way, Yii 2.0 does it differently from 1.1. |
||||||
|
In particular, in 1.1 a JOIN query would be used to bring both the primary and the relational |
||||||
|
records; while in 2.0, two SQL statements are executed without using JOIN: the first |
||||||
|
statement brings back the primary records and the second brings back the relational records |
||||||
|
by filtering with the primary keys of the primary records. |
||||||
|
|
||||||
|
|
||||||
|
Yii 2.0 no longer uses the `model()` method when performing queries. Instead, you |
||||||
|
use the `find()` method like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
// to retrieve all *active* customers and order them by their ID: |
||||||
|
$customers = Customer::find() |
||||||
|
->where(array('status' => $active)) |
||||||
|
->orderBy('id') |
||||||
|
->all(); |
||||||
|
// return the customer whose PK is 1 |
||||||
|
$customer = Customer::find(1); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
The `find()` method returns an instance of `ActiveQuery` which is a subclass of `Query`. |
||||||
|
Therefore, you can use all query methods of `Query`. |
||||||
|
|
||||||
|
Instead of returning ActiveRecord objects, you may call `ActiveQuery::asArray()` to |
||||||
|
return results in terms of arrays. This is more efficient and is especially useful |
||||||
|
when you need to return large number of records. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
$customers = Customer::find()->asArray()->all(); |
||||||
|
``` |
||||||
|
|
||||||
|
By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes |
||||||
|
would be saved to database when you call `save()`, regardless they are changed or not, |
||||||
|
unless you explicitly list the attributes to save. |
||||||
|
|
||||||
|
|
||||||
|
Auto-quoting Table and Column Names |
||||||
|
------------------------------------ |
||||||
|
|
||||||
|
Yii 2.0 supports automatic quoting of database table and column names. A name enclosed |
||||||
|
within double curly brackets is treated as a table name, and a name enclosed within |
||||||
|
double square brackets is treated as a column name. They will be quoted according to |
||||||
|
the database driver being used. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
$command = $connection->createCommand('SELECT [[id]] FROM {{posts}}'); |
||||||
|
echo $command->sql; // MySQL: SELECT `id` FROM `posts` |
||||||
|
``` |
||||||
|
|
||||||
|
This feature is especially useful if you are developing an application that supports |
||||||
|
different DBMS. |
||||||
|
|
||||||
|
|
||||||
|
User and Identity |
||||||
|
----------------- |
||||||
|
|
||||||
|
The `CWebUser` class in 1.1 is now replaced by `\yii\Web\User`, and there is no more |
||||||
|
`CUserIdentity` class. Instead, you should implement the `Identity` interface which |
||||||
|
is much more straightforward to implement. The bootstrap application provides such an example. |
||||||
|
|
||||||
|
|
||||||
|
URL Management |
||||||
|
-------------- |
||||||
|
|
||||||
|
URL management is similar to 1.1. A major enhancement is that it now supports optional |
||||||
|
parameters. For example, if you have rule declared as follows, then it will match |
||||||
|
both `post/popular` and `post/1/popular`. In 1.1, you would have to use two rules to achieve |
||||||
|
the same goal. |
||||||
|
|
||||||
|
```php |
||||||
|
array( |
||||||
|
'pattern' => 'post/<page:\d+>/<tag>', |
||||||
|
'route' => 'post/index', |
||||||
|
'defaults' => array('page' => 1), |
||||||
|
) |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Response |
||||||
|
-------- |
||||||
|
|
||||||
|
Extensions |
||||||
|
---------- |
||||||
|
|
||||||
|
Integration with Composer |
||||||
|
------------------------- |
||||||
|
|
||||||
|
TBD |
||||||
|
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
@ -1,17 +0,0 @@ |
|||||||
<?php |
|
||||||
/** @var $controller \yii\console\controllers\AppController */ |
|
||||||
$controller = $this; |
|
||||||
|
|
||||||
return array( |
|
||||||
'default' => array( |
|
||||||
'index.php' => array( |
|
||||||
'handler' => function($source) use ($controller) { |
|
||||||
return $controller->replaceRelativePath($source, realpath(YII_PATH.'/yii.php'), 'yii'); |
|
||||||
}, |
|
||||||
'permissions' => 0777, |
|
||||||
), |
|
||||||
'protected/runtime' => array( |
|
||||||
'permissions' => 0755, |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
@ -1,10 +0,0 @@ |
|||||||
<?php |
|
||||||
define('YII_DEBUG', true); |
|
||||||
|
|
||||||
require __DIR__.'/../framework/yii.php'; |
|
||||||
|
|
||||||
$config = require dirname(__DIR__).'/protected/config/main.php'; |
|
||||||
$config['basePath'] = dirname(__DIR__).'/protected'; |
|
||||||
|
|
||||||
$app = new \yii\web\Application($config); |
|
||||||
$app->run(); |
|
@ -1,20 +0,0 @@ |
|||||||
<?php |
|
||||||
return array( |
|
||||||
'id' => 'webapp', |
|
||||||
'name' => 'My Web Application', |
|
||||||
|
|
||||||
'components' => array( |
|
||||||
// uncomment the following to use a MySQL database |
|
||||||
/* |
|
||||||
'db' => array( |
|
||||||
'class' => 'yii\db\Connection', |
|
||||||
'dsn' => 'mysql:host=localhost;dbname=testdrive', |
|
||||||
'username' => 'root', |
|
||||||
'password' => '', |
|
||||||
), |
|
||||||
*/ |
|
||||||
'cache' => array( |
|
||||||
'class' => 'yii\caching\DummyCache', |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
@ -1,15 +0,0 @@ |
|||||||
<?php |
|
||||||
use \yii\web\Controller; |
|
||||||
|
|
||||||
/** |
|
||||||
* SiteController |
|
||||||
*/ |
|
||||||
class SiteController extends Controller |
|
||||||
{ |
|
||||||
public function actionIndex() |
|
||||||
{ |
|
||||||
echo $this->render('index', array( |
|
||||||
'name' => 'Qiang', |
|
||||||
)); |
|
||||||
} |
|
||||||
} |
|
@ -1,17 +0,0 @@ |
|||||||
<?php use yii\helpers\Html as Html; ?> |
|
||||||
<!doctype html> |
|
||||||
<html lang="<?php \Yii::$app->language?>">
|
|
||||||
<head> |
|
||||||
<meta charset="utf-8" /> |
|
||||||
<title><?php echo Html::encode($this->title)?></title>
|
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<h1><?php echo Html::encode($this->title)?></h1>
|
|
||||||
<div class="content"> |
|
||||||
<?php echo $content?> |
|
||||||
</div> |
|
||||||
<div class="footer"> |
|
||||||
<?php echo \Yii::powered()?> |
|
||||||
</div> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -1 +0,0 @@ |
|||||||
Hello, <?php echo $name?>!
|
|
@ -1,470 +0,0 @@ |
|||||||
<?php |
|
||||||
/** |
|
||||||
* @link http://www.yiiframework.com/ |
|
||||||
* @copyright Copyright (c) 2008 Yii Software LLC |
|
||||||
* @license http://www.yiiframework.com/license/ |
|
||||||
*/ |
|
||||||
|
|
||||||
namespace yii\helpers\base; |
|
||||||
|
|
||||||
// todo test this on all kinds of terminals, especially windows (check out lib ncurses) |
|
||||||
|
|
||||||
/** |
|
||||||
* Console View is the base class for console view components |
|
||||||
* |
|
||||||
* A console view provides functionality to create rich console application by allowing to format output |
|
||||||
* by adding color and font style to it. |
|
||||||
* |
|
||||||
* @author Carsten Brandt <mail@cebe.cc> |
|
||||||
* @since 2.0 |
|
||||||
*/ |
|
||||||
class ConsoleColor |
|
||||||
{ |
|
||||||
const FG_BLACK = 30; |
|
||||||
const FG_RED = 31; |
|
||||||
const FG_GREEN = 32; |
|
||||||
const FG_YELLOW = 33; |
|
||||||
const FG_BLUE = 34; |
|
||||||
const FG_PURPLE = 35; |
|
||||||
const FG_CYAN = 36; |
|
||||||
const FG_GREY = 37; |
|
||||||
|
|
||||||
const BG_BLACK = 40; |
|
||||||
const BG_RED = 41; |
|
||||||
const BG_GREEN = 42; |
|
||||||
const BG_YELLOW = 43; |
|
||||||
const BG_BLUE = 44; |
|
||||||
const BG_PURPLE = 45; |
|
||||||
const BG_CYAN = 46; |
|
||||||
const BG_GREY = 47; |
|
||||||
|
|
||||||
const BOLD = 1; |
|
||||||
const ITALIC = 3; |
|
||||||
const UNDERLINE = 4; |
|
||||||
const BLINK = 5; |
|
||||||
const NEGATIVE = 7; |
|
||||||
const CONCEALED = 8; |
|
||||||
const CROSSED_OUT = 9; |
|
||||||
const FRAMED = 51; |
|
||||||
const ENCIRCLED = 52; |
|
||||||
const OVERLINED = 53; |
|
||||||
|
|
||||||
/** |
|
||||||
* Moves the terminal cursor up by sending ANSI control code CUU to the terminal. |
|
||||||
* If the cursor is already at the edge of the screen, this has no effect. |
|
||||||
* @param integer $rows number of rows the cursor should be moved up |
|
||||||
*/ |
|
||||||
public static function moveCursorUp($rows=1) |
|
||||||
{ |
|
||||||
echo "\033[" . (int) $rows . 'A'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Moves the terminal cursor down by sending ANSI control code CUD to the terminal. |
|
||||||
* If the cursor is already at the edge of the screen, this has no effect. |
|
||||||
* @param integer $rows number of rows the cursor should be moved down |
|
||||||
*/ |
|
||||||
public static function moveCursorDown($rows=1) |
|
||||||
{ |
|
||||||
echo "\033[" . (int) $rows . 'B'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Moves the terminal cursor forward by sending ANSI control code CUF to the terminal. |
|
||||||
* If the cursor is already at the edge of the screen, this has no effect. |
|
||||||
* @param integer $steps number of steps the cursor should be moved forward |
|
||||||
*/ |
|
||||||
public static function moveCursorForward($steps=1) |
|
||||||
{ |
|
||||||
echo "\033[" . (int) $steps . 'C'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Moves the terminal cursor backward by sending ANSI control code CUB to the terminal. |
|
||||||
* If the cursor is already at the edge of the screen, this has no effect. |
|
||||||
* @param integer $steps number of steps the cursor should be moved backward |
|
||||||
*/ |
|
||||||
public static function moveCursorBackward($steps=1) |
|
||||||
{ |
|
||||||
echo "\033[" . (int) $steps . 'D'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Moves the terminal cursor to the beginning of the next line by sending ANSI control code CNL to the terminal. |
|
||||||
* @param integer $lines number of lines the cursor should be moved down |
|
||||||
*/ |
|
||||||
public static function moveCursorNextLine($lines=1) |
|
||||||
{ |
|
||||||
echo "\033[" . (int) $lines . 'E'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Moves the terminal cursor to the beginning of the previous line by sending ANSI control code CPL to the terminal. |
|
||||||
* @param integer $lines number of lines the cursor should be moved up |
|
||||||
*/ |
|
||||||
public static function moveCursorPrevLine($lines=1) |
|
||||||
{ |
|
||||||
echo "\033[" . (int) $lines . 'F'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Moves the cursor to an absolute position given as column and row by sending ANSI control code CUP or CHA to the terminal. |
|
||||||
* @param integer $column 1-based column number, 1 is the left edge of the screen. |
|
||||||
* @param integer|null $row 1-based row number, 1 is the top edge of the screen. if not set, will move cursor only in current line. |
|
||||||
*/ |
|
||||||
public static function moveCursorTo($column, $row=null) |
|
||||||
{ |
|
||||||
if ($row === null) { |
|
||||||
echo "\033[" . (int) $column . 'G'; |
|
||||||
} else { |
|
||||||
echo "\033[" . (int) $row . ';' . (int) $column . 'H'; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Scrolls whole page up by sending ANSI control code SU to the terminal. |
|
||||||
* New lines are added at the bottom. This is not supported by ANSI.SYS used in windows. |
|
||||||
* @param int $lines number of lines to scroll up |
|
||||||
*/ |
|
||||||
public static function scrollUp($lines=1) |
|
||||||
{ |
|
||||||
echo "\033[".(int)$lines."S"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Scrolls whole page down by sending ANSI control code SD to the terminal. |
|
||||||
* New lines are added at the top. This is not supported by ANSI.SYS used in windows. |
|
||||||
* @param int $lines number of lines to scroll down |
|
||||||
*/ |
|
||||||
public static function scrollDown($lines=1) |
|
||||||
{ |
|
||||||
echo "\033[".(int)$lines."T"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Saves the current cursor position by sending ANSI control code SCP to the terminal. |
|
||||||
* Position can then be restored with {@link restoreCursorPosition}. |
|
||||||
*/ |
|
||||||
public static function saveCursorPosition() |
|
||||||
{ |
|
||||||
echo "\033[s"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Restores the cursor position saved with {@link saveCursorPosition} by sending ANSI control code RCP to the terminal. |
|
||||||
*/ |
|
||||||
public static function restoreCursorPosition() |
|
||||||
{ |
|
||||||
echo "\033[u"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Hides the cursor by sending ANSI DECTCEM code ?25l to the terminal. |
|
||||||
* Use {@link showCursor} to bring it back. |
|
||||||
* Do not forget to show cursor when your application exits. Cursor might stay hidden in terminal after exit. |
|
||||||
*/ |
|
||||||
public static function hideCursor() |
|
||||||
{ |
|
||||||
echo "\033[?25l"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Will show a cursor again when it has been hidden by {@link hideCursor} by sending ANSI DECTCEM code ?25h to the terminal. |
|
||||||
*/ |
|
||||||
public static function showCursor() |
|
||||||
{ |
|
||||||
echo "\033[?25h"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Clears entire screen content by sending ANSI control code ED with argument 2 to the terminal. |
|
||||||
* Cursor position will not be changed. |
|
||||||
* **Note:** ANSI.SYS implementation used in windows will reset cursor position to upper left corner of the screen. |
|
||||||
*/ |
|
||||||
public static function clearScreen() |
|
||||||
{ |
|
||||||
echo "\033[2J"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Clears text from cursor to the beginning of the screen by sending ANSI control code ED with argument 1 to the terminal. |
|
||||||
* Cursor position will not be changed. |
|
||||||
*/ |
|
||||||
public static function clearScreenBeforeCursor() |
|
||||||
{ |
|
||||||
echo "\033[1J"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Clears text from cursor to the end of the screen by sending ANSI control code ED with argument 0 to the terminal. |
|
||||||
* Cursor position will not be changed. |
|
||||||
*/ |
|
||||||
public static function clearScreenAfterCursor() |
|
||||||
{ |
|
||||||
echo "\033[0J"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Clears the line, the cursor is currently on by sending ANSI control code EL with argument 2 to the terminal. |
|
||||||
* Cursor position will not be changed. |
|
||||||
*/ |
|
||||||
public static function clearLine() |
|
||||||
{ |
|
||||||
echo "\033[2K"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Clears text from cursor position to the beginning of the line by sending ANSI control code EL with argument 1 to the terminal. |
|
||||||
* Cursor position will not be changed. |
|
||||||
*/ |
|
||||||
public static function clearLineBeforeCursor() |
|
||||||
{ |
|
||||||
echo "\033[1K"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Clears text from cursor position to the end of the line by sending ANSI control code EL with argument 0 to the terminal. |
|
||||||
* Cursor position will not be changed. |
|
||||||
*/ |
|
||||||
public static function clearLineAfterCursor() |
|
||||||
{ |
|
||||||
echo "\033[0K"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Will send ANSI format for following output |
|
||||||
* |
|
||||||
* You can pass any of the FG_*, BG_* and TEXT_* constants and also xterm256ColorBg |
|
||||||
* TODO: documentation |
|
||||||
*/ |
|
||||||
public static function ansiStyle() |
|
||||||
{ |
|
||||||
echo "\033[" . implode(';', func_get_args()) . 'm'; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Will return a string formatted with the given ANSI style |
|
||||||
* |
|
||||||
* See {@link ansiStyle} for possible arguments. |
|
||||||
* @param string $string the string to be formatted |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public static function ansiStyleString($string) |
|
||||||
{ |
|
||||||
$args = func_get_args(); |
|
||||||
array_shift($args); |
|
||||||
$code = implode(';', $args); |
|
||||||
return "\033[0m" . ($code !== '' ? "\033[" . $code . "m" : '') . $string."\033[0m"; |
|
||||||
} |
|
||||||
|
|
||||||
//const COLOR_XTERM256 = 38;// http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors |
|
||||||
public static function xterm256ColorFg($i) // TODO naming! |
|
||||||
{ |
|
||||||
return '38;5;'.$i; |
|
||||||
} |
|
||||||
|
|
||||||
public static function xterm256ColorBg($i) // TODO naming! |
|
||||||
{ |
|
||||||
return '48;5;'.$i; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Usage: list($w, $h) = ConsoleHelper::getScreenSize(); |
|
||||||
* |
|
||||||
* @return array |
|
||||||
*/ |
|
||||||
public static function getScreenSize() |
|
||||||
{ |
|
||||||
// TODO implement |
|
||||||
return array(150,50); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* resets any ansi style set by previous method {@link ansiStyle} |
|
||||||
* Any output after this is will have default text style. |
|
||||||
*/ |
|
||||||
public static function reset() |
|
||||||
{ |
|
||||||
echo "\033[0m"; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Strips ANSI control codes from a string |
|
||||||
* |
|
||||||
* @param string $string String to strip |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public static function strip($string) |
|
||||||
{ |
|
||||||
return preg_replace('/\033\[[\d;]+m/', '', $string); // TODO currently only strips color |
|
||||||
} |
|
||||||
|
|
||||||
// TODO refactor and review |
|
||||||
public static function ansiToHtml($string) |
|
||||||
{ |
|
||||||
$tags = 0; |
|
||||||
return preg_replace_callback('/\033\[[\d;]+m/', function($ansi) use (&$tags) { |
|
||||||
$styleA = array(); |
|
||||||
foreach(explode(';', $ansi) as $controlCode) |
|
||||||
{ |
|
||||||
switch($controlCode) |
|
||||||
{ |
|
||||||
case static::FG_BLACK: $style = array('color' => '#000000'); break; |
|
||||||
case static::FG_BLUE: $style = array('color' => '#000078'); break; |
|
||||||
case static::FG_CYAN: $style = array('color' => '#007878'); break; |
|
||||||
case static::FG_GREEN: $style = array('color' => '#007800'); break; |
|
||||||
case static::FG_GREY: $style = array('color' => '#787878'); break; |
|
||||||
case static::FG_PURPLE: $style = array('color' => '#780078'); break; |
|
||||||
case static::FG_RED: $style = array('color' => '#780000'); break; |
|
||||||
case static::FG_YELLOW: $style = array('color' => '#787800'); break; |
|
||||||
case static::BG_BLACK: $style = array('background-color' => '#000000'); break; |
|
||||||
case static::BG_BLUE: $style = array('background-color' => '#000078'); break; |
|
||||||
case static::BG_CYAN: $style = array('background-color' => '#007878'); break; |
|
||||||
case static::BG_GREEN: $style = array('background-color' => '#007800'); break; |
|
||||||
case static::BG_GREY: $style = array('background-color' => '#787878'); break; |
|
||||||
case static::BG_PURPLE: $style = array('background-color' => '#780078'); break; |
|
||||||
case static::BG_RED: $style = array('background-color' => '#780000'); break; |
|
||||||
case static::BG_YELLOW: $style = array('background-color' => '#787800'); break; |
|
||||||
case static::BOLD: $style = array('font-weight' => 'bold'); break; |
|
||||||
case static::ITALIC: $style = array('font-style' => 'italic'); break; |
|
||||||
case static::UNDERLINE: $style = array('text-decoration' => array('underline')); break; |
|
||||||
case static::OVERLINED: $style = array('text-decoration' => array('overline')); break; |
|
||||||
case static::CROSSED_OUT:$style = array('text-decoration' => array('line-through')); break; |
|
||||||
case static::BLINK: $style = array('text-decoration' => array('blink')); break; |
|
||||||
case static::NEGATIVE: // ??? |
|
||||||
case static::CONCEALED: |
|
||||||
case static::ENCIRCLED: |
|
||||||
case static::FRAMED: |
|
||||||
// TODO allow resetting codes |
|
||||||
break; |
|
||||||
case 0: // ansi reset |
|
||||||
$return = ''; |
|
||||||
for($n=$tags; $tags>0; $tags--) { |
|
||||||
$return .= '</span>'; |
|
||||||
} |
|
||||||
return $return; |
|
||||||
} |
|
||||||
|
|
||||||
$styleA = ArrayHelper::merge($styleA, $style); |
|
||||||
} |
|
||||||
$styleString[] = array(); |
|
||||||
foreach($styleA as $name => $content) { |
|
||||||
if ($name === 'text-decoration') { |
|
||||||
$content = implode(' ', $content); |
|
||||||
} |
|
||||||
$styleString[] = $name.':'.$content; |
|
||||||
} |
|
||||||
$tags++; |
|
||||||
return '<span' . (!empty($styleString) ? 'style="' . implode(';', $styleString) : '') . '>'; |
|
||||||
}, $string); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* TODO syntax copied from https://github.com/pear/Console_Color2/blob/master/Console/Color2.php |
|
||||||
* |
|
||||||
* Converts colorcodes in the format %y (for yellow) into ansi-control |
|
||||||
* codes. The conversion table is: ('bold' meaning 'light' on some |
|
||||||
* terminals). It's almost the same conversion table irssi uses. |
|
||||||
* <pre> |
|
||||||
* text text background |
|
||||||
* ------------------------------------------------ |
|
||||||
* %k %K %0 black dark grey black |
|
||||||
* %r %R %1 red bold red red |
|
||||||
* %g %G %2 green bold green green |
|
||||||
* %y %Y %3 yellow bold yellow yellow |
|
||||||
* %b %B %4 blue bold blue blue |
|
||||||
* %m %M %5 magenta bold magenta magenta |
|
||||||
* %p %P magenta (think: purple) |
|
||||||
* %c %C %6 cyan bold cyan cyan |
|
||||||
* %w %W %7 white bold white white |
|
||||||
* |
|
||||||
* %F Blinking, Flashing |
|
||||||
* %U Underline |
|
||||||
* %8 Reverse |
|
||||||
* %_,%9 Bold |
|
||||||
* |
|
||||||
* %n Resets the color |
|
||||||
* %% A single % |
|
||||||
* </pre> |
|
||||||
* First param is the string to convert, second is an optional flag if |
|
||||||
* colors should be used. It defaults to true, if set to false, the |
|
||||||
* colorcodes will just be removed (And %% will be transformed into %) |
|
||||||
* |
|
||||||
* @param string $string String to convert |
|
||||||
* @param bool $colored Should the string be colored? |
|
||||||
* |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public static function renderColoredString($string) |
|
||||||
{ |
|
||||||
$colored = true; |
|
||||||
|
|
||||||
|
|
||||||
static $conversions = array ( // static so the array doesn't get built |
|
||||||
// everytime |
|
||||||
// %y - yellow, and so on... {{{ |
|
||||||
'%y' => array('color' => 'yellow'), |
|
||||||
'%g' => array('color' => 'green' ), |
|
||||||
'%b' => array('color' => 'blue' ), |
|
||||||
'%r' => array('color' => 'red' ), |
|
||||||
'%p' => array('color' => 'purple'), |
|
||||||
'%m' => array('color' => 'purple'), |
|
||||||
'%c' => array('color' => 'cyan' ), |
|
||||||
'%w' => array('color' => 'grey' ), |
|
||||||
'%k' => array('color' => 'black' ), |
|
||||||
'%n' => array('color' => 'reset' ), |
|
||||||
'%Y' => array('color' => 'yellow', 'style' => 'light'), |
|
||||||
'%G' => array('color' => 'green', 'style' => 'light'), |
|
||||||
'%B' => array('color' => 'blue', 'style' => 'light'), |
|
||||||
'%R' => array('color' => 'red', 'style' => 'light'), |
|
||||||
'%P' => array('color' => 'purple', 'style' => 'light'), |
|
||||||
'%M' => array('color' => 'purple', 'style' => 'light'), |
|
||||||
'%C' => array('color' => 'cyan', 'style' => 'light'), |
|
||||||
'%W' => array('color' => 'grey', 'style' => 'light'), |
|
||||||
'%K' => array('color' => 'black', 'style' => 'light'), |
|
||||||
'%N' => array('color' => 'reset', 'style' => 'light'), |
|
||||||
'%3' => array('background' => 'yellow'), |
|
||||||
'%2' => array('background' => 'green' ), |
|
||||||
'%4' => array('background' => 'blue' ), |
|
||||||
'%1' => array('background' => 'red' ), |
|
||||||
'%5' => array('background' => 'purple'), |
|
||||||
'%6' => array('background' => 'cyan' ), |
|
||||||
'%7' => array('background' => 'grey' ), |
|
||||||
'%0' => array('background' => 'black' ), |
|
||||||
// Don't use this, I can't stand flashing text |
|
||||||
'%F' => array('style' => 'blink'), |
|
||||||
'%U' => array('style' => 'underline'), |
|
||||||
'%8' => array('style' => 'inverse'), |
|
||||||
'%9' => array('style' => 'bold'), |
|
||||||
'%_' => array('style' => 'bold') |
|
||||||
// }}} |
|
||||||
); |
|
||||||
|
|
||||||
if ($colored) { |
|
||||||
$string = str_replace('%%', '% ', $string); |
|
||||||
foreach ($conversions as $key => $value) { |
|
||||||
$string = str_replace($key, Console_Color::color($value), |
|
||||||
$string); |
|
||||||
} |
|
||||||
$string = str_replace('% ', '%', $string); |
|
||||||
|
|
||||||
} else { |
|
||||||
$string = preg_replace('/%((%)|.)/', '$2', $string); |
|
||||||
} |
|
||||||
|
|
||||||
return $string; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Escapes % so they don't get interpreted as color codes |
|
||||||
* |
|
||||||
* @param string $string String to escape |
|
||||||
* |
|
||||||
* @access public |
|
||||||
* @return string |
|
||||||
*/ |
|
||||||
public static function escape($string) |
|
||||||
{ |
|
||||||
return str_replace('%', '%%', $string); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,13 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<phpunit bootstrap="./tests/unit/bootstrap.php" |
||||||
|
colors="true" |
||||||
|
convertErrorsToExceptions="true" |
||||||
|
convertNoticesToExceptions="true" |
||||||
|
convertWarningsToExceptions="true" |
||||||
|
stopOnFailure="false"> |
||||||
|
<testsuites> |
||||||
|
<testsuite name="Yii Test Suite"> |
||||||
|
<directory>./tests/unit</directory> |
||||||
|
</testsuite> |
||||||
|
</testsuites> |
||||||
|
</phpunit> |
@ -0,0 +1,50 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace yiiunit; |
||||||
|
|
||||||
|
class DatabaseTestCase extends TestCase |
||||||
|
{ |
||||||
|
protected $database; |
||||||
|
protected $driverName = 'mysql'; |
||||||
|
protected $db; |
||||||
|
|
||||||
|
protected function setUp() |
||||||
|
{ |
||||||
|
$databases = $this->getParam('databases'); |
||||||
|
$this->database = $databases[$this->driverName]; |
||||||
|
$pdo_database = 'pdo_'.$this->driverName; |
||||||
|
|
||||||
|
if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { |
||||||
|
$this->markTestSkipped('pdo and pdo_'.$pdo_database.' extension are required.'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param bool $reset whether to clean up the test database |
||||||
|
* @param bool $open whether to open and populate test database |
||||||
|
* @return \yii\db\Connection |
||||||
|
*/ |
||||||
|
public function getConnection($reset = true, $open = true) |
||||||
|
{ |
||||||
|
if (!$reset && $this->db) { |
||||||
|
return $this->db; |
||||||
|
} |
||||||
|
$db = new \yii\db\Connection; |
||||||
|
$db->dsn = $this->database['dsn']; |
||||||
|
if (isset($this->database['username'])) { |
||||||
|
$db->username = $this->database['username']; |
||||||
|
$db->password = $this->database['password']; |
||||||
|
} |
||||||
|
if ($open) { |
||||||
|
$db->open(); |
||||||
|
$lines = explode(';', file_get_contents($this->database['fixture'])); |
||||||
|
foreach ($lines as $line) { |
||||||
|
if (trim($line) !== '') { |
||||||
|
$db->pdo->exec($line); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
$this->db = $db; |
||||||
|
return $db; |
||||||
|
} |
||||||
|
} |
@ -1,10 +1,16 @@ |
|||||||
<?php |
<?php |
||||||
|
|
||||||
return array( |
return array( |
||||||
'mysql' => array( |
'databases' => array( |
||||||
'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', |
'mysql' => array( |
||||||
'username' => 'root', |
'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', |
||||||
'password' => '', |
'username' => 'travis', |
||||||
'fixture' => __DIR__ . '/mysql.sql', |
'password' => '', |
||||||
), |
'fixture' => __DIR__ . '/mysql.sql', |
||||||
|
), |
||||||
|
'sqlite' => array( |
||||||
|
'dsn' => 'sqlite::memory:', |
||||||
|
'fixture' => __DIR__ . '/sqlite.sql', |
||||||
|
), |
||||||
|
) |
||||||
); |
); |
||||||
|
Binary file not shown.
@ -0,0 +1,64 @@ |
|||||||
|
msgid "" |
||||||
|
msgstr "" |
||||||
|
"Project-Id-Version: \n" |
||||||
|
"POT-Creation-Date: \n" |
||||||
|
"PO-Revision-Date: \n" |
||||||
|
"Last-Translator: resurtm <resurtm@gmail.com>\n" |
||||||
|
"Language-Team: \n" |
||||||
|
"MIME-Version: 1.0\n" |
||||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||||
|
"X-Generator: Poedit 1.5.5\n" |
||||||
|
|
||||||
|
msgctxt "context1" |
||||||
|
msgid "" |
||||||
|
"Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\n" |
||||||
|
"aliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel " |
||||||
|
"malesuada.\n" |
||||||
|
"Nunc vel sapien nunc, a pretium nulla." |
||||||
|
msgstr "" |
||||||
|
"Олицетворение однократно. Представленный лексико-семантический анализ " |
||||||
|
"является\n" |
||||||
|
"психолингвистическим в своей основе, но механизм сочленений полидисперсен. " |
||||||
|
"Впечатление\n" |
||||||
|
"однократно. Различное расположение выбирает сюжетный механизм сочленений." |
||||||
|
|
||||||
|
msgctxt "context1" |
||||||
|
msgid "String number two." |
||||||
|
msgstr "Строка номер два." |
||||||
|
|
||||||
|
msgctxt "context2" |
||||||
|
msgid "" |
||||||
|
"The other\n" |
||||||
|
"\n" |
||||||
|
"context.\n" |
||||||
|
msgstr "" |
||||||
|
"Другой\n" |
||||||
|
"\n" |
||||||
|
"контекст.\n" |
||||||
|
|
||||||
|
msgctxt "context1" |
||||||
|
msgid "" |
||||||
|
"Missing\n" |
||||||
|
"\r\t\"translation." |
||||||
|
msgstr "" |
||||||
|
|
||||||
|
msgctxt "context1" |
||||||
|
msgid "" |
||||||
|
"Nunc vel sapien nunc, a pretium nulla.\n" |
||||||
|
"Pellentesque habitant morbi tristique senectus et netus et malesuada fames " |
||||||
|
"ac turpis egestas." |
||||||
|
msgstr "Короткий перевод." |
||||||
|
|
||||||
|
msgid "contextless" |
||||||
|
msgstr "" |
||||||
|
|
||||||
|
msgctxt "context2" |
||||||
|
msgid "" |
||||||
|
"test1\\ntest2\n" |
||||||
|
"\\\n" |
||||||
|
"test3" |
||||||
|
msgstr "" |
||||||
|
"тест1\\nтест2\n" |
||||||
|
"\\\n" |
||||||
|
"тест3" |
@ -1,262 +1,88 @@ |
|||||||
CREATE TABLE users |
/** |
||||||
( |
* This is the database schema for testing Sqlite support of Yii DAO and Active Record. |
||||||
id INTEGER NOT NULL PRIMARY KEY, |
* The database setup in config.php is required to perform then relevant tests: |
||||||
username VARCHAR(128) NOT NULL, |
*/ |
||||||
password VARCHAR(128) NOT NULL, |
|
||||||
email VARCHAR(128) NOT NULL |
DROP TABLE IF EXISTS tbl_order_item; |
||||||
); |
DROP TABLE IF EXISTS tbl_item; |
||||||
|
DROP TABLE IF EXISTS tbl_order; |
||||||
INSERT INTO users(id,username,password,email) VALUES (1,'user1','pass1','email1'); |
DROP TABLE IF EXISTS tbl_category; |
||||||
INSERT INTO users(id,username,password,email) VALUES (2,'user2','pass2','email2'); |
DROP TABLE IF EXISTS tbl_customer; |
||||||
INSERT INTO users(id,username,password,email) VALUES (3,'user3','pass3','email3'); |
DROP TABLE IF EXISTS tbl_type; |
||||||
INSERT INTO users(id,username,password,email) VALUES (4,'user4','pass4','email4'); |
|
||||||
|
CREATE TABLE tbl_customer ( |
||||||
CREATE TABLE groups |
id INTEGER NOT NULL, |
||||||
( |
email varchar(128) NOT NULL, |
||||||
id INTEGER NOT NULL PRIMARY KEY, |
name varchar(128) NOT NULL, |
||||||
name VARCHAR(128) NOT NULL |
address text, |
||||||
); |
status INTEGER DEFAULT 0, |
||||||
|
PRIMARY KEY (id) |
||||||
INSERT INTO groups(id,name) VALUES (1,'group1'); |
); |
||||||
INSERT INTO groups(id,name) VALUES (2,'group2'); |
|
||||||
INSERT INTO groups(id,name) VALUES (3,'group3'); |
CREATE TABLE tbl_category ( |
||||||
INSERT INTO groups(id,name) VALUES (4,'group4'); |
id INTEGER NOT NULL, |
||||||
INSERT INTO groups(id,name) VALUES (5,'group5'); |
name varchar(128) NOT NULL, |
||||||
INSERT INTO groups(id,name) VALUES (6,'group6'); |
PRIMARY KEY (id) |
||||||
|
); |
||||||
CREATE TABLE groups_descriptions |
|
||||||
( |
CREATE TABLE tbl_item ( |
||||||
group_id INTEGER NOT NULL PRIMARY KEY, |
id INTEGER NOT NULL, |
||||||
name VARCHAR(128) NOT NULL |
name varchar(128) NOT NULL, |
||||||
); |
category_id INTEGER NOT NULL, |
||||||
|
PRIMARY KEY (id) |
||||||
INSERT INTO groups_descriptions(group_id,name) VALUES (1,'room1'); |
); |
||||||
INSERT INTO groups_descriptions(group_id,name) VALUES (2,'room2'); |
|
||||||
INSERT INTO groups_descriptions(group_id,name) VALUES (3,'room3'); |
CREATE TABLE tbl_order ( |
||||||
INSERT INTO groups_descriptions(group_id,name) VALUES (4,'room4'); |
id INTEGER NOT NULL, |
||||||
|
customer_id INTEGER NOT NULL, |
||||||
CREATE TABLE roles |
create_time INTEGER NOT NULL, |
||||||
( |
total decimal(10,0) NOT NULL, |
||||||
user_id INTEGER NOT NULL, |
PRIMARY KEY (id) |
||||||
group_id INTEGER NOT NULL, |
); |
||||||
name VARCHAR(128) NOT NULL, |
|
||||||
PRIMARY KEY(user_id,group_id) |
CREATE TABLE tbl_order_item ( |
||||||
); |
order_id INTEGER NOT NULL, |
||||||
|
item_id INTEGER NOT NULL, |
||||||
INSERT INTO roles(user_id,group_id,name) VALUES (1,1,'dev'); |
quantity INTEGER NOT NULL, |
||||||
INSERT INTO roles(user_id,group_id,name) VALUES (1,2,'user'); |
subtotal decimal(10,0) NOT NULL, |
||||||
INSERT INTO roles(user_id,group_id,name) VALUES (2,1,'dev'); |
PRIMARY KEY (order_id, item_id) |
||||||
INSERT INTO roles(user_id,group_id,name) VALUES (2,3,'user'); |
); |
||||||
|
|
||||||
CREATE TABLE mentorships |
CREATE TABLE tbl_type ( |
||||||
( |
int_col INTEGER NOT NULL, |
||||||
teacher_id INTEGER NOT NULL, |
int_col2 INTEGER DEFAULT '1', |
||||||
student_id INTEGER NOT NULL, |
char_col char(100) NOT NULL, |
||||||
progress VARCHAR(128) NOT NULL, |
char_col2 varchar(100) DEFAULT 'something', |
||||||
PRIMARY KEY(teacher_id,student_id) |
char_col3 text, |
||||||
); |
float_col double(4,3) NOT NULL, |
||||||
|
float_col2 double DEFAULT '1.23', |
||||||
INSERT INTO mentorships(teacher_id,student_id,progress) VALUES (1,3,'good'); |
blob_col blob, |
||||||
INSERT INTO mentorships(teacher_id,student_id,progress) VALUES (2,4,'average'); |
numeric_col decimal(5,2) DEFAULT '33.22', |
||||||
|
time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', |
||||||
CREATE TABLE profiles |
bool_col tinyint(1) NOT NULL, |
||||||
( |
bool_col2 tinyint(1) DEFAULT '1' |
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
); |
||||||
first_name VARCHAR(128) NOT NULL, |
|
||||||
last_name VARCHAR(128) NOT NULL, |
INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); |
||||||
user_id INTEGER NOT NULL, |
INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); |
||||||
CONSTRAINT FK_profile_user FOREIGN KEY (user_id) |
INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2); |
||||||
REFERENCES users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
INSERT INTO tbl_category (name) VALUES ('Books'); |
||||||
|
INSERT INTO tbl_category (name) VALUES ('Movies'); |
||||||
INSERT INTO profiles (first_name, last_name, user_id) VALUES ('first 1','last 1',1); |
|
||||||
INSERT INTO profiles (first_name, last_name, user_id) VALUES ('first 2','last 2',2); |
INSERT INTO tbl_item (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); |
||||||
|
INSERT INTO tbl_item (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); |
||||||
CREATE TABLE posts |
INSERT INTO tbl_item (name, category_id) VALUES ('Ice Age', 2); |
||||||
( |
INSERT INTO tbl_item (name, category_id) VALUES ('Toy Story', 2); |
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2); |
||||||
title VARCHAR(128) NOT NULL, |
|
||||||
create_time TIMESTAMP NOT NULL, |
INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0); |
||||||
author_id INTEGER NOT NULL, |
INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0); |
||||||
content TEXT, |
INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0); |
||||||
CONSTRAINT FK_post_author FOREIGN KEY (author_id) |
|
||||||
REFERENCES users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); |
||||||
); |
INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); |
||||||
|
INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); |
||||||
INSERT INTO posts (title, create_time, author_id, content) VALUES ('post 1',100000,1,'content 1'); |
INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); |
||||||
INSERT INTO posts (title, create_time, author_id, content) VALUES ('post 2',100001,2,'content 2'); |
INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); |
||||||
INSERT INTO posts (title, create_time, author_id, content) VALUES ('post 3',100002,2,'content 3'); |
INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); |
||||||
INSERT INTO posts (title, create_time, author_id, content) VALUES ('post 4',100003,2,'content 4'); |
|
||||||
INSERT INTO posts (title, create_time, author_id, content) VALUES ('post 5',100004,3,'content 5'); |
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE posts_nofk |
|
||||||
( |
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
|
||||||
title VARCHAR(128) NOT NULL, |
|
||||||
create_time TIMESTAMP NOT NULL, |
|
||||||
author_id INTEGER NOT NULL, |
|
||||||
content TEXT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO posts_nofk (title, create_time, author_id, content) VALUES ('post 1',100000,1,'content 1'); |
|
||||||
INSERT INTO posts_nofk (title, create_time, author_id, content) VALUES ('post 2',100001,2,'content 2'); |
|
||||||
INSERT INTO posts_nofk (title, create_time, author_id, content) VALUES ('post 3',100002,2,'content 3'); |
|
||||||
INSERT INTO posts_nofk (title, create_time, author_id, content) VALUES ('post 4',100003,2,'content 4'); |
|
||||||
INSERT INTO posts_nofk (title, create_time, author_id, content) VALUES ('post 5',100004,3,'content 5'); |
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE comments |
|
||||||
( |
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
|
||||||
content TEXT NOT NULL, |
|
||||||
post_id INTEGER NOT NULL, |
|
||||||
author_id INTEGER NOT NULL, |
|
||||||
CONSTRAINT FK_post_comment FOREIGN KEY (post_id) |
|
||||||
REFERENCES posts (id) ON DELETE CASCADE ON UPDATE RESTRICT, |
|
||||||
CONSTRAINT FK_user_comment FOREIGN KEY (author_id) |
|
||||||
REFERENCES users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 1',1, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 2',1, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 3',1, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 4',2, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 5',2, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 6',3, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 7',3, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 8',3, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 9',3, 2); |
|
||||||
INSERT INTO comments (content, post_id, author_id) VALUES ('comment 10',5, 3); |
|
||||||
|
|
||||||
CREATE TABLE categories |
|
||||||
( |
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
|
||||||
name VARCHAR(128) NOT NULL, |
|
||||||
parent_id INTEGER, |
|
||||||
CONSTRAINT FK_category_category FOREIGN KEY (parent_id) |
|
||||||
REFERENCES categories (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO categories (name, parent_id) VALUES ('cat 1',NULL); |
|
||||||
INSERT INTO categories (name, parent_id) VALUES ('cat 2',NULL); |
|
||||||
INSERT INTO categories (name, parent_id) VALUES ('cat 3',NULL); |
|
||||||
INSERT INTO categories (name, parent_id) VALUES ('cat 4',1); |
|
||||||
INSERT INTO categories (name, parent_id) VALUES ('cat 5',1); |
|
||||||
INSERT INTO categories (name, parent_id) VALUES ('cat 6',5); |
|
||||||
INSERT INTO categories (name, parent_id) VALUES ('cat 7',5); |
|
||||||
|
|
||||||
CREATE TABLE post_category |
|
||||||
( |
|
||||||
category_id INTEGER NOT NULL, |
|
||||||
post_id INTEGER NOT NULL, |
|
||||||
PRIMARY KEY (category_id, post_id), |
|
||||||
CONSTRAINT FK_post_category_post FOREIGN KEY (post_id) |
|
||||||
REFERENCES posts (id) ON DELETE CASCADE ON UPDATE RESTRICT, |
|
||||||
CONSTRAINT FK_post_category_category FOREIGN KEY (category_id) |
|
||||||
REFERENCES categories (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO post_category (category_id, post_id) VALUES (1,1); |
|
||||||
INSERT INTO post_category (category_id, post_id) VALUES (2,1); |
|
||||||
INSERT INTO post_category (category_id, post_id) VALUES (3,1); |
|
||||||
INSERT INTO post_category (category_id, post_id) VALUES (4,2); |
|
||||||
INSERT INTO post_category (category_id, post_id) VALUES (1,2); |
|
||||||
INSERT INTO post_category (category_id, post_id) VALUES (1,3); |
|
||||||
|
|
||||||
CREATE TABLE orders |
|
||||||
( |
|
||||||
key1 INTEGER NOT NULL, |
|
||||||
key2 INTEGER NOT NULL, |
|
||||||
name VARCHAR(128), |
|
||||||
PRIMARY KEY (key1, key2) |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO orders (key1,key2,name) VALUES (1,2,'order 12'); |
|
||||||
INSERT INTO orders (key1,key2,name) VALUES (1,3,'order 13'); |
|
||||||
INSERT INTO orders (key1,key2,name) VALUES (2,1,'order 21'); |
|
||||||
INSERT INTO orders (key1,key2,name) VALUES (2,2,'order 22'); |
|
||||||
|
|
||||||
CREATE TABLE items |
|
||||||
( |
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
|
||||||
name VARCHAR(128), |
|
||||||
col1 INTEGER NOT NULL, |
|
||||||
col2 INTEGER NOT NULL, |
|
||||||
CONSTRAINT FK_order_item FOREIGN KEY (col1,col2) |
|
||||||
REFERENCES orders (key1,key2) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO items (name,col1,col2) VALUES ('item 1',1,2); |
|
||||||
INSERT INTO items (name,col1,col2) VALUES ('item 2',1,2); |
|
||||||
INSERT INTO items (name,col1,col2) VALUES ('item 3',1,3); |
|
||||||
INSERT INTO items (name,col1,col2) VALUES ('item 4',2,2); |
|
||||||
INSERT INTO items (name,col1,col2) VALUES ('item 5',2,2); |
|
||||||
|
|
||||||
CREATE TABLE types |
|
||||||
( |
|
||||||
int_col INT NOT NULL, |
|
||||||
int_col2 INTEGER DEFAULT 1, |
|
||||||
char_col CHAR(100) NOT NULL, |
|
||||||
char_col2 VARCHAR(100) DEFAULT 'something', |
|
||||||
char_col3 TEXT, |
|
||||||
float_col REAL(4,3) NOT NULL, |
|
||||||
float_col2 DOUBLE DEFAULT 1.23, |
|
||||||
blob_col BLOB, |
|
||||||
numeric_col NUMERIC(5,2) DEFAULT 33.22, |
|
||||||
time TIMESTAMP DEFAULT 123, |
|
||||||
bool_col BOOL NOT NULL, |
|
||||||
bool_col2 BOOLEAN DEFAULT 1, |
|
||||||
null_col INTEGER DEFAULT NULL |
|
||||||
); |
|
||||||
|
|
||||||
CREATE TABLE Content |
|
||||||
( |
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |
|
||||||
class VARCHAR(128), |
|
||||||
parentID INTEGER NOT NULL, |
|
||||||
ownerID INTEGER NOT NULL, |
|
||||||
title VARCHAR(100), |
|
||||||
CONSTRAINT FK_content_user FOREIGN KEY (ownerID) |
|
||||||
REFERENCES users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
CONSTRAINT FK_content_parent FOREIGN KEY (parentID) |
|
||||||
REFERENCES Content (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO Content (class,parentID,ownerID,title) VALUES ('Article',-1,1,'article 1'); |
|
||||||
INSERT INTO Content (class,parentID,ownerID,title) VALUES ('Article',-1,2,'article 2'); |
|
||||||
INSERT INTO Content (class,parentID,ownerID,title) VALUES ('Comment',1,1,'comment 1'); |
|
||||||
INSERT INTO Content (class,parentID,ownerID,title) VALUES ('Article',-1,2,'article 3'); |
|
||||||
INSERT INTO Content (class,parentID,ownerID,title) VALUES ('Comment',4,2,'comment 2'); |
|
||||||
INSERT INTO Content (class,parentID,ownerID,title) VALUES ('Comment',4,1,'comment 3'); |
|
||||||
|
|
||||||
CREATE TABLE Article |
|
||||||
( |
|
||||||
id INTEGER NOT NULL PRIMARY KEY, |
|
||||||
authorID INTEGER NOT NULL, |
|
||||||
body TEXT, |
|
||||||
CONSTRAINT FK_article_content FOREIGN KEY (id) |
|
||||||
REFERENCES Content (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
CONSTRAINT FK_article_author FOREIGN KEY (authorID) |
|
||||||
REFERENCES users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO Article (id,authorID,body) VALUES (1,1,'content for article 1'); |
|
||||||
INSERT INTO Article (id,authorID,body) VALUES (2,2,'content for article 2'); |
|
||||||
INSERT INTO Article (id,authorID,body) VALUES (4,1,'content for article 3'); |
|
||||||
|
|
||||||
CREATE TABLE Comment |
|
||||||
( |
|
||||||
id INTEGER NOT NULL PRIMARY KEY, |
|
||||||
authorID INTEGER NOT NULL, |
|
||||||
body TEXT, |
|
||||||
CONSTRAINT FK_comment_content FOREIGN KEY (id) |
|
||||||
REFERENCES Content (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
CONSTRAINT FK_article_author FOREIGN KEY (authorID) |
|
||||||
REFERENCES users (id) ON DELETE CASCADE ON UPDATE RESTRICT |
|
||||||
); |
|
||||||
|
|
||||||
INSERT INTO Comment (id,authorID,body) VALUES (3,1,'content for comment 1'); |
|
||||||
INSERT INTO Comment (id,authorID,body) VALUES (5,1,'content for comment 2'); |
|
||||||
INSERT INTO Comment (id,authorID,body) VALUES (6,1,'content for comment 3'); |
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue