Commit 105e277f by Antonio Ramirez

Merge branch 'master' into bootstrap

* master: (84 commits) remove from master (update track) minor fixes updated the README file of the bootstrap app. Inflector class readjusting files for the framework package. renamed files. Added punycode as part of the framework. Renamed core asset bundles. fixed wrong dependency name. Added bootstrap bundles. Reorganized the bootstrap app to prepare it as a separate composer package. Update Pagination.php "ManagerTestBase::testExecuteBizRule()" has been fixed to not produce side effects on other tests. changed back to "create_time". Always enable profiling for DB queries. Fixed SiteController about Yii. changed to insert_time. Minor doc fix. refactored AutoTimestamp. Added UrlRule::host. ... Conflicts: yii/assets.php
parents 25512733 ab695d11
......@@ -13,4 +13,7 @@ nbproject
Thumbs.db
# composer vendor dir
/yii/vendor
\ No newline at end of file
/yii/vendor
# composer itself is not needed
composer.phar
The Yii framework is free software. It is released under the terms of
the following BSD License.
Copyright © 2008-2012 by Yii Software LLC (http://www.yiisoft.com)
Copyright © 2008-2013 by Yii Software LLC (http://www.yiisoft.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
......
The Yii framework is free software. It is released under the terms of
the following BSD License.
Copyright © 2008-2013 by Yii Software LLC (http://www.yiisoft.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Yii Software LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
Yii 2 Bootstrap Application
===========================
**NOTE** Yii 2 and the relevant applications and extensions are still under heavy
development. We may make significant changes without prior notices. Please do not
use them for production. Please consider using [Yii v1.1](https://github.com/yiisoft/yii)
if you have a project to be deployed for production soon.
Thank you for choosing Yii 2 - the new generation of high-performance PHP framework.
The Yii 2 Bootstrap Application is a Web application template that you can easily customize
to fit for your needs. It is particularly suitable for small Websites which mainly contain
a few informational pages.
DIRECTORY STRUCTURE
-------------------
commands/ contains console commands (controllers)
config/ contains application configurations
controllers/ contains Web controller classes
models/ contains model classes
runtime/ contains files generated during runtime
vendor/ contains dependent 3rd-party packages
views/ contains view files for the Web application
www/ contains the entry script and Web resources
REQUIREMENTS
------------
The minimum requirement by Yii is that your Web server supports PHP 5.3.?.
INSTALLATION
------------
### Install via Composer
If you do not have [Composer](http://getcomposer.org/), you may download it from
[http://getcomposer.org/](http://getcomposer.org/) or run the following command on Linux/Unix/MacOS:
~~~
curl -s http://getcomposer.org/installer | php
~~~
You can then install the Bootstrap Application using the following command:
~~~
php composer.phar create-project --stability=dev yiisoft/yii2-bootstrap bootstrap
~~~
Now you should be able to access the Bootstrap Application using the URL `http://localhost/bootstrap/www/`,
assuming `bootstrap` is directly under the document root of your Web server.
### Install from an Archive File
This is not currently available. We will provide it when Yii 2 is formally released.
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace app\commands;
use yii\console\Controller;
/**
* This command echos what the first argument that you have entered.
*
* This command is provided as an example for you to learn how to create console commands.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class HelloController extends Controller
{
/**
* This command echos what you have entered as the message.
* @param string $message the message to be echoed.
*/
public function actionIndex($message = 'hello world')
{
echo $message;
}
}
\ No newline at end of file
{
"name": "yiisoft/yii2-bootstrap",
"description": "Yii 2 Bootstrap Application",
"keywords": ["yii", "framework", "bootstrap"],
"homepage": "http://www.yiiframework.com/",
"type": "project",
"license": "BSD-3-Clause",
"support": {
"issues": "https://github.com/yiisoft/yii2/issues?state=open",
"forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"config": {
"vendor-dir": "vendor"
},
"minimum-stability": "dev",
"require": {
"php": ">=5.3.0",
"yiisoft/yii2": "dev-master"
}
}
......@@ -5,8 +5,6 @@ return array(
'basePath' => '@wwwroot',
'baseUrl' => '@www',
'css' => array(
'css/bootstrap.min.css',
'css/bootstrap-responsive.min.css',
'css/site.css',
),
'js' => array(
......@@ -14,6 +12,7 @@ return array(
),
'depends' => array(
'yii',
'yii/bootstrap-responsive',
),
),
);
<?php
return array(
'id' => 'bootstrap-console',
'basePath' => dirname(__DIR__),
'preload' => array('log'),
'controllerPath' => dirname(__DIR__) . '/commands',
'controllerNamespace' => 'app\commands',
'modules' => array(
),
'components' => array(
'cache' => array(
'class' => 'yii\caching\FileCache',
),
'log' => array(
'class' => 'yii\logging\Router',
'targets' => array(
array(
'class' => 'yii\logging\FileTarget',
'levels' => array('error', 'warning'),
),
),
),
),
'params' => require(__DIR__ . '/params.php'),
);
<?php
return array(
'id' => 'hello',
'id' => 'bootstrap',
'basePath' => dirname(__DIR__),
'preload' => array('log'),
'controllerNamespace' => 'app\controllers',
'modules' => array(
'debug' => array(
'class' => 'yii\debug\Module',
)
// 'debug' => array(
// 'class' => 'yii\debug\Module',
// )
),
'components' => array(
'cache' => array(
......@@ -23,14 +24,15 @@ return array(
'log' => array(
'class' => 'yii\logging\Router',
'targets' => array(
'file' => array(
array(
'class' => 'yii\logging\FileTarget',
'levels' => array('error', 'warning'),
),
// array(
// 'class' => 'yii\logging\DebugTarget',
// )
),
),
),
'params' => array(
'adminEmail' => 'admin@example.com',
),
'params' => require(__DIR__ . '/params.php'),
);
<?php
return array(
'adminEmail' => 'admin@example.com',
);
\ No newline at end of file
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\LoginForm;
use app\models\ContactForm;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -11,7 +11,7 @@
*/
// you may need to adjust this path to the correct Yii framework path
$frameworkPath = dirname(__FILE__) . '/../../../yii';
$frameworkPath = dirname(__FILE__) . '/../../yii';
require_once($frameworkPath . '/requirements/YiiRequirementChecker.php');
$requirementsChecker = new YiiRequirementChecker();
......@@ -93,4 +93,4 @@ $requirements = array(
'memo' => 'PHP mail SMTP server required',
),
);
$requirementsChecker->checkYii()->check($requirements)->render();
\ No newline at end of file
$requirementsChecker->checkYii()->check($requirements)->render();
......@@ -27,7 +27,7 @@ $this->registerAssetBundle('app');
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<?php echo Menu::widget($this, array(
<?php echo Menu::widget(array(
'options' => array('class' => 'nav'),
'items' => array(
array('label' => 'Home', 'url' => array('/site/index')),
......@@ -44,7 +44,7 @@ $this->registerAssetBundle('app');
<!-- /.navbar -->
</div>
<?php echo Breadcrumbs::widget($this, array(
<?php echo Breadcrumbs::widget(array(
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(),
)); ?>
<?php echo $content; ?>
......@@ -60,7 +60,7 @@ $this->registerAssetBundle('app');
</div>
<?php $this->endBody(); ?>
</div>
<?php echo Toolbar::widget($this); ?>
<?php echo Toolbar::widget(); ?>
</body>
</html>
<?php $this->endPage(); ?>
......@@ -23,7 +23,7 @@ $this->params['breadcrumbs'][] = $this->title;
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you.
</p>
<?php $form = ActiveForm::begin($this, array(
<?php $form = ActiveForm::begin(array(
'options' => array('class' => 'form-horizontal'),
'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')),
)); ?>
......@@ -35,7 +35,7 @@ $this->params['breadcrumbs'][] = $this->title;
$field = $form->field($model, 'verifyCode');
echo $field->begin()
. $field->label()
. Captcha::widget($this)
. Captcha::widget()
. Html::activeTextInput($model, 'verifyCode', array('class' => 'input-medium'))
. $field->error()
. $field->end();
......
......@@ -14,7 +14,7 @@ $this->params['breadcrumbs'][] = $this->title;
<p>Please fill out the following fields to login:</p>
<?php $form = ActiveForm::begin($this, array('options' => array('class' => 'form-horizontal'))); ?>
<?php $form = ActiveForm::begin(array('options' => array('class' => 'form-horizontal'))); ?>
<?php echo $form->field($model, 'username')->textInput(); ?>
<?php echo $form->field($model, 'password')->passwordInput(); ?>
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?>
......
......@@ -3,12 +3,10 @@
// comment out the following line to disable debug mode
defined('YII_DEBUG') or define('YII_DEBUG', true);
$frameworkPath = __DIR__ . '/../../yii';
require(__DIR__ . '/../vendor/yiisoft/yii2/yii.php');
require(__DIR__ . '/../vendor/autoload.php');
require($frameworkPath . '/Yii.php');
// Register Composer autoloader
@include($frameworkPath . '/vendor/autoload.php');
$config = require(__DIR__ . '/../config/main.php');
$config = require(__DIR__ . '/protected/config/main.php');
$application = new yii\web\Application($config);
$application->run();
#!/usr/bin/env php
<?php
/**
* Yii command line script for Unix/Linux.
*
* This is the bootstrap script for running yiic on Unix/Linux.
* Yii console bootstrap file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
require_once(__DIR__ . '/yiic.php');
defined('YII_DEBUG') or define('YII_DEBUG', true);
// fcgi doesn't have STDIN defined by default
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
$frameworkPath = __DIR__ . '/../../yii';
require($frameworkPath . '/Yii.php');
$config = require(__DIR__ . '/config/console.php');
$application = new yii\console\Application($config);
$application->run();
@echo off
rem -------------------------------------------------------------
rem Yii command line script for Windows.
rem
rem This is the bootstrap script for running yiic on Windows.
rem Yii command line bootstrap script for Windows.
rem
rem @author Qiang Xue <qiang.xue@gmail.com>
rem @link http://www.yiiframework.com/
......@@ -17,6 +15,6 @@ set YII_PATH=%~dp0
if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
"%PHP_COMMAND%" "%YII_PATH%yiic" %*
"%PHP_COMMAND%" "%YII_PATH%yii" %*
@endlocal
\ No newline at end of file
@endlocal
......@@ -13,7 +13,7 @@ defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
require(__DIR__ . '/../yii/Yii.php');
$id = 'yiic-build';
$id = 'yii-build';
$basePath = __DIR__;
$application = new yii\console\Application(array('id' => $id, 'basePath' => $basePath));
......
......@@ -94,7 +94,7 @@
</fileset>
<fileset dir="." id="executables">
<include name="${build.src.dir}/**/yiic" />
<include name="${build.src.dir}/**/yii" />
</fileset>
<target name="src" depends="sync">
......
......@@ -93,7 +93,7 @@ class LocaleController extends Controller
/**
* Plural rules.
*
* This file is automatically generated by the "yiic locale/plural" command under the "build" folder.
* This file is automatically generated by the "yii locale/plural" command under the "build" folder.
* Do not modify it directly.
*
* The original plural rule data used for generating this file has the following copyright terms:
......
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "7d46ce9c4d8d5f4ecae1611ea8f0b49c",
"packages": [
{
"name": "ezyang/htmlpurifier",
"version": "v4.5.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "v4.5.0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/v4.5.0",
"reference": "v4.5.0",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"type": "library",
"autoload": {
"psr-0": {
"HTMLPurifier": "library/"
},
"files": [
"library/HTMLPurifier.composer.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"time": "2013-02-18 00:04:08"
},
{
"name": "michelf/php-markdown",
"version": "1.3",
"source": {
"type": "git",
"url": "https://github.com/michelf/php-markdown.git",
"reference": "1.3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/michelf/php-markdown/zipball/1.3",
"reference": "1.3",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-lib": "1.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Michelf": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Michel Fortin",
"email": "michel.fortin@michelf.ca",
"homepage": "http://michelf.ca/",
"role": "Developer"
},
{
"name": "John Gruber",
"homepage": "http://daringfireball.net/"
}
],
"description": "PHP Markdown",
"homepage": "http://michelf.ca/projects/php-markdown/",
"keywords": [
"markdown"
],
"time": "2013-04-11 18:53:11"
},
{
"name": "smarty/smarty",
"version": "v3.1.13",
"source": {
"type": "svn",
"url": "http://smarty-php.googlecode.com/svn",
"reference": "/tags/v3.1.13/@4699"
},
"require": {
"php": ">=5.2"
},
"type": "library",
"autoload": {
"classmap": [
"distribution/libs/Smarty.class.php",
"distribution/libs/SmartyBC.class.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
],
"authors": [
{
"name": "Monte Ohrt",
"email": "monte@ohrt.com"
},
{
"name": "Uwe Tews",
"email": "uwe.tews@googlemail.com"
},
{
"name": "Rodney Rehm",
"email": "rodney.rehm@medialize.de"
}
],
"description": "Smarty - the compiling PHP template engine",
"homepage": "http://www.smarty.net",
"keywords": [
"templating"
],
"time": "2013-01-26 12:03:52"
},
{
"name": "twig/twig",
"version": "v1.12.3",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "v1.12.3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.12.3",
"reference": "v1.12.3",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.12-dev"
}
},
"autoload": {
"psr-0": {
"Twig_": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org",
"keywords": [
"templating"
],
"time": "2013-04-08 12:40:11"
}
],
"packages-dev": [
],
"aliases": [
],
"minimum-stability": "stable",
"stability-flags": [
],
"platform": {
"php": ">=5.3.0"
},
"platform-dev": [
]
}
......@@ -446,3 +446,7 @@ $customers = Customer::find()->olderThan(50)->all();
The parameters should follow after the `$query` parameter when defining the scope method, and they
can take default values like shown above.
### Atomic operations and scenarios
TBD
......@@ -28,10 +28,9 @@ app/
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
yii yii command line script for Unix/Linux
yii.bat yii command line script for Windows
commands/ containing customized yii console commands
components/ containing reusable user components
config/ containing configuration files
console.php the console application configuration
......@@ -60,4 +59,4 @@ app/
~~~
TBD
\ No newline at end of file
TBD
......@@ -19,7 +19,7 @@ The following steps show how we can use database migration during development:
4. Doug applies the migration to his local development database
Yii supports database migration via the `yiic migrate` command line tool. This
Yii supports database migration via the `yii migrate` command line tool. This
tool supports creating new migrations, applying/reverting/redoing migrations, and
showing migration history and new migrations.
......@@ -29,7 +29,7 @@ Creating Migrations
To create a new migration (e.g. create a news table), we run the following command:
~~~
yiic migrate/create <name>
yii migrate/create <name>
~~~
The required `name` parameter specifies a very brief description of the migration
......@@ -38,7 +38,7 @@ 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
yii migrate/create create_news_table
~~~
The above command will create under the `protected/migrations` directory a new
......@@ -153,7 +153,7 @@ To apply all available new migrations (i.e., make the local database up-to-date)
run the following command:
~~~
yiic migrate
yii migrate
~~~
The command will show the list of all new migrations. If you confirm to apply
......@@ -170,7 +170,7 @@ Sometimes, we may only want to apply one or a few new migrations. We can use the
following command:
~~~
yiic migrate/up 3
yii migrate/up 3
~~~
This command will apply the 3 new migrations. Changing the value 3 will allow
......@@ -179,7 +179,7 @@ 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
yii migrate/to 101129_185401
~~~
That is, we use the timestamp part of a migration name to specify the version
......@@ -196,7 +196,7 @@ To revert the last one or several applied migrations, we can use the following
command:
~~~
yiic migrate/down [step]
yii migrate/down [step]
~~~
where the optional `step` parameter specifies how many migrations to be reverted
......@@ -213,7 +213,7 @@ Redoing migrations means first reverting and then applying the specified migrati
This can be done with the following command:
~~~
yiic migrate/redo [step]
yii migrate/redo [step]
~~~
where the optional `step` parameter specifies how many migrations to be redone.
......@@ -227,8 +227,8 @@ 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]
yii migrate/history [limit]
yii migrate/new [limit]
~~~
where the optional parameter `limit` specifies the number of migrations to be
......@@ -247,10 +247,10 @@ often happens when developing a new migration. We can use the following command
to achieve this goal.
~~~
yiic migrate/mark 101129_185401
yii migrate/mark 101129_185401
~~~
This command is very similar to `yiic migrate/to` command, except that it only
This command is very similar to `yii migrate/to` command, except that it only
modifies the migration history table to the specified version without applying
or reverting the migrations.
......@@ -291,7 +291,7 @@ line:
To specify these options, execute the migrate command using the following format
~~~
yiic migrate/up --option1=value1 --option2=value2 ...
yii migrate/up --option1=value1 --option2=value2 ...
~~~
For example, if we want to migrate for a `forum` module whose migration files
......@@ -299,7 +299,7 @@ are located within the module's `migrations` directory, we can use the following
command:
~~~
yiic migrate/up --migrationPath=ext.forum.migrations
yii migrate/up --migrationPath=ext.forum.migrations
~~~
......
......@@ -152,7 +152,7 @@ with significant improvements. For more details, please see the "assets" subsect
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
extension for your Smarty views, or `twig` for Twig views. You may also configure the
`View::renderers` property to use other template engines.
......@@ -218,7 +218,7 @@ methods of the `Widget` class. For example,
```php
// $this refers to the View object
// Note that you have to "echo" the result to display it
echo \yii\widgets\Menu::widget($this, array('items' => $items));
echo \yii\widgets\Menu::widget(array('items' => $items));
// $this refers to the View object
$form = \yii\widgets\ActiveForm::begin($this);
......@@ -252,7 +252,7 @@ Console applications are now composed by controllers, too, like Web applications
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>`
actions. You use the `yii <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()`.
......@@ -269,10 +269,6 @@ Message translation is still supported, but managed via the "i18n" application c
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
--------------
......
ActiveRecord
============
Scenarios
---------
Possible scenario formats supported by ActiveRecord:
```php
public function scenarios()
{
return array(
// attributes array, all operations won't be wrapped with transaction
'scenario1' => array('attribute1', 'attribute2'),
// insert and update operations will be wrapped with transaction, delete won't be wrapped
'scenario2' => array(
'attributes' => array('attribute1', 'attribute2'),
'atomic' => array(self::OP_INSERT, self::OP_UPDATE),
),
);
}
```
Query
-----
### Basic Queries
### Relational Queries
### Scopes
......@@ -45,6 +45,9 @@ class YiiBaseTest extends TestCase
Yii::setAlias('@yii', null);
$this->assertFalse(Yii::getAlias('@yii', false));
$this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file'));
Yii::setAlias('@some/alias', '/www');
$this->assertEquals('/www', Yii::getAlias('@some/alias'));
}
public function testGetVersion()
......
<?php
namespace yiiunit\framework\base;
use yii\base\Dictionary;
class MapItem
{
public $data='data';
}
class DictionaryTest extends \yiiunit\TestCase
{
/**
* @var \yii\base\Dictionary
*/
protected $dictionary;
protected $item1;
protected $item2;
protected $item3;
protected function setUp()
{
parent::setUp();
$this->dictionary = new Dictionary;
$this->item1 = new MapItem;
$this->item2 = new MapItem;
$this->item3 = new MapItem;
$this->dictionary->add('key1', $this->item1);
$this->dictionary->add('key2', $this->item2);
}
protected function tearDown()
{
parent::tearDown();
$this->dictionary = null;
$this->item1 = null;
$this->item2 = null;
$this->item3 = null;
}
public function testConstruct()
{
$a = array(1, 2, 'key3' => 3);
$dictionary = new Dictionary($a);
$this->assertEquals(3, $dictionary->getCount());
$dictionary2=new Dictionary($this->dictionary);
$this->assertEquals(2, $dictionary2->getCount());
}
public function testGetCount()
{
$this->assertEquals(2, $this->dictionary->getCount());
}
public function testGetKeys()
{
$keys = $this->dictionary->getKeys();
$this->assertEquals(2, count($keys));
$this->assertEquals('key1', $keys[0]);
$this->assertEquals('key2', $keys[1]);
}
public function testAdd()
{
$this->dictionary->add('key3', $this->item3);
$this->assertEquals(3, $this->dictionary->getCount());
$this->assertTrue($this->dictionary->has('key3'));
$this->dictionary[] = 'test';
}
public function testRemove()
{
$this->dictionary->remove('key1');
$this->assertEquals(1, $this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->has('key1'));
$this->assertTrue($this->dictionary->remove('unknown key') === null);
}
public function testRemoveAll()
{
$this->dictionary->add('key3', $this->item3);
$this->dictionary->removeAll();
$this->assertEquals(0, $this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2'));
$this->dictionary->add('key3', $this->item3);
$this->dictionary->removeAll(true);
$this->assertEquals(0, $this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2'));
}
public function testHas()
{
$this->assertTrue($this->dictionary->has('key1'));
$this->assertTrue($this->dictionary->has('key2'));
$this->assertFalse($this->dictionary->has('key3'));
}
public function testFromArray()
{
$array = array('key3' => $this->item3, 'key4' => $this->item1);
$this->dictionary->copyFrom($array);
$this->assertEquals(2, $this->dictionary->getCount());
$this->assertEquals($this->item3, $this->dictionary['key3']);
$this->assertEquals($this->item1, $this->dictionary['key4']);
$this->setExpectedException('yii\base\InvalidParamException');
$this->dictionary->copyFrom($this);
}
public function testMergeWith()
{
$a = array('a' => 'v1', 'v2', array('2'), 'c' => array('3', 'c' => 'a'));
$b = array('v22', 'a' => 'v11', array('2'), 'c' => array('c' => '3', 'a'));
$c = array('a' => 'v11', 'v2', array('2'), 'c' => array('3', 'c' => '3', 'a'), 'v22', array('2'));
$dictionary = new Dictionary($a);
$dictionary2 = new Dictionary($b);
$dictionary->mergeWith($dictionary2);
$this->assertTrue($dictionary->toArray() === $c);
$array = array('key2' => $this->item1, 'key3' => $this->item3);
$this->dictionary->mergeWith($array, false);
$this->assertEquals(3, $this->dictionary->getCount());
$this->assertEquals($this->item1, $this->dictionary['key2']);
$this->assertEquals($this->item3, $this->dictionary['key3']);
$this->setExpectedException('yii\base\InvalidParamException');
$this->dictionary->mergeWith($this, false);
}
public function testRecursiveMergeWithTraversable(){
$dictionary = new Dictionary();
$obj = new \ArrayObject(array(
'k1' => $this->item1,
'k2' => $this->item2,
'k3' => new \ArrayObject(array(
'k4' => $this->item3,
))
));
$dictionary->mergeWith($obj, true);
$this->assertEquals(3, $dictionary->getCount());
$this->assertEquals($this->item1, $dictionary['k1']);
$this->assertEquals($this->item2, $dictionary['k2']);
$this->assertEquals($this->item3, $dictionary['k3']['k4']);
}
public function testArrayRead()
{
$this->assertEquals($this->item1, $this->dictionary['key1']);
$this->assertEquals($this->item2, $this->dictionary['key2']);
$this->assertEquals(null, $this->dictionary['key3']);
}
public function testArrayWrite()
{
$this->dictionary['key3'] = $this->item3;
$this->assertEquals(3, $this->dictionary->getCount());
$this->assertEquals($this->item3, $this->dictionary['key3']);
$this->dictionary['key1'] = $this->item3;
$this->assertEquals(3, $this->dictionary->getCount());
$this->assertEquals($this->item3, $this->dictionary['key1']);
unset($this->dictionary['key2']);
$this->assertEquals(2, $this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->has('key2'));
unset($this->dictionary['unknown key']);
}
public function testArrayForeach()
{
$n = 0;
$found = 0;
foreach ($this->dictionary as $index => $item) {
$n++;
if ($index === 'key1' && $item === $this->item1) {
$found++;
}
if ($index === 'key2' && $item === $this->item2) {
$found++;
}
}
$this->assertTrue($n == 2 && $found == 2);
}
public function testArrayMisc()
{
$this->assertEquals($this->dictionary->Count, count($this->dictionary));
$this->assertTrue(isset($this->dictionary['key1']));
$this->assertFalse(isset($this->dictionary['unknown key']));
}
public function testToArray()
{
$dictionary = new Dictionary(array('key' => 'value'));
$this->assertEquals(array('key' => 'value'), $dictionary->toArray());
}
public function testIteratorCurrent()
{
$dictionary = new Dictionary(array('key1' => 'value1', 'key2' => 'value2'));
$val = $dictionary->getIterator()->current();
$this->assertEquals('value1', $val);
}
}
......@@ -12,7 +12,7 @@ use yiiunit\data\base\InvalidRulesModel;
*/
class ModelTest extends TestCase
{
public function testGetAttributeLalel()
public function testGetAttributeLabel()
{
$speaker = new Speaker();
$this->assertEquals('First Name', $speaker->getAttributeLabel('firstName'));
......
<?php
namespace yiiunit\framework\base;
use yii\base\Vector;
class ListItem
{
public $data='data';
}
class VectorTest extends \yiiunit\TestCase
{
/**
* @var Vector
*/
protected $vector;
protected $item1;
protected $item2;
protected $item3;
protected function setUp()
{
parent::setUp();
$this->vector = new Vector;
$this->item1 = new ListItem;
$this->item2 = new ListItem;
$this->item3 = new ListItem;
$this->vector->add($this->item1);
$this->vector->add($this->item2);
}
protected function tearDown()
{
parent::tearDown();
$this->vector = null;
$this->item1 = null;
$this->item2 = null;
$this->item3 = null;
}
public function testConstruct()
{
$a = array(1, 2, 3);
$vector = new Vector($a);
$this->assertEquals(3, $vector->getCount());
$vector2 = new Vector($this->vector);
$this->assertEquals(2, $vector2->getCount());
}
public function testItemAt()
{
$a = array(1, 2, null, 4);
$vector = new Vector($a);
$this->assertEquals(1, $vector->itemAt(0));
$this->assertEquals(2, $vector->itemAt(1));
$this->assertNull($vector->itemAt(2));
$this->assertEquals(4, $vector->itemAt(3));
}
public function testGetCount()
{
$this->assertEquals(2, $this->vector->getCount());
$this->assertEquals(2, $this->vector->Count);
}
public function testAdd()
{
$this->vector->add(null);
$this->vector->add($this->item3);
$this->assertEquals(4, $this->vector->getCount());
$this->assertEquals(3, $this->vector->indexOf($this->item3));
}
public function testInsertAt()
{
$this->vector->insertAt(0, $this->item3);
$this->assertEquals(3, $this->vector->getCount());
$this->assertEquals(2, $this->vector->indexOf($this->item2));
$this->assertEquals(0, $this->vector->indexOf($this->item3));
$this->assertEquals(1, $this->vector->indexOf($this->item1));
$this->setExpectedException('yii\base\InvalidParamException');
$this->vector->insertAt(4, $this->item3);
}
public function testRemove()
{
$this->vector->remove($this->item1);
$this->assertEquals(1, $this->vector->getCount());
$this->assertEquals(-1, $this->vector->indexOf($this->item1));
$this->assertEquals(0, $this->vector->indexOf($this->item2));
$this->assertEquals(false, $this->vector->remove($this->item1));
}
public function testRemoveAt()
{
$this->vector->add($this->item3);
$this->vector->removeAt(1);
$this->assertEquals(-1, $this->vector->indexOf($this->item2));
$this->assertEquals(1, $this->vector->indexOf($this->item3));
$this->assertEquals(0, $this->vector->indexOf($this->item1));
$this->setExpectedException('yii\base\InvalidParamException');
$this->vector->removeAt(2);
}
public function testRemoveAll()
{
$this->vector->add($this->item3);
$this->vector->removeAll();
$this->assertEquals(0, $this->vector->getCount());
$this->assertEquals(-1, $this->vector->indexOf($this->item1));
$this->assertEquals(-1, $this->vector->indexOf($this->item2));
$this->vector->add($this->item3);
$this->vector->removeAll(true);
$this->assertEquals(0, $this->vector->getCount());
$this->assertEquals(-1, $this->vector->indexOf($this->item1));
$this->assertEquals(-1, $this->vector->indexOf($this->item2));
}
public function testHas()
{
$this->assertTrue($this->vector->has($this->item1));
$this->assertTrue($this->vector->has($this->item2));
$this->assertFalse($this->vector->has($this->item3));
}
public function testIndexOf()
{
$this->assertEquals(0, $this->vector->indexOf($this->item1));
$this->assertEquals(1, $this->vector->indexOf($this->item2));
$this->assertEquals(-1, $this->vector->indexOf($this->item3));
}
public function testFromArray()
{
$array = array($this->item3, $this->item1);
$this->vector->copyFrom($array);
$this->assertTrue(count($array) == 2 && $this->vector[0] === $this->item3 && $this->vector[1] === $this->item1);
$this->setExpectedException('yii\base\InvalidParamException');
$this->vector->copyFrom($this);
}
public function testMergeWith()
{
$array = array($this->item3, $this->item1);
$this->vector->mergeWith($array);
$this->assertTrue($this->vector->getCount() == 4 && $this->vector[0] === $this->item1 &&
$this->vector[3] === $this->item1);
$a = array(1);
$vector = new Vector($a);
$this->vector->mergeWith($vector);
$this->assertTrue($this->vector->getCount() == 5 && $this->vector[0] === $this->item1 &&
$this->vector[3] === $this->item1 && $this->vector[4] === 1);
$this->setExpectedException('yii\base\InvalidParamException');
$this->vector->mergeWith($this);
}
public function testToArray()
{
$array = $this->vector->toArray();
$this->assertTrue(count($array) == 2 && $array[0] === $this->item1 && $array[1] === $this->item2);
}
public function testArrayRead()
{
$this->assertTrue($this->vector[0] === $this->item1);
$this->assertTrue($this->vector[1] === $this->item2);
$this->setExpectedException('yii\base\InvalidParamException');
$a = $this->vector[2];
}
public function testGetIterator()
{
$n = 0;
$found = 0;
foreach ($this->vector as $index => $item) {
foreach ($this->vector as $a => $b) {
// test of iterator
}
$n++;
if ($index === 0 && $item === $this->item1) {
$found++;
}
if ($index === 1 && $item === $this->item2) {
$found++;
}
}
$this->assertTrue($n == 2 && $found == 2);
}
public function testArrayMisc()
{
$this->assertEquals($this->vector->Count, count($this->vector));
$this->assertTrue(isset($this->vector[1]));
$this->assertFalse(isset($this->vector[2]));
}
public function testOffsetSetAdd()
{
$vector = new Vector(array(1, 2, 3));
$vector->offsetSet(null, 4);
$this->assertEquals(array(1, 2, 3, 4), $vector->toArray());
}
public function testOffsetSetReplace()
{
$vector = new Vector(array(1, 2, 3));
$vector->offsetSet(1, 4);
$this->assertEquals(array(1, 4, 3), $vector->toArray());
}
public function testOffsetUnset()
{
$vector = new Vector(array(1, 2, 3));
$vector->offsetUnset(1);
$this->assertEquals(array(1, 3), $vector->toArray());
}
public function testIteratorCurrent()
{
$vector = new Vector(array('value1', 'value2'));
$val = $vector->getIterator()->current();
$this->assertEquals('value1', $val);
}
}
<?php
use yiiunit\TestCase;
use yii\console\controllers\AssetController;
/**
* Unit test for [[\yii\console\controllers\AssetController]].
* @see AssetController
*/
class AssetControllerTest extends TestCase
{
/**
* @var string path for the test files.
*/
protected $testFilePath = '';
/**
* @var string test assets path.
*/
protected $testAssetsBasePath = '';
public function setUp()
{
$this->testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . get_class($this);
$this->createDir($this->testFilePath);
$this->testAssetsBasePath = $this->testFilePath . DIRECTORY_SEPARATOR . 'assets';
$this->createDir($this->testAssetsBasePath);
}
public function tearDown()
{
$this->removeDir($this->testFilePath);
}
/**
* Creates directory.
* @param $dirName directory full name.
*/
protected function createDir($dirName)
{
if (!file_exists($dirName)) {
mkdir($dirName, 0777, true);
}
}
/**
* Removes directory.
* @param $dirName directory full name
*/
protected function removeDir($dirName)
{
if (!empty($dirName) && file_exists($dirName)) {
exec("rm -rf {$dirName}");
}
}
/**
* Creates test asset controller instance.
* @return AssetController
*/
protected function createAssetController()
{
$module = $this->getMock('yii\\base\\Module', array('fake'), array('console'));
$assetController = new AssetController('asset', $module);
$assetController->interactive = false;
$assetController->jsCompressor = 'cp {from} {to}';
$assetController->cssCompressor = 'cp {from} {to}';
return $assetController;
}
/**
* Emulates running of the asset controller action.
* @param string $actionId id of action to be run.
* @param array $args action arguments.
* @return string command output.
*/
protected function runAssetControllerAction($actionId, array $args=array())
{
$controller = $this->createAssetController();
ob_start();
ob_implicit_flush(false);
$params = array(
\yii\console\Request::ANONYMOUS_PARAMS => $args
);
$controller->run($actionId, $params);
return ob_get_clean();
}
/**
* Creates test compress config.
* @param array[] $bundles asset bundles config.
* @return array config array.
*/
protected function createCompressConfig(array $bundles)
{
$baseUrl = '/test';
$config = array(
'bundles' => $this->createBundleConfig($bundles),
'targets' => array(
'all' => array(
'basePath' => $this->testAssetsBasePath,
'baseUrl' => $baseUrl,
'js' => 'all.js',
'css' => 'all.css',
),
),
'assetManager' => array(
'basePath' => $this->testAssetsBasePath,
'baseUrl' => $baseUrl,
),
);
return $config;
}
/**
* Creates test bundle configuration.
* @param array[] $bundles asset bundles config.
* @return array bundle config.
*/
protected function createBundleConfig(array $bundles)
{
foreach ($bundles as $name => $config) {
if (!array_key_exists('basePath', $config)) {
$bundles[$name]['basePath'] = $this->testFilePath;
}
if (!array_key_exists('baseUrl', $config)) {
$bundles[$name]['baseUrl'] = '';
}
}
return $bundles;
}
/**
* Creates test compress config file.
* @param string $fileName output file name.
* @param array[] $bundles asset bundles config.
* @throws Exception on failure.
*/
protected function createCompressConfigFile($fileName, array $bundles)
{
$content = '<?php return '.var_export($this->createCompressConfig($bundles), true).';';
if (file_put_contents($fileName, $content) <= 0) {
throw new \Exception("Unable to create file '{$fileName}'!");
}
}
/**
* Creates test asset file.
* @param string $fileRelativeName file name relative to [[testFilePath]]
* @param string $content file content
* @throws Exception on failure.
*/
protected function createAssetSourceFile($fileRelativeName, $content)
{
$fileFullName = $this->testFilePath.DIRECTORY_SEPARATOR.$fileRelativeName;
$this->createDir(dirname($fileFullName));
if (file_put_contents($fileFullName, $content)<=0) {
throw new \Exception("Unable to create file '{$fileFullName}'!");
}
}
/**
* Creates a list of asset source files.
* @param array $files assert source files in format: file/relative/name => fileContent
*/
protected function createAssertSourceFiles(array $files)
{
foreach ($files as $name => $content) {
$this->createAssetSourceFile($name, $content);
}
}
// Tests :
public function testActionTemplate()
{
$configFileName = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php';
$this->runAssetControllerAction('template', array($configFileName));
$this->assertTrue(file_exists($configFileName), 'Unable to create config file template!');
}
public function testActionCompress()
{
// Given :
$cssFiles = array(
'css/test_body.css' => 'body {
padding-top: 20px;
padding-bottom: 60px;
}',
'css/test_footer.css' => '.footer {
margin: 20px;
display: block;
}',
);
$this->createAssertSourceFiles($cssFiles);
$jsFiles = array(
'js/test_alert.js' => "function test() {
alert('Test message');
}",
'js/test_sum_ab.js' => "function sumAB(a, b) {
return a + b;
}",
);
$this->createAssertSourceFiles($jsFiles);
$bundles = array(
'app' => array(
'css' => array_keys($cssFiles),
'js' => array_keys($jsFiles),
),
);;
$bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php';
$configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php';
$this->createCompressConfigFile($configFile, $bundles);
// When :
$this->runAssetControllerAction('compress', array($configFile, $bundleFile));
// Then :
$this->assertTrue(file_exists($bundleFile), 'Unable to create output bundle file!');
$compressedCssFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.css';
$this->assertTrue(file_exists($compressedCssFileName), 'Unable to compress CSS files!');
$compressedJsFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.js';
$this->assertTrue(file_exists($compressedJsFileName), 'Unable to compress JS files!');
$compressedCssFileContent = file_get_contents($compressedCssFileName);
foreach ($cssFiles as $name => $content) {
$this->assertContains($content, $compressedCssFileContent, "Source of '{$name}' is missing in combined file!");
}
$compressedJsFileContent = file_get_contents($compressedJsFileName);
foreach ($jsFiles as $name => $content) {
$this->assertContains($content, $compressedJsFileContent, "Source of '{$name}' is missing in combined file!");
}
}
}
......@@ -3,6 +3,8 @@
namespace yiiunit\framework\helpers;
use yii\helpers\ArrayHelper;
use yii\helpers\VarDumper;
use yii\web\Sort;
class ArrayHelperTest extends \yii\test\TestCase
{
......@@ -54,16 +56,51 @@ class ArrayHelperTest extends \yii\test\TestCase
array('name' => 'A', 'age' => 1),
);
ArrayHelper::multisort($array, array('name', 'age'), SORT_ASC, array(SORT_STRING, SORT_REGULAR));
ArrayHelper::multisort($array, array('name', 'age'), false, array(SORT_STRING, SORT_REGULAR));
$this->assertEquals(array('name' => 'A', 'age' => 1), $array[0]);
$this->assertEquals(array('name' => 'B', 'age' => 4), $array[1]);
$this->assertEquals(array('name' => 'a', 'age' => 3), $array[2]);
$this->assertEquals(array('name' => 'b', 'age' => 2), $array[3]);
ArrayHelper::multisort($array, array('name', 'age'), SORT_ASC, array(SORT_STRING, SORT_REGULAR), false);
ArrayHelper::multisort($array, array('name', 'age'), false, array(SORT_STRING, SORT_REGULAR), false);
$this->assertEquals(array('name' => 'A', 'age' => 1), $array[0]);
$this->assertEquals(array('name' => 'a', 'age' => 3), $array[1]);
$this->assertEquals(array('name' => 'b', 'age' => 2), $array[2]);
$this->assertEquals(array('name' => 'B', 'age' => 4), $array[3]);
}
public function testMultisortUseSort()
{
// single key
$sort = new Sort();
$sort->attributes = array('name', 'age');
$sort->defaults = array('name' => Sort::ASC);
$orders = $sort->getOrders();
$array = array(
array('name' => 'b', 'age' => 3),
array('name' => 'a', 'age' => 1),
array('name' => 'c', 'age' => 2),
);
ArrayHelper::multisort($array, array_keys($orders), array_values($orders));
$this->assertEquals(array('name' => 'a', 'age' => 1), $array[0]);
$this->assertEquals(array('name' => 'b', 'age' => 3), $array[1]);
$this->assertEquals(array('name' => 'c', 'age' => 2), $array[2]);
// multiple keys
$sort = new Sort();
$sort->attributes = array('name', 'age');
$sort->defaults = array('name' => Sort::ASC, 'age' => Sort::DESC);
$orders = $sort->getOrders();
$array = array(
array('name' => 'b', 'age' => 3),
array('name' => 'a', 'age' => 2),
array('name' => 'a', 'age' => 1),
);
ArrayHelper::multisort($array, array_keys($orders), array_values($orders));
$this->assertEquals(array('name' => 'a', 'age' => 2), $array[0]);
$this->assertEquals(array('name' => 'a', 'age' => 1), $array[1]);
$this->assertEquals(array('name' => 'b', 'age' => 3), $array[2]);
}
}
......@@ -167,7 +167,7 @@ abstract class ManagerTestBase extends TestCase
$this->assertTrue($this->auth->executeBizRule(null, array(), null));
$this->assertTrue($this->auth->executeBizRule('return 1 == true;', array(), null));
$this->assertTrue($this->auth->executeBizRule('return $params[0] == $params[1];', array(1, '1'), null));
$this->assertFalse($this->auth->executeBizRule('invalid', array(), null));
$this->assertFalse($this->auth->executeBizRule('invalid;', array(), null));
}
public function testCheckAccess()
......
<?php
namespace yii\web;
use yiiunit\framework\web\ResponseTest;
/**
* Mock PHP header function to check for sent headers
* @param string $string
* @param bool $replace
* @param int $httpResponseCode
*/
function header($string, $replace = true, $httpResponseCode = null) {
ResponseTest::$headers[] = $string;
// TODO implement replace
if ($httpResponseCode !== null) {
ResponseTest::$httpResponseCode = $httpResponseCode;
}
}
namespace yiiunit\framework\web;
use yii\helpers\StringHelper;
use yii\web\Response;
class ResponseTest extends \yiiunit\TestCase
{
public static $headers = array();
public static $httpResponseCode = 200;
protected function setUp()
{
parent::setUp();
$this->reset();
}
protected function reset()
{
static::$headers = array();
static::$httpResponseCode = 200;
}
public function ranges()
{
// TODO test more cases for range requests and check for rfc compatibility
// http://www.w3.org/Protocols/rfc2616/rfc2616.txt
return array(
array('0-5', '0-5', 6, '12ёж'),
array('2-', '2-66', 65, 'ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'),
array('-12', '55-66', 12, '(ёжик)=?'),
);
}
/**
* @dataProvider ranges
*/
public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedFile)
{
$content = $this->generateTestFileContent();
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader;
$sent = $this->runSendFile('testFile.txt', $content, null);
$this->assertEquals($expectedFile, $sent);
$this->assertTrue(in_array('HTTP/1.1 206 Partial Content', static::$headers));
$this->assertTrue(in_array('Accept-Ranges: bytes', static::$headers));
$this->assertArrayHasKey('Content-Range: bytes ' . $expectedHeader . '/' . StringHelper::strlen($content), array_flip(static::$headers));
$this->assertTrue(in_array('Content-Type: text/plain', static::$headers));
$this->assertTrue(in_array('Content-Length: ' . $length, static::$headers));
}
protected function generateTestFileContent()
{
return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?';
}
protected function runSendFile($fileName, $content, $mimeType)
{
ob_start();
ob_implicit_flush(false);
$response = new Response();
$response->sendFile($fileName, $content, $mimeType, false);
$file = ob_get_clean();
return $file;
}
}
\ No newline at end of file
......@@ -14,9 +14,9 @@ class UrlManagerTest extends \yiiunit\TestCase
'cache' => null,
));
$url = $manager->createUrl('post/view');
$this->assertEquals('/?r=post/view', $url);
$this->assertEquals('?r=post/view', $url);
$url = $manager->createUrl('post/view', array('id' => 1, 'title' => 'sample post'));
$this->assertEquals('/?r=post/view&id=1&title=sample+post', $url);
$this->assertEquals('?r=post/view&id=1&title=sample+post', $url);
// default setting with '/test/' as base url
$manager = new UrlManager(array(
......@@ -24,7 +24,7 @@ class UrlManagerTest extends \yiiunit\TestCase
'cache' => null,
));
$url = $manager->createUrl('post/view', array('id' => 1, 'title' => 'sample post'));
$this->assertEquals('/test/?r=post/view&id=1&title=sample+post', $url);
$this->assertEquals('/test?r=post/view&id=1&title=sample+post', $url);
// pretty URL without rules
$manager = new UrlManager(array(
......@@ -85,6 +85,24 @@ class UrlManagerTest extends \yiiunit\TestCase
$this->assertEquals('/post/1/sample+post.html', $url);
$url = $manager->createUrl('post/index', array('page' => 1));
$this->assertEquals('/post/index.html?page=1', $url);
// pretty URL with rules that have host info
$manager = new UrlManager(array(
'enablePrettyUrl' => true,
'cache' => null,
'rules' => array(
array(
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
'host' => 'http://<lang:en|fr>.example.com',
),
),
'baseUrl' => '/test',
));
$url = $manager->createUrl('post/view', array('id' => 1, 'title' => 'sample post', 'lang' => 'en'));
$this->assertEquals('http://en.example.com/test/post/1/sample+post', $url);
$url = $manager->createUrl('post/index', array('page' => 1));
$this->assertEquals('/test/post/index?page=1', $url);
}
public function testCreateAbsoluteUrl()
......@@ -95,7 +113,7 @@ class UrlManagerTest extends \yiiunit\TestCase
'cache' => null,
));
$url = $manager->createAbsoluteUrl('post/view', array('id' => 1, 'title' => 'sample post'));
$this->assertEquals('http://www.example.com/?r=post/view&id=1&title=sample+post', $url);
$this->assertEquals('http://www.example.com?r=post/view&id=1&title=sample+post', $url);
}
public function testParseRequest()
......
......@@ -26,7 +26,7 @@ class UrlRuleTest extends \yiiunit\TestCase
public function testParseRequest()
{
$manager = new UrlManager(array('cache' => null));
$request = new Request;
$request = new Request(array('hostInfo' => 'http://en.example.com'));
$suites = $this->getTestsForParseRequest();
foreach ($suites as $i => $suite) {
list ($name, $config, $tests) = $suite;
......@@ -327,6 +327,19 @@ class UrlRuleTest extends \yiiunit\TestCase
array('post/index', array('page' => 1), 'posts/?page=1'),
),
),
array(
'with host info',
array(
'pattern' => 'post/<page:\d+>/<tag>',
'route' => 'post/index',
'defaults' => array('page' => 1),
'host' => 'http://<lang:en|fr>.example.com',
),
array(
array('post/index', array('page' => 1, 'tag' => 'a'), false),
array('post/index', array('page' => 1, 'tag' => 'a', 'lang' => 'en'), 'http://en.example.com/post/a'),
),
),
);
}
......@@ -610,6 +623,19 @@ class UrlRuleTest extends \yiiunit\TestCase
array('a', false),
),
),
array(
'with host info',
array(
'pattern' => 'post/<page:\d+>',
'route' => 'post/index',
'host' => 'http://<lang:en|fr>.example.com',
),
array(
array('post/1', 'post/index', array('page' => '1', 'lang' => 'en')),
array('post/a', false),
array('post/1/a', false),
),
),
);
}
}
Upgrading Instructions for Yii Framework v2
===========================================
!!!IMPORTANT!!!
The following upgrading instructions are cumulative. That is,
if you want to upgrade from version A to version C and there is
version B between A and C, you need to following the instructions
for both A and B.
General upgrade instructions
----------------------------
- Make a backup.
- Clean up your 'assets' folder.
- Replace 'framework' dir with the new one or point Git to a fresh
release tag and checkout.
- Check if everything is OK, if not — revert to previous stable version and post
issues to [Yii issue tracker](https://github.com/yiisoft/yii2/issues).
Upgrading from v1.1.x
---------------------
- All framework classes are now namespaced, and the name prefix `C` is removed.
- The format of path alias is changed to `@yii/base/Component`.
In 1.x, this would be `system.base.CComponent`. See guide for more details.
- The root alias `@yii` now represents the framework installation directory.
In 1.x, this is named as `system`. We also removed `zii` root alias.
- `Object` serves as the base class that supports properties. And `Component` extends
from `Object` and supports events and behaviors. Behaviors declared in
`Component::behaviors()` are attached on demand.
- `CList` is renamed to `Vector`, and `CMap` is renamed to `Dictionary`.
Other collection classes are dropped in favor of SPL classes.
- `CFormModel` is removed. Please use `yii\base\Model` instead.
- `CDbCriteria` is replaced by `yii\db\Query` which includes methods for
building a query. `CDbCommandBuilder` is replaced by `yii\db\QueryBuilder`
which has cleaner and more complete support of query building capabilities.
The Yii framework is free software. It is released under the terms of
the following BSD License.
Copyright © 2008-2013 by Yii Software LLC (http://www.yiisoft.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Yii Software LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
Yii 2.0 Public Preview
======================
Thank you for choosing Yii - a high-performance component-based PHP framework.
If you are looking for a production-ready PHP framework, please use
[Yii v1.1](https://github.com/yiisoft/yii).
Yii 2.0 is still under heavy development. We may make significant changes
without prior notices. **Yii 2.0 is not ready for production use yet.**
[![Build Status](https://secure.travis-ci.org/yiisoft/yii2.png)](http://travis-ci.org/yiisoft/yii2)
REQUIREMENTS
------------
The minimum requirement by Yii is that your Web server supports PHP 5.3.?.
Upgrading Instructions for Yii Framework v2
===========================================
!!!IMPORTANT!!!
The following upgrading instructions are cumulative. That is,
if you want to upgrade from version A to version C and there is
version B between A and C, you need to following the instructions
for both A and B.
......@@ -287,7 +287,11 @@ class YiiBase
if ($path !== null) {
$path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
if (!isset(self::$aliases[$root])) {
self::$aliases[$root] = $path;
if ($pos === false) {
self::$aliases[$root] = $path;
} else {
self::$aliases[$root] = array($alias => $path);
}
} elseif (is_string(self::$aliases[$root])) {
if ($pos === false) {
self::$aliases[$root] = $path;
......@@ -579,10 +583,9 @@ class YiiBase
/**
* Translates a message to the specified language.
*
* The translation will be conducted according to the message category and the target language.
* To specify the category of the message, prefix the message with the category name and separate it
* with "|". For example, "app|hello world". If the category is not specified, the default category "app"
* will be used. The actual message translation is done by a [[\yii\i18n\MessageSource|message source]].
* This is a shortcut method of [[\yii\i18n\I18N::translate()]].
*
* The translation will be conducted according to the message category and the target language will be used.
*
* In case when a translated message has different plural forms (separated by "|"), this method
* will also attempt to choose an appropriate one according to a given numeric value which is
......@@ -595,20 +598,18 @@ class YiiBase
* For more details on how plural rules are applied, please refer to:
* [[http://www.unicode.org/cldr/charts/supplemental/language_plural_rules.html]]
*
* @param string $category the message category.
* @param string $message the message to be translated.
* @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
* @param string $language the language code (e.g. `en_US`, `en`). If this is null, the current
* [[\yii\base\Application::language|application language]] will be used.
* @return string the translated message.
*/
public static function t($message, $params = array(), $language = null)
public static function t($category, $message, $params = array(), $language = null)
{
if (self::$app !== null) {
return self::$app->getI18N()->translate($message, $params, $language);
return self::$app->getI18N()->translate($category, $message, $params, $language);
} else {
if (strpos($message, '|') !== false && preg_match('/^([\w\-\\/\.\\\\]+)\|(.*)/', $message, $matches)) {
$message = $matches[2];
}
return is_array($params) ? strtr($message, $params) : $message;
}
}
......
<?php
return array(
'jquery' => array(
'yii' => array(
'sourcePath' => __DIR__ . '/assets',
'js' => array(
'jquery.min.js',
'yii.js',
),
'depends' => array('yii/jquery'),
),
'yii' => array(
'yii/jquery' => array(
'sourcePath' => __DIR__ . '/assets',
'js' => array(
'yii.js',
'jquery.min.js',
),
'depends' => array('jquery'),
),
'yii/validation' => array(
'sourcePath' => __DIR__ . '/assets',
......@@ -26,7 +26,7 @@ return array(
'js' => array(
'yii.activeForm.js',
),
'depends' => array('yii', 'yii/validation'),
'depends' => array('yii'),
),
'yii/captcha' => array(
'sourcePath' => __DIR__ . '/assets',
......@@ -43,20 +43,26 @@ return array(
'depends' => array('yii'),
),
'yii/bootstrap' => array(
'sourcePath' => __DIR__ . '/assets/bootstrap',
'js' => array(
'/js/bootstrap.min.js',
),
'sourcePath' => __DIR__ . '/assets',
'css' => array(
'css/bootstrap.css'
'bootstrap/css/bootstrap.css',
),
'depends' => array('yii'),
'js' => array(
'bootstrap/js/bootstrap.js',
),
'depends' => array('yii/jquery'),
),
'yii/bootstrap-responsive' => array(
'sourcePath' => __DIR__ . '/assets/bootstrap',
'sourcePath' => __DIR__ . '/assets',
'css' => array(
'css/bootstrap-responsive.css'
'bootstrap/css/bootstrap-responsive.css',
),
'depends' => array('yii/bootstrap'),
)
),
'yii/punycode' => array(
'sourcePath' => __DIR__ . '/assets',
'js' => array(
'punycode/punycode.min.js',
),
),
);
Copyright Mathias Bynens <http://mathiasbynens.be/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/*! http://mths.be/punycode v1.2.1 by @mathias */
(function(o){function e(o){throw RangeError(L[o])}function n(o,e){for(var n=o.length;n--;)o[n]=e(o[n]);return o}function t(o,e){return n(o.split(S),e).join(".")}function r(o){for(var e,n,t=[],r=0,u=o.length;u>r;)e=o.charCodeAt(r++),55296==(63488&e)&&u>r?(n=o.charCodeAt(r++),56320==(64512&n)?t.push(((1023&e)<<10)+(1023&n)+65536):t.push(e,n)):t.push(e);return t}function u(o){return n(o,function(o){var e="";return o>65535&&(o-=65536,e+=R(55296|1023&o>>>10),o=56320|1023&o),e+=R(o)}).join("")}function i(o){return 10>o-48?o-22:26>o-65?o-65:26>o-97?o-97:x}function f(o,e){return o+22+75*(26>o)-((0!=e)<<5)}function c(o,e,n){var t=0;for(o=n?P(o/m):o>>1,o+=P(o/e);o>M*y>>1;t+=x)o=P(o/M);return P(t+(M+1)*o/(o+j))}function l(o){var n,t,r,f,l,d,s,a,p,h,v=[],g=o.length,w=0,j=I,m=A;for(t=o.lastIndexOf(F),0>t&&(t=0),r=0;t>r;++r)o.charCodeAt(r)>=128&&e("not-basic"),v.push(o.charCodeAt(r));for(f=t>0?t+1:0;g>f;){for(l=w,d=1,s=x;f>=g&&e("invalid-input"),a=i(o.charCodeAt(f++)),(a>=x||a>P((b-w)/d))&&e("overflow"),w+=a*d,p=m>=s?C:s>=m+y?y:s-m,!(p>a);s+=x)h=x-p,d>P(b/h)&&e("overflow"),d*=h;n=v.length+1,m=c(w-l,n,0==l),P(w/n)>b-j&&e("overflow"),j+=P(w/n),w%=n,v.splice(w++,0,j)}return u(v)}function d(o){var n,t,u,i,l,d,s,a,p,h,v,g,w,j,m,E=[];for(o=r(o),g=o.length,n=I,t=0,l=A,d=0;g>d;++d)v=o[d],128>v&&E.push(R(v));for(u=i=E.length,i&&E.push(F);g>u;){for(s=b,d=0;g>d;++d)v=o[d],v>=n&&s>v&&(s=v);for(w=u+1,s-n>P((b-t)/w)&&e("overflow"),t+=(s-n)*w,n=s,d=0;g>d;++d)if(v=o[d],n>v&&++t>b&&e("overflow"),v==n){for(a=t,p=x;h=l>=p?C:p>=l+y?y:p-l,!(h>a);p+=x)m=a-h,j=x-h,E.push(R(f(h+m%j,0))),a=P(m/j);E.push(R(f(a,0))),l=c(t,w,u==i),t=0,++u}++t,++n}return E.join("")}function s(o){return t(o,function(o){return E.test(o)?l(o.slice(4).toLowerCase()):o})}function a(o){return t(o,function(o){return O.test(o)?"xn--"+d(o):o})}var p="object"==typeof exports&&exports,h="object"==typeof module&&module&&module.exports==p&&module,v="object"==typeof global&&global;(v.global===v||v.window===v)&&(o=v);var g,w,b=2147483647,x=36,C=1,y=26,j=38,m=700,A=72,I=128,F="-",E=/^xn--/,O=/[^ -~]/,S=/\x2E|\u3002|\uFF0E|\uFF61/g,L={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},M=x-C,P=Math.floor,R=String.fromCharCode;if(g={version:"1.2.1",ucs2:{decode:r,encode:u},decode:l,encode:d,toASCII:a,toUnicode:s},"function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return g});else if(p&&!p.nodeType)if(h)h.exports=g;else for(w in g)g.hasOwnProperty(w)&&(p[w]=g[w]);else o.punycode=g})(this);
\ No newline at end of file
......@@ -57,7 +57,7 @@
// whether to perform validation when a change is detected on the input
validateOnChange: false,
// whether to perform validation when the user is typing.
validateOnType: false,
validateOnType: false,
// number of milliseconds that the validation should be delayed when a user is typing in the input field.
validationDelay: 200,
// whether to enable AJAX-based validation.
......
......@@ -51,8 +51,8 @@
dataType: 'json',
cache: false,
success: function(data) {
$e.attr('src', data['url']);
$('body').data(settings.hashKey, [data['hash1'], data['hash2']]);
$e.attr('src', data.url);
$('body').data(settings.hashKey, [data.hash1, data.hash2]);
}
});
},
......
......@@ -18,7 +18,7 @@ yii.debug = (function ($) {
//dataType: 'json',
success: function(data) {
var $e = $('#' + id);
$e.html(data);
$e.html(data).show();
}
});
}
......
......@@ -110,9 +110,19 @@ yii.validation = (function ($) {
return;
}
var valid = value.match(options.pattern) && (!options.allowName || value.match(options.fullPattern));
var valid = true;
if (options.enableIDN) {
var regexp = /^(.*)@(.*)$/,
matches = regexp.exec(value);
if (matches === null) {
valid = false;
} else {
value = punycode.toASCII(matches[1]) + '@' + punycode.toASCII(matches[2]);
}
}
if (!valid) {
if (!valid || !(value.match(options.pattern) && (!options.allowName || value.match(options.fullPattern)))) {
messages.push(options.message);
}
},
......@@ -126,7 +136,19 @@ yii.validation = (function ($) {
value = options.defaultScheme + '://' + value;
}
if (!value.match(options.pattern)) {
var valid = true;
if (options.enableIDN) {
var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/,
matches = regexp.exec(value);
if (matches === null) {
valid = false;
} else {
value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3];
}
}
if (!valid || !value.match(options.pattern)) {
messages.push(options.message);
}
},
......
......@@ -183,7 +183,7 @@ class Controller extends Component
}
if (!empty($missing)) {
throw new InvalidRequestException(Yii::t('yii|Missing required parameters: {params}', array(
throw new InvalidRequestException(Yii::t('yii', 'Missing required parameters: {params}', array(
'{params}' => implode(', ', $missing),
)));
}
......@@ -410,6 +410,7 @@ class Controller extends Component
* Returns the view object that can be used to render views or view files.
* The [[render()]], [[renderPartial()]] and [[renderFile()]] methods will use
* this view object to implement the actual view rendering.
* If not set, it will default to the "view" application component.
* @return View the view object that can be used to render views or view files.
*/
public function getView()
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use yii\helpers\ArrayHelper;
/**
* Dictionary implements a collection that stores key-value pairs.
*
* You can access, add or remove an item with a key by using
* [[itemAt()]], [[add()]], and [[remove()]].
*
* To get the number of the items in the dictionary, use [[getCount()]].
*
* Because Dictionary implements a set of SPL interfaces, it can be used
* like a regular PHP array as follows,
*
* ~~~
* $dictionary[$key] = $value; // add a key-value pair
* unset($dictionary[$key]); // remove the value with the specified key
* if (isset($dictionary[$key])) // if the dictionary contains the key
* foreach ($dictionary as $key => $value) // traverse the items in the dictionary
* $n = count($dictionary); // returns the number of items in the dictionary
* ~~~
*
* @property integer $count the number of items in the dictionary
* @property array $keys The keys in the dictionary
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Countable
{
/**
* @var array internal data storage
*/
private $_d = array();
/**
* Constructor.
* Initializes the dictionary with an array or an iterable object.
* @param mixed $data the initial data to be populated into the dictionary.
* This can be an array or an iterable object.
* @param array $config name-value pairs that will be used to initialize the object properties
* @throws Exception if data is not well formed (neither an array nor an iterable object)
*/
public function __construct($data = array(), $config = array())
{
if (!empty($data)) {
$this->copyFrom($data);
}
parent::__construct($config);
}
/**
* Returns an iterator for traversing the items in the dictionary.
* This method is required by the SPL interface `IteratorAggregate`.
* It will be implicitly called when you use `foreach` to traverse the dictionary.
* @return DictionaryIterator an iterator for traversing the items in the dictionary.
*/
public function getIterator()
{
return new DictionaryIterator($this->_d);
}
/**
* Returns the number of items in the dictionary.
* This method is required by the SPL `Countable` interface.
* It will be implicitly called when you use `count($dictionary)`.
* @return integer number of items in the dictionary.
*/
public function count()
{
return $this->getCount();
}
/**
* Returns the number of items in the dictionary.
* @return integer the number of items in the dictionary
*/
public function getCount()
{
return count($this->_d);
}
/**
* Returns the keys stored in the dictionary.
* @return array the key list
*/
public function getKeys()
{
return array_keys($this->_d);
}
/**
* Returns the item with the specified key.
* @param mixed $key the key
* @return mixed the element with the specified key.
* Null if the key cannot be found in the dictionary.
*/
public function itemAt($key)
{
return isset($this->_d[$key]) ? $this->_d[$key] : null;
}
/**
* Adds an item into the dictionary.
* Note, if the specified key already exists, the old value will be overwritten.
* @param mixed $key key
* @param mixed $value value
* @throws Exception if the dictionary is read-only
*/
public function add($key, $value)
{
if ($key === null) {
$this->_d[] = $value;
} else {
$this->_d[$key] = $value;
}
}
/**
* Removes an item from the dictionary by its key.
* @param mixed $key the key of the item to be removed
* @return mixed the removed value, null if no such key exists.
* @throws Exception if the dictionary is read-only
*/
public function remove($key)
{
if (isset($this->_d[$key])) {
$value = $this->_d[$key];
unset($this->_d[$key]);
return $value;
} else { // the value is null
unset($this->_d[$key]);
return null;
}
}
/**
* Removes all items from the dictionary.
* @param boolean $safeClear whether to clear every item by calling [[remove]].
* Defaults to false, meaning all items in the dictionary will be cleared directly
* without calling [[remove]].
*/
public function removeAll($safeClear = false)
{
if ($safeClear) {
foreach (array_keys($this->_d) as $key) {
$this->remove($key);
}
} else {
$this->_d = array();
}
}
/**
* Returns a value indicating whether the dictionary contains the specified key.
* @param mixed $key the key
* @return boolean whether the dictionary contains an item with the specified key
*/
public function has($key)
{
return isset($this->_d[$key]) || array_key_exists($key, $this->_d);
}
/**
* Returns the dictionary as a PHP array.
* @return array the list of items in array
*/
public function toArray()
{
return $this->_d;
}
/**
* Copies iterable data into the dictionary.
* Note, existing data in the dictionary will be cleared first.
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable`
* @throws InvalidParamException if data is neither an array nor an iterator.
*/
public function copyFrom($data)
{
if (is_array($data) || $data instanceof \Traversable) {
if (!empty($this->_d)) {
$this->removeAll();
}
if ($data instanceof self) {
$data = $data->_d;
}
foreach ($data as $key => $value) {
$this->add($key, $value);
}
} else {
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.');
}
}
/**
* Merges iterable data into the dictionary.
*
* Existing elements in the dictionary will be overwritten if their keys are the same as those in the source.
* If the merge is recursive, the following algorithm is performed:
*
* - the dictionary data is saved as $a, and the source data is saved as $b;
* - if $a and $b both have an array indexed at the same string key, the arrays will be merged using this algorithm;
* - any integer-indexed elements in $b will be appended to $a;
* - any string-indexed elements in $b will overwrite elements in $a with the same index;
*
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable
* @param boolean $recursive whether the merging should be recursive.
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`.
*/
public function mergeWith($data, $recursive = true)
{
if (is_array($data) || $data instanceof \Traversable) {
if ($data instanceof self) {
$data = $data->_d;
}
if ($recursive) {
if ($data instanceof \Traversable) {
$d = array();
foreach ($data as $key => $value) {
$d[$key] = $value;
}
$this->_d = ArrayHelper::merge($this->_d, $d);
} else {
$this->_d = ArrayHelper::merge($this->_d, $data);
}
} else {
foreach ($data as $key => $value) {
$this->add($key, $value);
}
}
} else {
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.');
}
}
/**
* Returns whether there is an element at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `isset($dictionary[$offset])`.
* This is equivalent to [[contains]].
* @param mixed $offset the offset to check on
* @return boolean
*/
public function offsetExists($offset)
{
return $this->has($offset);
}
/**
* Returns the element at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `$value = $dictionary[$offset];`.
* This is equivalent to [[itemAt]].
* @param mixed $offset the offset to retrieve element.
* @return mixed the element at the offset, null if no element is found at the offset
*/
public function offsetGet($offset)
{
return $this->itemAt($offset);
}
/**
* Sets the element at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `$dictionary[$offset] = $item;`.
* If the offset is null, the new item will be appended to the dictionary.
* Otherwise, the existing item at the offset will be replaced with the new item.
* This is equivalent to [[add]].
* @param mixed $offset the offset to set element
* @param mixed $item the element value
*/
public function offsetSet($offset, $item)
{
$this->add($offset, $item);
}
/**
* Unsets the element at the specified offset.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `unset($dictionary[$offset])`.
* This is equivalent to [[remove]].
* @param mixed $offset the offset to unset element
*/
public function offsetUnset($offset)
{
$this->remove($offset);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* DictionaryIterator implements the SPL `Iterator` interface for [[Dictionary]].
*
* It allows [[Dictionary]] to return a new iterator for data traversing purpose.
* You normally do not use this class directly.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class DictionaryIterator implements \Iterator
{
/**
* @var array the data to be iterated through
*/
private $_d;
/**
* @var array list of keys in the map
*/
private $_keys;
/**
* @var mixed current key
*/
private $_key;
/**
* Constructor.
* @param array $data the data to be iterated through
*/
public function __construct(&$data)
{
$this->_d = &$data;
$this->_keys = array_keys($data);
$this->_key = reset($this->_keys);
}
/**
* Rewinds the index of the current item.
* This method is required by the SPL interface `Iterator`.
*/
public function rewind()
{
$this->_key = reset($this->_keys);
}
/**
* Returns the key of the current array element.
* This method is required by the SPL interface `Iterator`.
* @return mixed the key of the current array element
*/
public function key()
{
return $this->_key;
}
/**
* Returns the current array element.
* This method is required by the SPL interface `Iterator`.
* @return mixed the current array element
*/
public function current()
{
return $this->_d[$this->_key];
}
/**
* Moves the internal pointer to the next element.
* This method is required by the SPL interface `Iterator`.
*/
public function next()
{
$this->_key = next($this->_keys);
}
/**
* Returns whether there is an element at current position.
* This method is required by the SPL interface `Iterator`.
* @return boolean whether there is an item at current position.
*/
public function valid()
{
return $this->_key !== false;
}
}
......@@ -90,20 +90,20 @@ class ErrorException extends Exception
public function getName()
{
$names = array(
E_ERROR => Yii::t('yii|Fatal Error'),
E_PARSE => Yii::t('yii|Parse Error'),
E_CORE_ERROR => Yii::t('yii|Core Error'),
E_COMPILE_ERROR => Yii::t('yii|Compile Error'),
E_USER_ERROR => Yii::t('yii|User Error'),
E_WARNING => Yii::t('yii|Warning'),
E_CORE_WARNING => Yii::t('yii|Core Warning'),
E_COMPILE_WARNING => Yii::t('yii|Compile Warning'),
E_USER_WARNING => Yii::t('yii|User Warning'),
E_STRICT => Yii::t('yii|Strict'),
E_NOTICE => Yii::t('yii|Notice'),
E_RECOVERABLE_ERROR => Yii::t('yii|Recoverable Error'),
E_DEPRECATED => Yii::t('yii|Deprecated'),
E_ERROR => Yii::t('yii', 'Fatal Error'),
E_PARSE => Yii::t('yii', 'Parse Error'),
E_CORE_ERROR => Yii::t('yii', 'Core Error'),
E_COMPILE_ERROR => Yii::t('yii', 'Compile Error'),
E_USER_ERROR => Yii::t('yii', 'User Error'),
E_WARNING => Yii::t('yii', 'Warning'),
E_CORE_WARNING => Yii::t('yii', 'Core Warning'),
E_COMPILE_WARNING => Yii::t('yii', 'Compile Warning'),
E_USER_WARNING => Yii::t('yii', 'User Warning'),
E_STRICT => Yii::t('yii', 'Strict'),
E_NOTICE => Yii::t('yii', 'Notice'),
E_RECOVERABLE_ERROR => Yii::t('yii', 'Recoverable Error'),
E_DEPRECATED => Yii::t('yii', 'Deprecated'),
);
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : Yii::t('yii|Error');
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : Yii::t('yii', 'Error');
}
}
......@@ -75,8 +75,11 @@ class ErrorHandler extends Component
\Yii::$app->runAction($this->errorAction);
} elseif (\Yii::$app instanceof \yii\web\Application) {
if (!headers_sent()) {
$errorCode = $exception instanceof HttpException ? $exception->statusCode : 500;
header("HTTP/1.0 $errorCode " . get_class($exception));
if ($exception instanceof HttpException) {
header('HTTP/1.0 ' . $exception->statusCode . ' ' . $exception->getName());
} else {
header('HTTP/1.0 500 ' . get_class($exception));
}
}
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
\Yii::$app->renderException($exception);
......
......@@ -20,6 +20,6 @@ class Exception extends \Exception
*/
public function getName()
{
return \Yii::t('yii|Exception');
return \Yii::t('yii', 'Exception');
}
}
......@@ -103,7 +103,7 @@ class HttpException extends UserException
if (isset($httpCodes[$this->statusCode])) {
return $httpCodes[$this->statusCode];
} else {
return \Yii::t('yii|Error');
return \Yii::t('yii', 'Error');
}
}
}
......@@ -20,7 +20,7 @@ class InvalidCallException extends Exception
*/
public function getName()
{
return \Yii::t('yii|Invalid Call');
return \Yii::t('yii', 'Invalid Call');
}
}
......@@ -20,7 +20,7 @@ class InvalidConfigException extends Exception
*/
public function getName()
{
return \Yii::t('yii|Invalid Configuration');
return \Yii::t('yii', 'Invalid Configuration');
}
}
......@@ -20,7 +20,7 @@ class InvalidParamException extends Exception
*/
public function getName()
{
return \Yii::t('yii|Invalid Parameter');
return \Yii::t('yii', 'Invalid Parameter');
}
}
......@@ -20,7 +20,7 @@ class InvalidRequestException extends UserException
*/
public function getName()
{
return \Yii::t('yii|Invalid Request');
return \Yii::t('yii', 'Invalid Request');
}
}
......@@ -20,7 +20,7 @@ class InvalidRouteException extends UserException
*/
public function getName()
{
return \Yii::t('yii|Invalid Route');
return \Yii::t('yii', 'Invalid Route');
}
}
......@@ -7,6 +7,8 @@
namespace yii\base;
use ArrayObject;
use ArrayIterator;
use yii\helpers\StringHelper;
use yii\validators\RequiredValidator;
use yii\validators\Validator;
......@@ -30,7 +32,7 @@ use yii\validators\Validator;
* You may directly use Model to store model data, or extend it with customization.
* You may also customize Model by attaching [[ModelBehavior|model behaviors]].
*
* @property Vector $validators All the validators declared in the model.
* @property ArrayObject $validators All the validators declared in the model.
* @property array $activeValidators The validators applicable to the current [[scenario]].
* @property array $errors Errors for all attributes or the specified attribute. Empty array is returned if no error.
* @property array $attributes Attribute values (name => value).
......@@ -56,7 +58,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
*/
private $_errors;
/**
* @var Vector vector of validators
* @var ArrayObject list of validators
*/
private $_validators;
/**
......@@ -300,15 +302,15 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
* This method differs from [[getActiveValidators()]] in that the latter
* only returns the validators applicable to the current [[scenario]].
*
* Because this method returns a [[Vector]] object, you may
* Because this method returns an ArrayObject object, you may
* manipulate it by inserting or removing validators (useful in model behaviors).
* For example,
*
* ~~~
* $model->validators->add($newValidator);
* $model->validators[] = $newValidator;
* ~~~
*
* @return Vector all the validators declared in the model.
* @return ArrayObject all the validators declared in the model.
*/
public function getValidators()
{
......@@ -340,18 +342,18 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
/**
* Creates validator objects based on the validation rules specified in [[rules()]].
* Unlike [[getValidators()]], each time this method is called, a new list of validators will be returned.
* @return Vector validators
* @return ArrayObject validators
* @throws InvalidConfigException if any validation rule configuration is invalid
*/
public function createValidators()
{
$validators = new Vector;
$validators = new ArrayObject;
foreach ($this->rules() as $rule) {
if ($rule instanceof Validator) {
$validators->add($rule);
$validators->append($rule);
} elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
$validator = Validator::createValidator($rule[1], $this, $rule[0], array_slice($rule, 2));
$validators->add($validator);
$validators->append($validator);
} else {
throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.');
}
......@@ -590,18 +592,22 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
/**
* Returns the attribute names that are safe to be massively assigned in the current scenario.
* @return array safe attribute names
* @return string[] safe attribute names
*/
public function safeAttributes()
{
$scenario = $this->getScenario();
$scenarios = $this->scenarios();
if (!isset($scenarios[$scenario])) {
return array();
}
$attributes = array();
if (isset($scenarios[$scenario])) {
foreach ($scenarios[$scenario] as $attribute) {
if ($attribute[0] !== '!') {
$attributes[] = $attribute;
}
if (isset($scenarios[$scenario]['attributes']) && is_array($scenarios[$scenario]['attributes'])) {
$scenarios[$scenario] = $scenarios[$scenario]['attributes'];
}
foreach ($scenarios[$scenario] as $attribute) {
if ($attribute[0] !== '!') {
$attributes[] = $attribute;
}
}
return $attributes;
......@@ -609,34 +615,37 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
/**
* Returns the attribute names that are subject to validation in the current scenario.
* @return array safe attribute names
* @return string[] safe attribute names
*/
public function activeAttributes()
{
$scenario = $this->getScenario();
$scenarios = $this->scenarios();
if (isset($scenarios[$scenario])) {
$attributes = $scenarios[$this->getScenario()];
foreach ($attributes as $i => $attribute) {
if ($attribute[0] === '!') {
$attributes[$i] = substr($attribute, 1);
}
}
return $attributes;
} else {
if (!isset($scenarios[$scenario])) {
return array();
}
if (isset($scenarios[$scenario]['attributes']) && is_array($scenarios[$scenario]['attributes'])) {
$attributes = $scenarios[$scenario]['attributes'];
} else {
$attributes = $scenarios[$scenario];
}
foreach ($attributes as $i => $attribute) {
if ($attribute[0] === '!') {
$attributes[$i] = substr($attribute, 1);
}
}
return $attributes;
}
/**
* Returns an iterator for traversing the attributes in the model.
* This method is required by the interface IteratorAggregate.
* @return DictionaryIterator an iterator for traversing the items in the list.
* @return ArrayIterator an iterator for traversing the items in the list.
*/
public function getIterator()
{
$attributes = $this->getAttributes();
return new DictionaryIterator($attributes);
return new ArrayIterator($attributes);
}
/**
......
......@@ -449,7 +449,7 @@ abstract class Module extends Component
public function getComponent($id, $load = true)
{
if (isset($this->_components[$id])) {
if ($this->_components[$id] instanceof Component) {
if ($this->_components[$id] instanceof Object) {
return $this->_components[$id];
} elseif ($load) {
Yii::trace("Loading component: $id", __METHOD__);
......
......@@ -20,7 +20,7 @@ class NotSupportedException extends Exception
*/
public function getName()
{
return \Yii::t('yii|Not Supported');
return \Yii::t('yii', 'Not Supported');
}
}
......@@ -20,7 +20,7 @@ class UnknownClassException extends Exception
*/
public function getName()
{
return \Yii::t('yii|Unknown Class');
return \Yii::t('yii', 'Unknown Class');
}
}
......@@ -20,7 +20,7 @@ class UnknownMethodException extends Exception
*/
public function getName()
{
return \Yii::t('yii|Unknown Method');
return \Yii::t('yii', 'Unknown Method');
}
}
......@@ -20,7 +20,7 @@ class UnknownPropertyException extends Exception
*/
public function getName()
{
return \Yii::t('yii|Unknown Property');
return \Yii::t('yii', 'Unknown Property');
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* VectorIterator implements the SPL `Iterator` interface for [[Vector]].
*
* It allows [[Vector]] to return a new iterator for data traversing purpose.
* You normally do not use this class directly.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class VectorIterator implements \Iterator
{
/**
* @var array the data to be iterated through
*/
private $_d;
/**
* @var integer index of the current item
*/
private $_i;
/**
* @var integer count of the data items
*/
private $_c;
/**
* Constructor.
* @param array $data the data to be iterated through
*/
public function __construct(&$data)
{
$this->_d = &$data;
$this->_i = 0;
$this->_c = count($this->_d);
}
/**
* Rewinds the index of the current item.
* This method is required by the SPL interface `Iterator`.
*/
public function rewind()
{
$this->_i = 0;
}
/**
* Returns the key of the current item.
* This method is required by the SPL interface `Iterator`.
* @return integer the key of the current item
*/
public function key()
{
return $this->_i;
}
/**
* Returns the current item.
* This method is required by the SPL interface `Iterator`.
* @return mixed the current item
*/
public function current()
{
return $this->_d[$this->_i];
}
/**
* Moves the internal pointer to the next item.
* This method is required by the SPL interface `Iterator`.
*/
public function next()
{
$this->_i++;
}
/**
* Returns a value indicating whether there is an item at current position.
* This method is required by the SPL interface `Iterator`.
* @return boolean whether there is an item at current position.
*/
public function valid()
{
return $this->_i < $this->_c;
}
}
......@@ -373,9 +373,10 @@ class View extends Component
*/
public function beginBlock($id, $renderInPlace = false)
{
return Block::begin($this, array(
return Block::begin(array(
'id' => $id,
'renderInPlace' => $renderInPlace,
'view' => $this,
));
}
......@@ -390,10 +391,10 @@ class View extends Component
/**
* Begins the rendering of content that is to be decorated by the specified view.
* This method can be used to implement nested layout. For example, a layout can be embedded
* in another layout file specified as '@app/view/layouts/base' like the following:
* in another layout file specified as '@app/view/layouts/base.php' like the following:
*
* ~~~
* <?php $this->beginContent('@app/view/layouts/base'); ?>
* <?php $this->beginContent('@app/view/layouts/base.php'); ?>
* ...layout content here...
* <?php $this->endContent(); ?>
* ~~~
......@@ -406,9 +407,10 @@ class View extends Component
*/
public function beginContent($viewFile, $params = array())
{
return ContentDecorator::begin($this, array(
return ContentDecorator::begin(array(
'viewFile' => $viewFile,
'params' => $params,
'view' => $this,
));
}
......@@ -442,8 +444,9 @@ class View extends Component
public function beginCache($id, $properties = array())
{
$properties['id'] = $id;
$properties['view'] = $this;
/** @var $cache FragmentCache */
$cache = FragmentCache::begin($this, $properties);
$cache = FragmentCache::begin($properties);
if ($cache->getCachedContent() !== false) {
$this->endCache();
return false;
......
......@@ -18,16 +18,6 @@ use Yii;
class Widget extends Component
{
/**
* @var View the view object that this widget is associated with.
* The widget will use this view object to register any needed assets.
* This property is also required by [[render()]] and [[renderFile()]].
*/
public $view;
/**
* @var string id of the widget.
*/
private $_id;
/**
* @var integer a counter used to generate [[id]] for widgets.
* @internal
*/
......@@ -39,32 +29,19 @@ class Widget extends Component
*/
public static $_stack = array();
/**
* Constructor.
* @param View $view the view object that this widget is associated with.
* The widget will use this view object to register any needed assets.
* It is also required by [[render()]] and [[renderFile()]].
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($view, $config = array())
{
$this->view = $view;
parent::__construct($config);
}
/**
* Begins a widget.
* This method creates an instance of the calling class. It will apply the configuration
* to the created instance. A matching [[end()]] call should be called later.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties
* @return Widget the newly created widget instance
*/
public static function begin($view, $config = array())
public static function begin($config = array())
{
$config['class'] = get_called_class();
/** @var Widget $widget */
$widget = Yii::createObject($config, $view);
$widget = Yii::createObject($config);
self::$_stack[] = $widget;
return $widget;
}
......@@ -93,21 +70,22 @@ class Widget extends Component
/**
* Creates a widget instance and runs it.
* The widget rendering result is returned by this method.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties
* @return string the rendering result of the widget.
*/
public static function widget($view, $config = array())
public static function widget($config = array())
{
ob_start();
ob_implicit_flush(false);
/** @var Widget $widget */
$config['class'] = get_called_class();
$widget = Yii::createObject($config, $view);
$widget = Yii::createObject($config);
$widget->run();
return ob_get_clean();
}
private $_id;
/**
* Returns the ID of the widget.
* @param boolean $autoGenerate whether to generate an ID if it is not set previously
......@@ -130,6 +108,32 @@ class Widget extends Component
$this->_id = $value;
}
private $_view;
/**
* Returns the view object that can be used to render views or view files.
* The [[render()]] and [[renderFile()]] methods will use
* this view object to implement the actual view rendering.
* If not set, it will default to the "view" application component.
* @return View the view object that can be used to render views or view files.
*/
public function getView()
{
if ($this->_view === null) {
$this->_view = Yii::$app->getView();
}
return $this->_view;
}
/**
* Sets the view object to be used by this widget.
* @param View $view the view object that can be used to render views or view files.
*/
public function setView($view)
{
$this->_view = $view;
}
/**
* Executes the widget.
*/
......@@ -159,7 +163,7 @@ class Widget extends Component
public function render($view, $params = array())
{
$viewFile = $this->findViewFile($view);
return $this->view->renderFile($viewFile, $params, $this);
return $this->getView()->renderFile($viewFile, $params, $this);
}
/**
......@@ -171,7 +175,7 @@ class Widget extends Component
*/
public function renderFile($file, $params = array())
{
return $this->view->renderFile($file, $params, $this);
return $this->getView()->renderFile($file, $params, $this);
}
/**
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\behaviors;
use yii\base\Behavior;
use yii\db\Expression;
use yii\db\ActiveRecord;
/**
* AutoTimestamp will automatically fill the attributes about creation time and updating time.
*
* AutoTimestamp fills the attributes when the associated AR model is being inserted or updated.
* You may specify an AR to use this behavior like the following:
*
* ~~~
* public function behaviors()
* {
* return array(
* 'timestamp' => array(
* 'class' => 'yii\behaviors\AutoTimestamp',
* ),
* );
* }
* ~~~
*
* By default, AutoTimestamp will fill the `create_time` attribute with the current timestamp
* when the associated AR object is being inserted; it will fill the `update_time` attribute
* with the timestamp when the AR object is being updated.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class AutoTimestamp extends Behavior
{
/**
* @var array list of attributes that are to be automatically filled with timestamps.
* The array keys are the ActiveRecord events upon which the attributes are to be filled with timestamps,
* and the array values are the corresponding attribute to be updated. You can use a string to represent
* a single attribute, or an array to represent a list of attributes.
* The default setting is to update the `create_time` attribute upon AR insertion,
* and update the `update_time` attribute upon AR updating.
*/
public $attributes = array(
ActiveRecord::EVENT_BEFORE_INSERT => 'create_time',
ActiveRecord::EVENT_BEFORE_UPDATE => 'update_time',
);
/**
* @var \Closure|Expression The expression that will be used for generating the timestamp.
* This can be either an anonymous function that returns the timestamp value,
* or an [[Expression]] object representing a DB expression (e.g. `new Expression('NOW()')`).
* If not set, it will use the value of `time()` to fill the attributes.
*/
public $timestamp;
/**
* Declares event handlers for the [[owner]]'s events.
* @return array events (array keys) and the corresponding event handler methods (array values).
*/
public function events()
{
$events = array();
$behavior = $this;
foreach ($this->attributes as $event => $attributes) {
if (!is_array($attributes)) {
$attributes = array($attributes);
}
$events[$event] = function () use ($behavior, $attributes) {
$behavior->updateTimestamp($attributes);
};
}
return $events;
}
/**
* Updates the attributes with the current timestamp.
* @param array $attributes list of attributes to be updated.
*/
public function updateTimestamp($attributes)
{
foreach ($attributes as $attribute) {
$this->owner->$attribute = $this->evaluateTimestamp($attribute);
}
}
/**
* Gets the appropriate timestamp for the specified attribute.
* @param string $attribute attribute name
* @return mixed the timestamp value
*/
protected function evaluateTimestamp($attribute)
{
if ($this->timestamp instanceof Expression) {
return $this->timestamp;
} elseif ($this->timestamp !== null) {
return call_user_func($this->timestamp);
} else {
return time();
}
}
}
......@@ -63,12 +63,6 @@
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"config": {
"vendor-dir": "yii/vendor"
},
"bin": [
"yii/yiic"
],
"require": {
"php": ">=5.3.0",
"michelf/php-markdown": "1.3",
......
......@@ -30,7 +30,7 @@ use yii\base\InvalidRouteException;
* To run the console application, enter the following on the command line:
*
* ~~~
* yiic <route> [--param1=value1 --param2 ...]
* yii <route> [--param1=value1 --param2 ...]
* ~~~
*
* where `<route>` refers to a controller route in the form of `ModuleID/ControllerID/ActionID`
......@@ -42,7 +42,7 @@ use yii\base\InvalidRouteException;
* To use this command, simply type:
*
* ~~~
* yiic help
* yii help
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
......@@ -94,7 +94,7 @@ class Application extends \yii\base\Application
list ($route, $params) = $request->resolve();
return $this->runAction($route, $params);
} else {
throw new Exception(\Yii::t('yii|This script must be run from the command line.'));
throw new Exception(\Yii::t('yii', 'This script must be run from the command line.'));
}
}
......@@ -113,7 +113,7 @@ class Application extends \yii\base\Application
try {
return parent::runAction($route, $params);
} catch (InvalidRouteException $e) {
throw new Exception(\Yii::t('yii|Unknown command "{command}".', array('{command}' => $route)));
throw new Exception(\Yii::t('yii', 'Unknown command "{command}".', array('{command}' => $route)));
}
}
......
......@@ -18,10 +18,10 @@ use yii\helpers\Console;
*
* A controller consists of one or several actions known as sub-commands.
* Users call a console command by specifying the corresponding route which identifies a controller action.
* The `yiic` program is used when calling a console command, like the following:
* The `yii` program is used when calling a console command, like the following:
*
* ~~~
* yiic <route> [--param1=value1 --param2 ...]
* yii <route> [--param1=value1 --param2 ...]
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
......@@ -91,7 +91,7 @@ class Controller extends \yii\base\Controller
$args = isset($params[Request::ANONYMOUS_PARAMS]) ? $params[Request::ANONYMOUS_PARAMS] : array();
unset($params[Request::ANONYMOUS_PARAMS]);
if (!empty($params)) {
throw new Exception(Yii::t('yii|Unknown options: {params}', array(
throw new Exception(Yii::t('yii', 'Unknown options: {params}', array(
'{params}' => implode(', ', array_keys($params)),
)));
}
......@@ -115,7 +115,7 @@ class Controller extends \yii\base\Controller
}
if (!empty($missing)) {
throw new Exception(Yii::t('yii|Missing required arguments: {params}', array(
throw new Exception(Yii::t('yii', 'Missing required arguments: {params}', array(
'{params}' => implode(', ', $missing),
)));
}
......
......@@ -22,7 +22,7 @@ class Exception extends UserException
*/
public function getName()
{
return \Yii::t('yii|Error');
return \Yii::t('yii', 'Error');
}
}
......@@ -27,7 +27,7 @@ class Request extends \yii\base\Request
public function resolve()
{
$rawParams = $this->getRawParams();
array_shift($rawParams); // the 1st argument is the yiic script name
array_shift($rawParams); // the 1st argument is the yii script name
if (isset($rawParams[0])) {
$route = $rawParams[0];
......
......@@ -7,6 +7,7 @@
namespace yii\console\controllers;
use Yii;
use yii\console\Controller;
use yii\console\Exception;
use yii\caching\Cache;
......@@ -19,9 +20,28 @@ use yii\caching\Cache;
*/
class CacheController extends Controller
{
/**
* Lists the caches that can be flushed.
*/
public function actionIndex()
{
$this->forward('help/index', array('-args' => array('cache/flush')));
$caches = array();
$components = Yii::$app->getComponents();
foreach ($components as $name => $component) {
if ($component instanceof Cache) {
$caches[$name] = get_class($component);
} elseif (is_array($component) && isset($component['class']) && strpos($component['class'], 'Cache') !== false) {
$caches[$name] = $component['class'];
}
}
if (!empty($caches)) {
echo "The following caches can be flushed:\n\n";
foreach ($caches as $name => $class) {
echo " * $name: $class\n";
}
} else {
echo "No cache is used.\n";
}
}
/**
......@@ -33,7 +53,7 @@ class CacheController extends Controller
public function actionFlush($component = 'cache')
{
/** @var $cache Cache */
$cache = \Yii::$app->getComponent($component);
$cache = Yii::$app->getComponent($component);
if (!$cache || !$cache instanceof Cache) {
throw new Exception('Application component "'.$component.'" is not defined or not a cache.');
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
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