Browse Source
* 'master' of github.com:yiisoft/yii2: (87 commits) Added dirty attribute description. Fixed doc about renderers. Finished the initial draft of upgrading instructions Fix attaching behavior via config Changed default value of View::renderers. Fix attaching behavior via config Menu WIP upgrading instructions WIP Refactored Breadcrumbs. Fixes issue #54: Implemented Breadcrumbs. Added Breadcrumbs.php Fixes issue #134 Rollback word consistencty over entire codebase (ref. #139). Add ensureBehaviors() to detachBehavior*() Fixes issue #124. code reorganization fix. reorganized app code. removed app template from framework folder. Fixes issue #128. Fixes issue #124. Add Newlines ... Conflicts: tests/unit/framework/caching/ApcCacheTest.phptags/2.0.0-beta
Carsten Brandt
12 years ago
209 changed files with 13359 additions and 10720 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,26 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @var $this \yii\base\View |
||||
* @var $content string |
||||
*/ |
||||
use yii\helpers\Html; |
||||
?> |
||||
<?php $this->beginPage(); ?> |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="utf-8" /> |
||||
<title><?php echo Html::encode($this->title); ?></title>
|
||||
<?php echo Html::cssFile("css/bootstrap.min.css", array('media' => 'screen')); ?> |
||||
<?php $this->head(); ?> |
||||
</head> |
||||
<body> |
||||
<div class="container"> |
||||
<h1>Welcome</h1> |
||||
<?php $this->beginBody(); ?> |
||||
<?php echo $content; ?> |
||||
<?php $this->endBody(); ?> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
<?php $this->endPage(); ?> |
@ -1,17 +0,0 @@
|
||||
<?php |
||||
/** @var $this \yii\base\View */ |
||||
|
||||
use yii\helpers\Html; |
||||
|
||||
$this->title = 'Hello World'; |
||||
|
||||
$user = Yii::$app->getUser(); |
||||
if ($user->isGuest) { |
||||
echo Html::a('login', array('login')); |
||||
} else { |
||||
echo "You are logged in as " . $user->identity->username . "<br/>"; |
||||
echo Html::a('logout', array('logout')); |
||||
} |
||||
?> |
||||
|
||||
|
@ -0,0 +1,78 @@
|
||||
body { |
||||
padding-top: 20px; |
||||
padding-bottom: 60px; |
||||
} |
||||
|
||||
/* Custom container */ |
||||
.container { |
||||
margin: 0 auto; |
||||
max-width: 1000px; |
||||
} |
||||
|
||||
.container > hr { |
||||
margin: 60px 0; |
||||
} |
||||
|
||||
/* Main marketing message and sign up button */ |
||||
.jumbotron { |
||||
margin: 80px 0; |
||||
text-align: center; |
||||
} |
||||
|
||||
.jumbotron h1 { |
||||
font-size: 100px; |
||||
line-height: 1; |
||||
} |
||||
|
||||
.jumbotron .lead { |
||||
font-size: 24px; |
||||
line-height: 1.25; |
||||
} |
||||
|
||||
.jumbotron .btn { |
||||
font-size: 21px; |
||||
padding: 14px 24px; |
||||
} |
||||
|
||||
/* Supporting marketing content */ |
||||
.marketing { |
||||
margin: 60px 0; |
||||
} |
||||
|
||||
.marketing p + h4 { |
||||
margin-top: 28px; |
||||
} |
||||
|
||||
/* Customize the navbar links to be fill the entire space of the .navbar */ |
||||
.navbar .navbar-inner { |
||||
padding: 0; |
||||
} |
||||
|
||||
.navbar .nav { |
||||
margin: 0; |
||||
display: table; |
||||
width: 100%; |
||||
} |
||||
|
||||
.navbar .nav li { |
||||
display: table-cell; |
||||
width: 1%; |
||||
float: none; |
||||
} |
||||
|
||||
.navbar .nav li a { |
||||
font-weight: bold; |
||||
text-align: center; |
||||
border-left: 1px solid rgba(255, 255, 255, .75); |
||||
border-right: 1px solid rgba(0, 0, 0, .1); |
||||
} |
||||
|
||||
.navbar .nav li:first-child a { |
||||
border-left: 0; |
||||
border-radius: 3px 0 0 3px; |
||||
} |
||||
|
||||
.navbar .nav li:last-child a { |
||||
border-right: 0; |
||||
border-radius: 0 3px 3px 0; |
||||
} |
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,19 @@
|
||||
<?php |
||||
|
||||
return array( |
||||
'app' => array( |
||||
'basePath' => '@wwwroot', |
||||
'baseUrl' => '@www', |
||||
'css' => array( |
||||
'css/bootstrap.min.css', |
||||
'css/bootstrap-responsive.min.css', |
||||
'css/site.css', |
||||
), |
||||
'js' => array( |
||||
|
||||
), |
||||
'depends' => array( |
||||
'yii', |
||||
), |
||||
), |
||||
); |
@ -0,0 +1,63 @@
|
||||
<?php |
||||
|
||||
namespace app\models; |
||||
|
||||
use yii\base\Model; |
||||
|
||||
/** |
||||
* ContactForm is the model behind the contact form. |
||||
*/ |
||||
class ContactForm extends Model |
||||
{ |
||||
public $name; |
||||
public $email; |
||||
public $subject; |
||||
public $body; |
||||
public $verifyCode; |
||||
|
||||
/** |
||||
* @return array the validation rules. |
||||
*/ |
||||
public function rules() |
||||
{ |
||||
return array( |
||||
// name, email, subject and body are required |
||||
array('name, email, subject, body', 'required'), |
||||
// email has to be a valid email address |
||||
array('email', 'email'), |
||||
// verifyCode needs to be entered correctly |
||||
//array('verifyCode', 'captcha', 'allowEmpty' => !Captcha::checkRequirements()), |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* @return array customized attribute labels |
||||
*/ |
||||
public function attributeLabels() |
||||
{ |
||||
return array( |
||||
'verifyCode' => 'Verification Code', |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Sends an email to the specified email address using the information collected by this model. |
||||
* @param string $email the target email address |
||||
* @return boolean whether the model passes validation |
||||
*/ |
||||
public function contact($email) |
||||
{ |
||||
if ($this->validate()) { |
||||
$name = '=?UTF-8?B?' . base64_encode($this->name) . '?='; |
||||
$subject = '=?UTF-8?B?' . base64_encode($this->subject) . '?='; |
||||
$headers = "From: $name <{$this->email}>\r\n" . |
||||
"Reply-To: {$this->email}\r\n" . |
||||
"MIME-Version: 1.0\r\n" . |
||||
"Content-type: text/plain; charset=UTF-8"; |
||||
mail($email, $subject, $this->body, $headers); |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,60 @@
|
||||
<?php |
||||
/** |
||||
* @var $this \yii\base\View |
||||
* @var $content string |
||||
*/ |
||||
use yii\helpers\Html; |
||||
$this->registerAssetBundle('app'); |
||||
?> |
||||
<?php $this->beginPage(); ?> |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="utf-8"/> |
||||
<title><?php echo Html::encode($this->title); ?></title>
|
||||
<?php $this->head(); ?> |
||||
</head> |
||||
<body> |
||||
<div class="container"> |
||||
<?php $this->beginBody(); ?> |
||||
<div class="masthead"> |
||||
<h3 class="muted">My Company</h3> |
||||
|
||||
<div class="navbar"> |
||||
<div class="navbar-inner"> |
||||
<div class="container"> |
||||
<ul class="nav"> |
||||
<li><?php echo Html::a('Home', Yii::$app->homeUrl); ?></li>
|
||||
<li><?php echo Html::a('About', array('/site/about')); ?></li>
|
||||
<li><?php echo Html::a('Contact', array('/site/contact')); ?></li>
|
||||
<?php if (Yii::$app->user->isGuest): ?> |
||||
<li><?php echo Html::a('Login', array('/site/login')); ?></li>
|
||||
<?php else: ?> |
||||
<li><?php echo Html::a('Logout (' . Html::encode(Yii::$app->user->identity->username) . ')', array('/site/logout')); ?></li>
|
||||
<?php endif; ?> |
||||
</ul> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<!-- /.navbar --> |
||||
</div> |
||||
|
||||
<?php $this->widget('yii\widgets\Breadcrumbs', array( |
||||
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(), |
||||
)); ?> |
||||
<?php echo $content; ?> |
||||
|
||||
<hr> |
||||
|
||||
<div class="footer"> |
||||
<p>© My Company <?php echo date('Y'); ?></p>
|
||||
<p> |
||||
<?php echo Yii::powered(); ?> |
||||
Template by <a href="http://twitter.github.io/bootstrap/">Twitter Bootstrap</a> |
||||
</p> |
||||
</div> |
||||
<?php $this->endBody(); ?> |
||||
</div> |
||||
</body> |
||||
</html> |
||||
<?php $this->endPage(); ?> |
@ -0,0 +1,16 @@
|
||||
<?php |
||||
use yii\helpers\Html; |
||||
/** |
||||
* @var yii\base\View $this |
||||
*/ |
||||
$this->title = 'About'; |
||||
$this->params['breadcrumbs'][] = $this->title; |
||||
?> |
||||
<h1><?php echo Html::encode($this->title); ?></h1>
|
||||
|
||||
<p> |
||||
This is the About page. You may modify the following file to customize its content: |
||||
</p> |
||||
|
||||
<code><?php echo __FILE__; ?></code>
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?php |
||||
use yii\helpers\Html; |
||||
/** |
||||
* @var yii\base\View $this |
||||
* @var yii\widgets\ActiveForm $form |
||||
* @var app\models\ContactForm $model |
||||
*/ |
||||
$this->title = 'Contact'; |
||||
$this->params['breadcrumbs'][] = $this->title; |
||||
?> |
||||
<h1><?php echo Html::encode($this->title); ?></h1>
|
||||
|
||||
<?php if(Yii::$app->session->hasFlash('contactFormSubmitted')): ?> |
||||
<div class="alert alert-success"> |
||||
Thank you for contacting us. We will respond to you as soon as possible. |
||||
</div> |
||||
<?php return; endif; ?> |
||||
|
||||
<p> |
||||
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. |
||||
</p> |
||||
|
||||
<?php $form = $this->beginWidget('yii\widgets\ActiveForm', array( |
||||
'options' => array('class' => 'form-horizontal'), |
||||
'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')), |
||||
)); ?> |
||||
<?php echo $form->field($model, 'name')->textInput(); ?> |
||||
<?php echo $form->field($model, 'email')->textInput(); ?> |
||||
<?php echo $form->field($model, 'subject')->textInput(); ?> |
||||
<?php echo $form->field($model, 'body')->textArea(array('rows' => 6)); ?> |
||||
<div class="form-actions"> |
||||
<?php echo Html::submitButton('Submit', null, null, array('class' => 'btn btn-primary')); ?> |
||||
</div> |
||||
<?php $this->endWidget(); ?> |
@ -0,0 +1,47 @@
|
||||
<?php |
||||
/** |
||||
* @var yii\base\View $this |
||||
*/ |
||||
$this->title = 'Welcome'; |
||||
?> |
||||
<div class="jumbotron"> |
||||
<h1>Welcome!</h1> |
||||
|
||||
<p class="lead">Cras justo odio, dapibus ac facilisis in, egestas eget quam. Fusce dapibus, tellus ac cursus |
||||
commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p> |
||||
<a class="btn btn-large btn-success" href="http://www.yiiframework.com">Get started with Yii</a> |
||||
</div> |
||||
|
||||
<hr> |
||||
|
||||
<!-- Example row of columns --> |
||||
<div class="row-fluid"> |
||||
<div class="span4"> |
||||
<h2>Heading</h2> |
||||
|
||||
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris |
||||
condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. |
||||
Donec sed odio dui. </p> |
||||
|
||||
<p><a class="btn" href="#">View details »</a></p> |
||||
</div> |
||||
<div class="span4"> |
||||
<h2>Heading</h2> |
||||
|
||||
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris |
||||
condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. |
||||
Donec sed odio dui. </p> |
||||
|
||||
<p><a class="btn" href="#">View details »</a></p> |
||||
</div> |
||||
<div class="span4"> |
||||
<h2>Heading</h2> |
||||
|
||||
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta |
||||
felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum |
||||
massa.</p> |
||||
|
||||
<p><a class="btn" href="#">View details »</a></p> |
||||
</div> |
||||
</div> |
||||
|
@ -0,0 +1,63 @@
|
||||
Bootstrap with Yii |
||||
================== |
||||
|
||||
A ready-to-use Web application is distributed together with Yii. You may find |
||||
its source code under the `app` folder after you expand the Yii release file. |
||||
If you have installed Yii under a Web-accessible folder, you should be able to |
||||
access this application through the following URL: |
||||
|
||||
~~~ |
||||
http://localhost/yii/apps/bootstrap/index.php |
||||
~~~ |
||||
|
||||
|
||||
As you can see, the application has four pages: the homepage, the about page, |
||||
the contact page and the login page. The contact page displays a contact |
||||
form that users can fill in to submit their inquiries to the webmaster, |
||||
and the login page allows users to be authenticated before accessing privileged contents. |
||||
|
||||
|
||||
The following diagram shows the directory structure of this application. |
||||
|
||||
~~~ |
||||
app/ |
||||
index.php Web application entry script file |
||||
index-test.php entry script file for the functional tests |
||||
assets/ containing published resource files |
||||
css/ containing CSS files |
||||
img/ containing image files |
||||
themes/ containing application themes |
||||
protected/ containing protected application files |
||||
yiic yiic command line script for Unix/Linux |
||||
yiic.bat yiic command line script for Windows |
||||
yiic.php yiic command line PHP script |
||||
commands/ containing customized 'yiic' commands |
||||
components/ containing reusable user components |
||||
config/ containing configuration files |
||||
console.php the console application configuration |
||||
main.php the Web application configuration |
||||
controllers/ containing controller class files |
||||
SiteController.php the default controller class |
||||
data/ containing the sample database |
||||
schema.mysql.sql the DB schema for the sample MySQL database |
||||
schema.sqlite.sql the DB schema for the sample SQLite database |
||||
bootstrap.db the sample SQLite database file |
||||
vendor/ containing third-party extensions and libraries |
||||
messages/ containing translated messages |
||||
models/ containing model class files |
||||
User.php the User model |
||||
LoginForm.php the form model for 'login' action |
||||
ContactForm.php the form model for 'contact' action |
||||
runtime/ containing temporarily generated files |
||||
views/ containing controller view and layout files |
||||
layouts/ containing layout view files |
||||
main.php the base layout shared by all pages |
||||
site/ containing view files for the 'site' controller |
||||
about.php the view for the 'about' action |
||||
contact.php the view for the 'contact' action |
||||
index.php the view for the 'index' action |
||||
login.php the view for the 'login' action |
||||
~~~ |
||||
|
||||
|
||||
TBD |
@ -0,0 +1,30 @@
|
||||
* [Overview](overview.md) |
||||
* [Installation](installation.md) |
||||
* [Bootstrap with Yii](bootstrap.md) |
||||
* [MVC Overview](mvc.md) |
||||
* [Controller](controller.md) |
||||
* [Model](model.md) |
||||
* [View](view.md) |
||||
* [Application](application.md) |
||||
* [Form](form.md) |
||||
* [Data Validation](validation.md) |
||||
* [Database Access Objects](dao.md) |
||||
* [Query Builder](query-builder.md) |
||||
* [ActiveRecord](active-record.md) |
||||
* [Database Migration](migration.md) |
||||
* [Caching](caching.md) |
||||
* [Internationalization](i18n.md) |
||||
* [Extending Yii](extension.md) |
||||
* [Authentication](authentication.md) |
||||
* [Authorization](authorization.md) |
||||
* [Logging](logging.md) |
||||
* [URL Management](url.md) |
||||
* [Theming](theming.md) |
||||
* [Error Handling](error.md) |
||||
* [Template](template.md) |
||||
* [Console Application](console.md) |
||||
* [Security](security.md) |
||||
* [Performance Tuning](performance.md) |
||||
* [Testing](testing.md) |
||||
* [Automatic Code Generation](gii.md) |
||||
* [Upgrading from 1.1 to 2.0](upgrade-from-v1.md) |
@ -0,0 +1,112 @@
|
||||
Installation |
||||
============ |
||||
|
||||
Installation of Yii mainly involves the following two steps: |
||||
|
||||
1. Download Yii Framework from [yiiframework.com](http://www.yiiframework.com/). |
||||
2. Unpack the Yii release file to a Web-accessible directory. |
||||
|
||||
> Tip: Yii does not need to be installed under a Web-accessible directory. |
||||
A Yii application has one entry script which is usually the only file that |
||||
needs to be exposed to Web users. Other PHP scripts, including those from |
||||
Yii, should be protected from Web access; otherwise they might be exploited |
||||
by hackers. |
||||
|
||||
|
||||
Requirements |
||||
------------ |
||||
|
||||
After installing Yii, you may want to verify that your server satisfies |
||||
Yii's requirements. You can do so by accessing the requirement checker |
||||
script via the following URL in a Web browser: |
||||
|
||||
~~~ |
||||
http://hostname/path/to/yii/requirements/index.php |
||||
~~~ |
||||
|
||||
Yii requires PHP 5.3, so the server must have PHP 5.3 or above installed and |
||||
available to the web server. Yii has been tested with [Apache HTTP server](http://httpd.apache.org/) |
||||
on Windows and Linux. It may also run on other Web servers and platforms, |
||||
provided PHP 5.3 is supported. |
||||
|
||||
|
||||
Recommended Apache Configuration |
||||
-------------------------------- |
||||
|
||||
Yii is ready to work with a default Apache web server configuration. |
||||
The `.htaccess` files in Yii framework and application folders deny |
||||
access to the restricted resources. To hide the bootstrap file (usually `index.php`) |
||||
in your URLs you can add `mod_rewrite` instructions to the `.htaccess` file |
||||
in your document root or to the virtual host configuration: |
||||
|
||||
~~~ |
||||
RewriteEngine on |
||||
|
||||
# if a directory or a file exists, use it directly |
||||
RewriteCond %{REQUEST_FILENAME} !-f |
||||
RewriteCond %{REQUEST_FILENAME} !-d |
||||
# otherwise forward it to index.php |
||||
RewriteRule . index.php |
||||
~~~ |
||||
|
||||
|
||||
Recommended Nginx Configuration |
||||
------------------------------- |
||||
|
||||
You can use Yii with [Nginx](http://wiki.nginx.org/) and PHP with [FPM SAPI](http://php.net/install.fpm). |
||||
Here is a sample host configuration. It defines the bootstrap file and makes |
||||
Yii to catch all requests to nonexistent files, which allows us to have nice-looking URLs. |
||||
|
||||
~~~ |
||||
server { |
||||
set $host_path "/www/mysite"; |
||||
access_log /www/mysite/log/access.log main; |
||||
|
||||
server_name mysite; |
||||
root $host_path/htdocs; |
||||
set $yii_bootstrap "index.php"; |
||||
|
||||
charset utf-8; |
||||
|
||||
location / { |
||||
index index.html $yii_bootstrap; |
||||
try_files $uri $uri/ /$yii_bootstrap?$args; |
||||
} |
||||
|
||||
location ~ ^/(protected|framework|themes/\w+/views) { |
||||
deny all; |
||||
} |
||||
|
||||
#avoid processing of calls to unexisting static files by yii |
||||
location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ { |
||||
try_files $uri =404; |
||||
} |
||||
|
||||
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 |
||||
# |
||||
location ~ \.php { |
||||
fastcgi_split_path_info ^(.+\.php)(.*)$; |
||||
|
||||
#let yii catch the calls to unexising PHP files |
||||
set $fsn /$yii_bootstrap; |
||||
if (-f $document_root$fastcgi_script_name){ |
||||
set $fsn $fastcgi_script_name; |
||||
} |
||||
|
||||
fastcgi_pass 127.0.0.1:9000; |
||||
include fastcgi_params; |
||||
fastcgi_param SCRIPT_FILENAME $document_root$fsn; |
||||
|
||||
#PATH_INFO and PATH_TRANSLATED can be omitted, but RFC 3875 specifies them for CGI |
||||
fastcgi_param PATH_INFO $fastcgi_path_info; |
||||
fastcgi_param PATH_TRANSLATED $document_root$fsn; |
||||
} |
||||
|
||||
location ~ /\.ht { |
||||
deny all; |
||||
} |
||||
} |
||||
~~~ |
||||
|
||||
Using this configuration you can set `cgi.fix_pathinfo=0` in php.ini to avoid |
||||
many unnecessary system `stat()` calls. |
@ -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,52 @@
|
||||
MVC Overview |
||||
============ |
||||
|
||||
Yii implements the model-view-controller (MVC) design pattern, which is |
||||
widely adopted in Web programming. MVC aims to separate business logic from |
||||
user interface considerations, so that developers can more easily change |
||||
each part without affecting the other. In MVC, the model represents the |
||||
information (the data) and the business rules; the view contains elements |
||||
of the user interface such as text, form inputs; and the controller manages |
||||
the communication between the model and the view. |
||||
|
||||
Besides implementing MVC, Yii also introduces a front-controller, called |
||||
`Application`, which encapsulates the execution context for the processing |
||||
of a request. Application collects information about a user request and |
||||
then dispatches it to an appropriate controller for further handling. |
||||
|
||||
The following diagram shows the static structure of a Yii application: |
||||
|
||||
![Static structure of Yii application](structure.png) |
||||
|
||||
|
||||
A Typical Workflow |
||||
------------------ |
||||
|
||||
The following diagram shows a typical workflow of a Yii application when |
||||
it is handling a user request: |
||||
|
||||
![Typical workflow of a Yii application](flow.png) |
||||
|
||||
1. A user makes a request with the URL `http://www.example.com/index.php?r=post/show&id=1` |
||||
and the Web server handles the request by executing the bootstrap script `index.php`. |
||||
2. The bootstrap script creates an [Application](/doc/guide/basics.application) |
||||
instance and runs it. |
||||
3. The Application obtains detailed user request information from |
||||
an [application component](/doc/guide/basics.application#application-component) |
||||
named `request`. |
||||
4. The application determines the requested [controller](/doc/guide/basics.controller) |
||||
and [action](/doc/guide/basics.controller#action) with the help |
||||
of an application component named `urlManager`. For this example, the controller |
||||
is `post`, which refers to the `PostController` class; and the action is `show`, |
||||
whose actual meaning is determined by the controller. |
||||
5. The application creates an instance of the requested controller |
||||
to further handle the user request. The controller determines that the action |
||||
`show` refers to a method named `actionShow` in the controller class. It then |
||||
creates and executes filters (e.g. access control, benchmarking) associated |
||||
with this action. The action is executed if it is allowed by the filters. |
||||
6. The action reads a `Post` [model](/doc/guide/basics.model) whose ID is `1` from the database. |
||||
7. The action renders a [view](/doc/guide/basics.view) named `show` with the `Post` model. |
||||
8. The view reads and displays the attributes of the `Post` model. |
||||
9. The view executes some [widgets](/doc/guide/basics.view#widget). |
||||
10. The view rendering result is embedded in a [layout](/doc/guide/basics.view#layout). |
||||
11. The action completes the view rendering and displays the result to the user. |
@ -0,0 +1,36 @@
|
||||
What is Yii |
||||
=========== |
||||
|
||||
Yii is a high-performance, component-based PHP framework for developing |
||||
large-scale Web applications rapidly. It enables maximum reusability in Web |
||||
programming and can significantly accelerate your Web application development |
||||
process. The name Yii (pronounced `Yee` or `[ji:]`) is an acronym for |
||||
"**Yes It Is!**". |
||||
|
||||
|
||||
Requirements |
||||
------------ |
||||
|
||||
To run a Yii-powered Web application, you need a Web server that supports |
||||
PHP 5.3.?. |
||||
|
||||
For developers who want to use Yii, understanding object-oriented |
||||
programming (OOP) is very helpful, because Yii is a pure OOP framework. |
||||
|
||||
|
||||
What is Yii Best for? |
||||
--------------------- |
||||
|
||||
Yii is a generic Web programming framework that can be used for developing |
||||
virtually any type of Web application. Because it is light-weight and |
||||
equipped with sophisticated caching mechanisms, it is especially suited |
||||
to high-traffic applications, such as portals, forums, content |
||||
management systems (CMS), e-commerce systems, etc. |
||||
|
||||
|
||||
How does Yii Compare with Other Frameworks? |
||||
------------------------------------------- |
||||
|
||||
Like most PHP frameworks, Yii is an MVC (Model-View-Controller) framework. |
||||
|
||||
TBD |
@ -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,8 @@
|
||||
The Definitive Guide to Yii 2.0 |
||||
=============================== |
||||
|
||||
This tutorial is released under [the Terms of Yii Documentation](http://www.yiiframework.com/doc/terms/). |
||||
|
||||
All Rights Reserved. |
||||
|
||||
2008 (c) Yii Software LLC. |
@ -0,0 +1,437 @@
|
||||
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. |
||||
|
||||
|
||||
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 based 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: |
||||
|
||||
~~~ |
||||
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: |
||||
|
||||
~~~ |
||||
$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: |
||||
|
||||
~~~ |
||||
$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: |
||||
|
||||
~~~ |
||||
$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: |
||||
|
||||
~~~ |
||||
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: |
||||
|
||||
~~~ |
||||
$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, |
||||
|
||||
~~~ |
||||
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, |
||||
|
||||
~~~ |
||||
$post = new Post; |
||||
if ($this->populate($_POST, $model)) {...} |
||||
// which is equivalent to: |
||||
if (isset($_POST['Post'])) { |
||||
$post->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: |
||||
|
||||
~~~ |
||||
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 $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, |
||||
|
||||
~~~ |
||||
$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: |
||||
|
||||
~~~ |
||||
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: |
||||
|
||||
~~~ |
||||
// 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, |
||||
|
||||
~~~ |
||||
$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, |
||||
|
||||
~~~ |
||||
$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. |
||||
|
||||
~~~ |
||||
array( |
||||
'pattern' => 'post/<page:\d+>/<tag>', |
||||
'route' => 'post/index', |
||||
'defaults' => array('page' => 1), |
||||
) |
||||
~~~ |
||||
|
||||
|
||||
Response |
||||
-------- |
||||
|
||||
Extensions |
||||
---------- |
||||
|
||||
Integration with Composer |
||||
------------------------- |
||||
|
||||
TBD |
||||
|
@ -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?>!
|
@ -0,0 +1,45 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\helpers; |
||||
|
||||
use yii\base\Object; |
||||
|
||||
/** |
||||
* JsExpression marks a string as a JavaScript expression. |
||||
* When using [[Json::encode()]] to encode a value, JsonExpression objects |
||||
* will be specially handled and encoded as a JavaScript expression instead of a string. |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class JsExpression extends Object |
||||
{ |
||||
/** |
||||
* @var string the JavaScript expression represented by this object |
||||
*/ |
||||
public $expression; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param string $expression the JavaScript expression represented by this object |
||||
* @param array $config additional configurations for this object |
||||
*/ |
||||
public function __construct($expression, $config = array()) |
||||
{ |
||||
$this->expression = $expression; |
||||
parent::__construct($config); |
||||
} |
||||
|
||||
/** |
||||
* The PHP magic function converting an object into a string. |
||||
* @return string the JavaScript expression. |
||||
*/ |
||||
public function __toString() |
||||
{ |
||||
return $this->expression; |
||||
} |
||||
} |
@ -0,0 +1,18 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\helpers; |
||||
|
||||
/** |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Json extends base\Json |
||||
{ |
||||
|
||||
} |
@ -0,0 +1,107 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\helpers\base; |
||||
|
||||
use yii\base\InvalidParamException; |
||||
use yii\helpers\JsExpression; |
||||
|
||||
/** |
||||
* Json is a helper class providing JSON data encoding and decoding. |
||||
* It enhances the PHP built-in functions `json_encode()` and `json_decode()` |
||||
* by supporting encoding JavaScript expressions and throwing exceptions when decoding fails. |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Json |
||||
{ |
||||
/** |
||||
* Encodes the given value into a JSON string. |
||||
* The method enhances `json_encode()` by supporting JavaScript expressions. |
||||
* In particular, the method will not encode a JavaScript expression that is |
||||
* represented in terms of a [[JsExpression]] object. |
||||
* @param mixed $value the data to be encoded |
||||
* @param integer $options the encoding options. For more details please refer to |
||||
* [[http://www.php.net/manual/en/function.json-encode.php]] |
||||
* @return string the encoding result |
||||
*/ |
||||
public static function encode($value, $options = 0) |
||||
{ |
||||
$expressions = array(); |
||||
$value = static::processData($value, $expressions); |
||||
$json = json_encode($value, $options); |
||||
return $expressions === array() ? $json : strtr($json, $expressions); |
||||
} |
||||
|
||||
/** |
||||
* Decodes the given JSON string into a PHP data structure. |
||||
* @param string $json the JSON string to be decoded |
||||
* @param boolean $asArray whether to return objects in terms of associative arrays. |
||||
* @return mixed the PHP data |
||||
* @throws InvalidParamException if there is any decoding error |
||||
*/ |
||||
public static function decode($json, $asArray = true) |
||||
{ |
||||
if (is_array($json)) { |
||||
throw new InvalidParamException('Invalid JSON data.'); |
||||
} |
||||
$decode = json_decode((string)$json, $asArray); |
||||
switch (json_last_error()) { |
||||
case JSON_ERROR_NONE: |
||||
break; |
||||
case JSON_ERROR_DEPTH: |
||||
throw new InvalidParamException('The maximum stack depth has been exceeded.'); |
||||
case JSON_ERROR_CTRL_CHAR: |
||||
throw new InvalidParamException('Control character error, possibly incorrectly encoded.'); |
||||
case JSON_ERROR_SYNTAX: |
||||
throw new InvalidParamException('Syntax error.'); |
||||
case JSON_ERROR_STATE_MISMATCH: |
||||
throw new InvalidParamException('Invalid or malformed JSON.'); |
||||
case JSON_ERROR_UTF8: |
||||
throw new InvalidParamException('Malformed UTF-8 characters, possibly incorrectly encoded.'); |
||||
default: |
||||
throw new InvalidParamException('Unknown JSON decoding error.'); |
||||
} |
||||
|
||||
return $decode; |
||||
} |
||||
|
||||
/** |
||||
* Pre-processes the data before sending it to `json_encode()`. |
||||
* @param mixed $data the data to be processed |
||||
* @param array $expressions collection of JavaScript expressions |
||||
* @return mixed the processed data |
||||
*/ |
||||
protected static function processData($data, &$expressions) |
||||
{ |
||||
if (is_array($data)) { |
||||
foreach ($data as $key => $value) { |
||||
if (is_array($value) || is_object($value)) { |
||||
$data[$key] = static::processData($value, $expressions); |
||||
} |
||||
} |
||||
return $data; |
||||
} elseif (is_object($data)) { |
||||
if ($data instanceof JsExpression) { |
||||
$token = '!{[' . count($expressions) . ']}!'; |
||||
$expressions['"' . $token . '"'] = $data->expression; |
||||
return $token; |
||||
} |
||||
$result = array(); |
||||
foreach ($data as $key => $value) { |
||||
if (is_array($value) || is_object($value)) { |
||||
$result[$key] = static::processData($value, $expressions); |
||||
} else { |
||||
$result[$key] = $value; |
||||
} |
||||
} |
||||
return $result; |
||||
} else { |
||||
return $data; |
||||
} |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue