Commit f59f3908 by Carsten Brandt

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

* '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.php
parents dd9a3675 647a8027
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
\ No newline at end of file
<?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'));
}
?>
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;
}
......@@ -2,7 +2,7 @@
defined('YII_DEBUG') or define('YII_DEBUG', true);
require(__DIR__ . '/../framework/yii.php');
require(__DIR__ . '/../../framework/yii.php');
$config = require(__DIR__ . '/protected/config/main.php');
$application = new yii\web\Application($config);
......
<?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',
),
),
);
......@@ -10,6 +10,12 @@ return array(
'user' => array(
'class' => 'yii\web\User',
'identityClass' => 'app\models\User',
)
),
'assetManager' => array(
'bundles' => require(__DIR__ . '/assets.php'),
),
),
'params' => array(
'adminEmail' => 'admin@example.com',
),
);
\ No newline at end of file
);
......@@ -2,6 +2,7 @@
use yii\web\Controller;
use app\models\LoginForm;
use app\models\ContactForm;
class SiteController extends Controller
{
......@@ -14,7 +15,7 @@ class SiteController extends Controller
{
$model = new LoginForm();
if ($this->populate($_POST, $model) && $model->login()) {
Yii::$app->getResponse()->redirect(array('site/index'));
Yii::$app->response->redirect(array('site/index'));
} else {
echo $this->render('login', array(
'model' => $model,
......@@ -27,4 +28,22 @@ class SiteController extends Controller
Yii::$app->getUser()->logout();
Yii::$app->getResponse()->redirect(array('site/index'));
}
}
\ No newline at end of file
public function actionContact()
{
$model = new ContactForm;
if ($this->populate($_POST, $model) && $model->contact(Yii::$app->params['adminEmail'])) {
Yii::$app->session->setFlash('contactFormSubmitted');
Yii::$app->response->refresh();
} else {
echo $this->render('contact', array(
'model' => $model,
));
}
}
public function actionAbout()
{
echo $this->render('about');
}
}
<?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;
}
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace app\models;
......@@ -11,8 +6,7 @@ use Yii;
use yii\base\Model;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
* LoginForm is the model behind the login form.
*/
class LoginForm extends Model
{
......@@ -20,16 +14,25 @@ class LoginForm extends Model
public $password;
public $rememberMe = true;
/**
* @return array the validation rules.
*/
public function rules()
{
return array(
array('username', 'required'),
array('password', 'required'),
// username and password are both required
array('username, password', 'required'),
// password is validated by validatePassword()
array('password', 'validatePassword'),
// rememberMe must be a boolean value
array('rememberMe', 'boolean'),
);
}
/**
* Validates the password.
* This method serves as the inline validation for password.
*/
public function validatePassword()
{
$user = User::findByUsername($this->username);
......@@ -38,14 +41,18 @@ class LoginForm extends Model
}
}
/**
* Logs in a user using the provided username and password.
* @return boolean whether the user is logged in successfully
*/
public function login()
{
if ($this->validate()) {
$user = User::findByUsername($this->username);
Yii::$app->getUser()->login($user, $this->rememberMe ? 3600*24*30 : 0);
Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0);
return true;
} else {
return false;
}
}
}
\ No newline at end of file
}
......@@ -58,4 +58,4 @@ class User extends \yii\base\Object implements \yii\web\Identity
{
return $this->password === $password;
}
}
\ No newline at end of file
}
......@@ -4,23 +4,57 @@
* @var $content string
*/
use yii\helpers\Html;
$this->registerAssetBundle('app');
?>
<?php $this->beginPage(); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<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 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>&copy; 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(); ?>
\ No newline at end of file
<?php $this->endPage(); ?>
<?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>
<?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(); ?>
<?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 &raquo;</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 &raquo;</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 &raquo;</a></p>
</div>
</div>
......@@ -5,8 +5,10 @@ use yii\helpers\Html;
* @var yii\widgets\ActiveForm $form
* @var app\models\LoginForm $model
*/
$this->title = 'Login';
$this->params['breadcrumbs'][] = $this->title;
?>
<h1>Login</h1>
<h1><?php echo Html::encode($this->title); ?></h1>
<p>Please fill out the following fields to login:</p>
......@@ -14,9 +16,7 @@ use yii\helpers\Html;
<?php echo $form->field($model, 'username')->textInput(); ?>
<?php echo $form->field($model, 'password')->passwordInput(); ?>
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?>
<div class="control-group">
<div class="controls">
<?php echo Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')); ?>
</div>
<div class="form-actions">
<?php echo Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')); ?>
</div>
<?php $this->endWidget(); ?>
\ No newline at end of file
<?php $this->endWidget(); ?>
......@@ -16,5 +16,5 @@ require(__DIR__ . '/../framework/yii.php');
$id = 'yiic-build';
$basePath = __DIR__;
$application = new yii\console\Application($id, $basePath);
$application = new yii\console\Application(array('id' => $id, 'basePath' => $basePath));
$application->run();
......@@ -412,7 +412,7 @@ class Customer extends \yii\db\ActiveRecord
/**
* @param ActiveQuery $query
*/
public function active($query)
public static function active($query)
{
$query->andWhere('status = 1');
}
......@@ -435,7 +435,7 @@ class Customer extends \yii\db\ActiveRecord
* @param ActiveQuery $query
* @param integer $age
*/
public function olderThan($query, $age = 30)
public static function olderThan($query, $age = 30)
{
$query->andWhere('age > :age', array(':age' => $age));
}
......
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
\ No newline at end of file
Error Handling
==============
* [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)
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.
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.
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
\ No newline at end of file
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
\ No newline at end of file
Template
========
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.
URL Management
==============
......@@ -18,6 +18,7 @@ array(
),
'twig' => array(
'class' => 'yii\renderers\TwigViewRenderer',
'twigPath' => '@app/vendors/Twig',
),
// ...
),
......@@ -26,6 +27,9 @@ array(
)
```
Note that Smarty and Twig are not bundled with Yii and you have to download and
unpack these yourself and then specify `twigPath` and `smartyPath` respectively.
Twig
----
......@@ -38,6 +42,21 @@ or `$this->renderPartial()` from your controller:
echo $this->render('renderer.twig', array('username' => 'Alex'));
```
### Additional functions
Additionally to regular Twig syntax the following is available in Yii:
```php
<a href="{{ path('blog/view', {'alias' : post.alias}) }}">{{ post.title }}</a>
```
path function calls `Html::url()` internally.
### Additional variables
- `app` = `\Yii::$app`
- `this` = current `View` object
Smarty
------
......@@ -49,3 +68,18 @@ or `$this->renderPartial()` from your controller:
```php
echo $this->render('renderer.tpl', array('username' => 'Alex'));
```
### Additional functions
Additionally to regular Smarty syntax the following is available in Yii:
```php
<a href="{path route='blog/view' alias=$post.alias}">{$post.title}</a>
```
path function calls `Html::url()` internally.
### Additional variables
- `$app` = `\Yii::$app`
- `$this` = current `View` object
\ No newline at end of file
......@@ -600,6 +600,13 @@ class YiiBase
*/
public static function t($message, $params = array(), $language = null)
{
return self::$app->getI18N()->translate($message, $params, $language);
if (self::$app !== null) {
return self::$app->getI18N()->translate($message, $params, $language);
} else {
if (strpos($message, '|') !== false && preg_match('/^([\w\-\\/\.\\\\]+)\|(.*)/', $message, $matches)) {
$message = $matches[2];
}
return is_array($params) ? strtr($message, $params) : $message;
}
}
}
......@@ -28,4 +28,4 @@ return array(
),
'depends' => array('yii', 'yii/validation'),
),
);
\ No newline at end of file
);
......@@ -7,24 +7,59 @@
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
/**
* yii is the root module for all Yii JavaScript modules.
* It implements a mechanism of organizing JavaScript code in modules through the function "yii.initModule()".
*
* Each module should be named as "x.y.z", where "x" stands for the root module (for the Yii core code, this is "yii").
*
* A module may be structured as follows:
*
* ~~~
* yii.sample = (function($) {
* var pub = {
* // whether this module is currently active. If false, init() will not be called for this module
* // it will also not be called for all its child modules. If this property is undefined, it means true.
* isActive: true,
* init: function() {
* // ... module initialization code go here ...
* },
*
* // ... other public functions and properties go here ...
* };
*
* // ... private functions and properties go here ...
*
* return pub;
* });
* ~~~
*
* Using this structure, you can define public and private functions/properties for a module.
* Private functions/properties are only visible within the module, while public functions/properties
* may be accessed outside of the module. For example, you can access "yii.sample.init()".
*
* You must call "yii.initModule()" once for the root module of all your modules.
*/
yii = (function ($) {
var pub = {
version: '2.0'
version: '2.0',
initModule: function (module) {
if (module.isActive === undefined || module.isActive) {
if ($.isFunction(module.init)) {
module.init();
}
$.each(module, function () {
if ($.isPlainObject(this)) {
pub.initModule(this);
}
});
}
}
};
return pub;
})(jQuery);
jQuery(document).ready(function ($) {
// call the init() method of every module
var init = function (module) {
if ($.isFunction(module.init) && (module.trigger == undefined || $(module.trigger).length)) {
module.init();
}
$.each(module, function () {
if ($.isPlainObject(this)) {
init(this);
}
});
};
init(yii);
jQuery(document).ready(function () {
yii.initModule(yii);
});
/**
* Yii validation module.
*
* This is the JavaScript widget used by the yii\widgets\ActiveForm widget.
* This JavaScript module provides the validation methods for the built-in validaotrs.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
......@@ -11,7 +11,188 @@
*/
yii.validation = (function ($) {
var pub = {
var isEmpty = function (value, trim) {
return value === null || value === undefined || value == []
|| value === '' || trim && $.trim(value) === '';
};
return {
required: function (value, messages, options) {
var valid = false;
if (options.requiredValue === undefined) {
if (options.strict && value !== undefined || !options.strict && !isEmpty(value, true)) {
valid = true;
}
} else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
valid = true;
}
if (!valid) {
messages.push(options.message);
}
},
boolean: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
|| options.strict && (value === options.trueValue || value === options.falseValue);
if (!valid) {
messages.push(options.message);
}
},
string: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
if (typeof value !== 'string') {
messages.push(options.message);
return;
}
if (options.min !== undefined && value.length < options.min) {
messages.push(options.tooShort);
}
if (options.max !== undefined && value.length > options.max) {
messages.push(options.tooLong);
}
if (options.is !== undefined && value.length != options.is) {
messages.push(options.is);
}
},
number: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
if (typeof value === 'string' && !value.match(options.pattern)) {
messages.push(options.message);
return;
}
if (options.min !== undefined && value < options.min) {
messages.push(options.tooSmall);
}
if (options.max !== undefined && value > options.max) {
messages.push(options.tooBig);
}
},
range: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
var valid = !options.not && $.inArray(value, options.range)
|| options.not && !$.inArray(value, options.range);
if (!valid) {
messages.push(options.message);
}
},
regularExpression: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) {
messages.push(options.message)
}
},
email: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
var valid = value.match(options.pattern) && (!options.allowName || value.match(options.fullPattern));
if (!valid) {
messages.push(options.message);
}
},
url: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
if (options.defaultScheme && !value.match(/:\/\//)) {
value = options.defaultScheme + '://' + value;
}
if (!value.match(options.pattern)) {
messages.push(options.message);
}
},
captcha: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
// CAPTCHA may be updated via AJAX and the updated hash is stored in body data
var hash = $('body').data(options.hashKey);
if (hash == null) {
hash = options.hash;
} else {
hash = hash[options.caseSensitive ? 0 : 1];
}
var v = options.caseSensitive ? value : value.toLowerCase();
for (var i = v.length - 1, h = 0; i >= 0; --i) {
h += v.charCodeAt(i);
}
if (h != hash) {
messages.push(options.message);
}
},
compare: function (value, messages, options) {
if (options.skipOnEmpty && isEmpty(value)) {
return;
}
var compareValue, valid = true;
if (options.compareAttribute === undefined) {
compareValue = options.compareValue;
} else {
compareValue = $('#' + options.compareAttribute).val();
}
switch (options.operator) {
case '==':
valid = value == compareValue;
break;
case '===':
valid = value === compareValue;
break;
case '!=':
valid = value != compareValue;
break;
case '!==':
valid = value !== compareValue;
break;
case '>':
valid = value > compareValue;
break;
case '>=':
valid = value >= compareValue;
break;
case '<':
valid = value < compareValue;
break;
case '<=':
valid = value <= compareValue;
break;
}
if (!valid) {
messages.push(options.message);
}
}
};
return pub;
})(jQuery);
......@@ -87,4 +87,4 @@ class ActionFilter extends Behavior
{
return !in_array($action->id, $this->except, true) && (empty($this->only) || in_array($action->id, $this->only, true));
}
}
\ No newline at end of file
}
......@@ -306,6 +306,15 @@ class Application extends Module
}
/**
* @return null|Component
* @todo
*/
public function getAuthManager()
{
return $this->getComponent('auth');
}
/**
* Registers the core application components.
* @see setComponents
*/
......
......@@ -90,6 +90,7 @@ class Component extends Object
// as behavior: attach behavior
$name = trim(substr($name, 3));
$this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value));
return;
} else {
// behavior property
$this->ensureBehaviors();
......@@ -496,6 +497,7 @@ class Component extends Object
*/
public function detachBehavior($name)
{
$this->ensureBehaviors();
if (isset($this->_behaviors[$name])) {
$behavior = $this->_behaviors[$name];
unset($this->_behaviors[$name]);
......@@ -511,6 +513,7 @@ class Component extends Object
*/
public function detachBehaviors()
{
$this->ensureBehaviors();
if ($this->_behaviors !== null) {
foreach ($this->_behaviors as $name => $behavior) {
$this->detachBehavior($name);
......
......@@ -22,4 +22,4 @@ class Exception extends \Exception
{
return \Yii::t('yii|Exception');
}
}
\ No newline at end of file
}
......@@ -72,23 +72,21 @@ class View extends Component
/**
* @var array a list of available renderers indexed by their corresponding supported file extensions.
* Each renderer may be a view renderer object or the configuration for creating the renderer object.
* For example,
*
* ~~~
* array(
* 'tpl' => array(
* 'class' => 'yii\renderers\SmartyRenderer',
* ),
* 'twig' => array(
* 'class' => 'yii\renderers\TwigRenderer',
* ),
* )
* ~~~
* The default setting supports both Smarty and Twig (their corresponding file extension is "tpl"
* and "twig" respectively. Please refer to [[SmartyRenderer]] and [[TwigRenderer]] on how to install
* the needed libraries for these template engines.
*
* If no renderer is available for the given view file, the view file will be treated as a normal PHP
* and rendered via [[renderPhpFile()]].
*/
public $renderers = array();
public $renderers = array(
'tpl' => array(
'class' => 'yii\renderers\SmartyRenderer',
),
'twig' => array(
'class' => 'yii\renderers\TwigRenderer',
),
);
/**
* @var Theme|array the theme object or the configuration array for creating the theme object.
* If not set, it means theming is not enabled.
......@@ -744,10 +742,10 @@ class View extends Component
{
$lines = array();
if (!empty($this->metaTags)) {
$lines[] = implode("\n", $this->cssFiles);
$lines[] = implode("\n", $this->metaTags);
}
if (!empty($this->linkTags)) {
$lines[] = implode("\n", $this->cssFiles);
$lines[] = implode("\n", $this->linkTags);
}
if (!empty($this->cssFiles)) {
$lines[] = implode("\n", $this->cssFiles);
......@@ -797,4 +795,4 @@ class View extends Component
}
return implode("\n", $lines);
}
}
\ No newline at end of file
}
......@@ -41,4 +41,4 @@ class ViewEvent extends Event
$this->viewFile = $viewFile;
parent::__construct($config);
}
}
\ No newline at end of file
}
......@@ -83,7 +83,8 @@ class Widget extends Component
*/
public function render($view, $params = array())
{
return $this->view->render($view, $params, $this);
$viewFile = $this->findViewFile($view);
return $this->view->renderFile($viewFile, $params, $this);
}
/**
......@@ -133,4 +134,4 @@ class Widget extends Component
return pathinfo($file, PATHINFO_EXTENSION) === '' ? $file . '.php' : $file;
}
}
\ No newline at end of file
}
......@@ -349,4 +349,4 @@ abstract class Cache extends Component implements \ArrayAccess
{
$this->delete($key);
}
}
\ No newline at end of file
}
......@@ -49,4 +49,4 @@ abstract class Dependency extends \yii\base\Object
* @return mixed the data needed to determine if dependency has been changed.
*/
abstract protected function generateDependencyData();
}
\ No newline at end of file
}
......@@ -14,24 +14,36 @@ namespace yii\caching;
* The dependency is reported as unchanged if and only if the result of the expression is
* the same as the one evaluated when storing the data to cache.
*
* A PHP expression can be any PHP code that has a value. To learn more about what an expression is,
* please refer to the [php manual](http://www.php.net/manual/en/language.expressions.php).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ExpressionDependency extends Dependency
{
/**
* @var string the PHP expression whose result is used to determine the dependency.
* @var string the string representation of a PHP expression whose result is used to determine the dependency.
* A PHP expression can be any PHP code that has a value. To learn more about what an expression is,
* please refer to the [php manual](http://www.php.net/manual/en/language.expressions.php).
*/
public $expression;
/**
* @var mixed custom data associated with this dependency. In [[expression]], you may compare the value of
* this property with the latest data to determine if the dependency has changed or not.
*/
public $data;
/**
* Constructor.
* @param string $expression the PHP expression whose result is used to determine the dependency.
* @param mixed $data the custom data associated with this dependency
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($expression = 'true', $config = array())
public function __construct($expression = 'true', $data = null, $config = array())
{
$this->expression = $expression;
$this->data = $data;
parent::__construct($config);
}
......
......@@ -46,4 +46,4 @@ class MemCacheServer extends \yii\base\Object
* @var boolean if the server should be flagged as online upon a failure. This is used by memcache only.
*/
public $status = true;
}
\ No newline at end of file
}
......@@ -89,4 +89,4 @@ class WinCache extends Cache
{
return wincache_ucache_clear();
}
}
\ No newline at end of file
}
......@@ -147,4 +147,4 @@ class Controller extends \yii\base\Controller
{
return array();
}
}
\ No newline at end of file
}
......@@ -321,4 +321,4 @@ class AppController extends Controller
closedir($handle);
return $list;
}
}
\ No newline at end of file
}
......@@ -350,4 +350,4 @@ return array(
EOD;
file_put_contents($configFile, $template);
}
}
\ No newline at end of file
}
......@@ -418,4 +418,4 @@ class HelpController extends Controller
$name = $required ? "$name (required)" : $name;
return $doc === '' ? $name : "$name: $doc";
}
}
\ No newline at end of file
}
<?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,
),
),
);
\ No newline at end of file
<?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();
\ No newline at end of file
<?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',
),
),
);
\ No newline at end of file
<?php
use \yii\web\Controller;
/**
* SiteController
*/
class SiteController extends Controller
{
public function actionIndex()
{
echo $this->render('index', array(
'name' => 'Qiang',
));
}
}
\ No newline at end of file
<?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>
\ No newline at end of file
Hello, <?php echo $name?>!
\ No newline at end of file
......@@ -88,7 +88,8 @@ class ActiveQuery extends Query
{
if (method_exists($this->modelClass, $name)) {
array_unshift($params, $this);
return call_user_func_array(array($this->modelClass, $name), $params);
call_user_func_array(array($this->modelClass, $name), $params);
return $this;
} else {
return parent::__call($name, $params);
}
......
......@@ -266,7 +266,7 @@ class ActiveRelation extends ActiveQuery
{
$attributes = array_keys($this->link);
$values = array();
if (count($attributes) ===1) {
if (count($attributes) === 1) {
// single key
$attribute = reset($this->link);
foreach ($models as $model) {
......
......@@ -66,7 +66,7 @@ use yii\caching\Cache;
* // ... executing other SQL statements ...
* $transaction->commit();
* } catch(Exception $e) {
* $transaction->rollBack();
* $transaction->rollback();
* }
* ~~~
*
......@@ -517,7 +517,7 @@ class Connection extends Component
public function quoteSql($sql)
{
$db = $this;
return preg_replace_callback('/(\\{\\{([\w\-\. ]+)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/',
return preg_replace_callback('/(\\{\\{([%\w\-\. ]+)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/',
function($matches) use($db) {
if (isset($matches[3])) {
return $db->quoteColumnName($matches[3]);
......
......@@ -41,4 +41,4 @@ class Exception extends \yii\base\Exception
{
return \Yii::t('yii|Database Exception');
}
}
\ No newline at end of file
}
......@@ -57,4 +57,4 @@ class Expression extends \yii\base\Object
{
return $this->expression;
}
}
\ No newline at end of file
}
......@@ -64,14 +64,14 @@ class Migration extends \yii\base\Component
$transaction = $this->db->beginTransaction();
try {
if ($this->safeUp() === false) {
$transaction->rollBack();
$transaction->rollback();
return false;
}
$transaction->commit();
} catch (\Exception $e) {
echo "Exception: " . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n";
echo $e->getTraceAsString() . "\n";
$transaction->rollBack();
$transaction->rollback();
return false;
}
return null;
......@@ -89,14 +89,14 @@ class Migration extends \yii\base\Component
$transaction = $this->db->beginTransaction();
try {
if ($this->safeDown() === false) {
$transaction->rollBack();
$transaction->rollback();
return false;
}
$transaction->commit();
} catch (\Exception $e) {
echo "Exception: " . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n";
echo $e->getTraceAsString() . "\n";
$transaction->rollBack();
$transaction->rollback();
return false;
}
return null;
......@@ -368,4 +368,4 @@ class Migration extends \yii\base\Component
$this->db->createCommand()->dropIndex($name, $table)->execute();
echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n";
}
}
\ No newline at end of file
}
......@@ -483,7 +483,7 @@ class Query extends \yii\base\Component
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`).
* (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
......@@ -499,7 +499,7 @@ class Query extends \yii\base\Component
* Adds additional ORDER BY columns to the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`).
* (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
......
......@@ -20,4 +20,4 @@ class StaleObjectException extends Exception
{
return \Yii::t('yii|Stale Object Exception');
}
}
\ No newline at end of file
}
......@@ -25,7 +25,7 @@ use yii\base\InvalidConfigException;
* //.... other SQL executions
* $transaction->commit();
* } catch(Exception $e) {
* $transaction->rollBack();
* $transaction->rollback();
* }
* ~~~
*
......@@ -42,14 +42,14 @@ class Transaction extends \yii\base\Object
public $db;
/**
* @var boolean whether this transaction is active. Only an active transaction
* can [[commit()]] or [[rollBack()]]. This property is set true when the transaction is started.
* can [[commit()]] or [[rollback()]]. This property is set true when the transaction is started.
*/
private $_active = false;
/**
* Returns a value indicating whether this transaction is active.
* @return boolean whether this transaction is active. Only an active transaction
* can [[commit()]] or [[rollBack()]].
* can [[commit()]] or [[rollback()]].
*/
public function getIsActive()
{
......
......@@ -16,4 +16,4 @@ namespace yii\helpers;
*/
class ArrayHelper extends base\ArrayHelper
{
}
\ No newline at end of file
}
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment