Browse Source

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

tags/2.0.0-beta
Paul Klimov 11 years ago
parent
commit
de83e4ddd1
  1. 2
      apps/advanced/frontend/web/robots.txt
  2. 1
      apps/basic/codeception.yml
  3. 2
      apps/basic/commands/HelloController.php
  4. 5
      apps/basic/composer.json
  5. 11
      apps/basic/config/codeception/acceptance.php
  6. 11
      apps/basic/config/codeception/functional.php
  7. 15
      apps/basic/config/codeception/unit.php
  8. 7
      apps/basic/config/web-test.php
  9. 21
      apps/basic/config/web.php
  10. 4
      apps/basic/tests/.gitignore
  11. 32
      apps/basic/tests/README.md
  12. 9
      apps/basic/tests/_bootstrap.php
  13. 3
      apps/basic/tests/_helpers/CodeHelper.php
  14. 3
      apps/basic/tests/_helpers/TestHelper.php
  15. 3
      apps/basic/tests/_helpers/WebHelper.php
  16. 10
      apps/basic/tests/_pages/AboutPage.php
  17. 58
      apps/basic/tests/_pages/ContactPage.php
  18. 38
      apps/basic/tests/_pages/LoginPage.php
  19. 10
      apps/basic/tests/acceptance.suite.yml
  20. 5
      apps/basic/tests/acceptance/AboutCept.php
  21. 41
      apps/basic/tests/acceptance/ContactCept.php
  22. 1
      apps/basic/tests/acceptance/HomeCept.php
  23. 36
      apps/basic/tests/acceptance/LoginCept.php
  24. 2008
      apps/basic/tests/acceptance/WebGuy.php
  25. 8
      apps/basic/tests/acceptance/_bootstrap.php
  26. 9
      apps/basic/tests/functional.suite.yml
  27. 5
      apps/basic/tests/functional/AboutCept.php
  28. 38
      apps/basic/tests/functional/ContactCept.php
  29. 1
      apps/basic/tests/functional/HomeCept.php
  30. 33
      apps/basic/tests/functional/LoginCept.php
  31. 2169
      apps/basic/tests/functional/TestGuy.php
  32. 8
      apps/basic/tests/functional/_bootstrap.php
  33. 51
      apps/basic/tests/functional/_pages/ContactPage.php
  34. 30
      apps/basic/tests/functional/_pages/LoginPage.php
  35. 3
      apps/basic/tests/unit.suite.dist.yml
  36. 30
      apps/basic/tests/unit/CodeGuy.php
  37. 8
      apps/basic/tests/unit/_bootstrap.php
  38. 10
      apps/basic/tests/unit/models/ContactFormTest.php
  39. 10
      apps/basic/tests/unit/models/LoginFormTest.php
  40. 20
      apps/basic/tests/unit/models/UserTest.php
  41. 17
      apps/basic/web/index-test-acceptance.php
  42. 11
      apps/basic/web/index-test-functional.php
  43. 24
      apps/basic/web/index-test.php
  44. 2
      apps/basic/web/robots.txt
  45. 2
      composer.json
  46. 46
      docs/guide/gii.md
  47. 3
      extensions/yii/bootstrap/CHANGELOG.md
  48. 26
      extensions/yii/bootstrap/NavBar.php
  49. 55
      extensions/yii/codeception/BasePage.php
  50. 7
      extensions/yii/codeception/CHANGELOG.md
  51. 32
      extensions/yii/codeception/LICENSE.md
  52. 128
      extensions/yii/codeception/README.md
  53. 56
      extensions/yii/codeception/TestCase.php
  54. 26
      extensions/yii/codeception/composer.json
  55. 14
      extensions/yii/elasticsearch/QueryBuilder.php
  56. 14
      extensions/yii/redis/LuaScriptBuilder.php
  57. 4
      framework/CHANGELOG.md
  58. 1
      framework/yii/base/Application.php
  59. 5
      framework/yii/db/ActiveQuery.php
  60. 25
      framework/yii/db/QueryBuilder.php
  61. 2
      framework/yii/helpers/BaseSecurity.php
  62. 29
      framework/yii/i18n/Formatter.php
  63. 3
      framework/yii/validators/UrlValidator.php
  64. 3
      framework/yii/widgets/LinkSorter.php
  65. 4
      tests/unit/framework/i18n/FormatterTest.php

2
apps/advanced/frontend/web/robots.txt

@ -0,0 +1,2 @@
User-agent: *
Disallow:

1
apps/basic/codeception.yml

@ -8,6 +8,7 @@ settings:
suite_class: \PHPUnit_Framework_TestSuite suite_class: \PHPUnit_Framework_TestSuite
memory_limit: 1024M memory_limit: 1024M
log: true log: true
colors: true
modules: modules:
config: config:
Db: Db:

2
apps/basic/commands/HelloController.php

@ -10,7 +10,7 @@ namespace app\commands;
use yii\console\Controller; use yii\console\Controller;
/** /**
* This command echoes what the first argument that you have entered. * This command echoes the first argument that you have entered.
* *
* This command is provided as an example for you to learn how to create console commands. * This command is provided as an example for you to learn how to create console commands.
* *

5
apps/basic/composer.json

@ -16,10 +16,11 @@
"require": { "require": {
"php": ">=5.4.0", "php": ">=5.4.0",
"yiisoft/yii2": "*", "yiisoft/yii2": "*",
"yiisoft/yii2-swiftmailer": "*",
"yiisoft/yii2-bootstrap": "*", "yiisoft/yii2-bootstrap": "*",
"yiisoft/yii2-codeception": "*",
"yiisoft/yii2-debug": "*", "yiisoft/yii2-debug": "*",
"yiisoft/yii2-gii": "*" "yiisoft/yii2-gii": "*",
"yiisoft/yii2-swiftmailer": "*"
}, },
"scripts": { "scripts": {
"post-create-project-cmd": [ "post-create-project-cmd": [

11
apps/basic/config/codeception/acceptance.php

@ -0,0 +1,11 @@
<?php
// configuration adjustments for codeception acceptance tests. Will be merged with web.php config.
return [
'components' => [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=yii2basic_acceptance',
],
],
];

11
apps/basic/config/codeception/functional.php

@ -0,0 +1,11 @@
<?php
// configuration adjustments for codeception functional tests. Will be merged with web.php config.
return [
'components' => [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=yii2basic_functional',
],
],
];

15
apps/basic/config/codeception/unit.php

@ -0,0 +1,15 @@
<?php
// configuration adjustments for codeception unit tests. Will be merged with web.php config.
return [
'components' => [
'fixture' => [
'class' => 'yii\test\DbFixtureManager',
'basePath' => '@tests/unit/fixtures',
],
'db' => [
'dsn' => 'mysql:host=localhost;dbname=yii2basic_unit',
],
],
];

7
apps/basic/config/web-test.php

@ -1,7 +0,0 @@
<?php
$config = require(__DIR__ . '/web.php');
// ... customize $config for the "test" environment here...
return $config;

21
apps/basic/config/web.php

@ -1,5 +1,7 @@
<?php <?php
$params = require(__DIR__ . '/params.php'); $params = require(__DIR__ . '/params.php');
$config = [ $config = [
'id' => 'basic', 'id' => 'basic',
'basePath' => dirname(__DIR__), 'basePath' => dirname(__DIR__),
@ -26,14 +28,31 @@ $config = [
], ],
], ],
], ],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=yii2basic',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
], ],
'params' => $params, 'params' => $params,
]; ];
if (YII_ENV_DEV) { if (YII_ENV_DEV)
{
// configuration adjustments for 'dev' environment
$config['preload'][] = 'debug'; $config['preload'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module'; $config['modules']['debug'] = 'yii\debug\Module';
$config['modules']['gii'] = 'yii\gii\Module'; $config['modules']['gii'] = 'yii\gii\Module';
} }
if (YII_ENV_TEST)
{
// configuration adjustments for 'test' environment.
// configuration for codeception test environments can be found in codeception folder.
// if needed, customize $config here.
}
return $config; return $config;

4
apps/basic/tests/.gitignore vendored

@ -0,0 +1,4 @@
# these files are auto generated by codeception build
/unit/CodeGuy.php
/functional/TestGuy.php
/acceptance/WebGuy.php

32
apps/basic/tests/README.md

@ -3,18 +3,26 @@ These tests are developed with [Codeception PHP Testing Framework](http://codece
To run the tests, follow these steps: To run the tests, follow these steps:
1. [Install Codeception](http://codeception.com/quickstart) if you do not have it yet. 1. Download Codeception([Quickstart step 1](http://codeception.com/quickstart)) and put the codeception.phar in the
2. Create test configuration files based on your environment: application base directory (not in this `tests` directory!).
- Copy `acceptance.suite.dist.yml` to `acceptance.suite.yml` and customize it; 2. Adjust the test configuration files based on your environment:
- Copy `functional.suite.dist.yml` to `functional.suite.yml` and customize it; - Configure the URL for [acceptance tests](http://codeception.com/docs/04-AcceptanceTests) in `acceptance.suite.yml`.
- Copy `unit.suite.dist.yml` to `unit.suite.yml` and customize it. The URL should point to the `index-test-acceptance.php` file that is located under the `web` directory of the application.
3. Switch to the parent folder and run tests: - `functional.suite.yml` for [functional testing](http://codeception.com/docs/05-FunctionalTests) and
`unit.suite.yml` for [unit testing](http://codeception.com/docs/06-UnitTests) should already work out of the box
``` and should not need to be adjusted.
cd .. 3. Go to the application base directory and build the test suites:
php codecept.phar build // rebuild test scripts, only need to be run once ```
php codecept.phar run // run all available tests php codecept.phar build // rebuild test scripts, only need to be run once
``` ```
4. Run the tests:
```
php codecept.phar run // run all available tests
// you can also run a test suite alone:
php codecept.phar run acceptance
php codecept.phar run functional
php codecept.phar run unit
```
Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for
more details about writing acceptance, functional and unit tests. more details about writing acceptance, functional and unit tests.

9
apps/basic/tests/_bootstrap.php

@ -0,0 +1,9 @@
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/../vendor/yiisoft/yii2/yii/Yii.php');
Yii::setAlias('@tests', __DIR__);

3
apps/basic/tests/_helpers/CodeHelper.php

@ -1,8 +1,7 @@
<?php <?php
namespace Codeception\Module; namespace Codeception\Module;
// here you can define custom functions for CodeGuy
class CodeHelper extends \Codeception\Module class CodeHelper extends \Codeception\Module
{ {
// here you can define custom methods for CodeGuy
} }

3
apps/basic/tests/_helpers/TestHelper.php

@ -1,8 +1,7 @@
<?php <?php
namespace Codeception\Module; namespace Codeception\Module;
// here you can define custom functions for TestGuy
class TestHelper extends \Codeception\Module class TestHelper extends \Codeception\Module
{ {
// here you can define custom methods for TestGuy
} }

3
apps/basic/tests/_helpers/WebHelper.php

@ -1,8 +1,7 @@
<?php <?php
namespace Codeception\Module; namespace Codeception\Module;
// here you can define custom functions for WebGuy
class WebHelper extends \Codeception\Module class WebHelper extends \Codeception\Module
{ {
// here you can define custom methods for WebGuy
} }

10
apps/basic/tests/_pages/AboutPage.php

@ -0,0 +1,10 @@
<?php
namespace tests\_pages;
use yii\codeception\BasePage;
class AboutPage extends BasePage
{
public static $URL = '?r=site/about';
}

58
apps/basic/tests/_pages/ContactPage.php

@ -0,0 +1,58 @@
<?php
namespace tests\_pages;
use yii\codeception\BasePage;
class ContactPage extends BasePage
{
public static $URL = '?r=site/contact';
/**
* contact form name text field locator
* @var string
*/
public $name = 'input[name="ContactForm[name]"]';
/**
* contact form email text field locator
* @var string
*/
public $email = 'input[name="ContactForm[email]"]';
/**
* contact form subject text field locator
* @var string
*/
public $subject = 'input[name="ContactForm[subject]"]';
/**
* contact form body textarea locator
* @var string
*/
public $body = 'textarea[name="ContactForm[body]"]';
/**
* contact form verification code text field locator
* @var string
*/
public $verifyCode = 'input[name="ContactForm[verifyCode]"]';
/**
* contact form submit button
* @var string
*/
public $button = 'button[type=submit]';
/**
*
* @param array $contactData
*/
public function submit(array $contactData)
{
if (!empty($contactData))
{
$this->guy->fillField($this->name, $contactData['name']);
$this->guy->fillField($this->email, $contactData['email']);
$this->guy->fillField($this->subject, $contactData['subject']);
$this->guy->fillField($this->body, $contactData['body']);
$this->guy->fillField($this->verifyCode, $contactData['verifyCode']);
}
$this->guy->click($this->button);
}
}

38
apps/basic/tests/_pages/LoginPage.php

@ -0,0 +1,38 @@
<?php
namespace tests\_pages;
use yii\codeception\BasePage;
class LoginPage extends BasePage
{
public static $URL = '?r=site/login';
/**
* login form username text field locator
* @var string
*/
public $username = 'input[name="LoginForm[username]"]';
/**
* login form password text field locator
* @var string
*/
public $password = 'input[name="LoginForm[password]"]';
/**
* login form submit button locator
* @var string
*/
public $button = 'button[type=submit]';
/**
*
* @param string $username
* @param string $password
*/
public function login($username, $password)
{
$this->guy->fillField($this->username, $username);
$this->guy->fillField($this->password, $password);
$this->guy->click($this->button);
}
}

10
apps/basic/tests/acceptance.suite.dist.yml → apps/basic/tests/acceptance.suite.yml

@ -11,8 +11,14 @@
class_name: WebGuy class_name: WebGuy
modules: modules:
enabled: enabled:
- PhpBrowser
- WebHelper - WebHelper
- PhpBrowser
# you can use WebDriver instead of PhpBrowser to test javascript and ajax.
# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium
# - WebDriver
config: config:
PhpBrowser: PhpBrowser:
url: 'http://localhost/index-test.php' url: 'http://localhost/basic-app/web/index-test-acceptance.php'
# WebDriver:
# url: 'http://localhost/basic-app/web/index-test-acceptance.php'
# browser: firefox

5
apps/basic/tests/acceptance/AboutCept.php

@ -1,5 +1,8 @@
<?php <?php
use tests\_pages\AboutPage;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure that about works'); $I->wantTo('ensure that about works');
$I->amOnPage('?r=site/about'); $I->amOnPage(AboutPage::$URL);
$I->see('About', 'h1'); $I->see('About', 'h1');

41
apps/basic/tests/acceptance/ContactCept.php

@ -1,10 +1,17 @@
<?php <?php
use tests\_pages\ContactPage;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure that contact works'); $I->wantTo('ensure that contact works');
$I->amOnPage('?r=site/contact'); $contactPage = ContactPage::of($I);
$I->amOnPage(ContactPage::$URL);
$I->see('Contact', 'h1'); $I->see('Contact', 'h1');
$I->submitForm('#contact-form', []); $I->amGoingTo('submit contact form with no data');
$contactPage->submit([]);
$I->expectTo('see validations errors');
$I->see('Contact', 'h1'); $I->see('Contact', 'h1');
$I->see('Name cannot be blank'); $I->see('Name cannot be blank');
$I->see('Email cannot be blank'); $I->see('Email cannot be blank');
@ -12,25 +19,31 @@ $I->see('Subject cannot be blank');
$I->see('Body cannot be blank'); $I->see('Body cannot be blank');
$I->see('The verification code is incorrect'); $I->see('The verification code is incorrect');
$I->submitForm('#contact-form', [ $I->amGoingTo('submit contact form with not correct email');
'ContactForm[name]' => 'tester', $contactPage->submit([
'ContactForm[email]' => 'tester.email', 'name' => 'tester',
'ContactForm[subject]' => 'test subject', 'email' => 'tester.email',
'ContactForm[body]' => 'test content', 'subject' => 'test subject',
'ContactForm[verifyCode]' => 'testme', 'body' => 'test content',
'verifyCode' => 'testme',
]); ]);
$I->expectTo('see that email adress is wrong');
$I->dontSee('Name cannot be blank', '.help-inline'); $I->dontSee('Name cannot be blank', '.help-inline');
$I->see('Email is not a valid email address.'); $I->see('Email is not a valid email address.');
$I->dontSee('Subject cannot be blank', '.help-inline'); $I->dontSee('Subject cannot be blank', '.help-inline');
$I->dontSee('Body cannot be blank', '.help-inline'); $I->dontSee('Body cannot be blank', '.help-inline');
$I->dontSee('The verification code is incorrect', '.help-inline'); $I->dontSee('The verification code is incorrect', '.help-inline');
$I->submitForm('#contact-form', [ $I->amGoingTo('submit contact form with correct data');
'ContactForm[name]' => 'tester', $contactPage->submit([
'ContactForm[email]' => 'tester@example.com', 'name' => 'tester',
'ContactForm[subject]' => 'test subject', 'email' => 'tester@example.com',
'ContactForm[body]' => 'test content', 'subject' => 'test subject',
'ContactForm[verifyCode]' => 'testme', 'body' => 'test content',
'verifyCode' => 'testme',
]); ]);
if (method_exists($I, 'wait')) {
$I->wait(3); // only for selenium
}
$I->dontSeeElement('#contact-form'); $I->dontSeeElement('#contact-form');
$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); $I->see('Thank you for contacting us. We will respond to you as soon as possible.');

1
apps/basic/tests/acceptance/HomeCept.php

@ -1,4 +1,5 @@
<?php <?php
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure that home page works'); $I->wantTo('ensure that home page works');
$I->amOnPage(''); $I->amOnPage('');

36
apps/basic/tests/acceptance/LoginCept.php

@ -1,23 +1,29 @@
<?php <?php
use tests\_pages\LoginPage;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure that login works'); $I->wantTo('ensure that login works');
$I->amOnPage('?r=site/login'); $loginPage = LoginPage::of($I);
$I->amOnPage(LoginPage::$URL);
$I->see('Login', 'h1'); $I->see('Login', 'h1');
$I->submitForm('#login-form', []); $I->amGoingTo('try to login with empty credentials');
$I->dontSee('Logout (admin)'); $loginPage->login('', '');
$I->see('Username cannot be blank'); $I->expectTo('see validations errors');
$I->see('Password cannot be blank'); $I->see('Username cannot be blank.');
$I->see('Password cannot be blank.');
$I->submitForm('#login-form', [ $I->amGoingTo('try to login with wrong credentials');
'LoginForm[username]' => 'admin', $loginPage->login('admin', 'wrong');
'LoginForm[password]' => 'wrong', $I->expectTo('see validations errors');
]); $I->see('Incorrect username or password.');
$I->dontSee('Logout (admin)');
$I->see('Incorrect username or password');
$I->submitForm('#login-form', [ $I->amGoingTo('try to login with correct credentials');
'LoginForm[username]' => 'admin', $loginPage->login('admin', 'admin');
'LoginForm[password]' => 'admin', if (method_exists($I, 'wait')) {
]); $I->wait(3); // only for selenium
}
$I->expectTo('see user info');
$I->see('Logout (admin)'); $I->see('Logout (admin)');

2008
apps/basic/tests/acceptance/WebGuy.php

File diff suppressed because it is too large Load Diff

8
apps/basic/tests/acceptance/_bootstrap.php

@ -1,2 +1,8 @@
<?php <?php
// Here you can initialize variables that will for your tests
$config = yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../config/web.php'),
require(__DIR__ . '/../../config/codeception/acceptance.php')
);
$application = new yii\web\Application($config);

9
apps/basic/tests/functional.suite.dist.yml → apps/basic/tests/functional.suite.yml

@ -5,11 +5,14 @@
# (tip: better to use with frameworks). # (tip: better to use with frameworks).
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
#basic/web/index.php
class_name: TestGuy class_name: TestGuy
modules: modules:
enabled: [Filesystem, TestHelper, Yii2] enabled:
- Filesystem
- TestHelper
- Yii2
config: config:
Yii2: Yii2:
entryScript: 'web/index-test.php' entryScript: 'web/index-test-functional.php'
url: 'http://localhost/' url: 'http://localhost/'

5
apps/basic/tests/functional/AboutCept.php

@ -1,5 +1,8 @@
<?php <?php
use tests\_pages\AboutPage;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure that about works'); $I->wantTo('ensure that about works');
$I->amOnPage('?r=site/about'); $I->amOnPage(AboutPage::$URL);
$I->see('About', 'h1'); $I->see('About', 'h1');

38
apps/basic/tests/functional/ContactCept.php

@ -1,10 +1,17 @@
<?php <?php
use tests\functional\_pages\ContactPage;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure that contact works'); $I->wantTo('ensure that contact works');
$I->amOnPage('?r=site/contact'); $contactPage = ContactPage::of($I);
$I->amOnPage(ContactPage::$URL);
$I->see('Contact', 'h1'); $I->see('Contact', 'h1');
$I->submitForm('#contact-form', []); $I->amGoingTo('submit contact form with no data');
$contactPage->submit([]);
$I->expectTo('see validations errors');
$I->see('Contact', 'h1'); $I->see('Contact', 'h1');
$I->see('Name cannot be blank'); $I->see('Name cannot be blank');
$I->see('Email cannot be blank'); $I->see('Email cannot be blank');
@ -12,25 +19,28 @@ $I->see('Subject cannot be blank');
$I->see('Body cannot be blank'); $I->see('Body cannot be blank');
$I->see('The verification code is incorrect'); $I->see('The verification code is incorrect');
$I->submitForm('#contact-form', [ $I->amGoingTo('submit contact form with not correct email');
'ContactForm[name]' => 'tester', $contactPage->submit([
'ContactForm[email]' => 'tester.email', 'name' => 'tester',
'ContactForm[subject]' => 'test subject', 'email' => 'tester.email',
'ContactForm[body]' => 'test content', 'subject' => 'test subject',
'ContactForm[verifyCode]' => 'testme', 'body' => 'test content',
'verifyCode' => 'testme',
]); ]);
$I->expectTo('see that email adress is wrong');
$I->dontSee('Name cannot be blank', '.help-inline'); $I->dontSee('Name cannot be blank', '.help-inline');
$I->see('Email is not a valid email address.'); $I->see('Email is not a valid email address.');
$I->dontSee('Subject cannot be blank', '.help-inline'); $I->dontSee('Subject cannot be blank', '.help-inline');
$I->dontSee('Body cannot be blank', '.help-inline'); $I->dontSee('Body cannot be blank', '.help-inline');
$I->dontSee('The verification code is incorrect', '.help-inline'); $I->dontSee('The verification code is incorrect', '.help-inline');
$I->submitForm('#contact-form', [ $I->amGoingTo('submit contact form with correct data');
'ContactForm[name]' => 'tester', $contactPage->submit([
'ContactForm[email]' => 'tester@example.com', 'name' => 'tester',
'ContactForm[subject]' => 'test subject', 'email' => 'tester@example.com',
'ContactForm[body]' => 'test content', 'subject' => 'test subject',
'ContactForm[verifyCode]' => 'testme', 'body' => 'test content',
'verifyCode' => 'testme',
]); ]);
$I->dontSeeElement('#contact-form'); $I->dontSeeElement('#contact-form');
$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); $I->see('Thank you for contacting us. We will respond to you as soon as possible.');

1
apps/basic/tests/functional/HomeCept.php

@ -1,4 +1,5 @@
<?php <?php
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure that home page works'); $I->wantTo('ensure that home page works');
$I->amOnPage(''); $I->amOnPage('');

33
apps/basic/tests/functional/LoginCept.php

@ -1,23 +1,26 @@
<?php <?php
use tests\functional\_pages\LoginPage;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure that login works'); $I->wantTo('ensure that login works');
$I->amOnPage('?r=site/login'); $loginPage = LoginPage::of($I);
$I->amOnPage(LoginPage::$URL);
$I->see('Login', 'h1'); $I->see('Login', 'h1');
$I->submitForm('#login-form', []); $I->amGoingTo('try to login with empty credentials');
$I->dontSee('Logout (admin)'); $loginPage->login('', '');
$I->see('Username cannot be blank'); $I->expectTo('see validations errors');
$I->see('Password cannot be blank'); $I->see('Username cannot be blank.');
$I->see('Password cannot be blank.');
$I->submitForm('#login-form', [ $I->amGoingTo('try to login with wrong credentials');
'LoginForm[username]' => 'admin', $loginPage->login('admin', 'wrong');
'LoginForm[password]' => 'wrong', $I->expectTo('see validations errors');
]); $I->see('Incorrect username or password.');
$I->dontSee('Logout (admin)');
$I->see('Incorrect username or password');
$I->submitForm('#login-form', [ $I->amGoingTo('try to login with correct credentials');
'LoginForm[username]' => 'admin', $loginPage->login('admin', 'admin');
'LoginForm[password]' => 'admin', $I->expectTo('see user info');
]);
$I->see('Logout (admin)'); $I->see('Logout (admin)');

2169
apps/basic/tests/functional/TestGuy.php

File diff suppressed because it is too large Load Diff

8
apps/basic/tests/functional/_bootstrap.php

@ -1,2 +1,8 @@
<?php <?php
// Here you can initialize variables that will for your tests
$config = yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../config/web.php'),
require(__DIR__ . '/../../config/codeception/functional.php')
);
$application = new yii\web\Application($config);

51
apps/basic/tests/functional/_pages/ContactPage.php

@ -0,0 +1,51 @@
<?php
namespace tests\functional\_pages;
class ContactPage extends \tests\_pages\ContactPage
{
/**
* contact form name text field locator
* @var string
*/
public $name = 'ContactForm[name]';
/**
* contact form email text field locator
* @var string
*/
public $email = 'ContactForm[email]';
/**
* contact form subject text field locator
* @var string
*/
public $subject = 'ContactForm[subject]';
/**
* contact form body textarea locator
* @var string
*/
public $body = 'ContactForm[body]';
/**
* contact form verification code text field locator
* @var string
*/
public $verifyCode = 'ContactForm[verifyCode]';
/**
*
* @param array $contactData
*/
public function submit(array $contactData)
{
if (empty($contactData)) {
$this->guy->submitForm('#contact-form', []);
} else {
$this->guy->submitForm('#contact-form', [
$this->name => $contactData['name'],
$this->email => $contactData['email'],
$this->subject => $contactData['subject'],
$this->body => $contactData['body'],
$this->verifyCode => $contactData['verifyCode'],
]);
}
}
}

30
apps/basic/tests/functional/_pages/LoginPage.php

@ -0,0 +1,30 @@
<?php
namespace tests\functional\_pages;
class LoginPage extends \tests\_pages\LoginPage
{
/**
* login form username text field locator
* @var string
*/
public $username = 'LoginForm[username]';
/**
* login form password text field locator
* @var string
*/
public $password = 'LoginForm[password]';
/**
*
* @param string $username
* @param string $password
*/
public function login($username, $password)
{
$this->guy->submitForm('#login-form', [
$this->username => $username,
$this->password => $password,
]);
}
}

3
apps/basic/tests/unit.suite.dist.yml

@ -5,4 +5,5 @@
class_name: CodeGuy class_name: CodeGuy
modules: modules:
enabled: [CodeHelper] enabled:
- CodeHelper

30
apps/basic/tests/unit/CodeGuy.php

@ -1,30 +0,0 @@
<?php
// This class was automatically generated by build task
// You should not change it manually as it will be overwritten on next build
// @codingStandardsIgnoreFile
use \Codeception\Maybe;
use Codeception\Module\CodeHelper;
/**
* Inherited methods
* @method void execute($callable)
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void offsetGet($offset)
* @method void offsetSet($offset, $value)
* @method void offsetExists($offset)
* @method void offsetUnset($offset)
*/
class CodeGuy extends \Codeception\AbstractGuy
{
}

8
apps/basic/tests/unit/_bootstrap.php

@ -1,2 +1,8 @@
<?php <?php
// Here you can initialize variables that will for your tests
// add unit testing specific bootstrap code here
yii\codeception\TestCase::$applicationConfig = yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../config/web.php'),
require(__DIR__ . '/../../config/codeception/unit.php')
);

10
apps/basic/tests/unit/models/ContactFormTest.php

@ -0,0 +1,10 @@
<?php
namespace tests\unit\models;
use yii\codeception\TestCase;
class ContactFormTest extends TestCase
{
// TODO add test methods here
}

10
apps/basic/tests/unit/models/LoginFormTest.php

@ -0,0 +1,10 @@
<?php
namespace tests\unit\models;
use yii\codeception\TestCase;
class LoginFormTest extends TestCase
{
// TODO add test methods here
}

20
apps/basic/tests/unit/models/UserTest.php

@ -0,0 +1,20 @@
<?php
namespace tests\unit\models;
use yii\codeception\TestCase;
use yii\test\DbTestTrait;
class UserTest extends TestCase
{
use DbTestTrait;
protected function setUp()
{
parent::setUp();
// uncomment the following to load fixtures for table tbl_user
//$this->loadFixtures(['tbl_user']);
}
// TODO add test methods here
}

17
apps/basic/web/index-test-acceptance.php

@ -0,0 +1,17 @@
<?php
// NOTE: Make sure this file is not accessable when deployed to production
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/yii/Yii.php');
$config = yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../config/web.php'),
require(__DIR__ . '/../config/codeception/acceptance.php')
);
$application = new yii\web\Application($config);
$application->run();

11
apps/basic/web/index-test-functional.php

@ -0,0 +1,11 @@
<?php
// this file is used as the entry script for codeception functional testing
$config = yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../config/web.php'),
require(__DIR__ . '/../config/codeception/functional.php')
);
$config['class'] = 'yii\web\Application';
return $config;

24
apps/basic/web/index-test.php

@ -1,24 +0,0 @@
<?php
if (!in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
die('You are not allowed to access this file.');
}
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/../vendor/yiisoft/yii2/yii/Yii.php');
$config = require(__DIR__ . '/../config/web-test.php');
if (isset($this)) {
// run in functional tests
$config['class'] = 'yii\web\Application';
return $config;
} else {
// run in acceptance tests
$application = new yii\web\Application($config);
$application->run();
}

2
apps/basic/web/robots.txt

@ -0,0 +1,2 @@
User-agent: *
Disallow:

2
composer.json

@ -51,6 +51,7 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"replace": { "replace": {
"yiisoft/yii2-bootstrap": "self.version", "yiisoft/yii2-bootstrap": "self.version",
"yiisoft/yii2-codeception": "self.version",
"yiisoft/yii2-debug": "self.version", "yiisoft/yii2-debug": "self.version",
"yiisoft/yii2-elasticsearch": "self.version", "yiisoft/yii2-elasticsearch": "self.version",
"yiisoft/yii2-gii": "self.version", "yiisoft/yii2-gii": "self.version",
@ -80,6 +81,7 @@
"autoload": { "autoload": {
"psr-0": { "psr-0": {
"yii\\bootstrap\\": "extensions/", "yii\\bootstrap\\": "extensions/",
"yii\\codeception\\": "extensions/",
"yii\\debug\\": "extensions/", "yii\\debug\\": "extensions/",
"yii\\elasticsearch\\": "extensions/", "yii\\elasticsearch\\": "extensions/",
"yii\\gii\\": "extensions/", "yii\\gii\\": "extensions/",

46
docs/guide/gii.md

@ -8,7 +8,8 @@ as well as complete CRUD controllers.
Installing and configuring Installing and configuring
-------------------------- --------------------------
Gii comes as an offical extension and the preferred way to install this extension is through [composer](http://getcomposer.org/download/). Gii comes as an offical extension and the preferred way to install this extension is through
[composer](http://getcomposer.org/download/).
Either run Either run
@ -42,13 +43,44 @@ http://localhost/path/to/index.php?r=gii
> Note: if you are accessing gii from another IP than localhost, access will be denied by default. > Note: if you are accessing gii from another IP than localhost, access will be denied by default.
You have to add allowed IPs to the configuration in this case: You have to add allowed IPs to the configuration in this case:
```php >
'gii' => [ ```php
'class' => 'yii\gii\Module', 'gii' => [
'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // adjust this to your needs 'class' => 'yii\gii\Module',
], 'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // adjust this to your needs
``` ],
```
### Basic application
In basic application template configuration structure is a bit different so Gii should be configured in
`config/web.php`:
```php
// ...
if (YII_ENV_DEV)
{
// configuration adjustments for 'dev' environment
$config['preload'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module';
$config['modules']['gii'] = 'yii\gii\Module'; // <--- here
}
```
So in order to adjust IP address you need to do it like the following:
```php
if (YII_ENV_DEV)
{
// configuration adjustments for 'dev' environment
$config['preload'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'],
];
}
```
How to use it How to use it
------------- -------------

3
extensions/yii/bootstrap/CHANGELOG.md

@ -4,7 +4,8 @@ Yii Framework 2 bootstrap extension Change Log
2.0.0 beta under development 2.0.0 beta under development
---------------------------- ----------------------------
- no changes in this release. - Enh #1474: Added option to make NavBar 100% width (cebe)
- Enh #1553: Only add navbar-default class to NavBar when no other class is specified (cebe)
2.0.0 alpha, December 1, 2013 2.0.0 alpha, December 1, 2013
----------------------------- -----------------------------

26
extensions/yii/bootstrap/NavBar.php

@ -50,8 +50,15 @@ class NavBar extends Widget
* @var array the HTML attributes of the brand link. * @var array the HTML attributes of the brand link.
*/ */
public $brandOptions = []; public $brandOptions = [];
/**
* @var string text to show for screen readers for the button to toggle the navbar.
*/
public $screenReaderToggleText = 'Toggle navigation'; public $screenReaderToggleText = 'Toggle navigation';
/**
* @var bool whether the navbar content should be included in a `container` div which adds left and right padding.
* Set this to false for a 100% width navbar.
*/
public $padded = true;
/** /**
* Initializes the widget. * Initializes the widget.
@ -60,14 +67,19 @@ class NavBar extends Widget
{ {
parent::init(); parent::init();
$this->clientOptions = false; $this->clientOptions = false;
Html::addCssClass($this->options, 'navbar navbar-default'); Html::addCssClass($this->options, 'navbar');
if ($this->options['class'] == 'navbar') {
Html::addCssClass($this->options, 'navbar-default');
}
Html::addCssClass($this->brandOptions, 'navbar-brand'); Html::addCssClass($this->brandOptions, 'navbar-brand');
if (empty($this->options['role'])) { if (empty($this->options['role'])) {
$this->options['role'] = 'navigation'; $this->options['role'] = 'navigation';
} }
echo Html::beginTag('nav', $this->options); echo Html::beginTag('nav', $this->options);
echo Html::beginTag('div', ['class' => 'container']); if ($this->padded) {
echo Html::beginTag('div', ['class' => 'container']);
}
echo Html::beginTag('div', ['class' => 'navbar-header']); echo Html::beginTag('div', ['class' => 'navbar-header']);
echo $this->renderToggleButton(); echo $this->renderToggleButton();
@ -76,7 +88,7 @@ class NavBar extends Widget
} }
echo Html::endTag('div'); echo Html::endTag('div');
echo Html::beginTag('div', ['class' => 'collapse navbar-collapse navbar-ex1-collapse']); echo Html::beginTag('div', ['class' => "collapse navbar-collapse navbar-{$this->options['id']}-collapse"]);
} }
/** /**
@ -86,7 +98,9 @@ class NavBar extends Widget
{ {
echo Html::endTag('div'); echo Html::endTag('div');
echo Html::endTag('div'); if ($this->padded) {
echo Html::endTag('div');
}
echo Html::endTag('nav'); echo Html::endTag('nav');
BootstrapPluginAsset::register($this->getView()); BootstrapPluginAsset::register($this->getView());
} }
@ -102,7 +116,7 @@ class NavBar extends Widget
return Html::button("{$screenReader}\n{$bar}\n{$bar}\n{$bar}", [ return Html::button("{$screenReader}\n{$bar}\n{$bar}\n{$bar}", [
'class' => 'navbar-toggle', 'class' => 'navbar-toggle',
'data-toggle' => 'collapse', 'data-toggle' => 'collapse',
'data-target' => '.navbar-ex1-collapse', 'data-target' => ".navbar-{$this->options['id']}-collapse",
]); ]);
} }
} }

55
extensions/yii/codeception/BasePage.php

@ -0,0 +1,55 @@
<?php
namespace yii\codeception;
/**
* Represents a web page to test
*
* Pages extend from this class and declare UI map for this page via
* static properties. CSS or XPath allowed.
*
* Here is an example:
*
* ```php
* public static $usernameField = '#username';
* public static $formSubmitButton = "#mainForm input[type=submit]";
* ```
*
* @author Mark Jebri <mark.github@yandex.ru>
* @since 2.0
*/
abstract class BasePage
{
/**
* @var string include url of current page. This property has to be overwritten by subclasses
*/
public static $URL = '';
/**
* @var \Codeception\AbstractGuy
*/
protected $guy;
public function __construct($I)
{
$this->guy = $I;
}
/**
* Basic route example for your current URL
* You can append any additional parameter to URL
* and use it in tests like: EditPage::route('/123-post');
*/
public static function route($param)
{
return static::$URL.$param;
}
/**
* @param $I
* @return static
*/
public static function of($I)
{
return new static($I);
}
}

7
extensions/yii/codeception/CHANGELOG.md

@ -0,0 +1,7 @@
Yii Framework 2 Codeception extension Change Log
================================================
2.0.0 beta under development
----------------------------
- Initial release.

32
extensions/yii/codeception/LICENSE.md

@ -0,0 +1,32 @@
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.

128
extensions/yii/codeception/README.md

@ -0,0 +1,128 @@
Codeception Extension for Yii 2
===============================
This extension provides a `Codeception` mail solution for Yii 2. It includes some classes that are useful
for unit-testing (```TestCase```) or for codeception page-objects (```BasePage```).
When using codeception page-objects they have some similar code, this code was extracted and put into the ```BasePage```
class to reduce code duplication. Simply extend your page object from this class, like it is done in ```yii2-basic``` and
```yii2-advanced``` boilerplates.
For unit testing there is a ```TestCase``` class which holds some common features like application creation before each test
and application destroy after each test. You can configure your application by this class. ```TestCase``` is extended from ```PHPUnit_Framework_TestCase``` so all
methods and assertions are available.
```php
SomeConsoleTest extends yii\codeception\TestCase
{
# by default it is @tests/unit/_bootstrap.php which holds some basic things like:
# including composer autoload, include BaseYii class.
public $baseConfig = '@app/config/console.php';
public $applicationClass = 'yii\console\Application';
}
```
Dont forget that you still need to include autoload and BaseYii class, like in the _bootstrap.php file (comments above).
You also can reconfigure some components for tests, for this purpose there is a ```$config``` property in the testcase.
```php
SomeOtherTest extends yii\codeception\TestCase
{
public $config = [
'components' => [
'mail' => [
'useFileTransport' => true,
],
]
];
}
```
Because of Codeception buffers all output you cant make simple ```var_dump()``` in the TestCase, instead you need to use
```Codeception\Util\Debug::debug()``` function and then run test with ```--debug``` key, for example:
```php
use \Codeception\Util\Debug;
SomeDebugTest extends yii\codeception\TestCase
{
public function testSmth()
{
Debug::debug('some my string');
Debug::debug($someArray);
Debug::debug($someObject);
}
}
```
Then run command ```php codecept.phar run --debug unit/SomeDebugTest``` (Codeception also available through composer) and you will see in output:
```html
some my string
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
yii\web\User Object
(
[identityClass] => app\models\User
[enableAutoLogin] =>
[loginUrl] => Array
(
[0] => site/login
)
[identityCookie] => Array
(
[name] => _identity
[httpOnly] => 1
)
[authTimeout] =>
[autoRenewCookie] => 1
[idVar] => __id
[authTimeoutVar] => __expire
[returnUrlVar] => __returnUrl
[_access:yii\web\User:private] => Array
(
)
[_identity:yii\web\User:private] =>
[_events:yii\base\Component:private] =>
[_behaviors:yii\base\Component:private] =>
)
```
For further instructions refer to the related section in the Yii Definitive Guide (https://github.com/yiisoft/yii2/blob/master/docs/guide/testing.md).
Installation
------------
The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
Either run
```
php composer.phar require yiisoft/yii2-codeception "*"
```
or add
```json
"yiisoft/yii2-codeception": "*"
```
to the require section of your composer.json.

56
extensions/yii/codeception/TestCase.php

@ -0,0 +1,56 @@
<?php
namespace yii\codeception;
use Yii;
use yii\helpers\ArrayHelper;
/**
* TestCase is the base class for all codeception unit tests
*
* @author Mark Jebri <mark.github@yandex.ru>
* @since 2.0
*/
class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* @var array|string Your application base config that will be used for creating application each time before test.
* This can be an array or alias, pointing to the config file. For example for console application it can be
* '@tests/unit/console_bootstrap.php' that can be similar to existing unit tests bootstrap file.
*/
public static $applicationConfig = '@app/config/web.php';
/**
* @var array|string Your application config, will be merged with base config when creating application. Can be an alias too.
*/
protected $config = [];
/**
* Created application class
* @var string
*/
protected $applicationClass = 'yii\web\Application';
protected function tearDown()
{
$this->destroyApplication();
parent::tearDown();
}
/**
* Sets up `Yii::$app`.
*/
protected function mockApplication()
{
$baseConfig = is_array(static::$applicationConfig) ? static::$applicationConfig : require(Yii::getAlias(static::$applicationConfig));
$config = is_array($this->config)? $this->config : require(Yii::getAlias($this->config));
new $this->applicationClass(ArrayHelper::merge($baseConfig,$config));
}
/**
* Destroys an application created via [[mockApplication]].
*/
protected function destroyApplication()
{
\Yii::$app = null;
}
}

26
extensions/yii/codeception/composer.json

@ -0,0 +1,26 @@
{
"name": "yiisoft/yii2-codeception",
"description": "The Codeception integration for the Yii framework",
"keywords": ["yii", "codeception"],
"type": "yii2-extension",
"license": "BSD-3-Clause",
"support": {
"forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"authors": [
{
"name": "Mark Jebri",
"email": "mark.github@yandex.ru"
}
],
"require": {
"yiisoft/yii2": "*"
},
"autoload": {
"psr-0": { "yii\\codeception\\": "" }
},
"target-dir": "yii/codeception"
}

14
extensions/yii/elasticsearch/QueryBuilder.php

@ -139,6 +139,7 @@ class QueryBuilder extends \yii\base\Object
public function buildCondition($condition) public function buildCondition($condition)
{ {
static $builders = array( static $builders = array(
'not' => 'buildNotCondition',
'and' => 'buildAndCondition', 'and' => 'buildAndCondition',
'or' => 'buildAndCondition', 'or' => 'buildAndCondition',
'between' => 'buildBetweenCondition', 'between' => 'buildBetweenCondition',
@ -196,6 +197,19 @@ class QueryBuilder extends \yii\base\Object
return count($parts) === 1 ? $parts[0] : ['and' => $parts]; return count($parts) === 1 ? $parts[0] : ['and' => $parts];
} }
private function buildNotCondition($operator, $operands, &$params)
{
if (count($operands) != 1) {
throw new InvalidParamException("Operator '$operator' requires exactly one operand.");
}
$operand = reset($operands);
if (is_array($operand)) {
$operand = $this->buildCondition($operand, $params);
}
return [$operator => $operand];
}
private function buildAndCondition($operator, $operands) private function buildAndCondition($operator, $operands)
{ {
$parts = []; $parts = [];

14
extensions/yii/redis/LuaScriptBuilder.php

@ -219,6 +219,7 @@ EOF;
public function buildCondition($condition, &$columns) public function buildCondition($condition, &$columns)
{ {
static $builders = [ static $builders = [
'not' => 'buildNotCondition',
'and' => 'buildAndCondition', 'and' => 'buildAndCondition',
'or' => 'buildAndCondition', 'or' => 'buildAndCondition',
'between' => 'buildBetweenCondition', 'between' => 'buildBetweenCondition',
@ -269,6 +270,19 @@ EOF;
return count($parts) === 1 ? $parts[0] : '(' . implode(') and (', $parts) . ')'; return count($parts) === 1 ? $parts[0] : '(' . implode(') and (', $parts) . ')';
} }
private function buildNotCondition($operator, $operands, &$params)
{
if (count($operands) != 1) {
throw new InvalidParamException("Operator '$operator' requires exactly one operand.");
}
$operand = reset($operands);
if (is_array($operand)) {
$operand = $this->buildCondition($operand, $params);
}
return "!($operand)";
}
private function buildAndCondition($operator, $operands, &$columns) private function buildAndCondition($operator, $operands, &$columns)
{ {
$parts = []; $parts = [];

4
framework/CHANGELOG.md

@ -8,17 +8,21 @@ Yii Framework 2 Change Log
- Bug #1497: Localized view files are not correctly returned (mintao) - Bug #1497: Localized view files are not correctly returned (mintao)
- Bug #1500: Log messages exported to files are not separated by newlines (omnilight, qiangxue) - Bug #1500: Log messages exported to files are not separated by newlines (omnilight, qiangxue)
- Bug #1509: The SQL for creating Postgres RBAC tables is incorrect (qiangxue) - Bug #1509: The SQL for creating Postgres RBAC tables is incorrect (qiangxue)
- Bug #1545: It was not possible to execute db Query twice, params where missing (cebe)
- Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) - Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark)
- Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark) - Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark)
- Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) - Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe)
- Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) - Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue)
- Enh #1437: Added ListView::viewParams (qiangxue) - Enh #1437: Added ListView::viewParams (qiangxue)
- Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) - Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe)
- Enh #1523: Query conditions now allow to use the NOT operator (cebe)
- Enh #1552: It is now possible to use multiple bootstrap NavBar in a single page (Alex-Code)
- Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark) - Enh: Added `favicon.ico` and `robots.txt` to defauly application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) - Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
- Enh: Support for file aliases in console command 'message' (omnilight) - Enh: Support for file aliases in console command 'message' (omnilight)
- Chg: Renamed yii\jui\Widget::clientEventsMap to clientEventMap (qiangxue) - Chg: Renamed yii\jui\Widget::clientEventsMap to clientEventMap (qiangxue)
- New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) - New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul)
- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo)
2.0.0 alpha, December 1, 2013 2.0.0 alpha, December 1, 2013
--------------------------- ---------------------------

1
framework/yii/base/Application.php

@ -370,6 +370,7 @@ abstract class Application extends Module
/** /**
* Sets the time zone used by this application. * Sets the time zone used by this application.
* This is a simple wrapper of PHP function date_default_timezone_set(). * This is a simple wrapper of PHP function date_default_timezone_set().
* Refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available timezones.
* @param string $value the time zone used by this application. * @param string $value the time zone used by this application.
* @see http://php.net/manual/en/function.date-default-timezone-set.php * @see http://php.net/manual/en/function.date-default-timezone-set.php
*/ */

5
framework/yii/db/ActiveQuery.php

@ -122,7 +122,6 @@ class ActiveQuery extends Query implements ActiveQueryInterface
$db = $modelClass::getDb(); $db = $modelClass::getDb();
} }
$params = $this->params;
if ($this->sql === null) { if ($this->sql === null) {
if ($this->from === null) { if ($this->from === null) {
$tableName = $modelClass::tableName(); $tableName = $modelClass::tableName();
@ -131,8 +130,8 @@ class ActiveQuery extends Query implements ActiveQueryInterface
} }
$this->from = [$tableName]; $this->from = [$tableName];
} }
list ($this->sql, $params) = $db->getQueryBuilder()->build($this); list ($this->sql, $this->params) = $db->getQueryBuilder()->build($this);
} }
return $db->createCommand($this->sql, $params); return $db->createCommand($this->sql, $this->params);
} }
} }

25
framework/yii/db/QueryBuilder.php

@ -788,6 +788,7 @@ class QueryBuilder extends \yii\base\Object
public function buildCondition($condition, &$params) public function buildCondition($condition, &$params)
{ {
static $builders = [ static $builders = [
'NOT' => 'buildNotCondition',
'AND' => 'buildAndCondition', 'AND' => 'buildAndCondition',
'OR' => 'buildAndCondition', 'OR' => 'buildAndCondition',
'BETWEEN' => 'buildBetweenCondition', 'BETWEEN' => 'buildBetweenCondition',
@ -878,6 +879,30 @@ class QueryBuilder extends \yii\base\Object
} }
/** /**
* Inverts an SQL expressions with `NOT` operator.
* @param string $operator the operator to use for connecting the given operands
* @param array $operands the SQL expressions to connect.
* @param array $params the binding parameters to be populated
* @return string the generated SQL expression
* @throws InvalidParamException if wrong number of operands have been given.
*/
public function buildNotCondition($operator, $operands, &$params)
{
if (count($operands) != 1) {
throw new InvalidParamException("Operator '$operator' requires exactly one operand.");
}
$operand = reset($operands);
if (is_array($operand)) {
$operand = $this->buildCondition($operand, $params);
}
if ($operand === '') {
return '';
}
return "$operator ($operand)";
}
/**
* Creates an SQL expressions with the `BETWEEN` operator. * Creates an SQL expressions with the `BETWEEN` operator.
* @param string $operator the operator to use (e.g. `BETWEEN` or `NOT BETWEEN`) * @param string $operator the operator to use (e.g. `BETWEEN` or `NOT BETWEEN`)
* @param array $operands the first operand is the column name. The second and third operands * @param array $operands the first operand is the column name. The second and third operands

2
framework/yii/helpers/BaseSecurity.php

@ -178,7 +178,7 @@ class BaseSecurity
/** /**
* Returns a secret key associated with the specified name. * Returns a secret key associated with the specified name.
* If the secret key does not exist, a random key will be generated * If the secret key does not exist, a random key will be generated
* and saved in the file "keys.data" under the application's runtime directory * and saved in the file "keys.json" under the application's runtime directory
* so that the same secret key can be returned in future requests. * so that the same secret key can be returned in future requests.
* @param string $name the name that is associated with the secret key * @param string $name the name that is associated with the secret key
* @param integer $length the length of the key that should be generated if not exists * @param integer $length the length of the key that should be generated if not exists

29
framework/yii/i18n/Formatter.php

@ -39,6 +39,15 @@ class Formatter extends \yii\base\Formatter
*/ */
public $locale; public $locale;
/** /**
* @var string|\IntlTimeZone|\DateTimeZone the timezone to use for formatting time and date values.
* This can be any value that may be passed to [date_default_timezone_set()](http://www.php.net/manual/en/function.date-default-timezone-set.php)
* e.g. `UTC`, `Europe/Berlin` or `America/Chicago`.
* Refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available timezones.
* This can also be an IntlTimeZone or a DateTimeZone object.
* If not set, [[\yii\base\Application::timezone]] will be used.
*/
public $timeZone;
/**
* @var string the default format string to be used to format a date. * @var string the default format string to be used to format a date.
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths. * This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
@ -84,11 +93,14 @@ class Formatter extends \yii\base\Formatter
public function init() public function init()
{ {
if (!extension_loaded('intl')) { if (!extension_loaded('intl')) {
throw new InvalidConfigException('The "intl" PHP extension is not install. It is required to format data values in localized formats.'); throw new InvalidConfigException('The "intl" PHP extension is not installed. It is required to format data values in localized formats.');
} }
if ($this->locale === null) { if ($this->locale === null) {
$this->locale = Yii::$app->language; $this->locale = Yii::$app->language;
} }
if ($this->timeZone === null) {
$this->timeZone = Yii::$app->timeZone;
}
if ($this->decimalSeparator === null || $this->thousandSeparator === null) { if ($this->decimalSeparator === null || $this->thousandSeparator === null) {
$formatter = new NumberFormatter($this->locale, NumberFormatter::DECIMAL); $formatter = new NumberFormatter($this->locale, NumberFormatter::DECIMAL);
if ($this->decimalSeparator === null) { if ($this->decimalSeparator === null) {
@ -125,6 +137,7 @@ class Formatter extends \yii\base\Formatter
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
* *
* @return string the formatted result * @return string the formatted result
* @throws InvalidConfigException when formatting fails due to invalid parameters.
* @see dateFormat * @see dateFormat
*/ */
public function asDate($value, $format = null) public function asDate($value, $format = null)
@ -137,9 +150,9 @@ class Formatter extends \yii\base\Formatter
$format = $this->dateFormat; $format = $this->dateFormat;
} }
if (isset($this->_dateFormats[$format])) { if (isset($this->_dateFormats[$format])) {
$formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], IntlDateFormatter::NONE); $formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], IntlDateFormatter::NONE, $this->timeZone);
} else { } else {
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE); $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $this->timeZone);
if ($formatter !== null) { if ($formatter !== null) {
$formatter->setPattern($format); $formatter->setPattern($format);
} }
@ -166,6 +179,7 @@ class Formatter extends \yii\base\Formatter
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
* *
* @return string the formatted result * @return string the formatted result
* @throws InvalidConfigException when formatting fails due to invalid parameters.
* @see timeFormat * @see timeFormat
*/ */
public function asTime($value, $format = null) public function asTime($value, $format = null)
@ -178,9 +192,9 @@ class Formatter extends \yii\base\Formatter
$format = $this->timeFormat; $format = $this->timeFormat;
} }
if (isset($this->_dateFormats[$format])) { if (isset($this->_dateFormats[$format])) {
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, $this->_dateFormats[$format]); $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, $this->_dateFormats[$format], $this->timeZone);
} else { } else {
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE); $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $this->timeZone);
if ($formatter !== null) { if ($formatter !== null) {
$formatter->setPattern($format); $formatter->setPattern($format);
} }
@ -207,6 +221,7 @@ class Formatter extends \yii\base\Formatter
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
* *
* @return string the formatted result * @return string the formatted result
* @throws InvalidConfigException when formatting fails due to invalid parameters.
* @see datetimeFormat * @see datetimeFormat
*/ */
public function asDatetime($value, $format = null) public function asDatetime($value, $format = null)
@ -219,9 +234,9 @@ class Formatter extends \yii\base\Formatter
$format = $this->datetimeFormat; $format = $this->datetimeFormat;
} }
if (isset($this->_dateFormats[$format])) { if (isset($this->_dateFormats[$format])) {
$formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], $this->_dateFormats[$format]); $formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], $this->_dateFormats[$format], $this->timeZone);
} else { } else {
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE); $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $this->timeZone);
if ($formatter !== null) { if ($formatter !== null) {
$formatter->setPattern($format); $formatter->setPattern($format);
} }

3
framework/yii/validators/UrlValidator.php

@ -16,6 +16,9 @@ use yii\helpers\Json;
/** /**
* UrlValidator validates that the attribute value is a valid http or https URL. * UrlValidator validates that the attribute value is a valid http or https URL.
* *
* Note that this validator only checks if the URL scheme and host part are correct.
* It does not check the rest part of a URL.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */

3
framework/yii/widgets/LinkSorter.php

@ -34,6 +34,7 @@ class LinkSorter extends Widget
public $attributes; public $attributes;
/** /**
* @var array HTML attributes for the sorter container tag. * @var array HTML attributes for the sorter container tag.
* See [[yii\helpers\Html::ul()]] for special attributes.
*/ */
public $options = ['class' => 'sorter']; public $options = ['class' => 'sorter'];
@ -68,6 +69,6 @@ class LinkSorter extends Widget
foreach ($attributes as $name) { foreach ($attributes as $name) {
$links[] = $this->sort->link($name); $links[] = $this->sort->link($name);
} }
return Html::ul($links, ['encode' => false]); return Html::ul($links, array_merge($this->options, ['encode' => false]));
} }
} }

4
tests/unit/framework/i18n/FormatterTest.php

@ -28,7 +28,9 @@ class FormatterTest extends TestCase
if (!extension_loaded('intl')) { if (!extension_loaded('intl')) {
$this->markTestSkipped('intl extension is required.'); $this->markTestSkipped('intl extension is required.');
} }
$this->mockApplication(); $this->mockApplication([
'timeZone' => 'UTC',
]);
$this->formatter = new Formatter(['locale' => 'en-US']); $this->formatter = new Formatter(['locale' => 'en-US']);
} }

Loading…
Cancel
Save