Commit a315f2b7 by DaSourcerer

Merge with master

parents e944ca18 6261bbda

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

...@@ -19,6 +19,8 @@ Thumbs.db ...@@ -19,6 +19,8 @@ Thumbs.db
composer.phar composer.phar
# composer.lock should not be committed as we always want the latest versions # composer.lock should not be committed as we always want the latest versions
/composer.lock /composer.lock
# composer.lock in applications is ignored in dev repo, will be committed in checked out app repos
/apps/*/composer.lock
# Mac DS_Store Files # Mac DS_Store Files
.DS_Store .DS_Store
......
...@@ -5,14 +5,15 @@ php: ...@@ -5,14 +5,15 @@ php:
- 5.5 - 5.5
- 5.6 - 5.6
- hhvm - hhvm
- hhvm-nightly
# run build against PHP 5.6 and hhvm but allow them to fail # run build against hhvm but allow them to fail
# http://docs.travis-ci.com/user/build-configuration/#Rows-That-are-Allowed-To-Fail # http://docs.travis-ci.com/user/build-configuration/#Rows-That-are-Allowed-To-Fail
matrix: matrix:
fast_finish: true fast_finish: true
allow_failures: allow_failures:
- php: hhvm - php: hhvm
- php: 5.6 - php: hhvm-nightly
services: services:
- redis-server - redis-server
...@@ -20,6 +21,10 @@ services: ...@@ -20,6 +21,10 @@ services:
- elasticsearch - elasticsearch
- mongodb - mongodb
# try running against postgres 9.3
addons:
postgresql: "9.3"
install: install:
- composer self-update && composer --version - composer self-update && composer --version
# core framework: # core framework:
...@@ -28,20 +33,8 @@ install: ...@@ -28,20 +33,8 @@ install:
- tests/unit/data/travis/apc-setup.sh - tests/unit/data/travis/apc-setup.sh
- tests/unit/data/travis/memcache-setup.sh - tests/unit/data/travis/memcache-setup.sh
- tests/unit/data/travis/cubrid-setup.sh - tests/unit/data/travis/cubrid-setup.sh
# basic application: # basic and advanced application:
- composer install --dev --prefer-dist -d apps/basic - tests/unit/data/travis/setup-apps.sh
- cd apps/basic && composer require --dev codeception/codeception:1.8.*@dev codeception/specify:* codeception/verify:*
- php vendor/bin/codecept build && cd ../..
# advanced application:
- composer install --dev --prefer-dist -d apps/advanced
- cd apps/advanced && composer require --dev codeception/codeception:1.8.*@dev codeception/specify:* codeception/verify:*
- ./init --env=Development
- sed -i s/root/travis/ common/config/main-local.php
- cd backend && php ../vendor/bin/codecept build
- cd ../common && php ../vendor/bin/codecept build
- cd ../frontend && php ../vendor/bin/codecept build && cd ../../..
# boot server
- cd apps && php -S localhost:8080 > /dev/null 2>&1 &
before_script: before_script:
- echo 'elasticsearch version ' && curl http://localhost:9200/ - echo 'elasticsearch version ' && curl http://localhost:9200/
...@@ -49,12 +42,8 @@ before_script: ...@@ -49,12 +42,8 @@ before_script:
- psql -U postgres -c 'CREATE DATABASE yiitest;'; - psql -U postgres -c 'CREATE DATABASE yiitest;';
- tests/unit/data/travis/sphinx-setup.sh - tests/unit/data/travis/sphinx-setup.sh
- mongo yii2test --eval 'db.addUser("travis", "test");' - mongo yii2test --eval 'db.addUser("travis", "test");'
- mysql -e 'CREATE DATABASE yii2_advanced_acceptance;'; # basic and advanced application:
- mysql -e 'CREATE DATABASE yii2_advanced_functional;'; - tests/unit/data/travis/init-apps.sh
- mysql -e 'CREATE DATABASE yii2_advanced_unit;';
- cd apps/advanced/frontend/tests/acceptance && php yii migrate --interactive=0
- cd ../functional && php yii migrate --interactive=0
- cd ../unit && php yii migrate --interactive=0 && cd ../../../../..
script: script:
- vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --exclude-group mssql,oci,wincache,xcache,zenddata - vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --exclude-group mssql,oci,wincache,xcache,zenddata
......
...@@ -2,5 +2,5 @@ Contributing to Yii2 ...@@ -2,5 +2,5 @@ Contributing to Yii2
==================== ====================
- [Report an issue](docs/internals/report-an-issue.md) - [Report an issue](docs/internals/report-an-issue.md)
- [Translate documentation or messages](docs/internals/translations.md) - [Translate documentation or messages](docs/internals/translation-workflow.md)
- [Contribute to the core code or fix bugs](docs/internals/getting-started.md) - [Contribute to the core code or fix bugs](docs/internals/getting-started.md)
...@@ -20,10 +20,13 @@ which is the latest stable release of Yii. ...@@ -20,10 +20,13 @@ which is the latest stable release of Yii.
[![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2/v/stable.png)](https://packagist.org/packages/yiisoft/yii2) [![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2/v/stable.png)](https://packagist.org/packages/yiisoft/yii2)
[![Total Downloads](https://poser.pugx.org/yiisoft/yii2/downloads.png)](https://packagist.org/packages/yiisoft/yii2) [![Total Downloads](https://poser.pugx.org/yiisoft/yii2/downloads.png)](https://packagist.org/packages/yiisoft/yii2)
[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master)
[![Build Status](https://secure.travis-ci.org/yiisoft/yii2.png)](http://travis-ci.org/yiisoft/yii2) [![Build Status](https://secure.travis-ci.org/yiisoft/yii2.png)](http://travis-ci.org/yiisoft/yii2)
[![HHVM Status](http://hhvm.h4cc.de/badge/yiisoft/yii2-dev.png)](http://hhvm.h4cc.de/package/yiisoft/yii2-dev)
[![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/coverage.png?s=31d80f1036099e9d6a3e4d7738f6b000b3c3d10e)](https://scrutinizer-ci.com/g/yiisoft/yii2/) [![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/coverage.png?s=31d80f1036099e9d6a3e4d7738f6b000b3c3d10e)](https://scrutinizer-ci.com/g/yiisoft/yii2/)
[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/quality-score.png?s=b1074a1ff6d0b214d54fa5ab7abbb90fc092471d)](https://scrutinizer-ci.com/g/yiisoft/yii2/) [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/quality-score.png?s=b1074a1ff6d0b214d54fa5ab7abbb90fc092471d)](https://scrutinizer-ci.com/g/yiisoft/yii2/)
[![Code Climate](https://codeclimate.com/github/yiisoft/yii2.png)](https://codeclimate.com/github/yiisoft/yii2)
[![Reference Status](https://www.versioneye.com/php/yiisoft:yii2/reference_badge.svg)](https://www.versioneye.com/php/yiisoft:yii2/references)
DIRECTORY STRUCTURE DIRECTORY STRUCTURE
------------------- -------------------
...@@ -53,7 +56,11 @@ DOCUMENTATION ...@@ -53,7 +56,11 @@ DOCUMENTATION
A draft of the [Definitive Guide](docs/guide/README.md) is available. A draft of the [Definitive Guide](docs/guide/README.md) is available.
API docs and a rendering of the definitive guide are currently API docs and a rendering of the definitive guide are currently
available at http://stuff.cebe.cc/yii2docs/ (updated four times per hour) and at http://www.yiiframework.com/doc-2.0/guide-index.html. available under the following urls:
- http://stuff.cebe.cc/yii2docs/ API and Definitive Guide (updated every 15 minutes from the github source)
- http://www.yiiframework.com/doc-2.0/guide-index.html API and Definitive Guide (last updated for the beta release)
- http://stuff.cebe.cc/yii2-guide.pdf The PDF version of the Guide
For 1.1 users, you may refer to [Upgrading from Yii 1.1](docs/guide/intro-upgrade-from-v1.md) For 1.1 users, you may refer to [Upgrading from Yii 1.1](docs/guide/intro-upgrade-from-v1.md)
to have a general idea of what has changed in 2.0. to have a general idea of what has changed in 2.0.
......
...@@ -100,7 +100,7 @@ TESTING ...@@ -100,7 +100,7 @@ TESTING
------- -------
Install additional composer packages: Install additional composer packages:
* `php composer.phar require --dev "codeception/codeception: 1.8.*@dev" "codeception/specify: *" "codeception/verify: *"` * `php composer.phar require --dev codeception/codeception:2.0.* codeception/specify:* codeception/verify:* yiisoft/yii2-faker:*`
This application boilerplate use database in testing, so you should create three databases that are used in tests: This application boilerplate use database in testing, so you should create three databases that are used in tests:
* `yii2_advanced_unit` - database for unit tests; * `yii2_advanced_unit` - database for unit tests;
...@@ -113,7 +113,7 @@ it will upgrade your database to the last state according migrations. ...@@ -113,7 +113,7 @@ it will upgrade your database to the last state according migrations.
To be able to run acceptance tests you need a running webserver. For this you can use the php builtin server and run it in the directory where your main project folder is located. For example if your application is located in `/www/advanced` all you need to is: To be able to run acceptance tests you need a running webserver. For this you can use the php builtin server and run it in the directory where your main project folder is located. For example if your application is located in `/www/advanced` all you need to is:
`cd /www` and then `php -S 127.0.0.1:8080` because the default configuration of acceptance tests expects the url of the application to be `/advanced/`. `cd /www` and then `php -S 127.0.0.1:8080` because the default configuration of acceptance tests expects the url of the application to be `/advanced/`.
If you already have a server configured or your application is not located in a folder called `advanced`, you may need to adjust the `TEST_ENTRY_URL` in `frontend/tests/_bootstrap.php` and `backend/tests/_bootstrap.php`. If you already have a server configured or your application is not located in a folder called `advanced`, you may need to adjust the `test_entry_url` in `backend/codeception.yml` and `frontend/codeception.yml`.
After that is done you should be able to run your tests, for example to run `frontend` tests do: After that is done you should be able to run your tests, for example to run `frontend` tests do:
...@@ -123,4 +123,7 @@ After that is done you should be able to run your tests, for example to run `fro ...@@ -123,4 +123,7 @@ After that is done you should be able to run your tests, for example to run `fro
In similar way you can run tests for other application tiers - `backend`, `console`, `common`. In similar way you can run tests for other application tiers - `backend`, `console`, `common`.
If you already have run `../vendor/bin/codecept build` for each application, you can run all tests by one command: `vendor/bin/codecept run`
You also can adjust you application suite configs and `_bootstrap.php` settings to use other urls and files, as it is can be done in `yii2-basic`. You also can adjust you application suite configs and `_bootstrap.php` settings to use other urls and files, as it is can be done in `yii2-basic`.
Current template also includes [yii2-faker](https://github.com/yiisoft/yii2/tree/master/extensions/faker) extension, that is correctly setup for each application tier.
namespace: backend
actor: Tester
paths: paths:
tests: tests tests: tests
log: tests/_log log: tests/_log
...@@ -16,3 +18,7 @@ modules: ...@@ -16,3 +18,7 @@ modules:
user: '' user: ''
password: '' password: ''
dump: tests/_data/dump.sql dump: tests/_data/dump.sql
config:
# the entry script URL (without host info) for functional and acceptance tests
# PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL
test_entry_url: /advanced/backend/web/index-test.php
<?php <?php
// the entry script URL (without host info) for functional and acceptance tests
// PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL
defined('TEST_ENTRY_URL') or define('TEST_ENTRY_URL', '/advanced/backend/web/index-test.php');
// the entry script file path for functional and acceptance tests
defined('TEST_ENTRY_FILE') or define('TEST_ENTRY_FILE', dirname(__DIR__) . '/web/index-test.php');
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test'); defined('YII_ENV') or define('YII_ENV', 'test');
...@@ -18,6 +11,8 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php'); ...@@ -18,6 +11,8 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../../common/config/aliases.php'); require(__DIR__ . '/../../common/config/aliases.php');
// set correct script paths // set correct script paths
$_SERVER['SCRIPT_FILENAME'] = TEST_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = TEST_ENTRY_URL; // the entry script file path for functional and acceptance tests
$_SERVER['SCRIPT_FILENAME'] = dirname(__DIR__) . '/web/index-test.php';
$_SERVER['SCRIPT_NAME'] = \Codeception\Configuration::config()['config']['test_entry_url'];
$_SERVER['SERVER_NAME'] = 'localhost'; $_SERVER['SERVER_NAME'] = 'localhost';
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
return [ return [
'components' => [ 'components' => [
'mail' => [ 'mailer' => [
'useFileTransport' => true, 'useFileTransport' => true,
], ],
'urlManager' => [ 'urlManager' => [
......
<?php
namespace Codeception\Module;
// here you can define custom functions for CodeGuy
class CodeHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for TestGuy
class TestHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for WebGuy
class WebHelper extends \Codeception\Module
{
}
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
class_name: WebGuy class_name: WebGuy
modules: modules:
enabled: enabled:
- WebHelper
- PhpBrowser - PhpBrowser
- common\tests\_helpers\FixtureHelper - common\tests\_helpers\FixtureHelper
# you can use WebDriver instead of PhpBrowser to test javascript and ajax. # you can use WebDriver instead of PhpBrowser to test javascript and ajax.
......
<?php <?php
use common\tests\_pages\LoginPage; use common\tests\_pages\LoginPage;
use backend\WebGuy;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure login page works'); $I->wantTo('ensure login page works');
......
...@@ -10,7 +10,6 @@ class_name: TestGuy ...@@ -10,7 +10,6 @@ class_name: TestGuy
modules: modules:
enabled: enabled:
- Filesystem - Filesystem
- TestHelper
- Yii2 - Yii2
- common\tests\_helpers\FixtureHelper - common\tests\_helpers\FixtureHelper
config: config:
......
<?php <?php
use common\tests\_pages\LoginPage; use common\tests\_pages\LoginPage;
use backend\TestGuy;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure login page works'); $I->wantTo('ensure login page works');
......
<?php <?php
// set correct script paths // set correct script paths
$_SERVER['SCRIPT_FILENAME'] = TEST_ENTRY_FILE; $_SERVER['SCRIPT_FILENAME'] = dirname(dirname(__DIR__)) . '/web/index-test.php';
$_SERVER['SCRIPT_NAME'] = TEST_ENTRY_URL; $_SERVER['SCRIPT_NAME'] = \Codeception\Configuration::config()['config']['test_entry_url'];;
return yii\helpers\ArrayHelper::merge( return yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../config/main.php'), require(__DIR__ . '/../../config/main.php'),
......
...@@ -4,5 +4,3 @@ ...@@ -4,5 +4,3 @@
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
class_name: CodeGuy class_name: CodeGuy
modules:
enabled: [CodeHelper]
...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge( ...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge(
'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit',
], ],
], ],
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => '@backend/tests/unit/fixtures/data',
'templatePath' => '@commmon/tests/templates/fixtures'
],
],
] ]
); );
...@@ -5,10 +5,9 @@ use yii\bootstrap\Nav; ...@@ -5,10 +5,9 @@ use yii\bootstrap\Nav;
use yii\bootstrap\NavBar; use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs; use yii\widgets\Breadcrumbs;
/** /* @var $this \yii\web\View */
* @var \yii\web\View $this /* @var $content string */
* @var string $content
*/
AppAsset::register($this); AppAsset::register($this);
?> ?>
<?php $this->beginPage() ?> <?php $this->beginPage() ?>
...@@ -17,6 +16,7 @@ AppAsset::register($this); ...@@ -17,6 +16,7 @@ AppAsset::register($this);
<head> <head>
<meta charset="<?= Yii::$app->charset ?>"/> <meta charset="<?= Yii::$app->charset ?>"/>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<?= Html::csrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title> <title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?> <?php $this->head() ?>
</head> </head>
......
...@@ -2,12 +2,10 @@ ...@@ -2,12 +2,10 @@
use yii\helpers\Html; use yii\helpers\Html;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $name string */
* @var string $name /* @var $message string */
* @var string $message /* @var $exception Exception */
* @var Exception $exception
*/
$this->title = $name; $this->title = $name;
?> ?>
......
<?php <?php
/** /* @var $this yii\web\View */
* @var yii\web\View $this
*/
$this->title = 'My Yii Application'; $this->title = 'My Yii Application';
?> ?>
<div class="site-index"> <div class="site-index">
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $form yii\widgets\ActiveForm */
* @var yii\widgets\ActiveForm $form /* @var $model \common\models\LoginForm */
* @var \common\models\LoginForm $model
*/
$this->title = 'Login'; $this->title = 'Login';
$this->params['breadcrumbs'][] = $this->title; $this->params['breadcrumbs'][] = $this->title;
?> ?>
......
html, html,
body { body {
height: 100%; height: 100%;
} }
.wrap { .wrap {
min-height: 100%; min-height: 100%;
height: auto; height: auto;
margin: 0 auto -60px; margin: 0 auto -60px;
padding: 0 0 60px; padding: 0 0 60px;
} }
.wrap > .container { .wrap > .container {
...@@ -15,61 +15,61 @@ body { ...@@ -15,61 +15,61 @@ body {
} }
.footer { .footer {
height: 60px; height: 60px;
background-color: #f5f5f5; background-color: #f5f5f5;
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
padding-top: 20px; padding-top: 20px;
} }
.jumbotron { .jumbotron {
text-align: center; text-align: center;
background-color: transparent; background-color: transparent;
} }
.jumbotron .btn { .jumbotron .btn {
font-size: 21px; font-size: 21px;
padding: 14px 24px; padding: 14px 24px;
} }
.not-set { .not-set {
color: #c55; color: #c55;
font-style: italic; font-style: italic;
} }
/* add sorting icons to gridview sort links */ /* add sorting icons to gridview sort links */
a.asc:after, a.desc:after { a.asc:after, a.desc:after {
position: relative; position: relative;
top: 1px; top: 1px;
display: inline-block; display: inline-block;
font-family: 'Glyphicons Halflings'; font-family: 'Glyphicons Halflings';
font-style: normal; font-style: normal;
font-weight: normal; font-weight: normal;
line-height: 1; line-height: 1;
padding-left: 5px; padding-left: 5px;
} }
a.asc:after { a.asc:after {
content: /*"\e113"*/ "\e151"; content: /*"\e113"*/ "\e151";
} }
a.desc:after { a.desc:after {
content: /*"\e114"*/ "\e152"; content: /*"\e114"*/ "\e152";
} }
.sort-numerical a.asc:after { .sort-numerical a.asc:after {
content: "\e153"; content: "\e153";
} }
.sort-numerical a.desc:after { .sort-numerical a.desc:after {
content: "\e154"; content: "\e154";
} }
.sort-ordinal a.asc:after { .sort-ordinal a.asc:after {
content: "\e155"; content: "\e155";
} }
.sort-ordinal a.desc:after { .sort-ordinal a.desc:after {
content: "\e156"; content: "\e156";
} }
.grid-view th { .grid-view th {
...@@ -77,15 +77,15 @@ a.desc:after { ...@@ -77,15 +77,15 @@ a.desc:after {
} }
.hint-block { .hint-block {
display: block; display: block;
margin-top: 5px; margin-top: 5px;
color: #999; color: #999;
} }
.error-summary { .error-summary {
color: #a94442; color: #a94442;
background: #fdf7f7; background: #fdf7f7;
border-left: 3px solid #eed3d7; border-left: 3px solid #eed3d7;
padding: 10px 20px; padding: 10px 20px;
margin: 0 0 15px 0; margin: 0 0 15px 0;
} }
include:
- common
- console
- backend
- frontend
paths:
log: tests/_log
settings:
colors: true
namespace: common
actor: Tester
paths: paths:
tests: tests tests: tests
log: tests/_log log: tests/_log
......
<?php <?php
return [ return [
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'extensions' => require(__DIR__ . '/../../vendor/yiisoft/extensions.php'),
'components' => [ 'components' => [
'cache' => [ 'cache' => [
'class' => 'yii\caching\FileCache', 'class' => 'yii\caching\FileCache',
......
<?php <?php
use yii\helpers\Html; use yii\helpers\Html;
/** /* @var $this \yii\web\View view component instance */
* @var \yii\web\View $this /* @var $message \yii\mail\MessageInterface the message being composed */
* @var \yii\mail\BaseMessage $content /* @var $content string main view render result */
*/
?> ?>
<?php $this->beginPage() ?> <?php $this->beginPage() ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
......
<?php <?php
use yii\helpers\Html; use yii\helpers\Html;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $user common\models\User */
* @var common\models\User $user
*/
$resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); $resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]);
?> ?>
......
...@@ -33,13 +33,16 @@ class LoginForm extends Model ...@@ -33,13 +33,16 @@ class LoginForm extends Model
/** /**
* Validates the password. * Validates the password.
* This method serves as the inline validation for password. * This method serves as the inline validation for password.
*
* @param string $attribute the attribute currently being validated
* @param array $params the additional name-value pairs given in the rule
*/ */
public function validatePassword() public function validatePassword($attribute, $params)
{ {
if (!$this->hasErrors()) { if (!$this->hasErrors()) {
$user = $this->getUser(); $user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) { if (!$user || !$user->validatePassword($this->password)) {
$this->addError('password', 'Incorrect username or password.'); $this->addError($attribute, 'Incorrect username or password.');
} }
} }
} }
......
<?php <?php
namespace common\models; namespace common\models;
use Yii;
use yii\base\NotSupportedException; use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord; use yii\db\ActiveRecord;
use yii\helpers\Security;
use yii\web\IdentityInterface; use yii\web\IdentityInterface;
/** /**
...@@ -25,45 +26,46 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -25,45 +26,46 @@ class User extends ActiveRecord implements IdentityInterface
{ {
const STATUS_DELETED = 0; const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10; const STATUS_ACTIVE = 10;
const ROLE_USER = 10; const ROLE_USER = 10;
/** /**
* @inheritdoc * @inheritdoc
*/ */
public static function tableName()
{
return '{{%user}}';
}
/**
* @inheritdoc
*/
public function behaviors() public function behaviors()
{ {
return [ return [
'timestamp' => [ TimestampBehavior::className(),
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
],
]; ];
} }
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function rules() public function rules()
{ {
return [ return [
['status', 'default', 'value' => self::STATUS_ACTIVE], ['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
['role', 'default', 'value' => self::ROLE_USER], ['role', 'default', 'value' => self::ROLE_USER],
['role', 'in', 'range' => [self::ROLE_USER]], ['role', 'in', 'range' => [self::ROLE_USER]],
]; ];
} }
/** /**
* @inheritdoc * @inheritdoc
*/ */
public static function findIdentity($id) public static function findIdentity($id)
{ {
return static::findOne($id); return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
} }
/** /**
...@@ -77,7 +79,7 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -77,7 +79,7 @@ class User extends ActiveRecord implements IdentityInterface
/** /**
* Finds user by username * Finds user by username
* *
* @param string $username * @param string $username
* @return static|null * @return static|null
*/ */
public static function findByUsername($username) public static function findByUsername($username)
...@@ -88,12 +90,12 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -88,12 +90,12 @@ class User extends ActiveRecord implements IdentityInterface
/** /**
* Finds user by password reset token * Finds user by password reset token
* *
* @param string $token password reset token * @param string $token password reset token
* @return static|null * @return static|null
*/ */
public static function findByPasswordResetToken($token) public static function findByPasswordResetToken($token)
{ {
$expire = \Yii::$app->params['user.passwordResetTokenExpire']; $expire = Yii::$app->params['user.passwordResetTokenExpire'];
$parts = explode('_', $token); $parts = explode('_', $token);
$timestamp = (int) end($parts); $timestamp = (int) end($parts);
if ($timestamp + $expire < time()) { if ($timestamp + $expire < time()) {
...@@ -134,12 +136,12 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -134,12 +136,12 @@ class User extends ActiveRecord implements IdentityInterface
/** /**
* Validates password * Validates password
* *
* @param string $password password to validate * @param string $password password to validate
* @return boolean if password provided is valid for current user * @return boolean if password provided is valid for current user
*/ */
public function validatePassword($password) public function validatePassword($password)
{ {
return Security::validatePassword($password, $this->password_hash); return Yii::$app->security->validatePassword($password, $this->password_hash);
} }
/** /**
...@@ -149,7 +151,7 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -149,7 +151,7 @@ class User extends ActiveRecord implements IdentityInterface
*/ */
public function setPassword($password) public function setPassword($password)
{ {
$this->password_hash = Security::generatePasswordHash($password); $this->password_hash = Yii::$app->security->generatePasswordHash($password);
} }
/** /**
...@@ -157,7 +159,7 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -157,7 +159,7 @@ class User extends ActiveRecord implements IdentityInterface
*/ */
public function generateAuthKey() public function generateAuthKey()
{ {
$this->auth_key = Security::generateRandomKey(); $this->auth_key = Yii::$app->security->generateRandomString();
} }
/** /**
...@@ -165,7 +167,7 @@ class User extends ActiveRecord implements IdentityInterface ...@@ -165,7 +167,7 @@ class User extends ActiveRecord implements IdentityInterface
*/ */
public function generatePasswordResetToken() public function generatePasswordResetToken()
{ {
$this->password_reset_token = Security::generateRandomKey() . '_' . time(); $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
} }
/** /**
......
# these files are auto generated by codeception build
/unit/CodeGuy.php
/functional/TestGuy.php
/acceptance/WebGuy.php
<?php <?php
// the entry script URL (without host info) for functional and acceptance tests
// PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL
defined('TEST_ENTRY_URL') or define('TEST_ENTRY_URL', '/index-test.php');
// the entry script file path for functional and acceptance tests
defined('TEST_ENTRY_FILE') or define('TEST_ENTRY_FILE', dirname(__DIR__) . '/index-test.php');
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test'); defined('YII_ENV') or define('YII_ENV', 'test');
...@@ -18,6 +11,4 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php'); ...@@ -18,6 +11,4 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../../common/config/aliases.php'); require(__DIR__ . '/../../common/config/aliases.php');
// set correct script paths // set correct script paths
$_SERVER['SCRIPT_FILENAME'] = TEST_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = TEST_ENTRY_URL;
$_SERVER['SERVER_NAME'] = 'localhost'; $_SERVER['SERVER_NAME'] = 'localhost';
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
return [ return [
'components' => [ 'components' => [
'mail' => [ 'mailer' => [
'useFileTransport' => true, 'useFileTransport' => true,
], ],
'urlManager' => [ 'urlManager' => [
......
<?php
namespace Codeception\Module;
// here you can define custom functions for CodeGuy
class CodeHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for TestGuy
class TestHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for WebGuy
class WebHelper extends \Codeception\Module
{
}
<?php <?php
/**
* @var $faker \Faker\Generator
* @var $index integer
*/
use yii\helpers\Security; $security = Yii::$app->getSecurity();
return [ return [
'username' => 'userName', 'username' => $faker->userName,
'auth_key' => function ($fixture, $faker, $index) { 'email' => $faker->email,
$fixture['auth_key'] = Security::generateRandomKey(); 'auth_key' => $security->generateRandomString(),
'password_hash' => $security->generatePasswordHash('password_' . $index),
return $fixture; 'password_reset_token' => $security->generateRandomString() . '_' . time(),
}, 'created_at' => time(),
'password_hash' => function ($fixture, $faker, $index) { 'updated_at' => time(),
$fixture['password_hash'] = Security::generatePasswordHash('password_' . $index);
return $fixture;
},
'password_reset_token' => function ($fixture, $faker, $index) {
$fixture['password_reset_token'] = Security::generateRandomKey() . '_' . time();
return $fixture;
},
'created_at' => function ($fixture, $faker, $index) {
$fixture['created_at'] = time();
return $fixture;
},
'updated_at' => function ($fixture, $faker, $index) {
$fixture['updated_at'] = time();
return $fixture;
},
'email' => 'email',
]; ];
...@@ -4,6 +4,3 @@ ...@@ -4,6 +4,3 @@
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
class_name: CodeGuy class_name: CodeGuy
modules:
enabled:
- CodeHelper
...@@ -4,5 +4,5 @@ namespace common\tests\unit; ...@@ -4,5 +4,5 @@ namespace common\tests\unit;
class DbTestCase extends \yii\codeception\DbTestCase class DbTestCase extends \yii\codeception\DbTestCase
{ {
public $appConfig = '@frontend/tests/unit/_config.php'; public $appConfig = '@common/tests/unit/_config.php';
} }
...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge( ...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge(
'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit',
], ],
], ],
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => '@common/tests/unit/fixtures/data',
'templatePath' => '@common/tests/templates/fixtures'
],
],
] ]
); );
<?php
return [
[
'username' => 'bayer.hudson',
'auth_key' => 'HP187Mvq7Mmm3CTU80dLkGmni_FUH_lR',
//password_0
'password_hash' => '$2y$13$EjaPFBnZOQsHdGuHI.xvhuDp1fHpo8hKRSk6yshqa9c5EG8s3C3lO',
'password_reset_token' => 'ExzkCOaYc1L8IOBs4wdTGGbgNiG3Wz1I_1402312317',
'created_at' => '1402312317',
'updated_at' => '1402312317',
'email' => 'nicole.paucek@schultz.info',
],
];
...@@ -3,14 +3,29 @@ ...@@ -3,14 +3,29 @@
namespace common\tests\unit\models; namespace common\tests\unit\models;
use Yii; use Yii;
use frontend\tests\unit\TestCase; use common\tests\unit\DbTestCase;
use common\models\User; use Codeception\Specify;
use yii\helpers\Security; use common\models\LoginForm;
use common\tests\fixtures\UserFixture;
class LoginFormTest extends TestCase class LoginFormTest extends DbTestCase
{ {
use \Codeception\Specify; use Specify;
public function setUp()
{
parent::setUp();
Yii::configure(Yii::$app, [
'components' => [
'user' => [
'class' => 'yii\web\User',
'identityClass' => 'common\models\User',
],
],
]);
}
protected function tearDown() protected function tearDown()
{ {
...@@ -20,10 +35,10 @@ class LoginFormTest extends TestCase ...@@ -20,10 +35,10 @@ class LoginFormTest extends TestCase
public function testLoginNoUser() public function testLoginNoUser()
{ {
$model = $this->mockUser(null); $model = new LoginForm([
'username' => 'not_existing_username',
$model->username = 'some_username'; 'password' => 'not_existing_password',
$model->password = 'some_password'; ]);
$this->specify('user should not be able to login, when there is no identity', function () use ($model) { $this->specify('user should not be able to login, when there is no identity', function () use ($model) {
expect('model should not login user', $model->login())->false(); expect('model should not login user', $model->login())->false();
...@@ -33,10 +48,10 @@ class LoginFormTest extends TestCase ...@@ -33,10 +48,10 @@ class LoginFormTest extends TestCase
public function testLoginWrongPassword() public function testLoginWrongPassword()
{ {
$model = $this->mockUser(new User(['password_hash' => Security::generatePasswordHash('will-not-match')])); $model = new LoginForm([
'username' => 'bayer.hudson',
$model->username = 'demo'; 'password' => 'wrong_password',
$model->password = 'wrong-password'; ]);
$this->specify('user should not be able to login with wrong password', function () use ($model) { $this->specify('user should not be able to login with wrong password', function () use ($model) {
expect('model should not login user', $model->login())->false(); expect('model should not login user', $model->login())->false();
...@@ -47,10 +62,11 @@ class LoginFormTest extends TestCase ...@@ -47,10 +62,11 @@ class LoginFormTest extends TestCase
public function testLoginCorrect() public function testLoginCorrect()
{ {
$model = $this->mockUser(new User(['password_hash' => Security::generatePasswordHash('demo')]));
$model->username = 'demo'; $model = new LoginForm([
$model->password = 'demo'; 'username' => 'bayer.hudson',
'password' => 'password_0',
]);
$this->specify('user should be able to login with correct credentials', function () use ($model) { $this->specify('user should be able to login with correct credentials', function () use ($model) {
expect('model should login user', $model->login())->true(); expect('model should login user', $model->login())->true();
...@@ -59,11 +75,14 @@ class LoginFormTest extends TestCase ...@@ -59,11 +75,14 @@ class LoginFormTest extends TestCase
}); });
} }
private function mockUser($user) public function fixtures()
{ {
$loginForm = $this->getMock('common\models\LoginForm', ['getUser']); return [
$loginForm->expects($this->any())->method('getUser')->will($this->returnValue($user)); 'user' => [
'class' => UserFixture::className(),
return $loginForm; 'dataFile' => '@common/tests/unit/fixtures/data/models/user.php'
],
];
} }
} }
{ {
"name": "yiisoft/yii2-app-advanced", "name": "yiisoft/yii2-app-advanced",
"description": "Yii 2 Advanced Application Template", "description": "Yii 2 Advanced Application Template",
"keywords": ["yii2", "framework", "advanced", "application template"], "keywords": ["yii2", "framework", "advanced", "application template"],
"homepage": "http://www.yiiframework.com/", "homepage": "http://www.yiiframework.com/",
"type": "project", "type": "project",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"support": { "support": {
"issues": "https://github.com/yiisoft/yii2/issues?state=open", "issues": "https://github.com/yiisoft/yii2/issues?state=open",
"forum": "http://www.yiiframework.com/forum/", "forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/", "wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii", "irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2" "source": "https://github.com/yiisoft/yii2"
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"php": ">=5.4.0", "php": ">=5.4.0",
"yiisoft/yii2": "*", "yiisoft/yii2": "*",
"yiisoft/yii2-bootstrap": "*", "yiisoft/yii2-bootstrap": "*",
"yiisoft/yii2-swiftmailer": "*" "yiisoft/yii2-swiftmailer": "*"
}, },
"require-dev": { "require-dev": {
"yiisoft/yii2-codeception": "*", "yiisoft/yii2-codeception": "*",
"yiisoft/yii2-debug": "*", "yiisoft/yii2-debug": "*",
"yiisoft/yii2-gii": "*" "yiisoft/yii2-gii": "*"
}, },
"suggest": { "suggest": {
"codeception/codeception": "Codeception, 1.8.*@dev is currently works well with Yii.", "codeception/codeception": "Codeception, 2.0.* is currently works well with Yii.",
"codeception/specify": "BDD style code blocks for PHPUnit and Codeception", "codeception/specify": "BDD style code blocks for PHPUnit and Codeception",
"codeception/verify": "BDD Assertions for PHPUnit and Codeception", "codeception/verify": "BDD Assertions for PHPUnit and Codeception",
"yiisoft/yii2-faker": "Fixtures generator for Yii2 based on Faker lib" "yiisoft/yii2-faker": "Fixtures generator for Yii2 based on Faker lib"
}, },
"scripts": { "scripts": {
"post-create-project-cmd": [ "post-create-project-cmd": [
"yii\\composer\\Installer::setPermission" "yii\\composer\\Installer::setPermission"
] ]
}, },
"config": { "config": {
"process-timeout": 1800 "process-timeout": 1800
}, },
"extra": { "extra": {
"writable": [ "writable": [
"backend/runtime", "backend/runtime",
"backend/web/assets", "backend/web/assets",
"frontend/runtime", "frontend/runtime",
"frontend/web/assets" "frontend/web/assets"
] ]
} }
} }
namespace: console
actor: Tester
paths: paths:
tests: tests tests: tests
log: tests/_log log: tests/_log
......
<?php <?php
use yii\db\Schema; use yii\db\Schema;
use yii\db\Migration;
class m130524_201442_init extends \yii\db\Migration class m130524_201442_init extends Migration
{ {
public function up() public function up()
{ {
......
<?php <?php
// the entry script URL (without host info) for functional and acceptance tests
// PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL
defined('TEST_ENTRY_URL') or define('TEST_ENTRY_URL', '/index-test.php');
// the entry script file path for functional and acceptance tests
defined('TEST_ENTRY_FILE') or define('TEST_ENTRY_FILE', dirname(__DIR__) . '/index-test.php');
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test'); defined('YII_ENV') or define('YII_ENV', 'test');
...@@ -18,6 +11,4 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php'); ...@@ -18,6 +11,4 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../../common/config/aliases.php'); require(__DIR__ . '/../../common/config/aliases.php');
// set correct script paths // set correct script paths
$_SERVER['SCRIPT_FILENAME'] = TEST_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = TEST_ENTRY_URL;
$_SERVER['SERVER_NAME'] = 'localhost'; $_SERVER['SERVER_NAME'] = 'localhost';
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
return [ return [
'components' => [ 'components' => [
'mail' => [ 'mailer' => [
'useFileTransport' => true, 'useFileTransport' => true,
], ],
'urlManager' => [ 'urlManager' => [
......
<?php
namespace Codeception\Module;
// here you can define custom functions for CodeGuy
class CodeHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for TestGuy
class TestHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for WebGuy
class WebHelper extends \Codeception\Module
{
}
...@@ -4,5 +4,3 @@ ...@@ -4,5 +4,3 @@
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
class_name: CodeGuy class_name: CodeGuy
modules:
enabled: [CodeHelper]
<?php <?php
return yii\helpers\ArrayHelper::merge( return yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../../common/config/main.php'),
require(__DIR__ . '/../../../common/config/main-local.php'),
require(__DIR__ . '/../../config/main.php'), require(__DIR__ . '/../../config/main.php'),
require(__DIR__ . '/../../config/main-local.php'), require(__DIR__ . '/../../config/main-local.php'),
require(__DIR__ . '/../_config.php'), require(__DIR__ . '/../_config.php'),
......
...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge( ...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge(
'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit',
], ],
], ],
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => '@console/tests/unit/fixtures/data',
'templatePath' => '@common/tests/templates/fixtures'
],
],
] ]
); );
<?php <?php
$config = []; $config = [
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => '',
],
],
];
if (!YII_ENV_TEST) { if (!YII_ENV_TEST) {
// configuration adjustments for 'dev' environment // configuration adjustments for 'dev' environment
......
...@@ -8,9 +8,12 @@ return [ ...@@ -8,9 +8,12 @@ return [
'password' => '', 'password' => '',
'charset' => 'utf8', 'charset' => 'utf8',
], ],
'mail' => [ 'mailer' => [
'class' => 'yii\swiftmailer\Mailer', 'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail', 'viewPath' => '@common/mail',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true, 'useFileTransport' => true,
], ],
], ],
......
<?php <?php
$config = []; $config = [
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => '',
],
],
];
if (!YII_ENV_TEST) { if (!YII_ENV_TEST) {
// configuration adjustments for 'dev' environment // configuration adjustments for 'dev' environment
......
...@@ -9,9 +9,15 @@ ...@@ -9,9 +9,15 @@
* return [ * return [
* 'environment name' => [ * 'environment name' => [
* 'path' => 'directory storing the local files', * 'path' => 'directory storing the local files',
* 'writable' => [ * 'setWritable' => [
* // list of directories that should be set writable * // list of directories that should be set writable
* ], * ],
* 'setExecutable' => [
* // list of directories that should be set executable
* ],
* 'setCookieValidationKey' => [
* // list of config files that need to be inserted with automatically generated cookie validation keys
* ],
* ], * ],
* ]; * ];
* ``` * ```
...@@ -19,26 +25,34 @@ ...@@ -19,26 +25,34 @@
return [ return [
'Development' => [ 'Development' => [
'path' => 'dev', 'path' => 'dev',
'writable' => [ 'setWritable' => [
'backend/runtime', 'backend/runtime',
'backend/web/assets', 'backend/web/assets',
'frontend/runtime', 'frontend/runtime',
'frontend/web/assets', 'frontend/web/assets',
], ],
'executable' => [ 'setExecutable' => [
'yii', 'yii',
], ],
'setCookieValidationKey' => [
'backend/config/main-local.php',
'frontend/config/main-local.php',
],
], ],
'Production' => [ 'Production' => [
'path' => 'prod', 'path' => 'prod',
'writable' => [ 'setWritable' => [
'backend/runtime', 'backend/runtime',
'backend/web/assets', 'backend/web/assets',
'frontend/runtime', 'frontend/runtime',
'frontend/web/assets', 'frontend/web/assets',
], ],
'executable' => [ 'setExecutable' => [
'yii', 'yii',
], ],
'setCookieValidationKey' => [
'backend/config/main-local.php',
'frontend/config/main-local.php',
],
], ],
]; ];
<?php <?php
return [ return [
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => '',
],
],
]; ];
...@@ -8,7 +8,7 @@ return [ ...@@ -8,7 +8,7 @@ return [
'password' => '', 'password' => '',
'charset' => 'utf8', 'charset' => 'utf8',
], ],
'mail' => [ 'mailer' => [
'class' => 'yii\swiftmailer\Mailer', 'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail', 'viewPath' => '@common/mail',
], ],
......
<?php <?php
return [ return [
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => '',
],
],
]; ];
namespace: frontend
actor: Tester
paths: paths:
tests: tests tests: tests
log: tests/_log log: tests/_log
...@@ -16,3 +18,7 @@ modules: ...@@ -16,3 +18,7 @@ modules:
user: '' user: ''
password: '' password: ''
dump: tests/_data/dump.sql dump: tests/_data/dump.sql
config:
# the entry script URL (without host info) for functional and acceptance tests
# PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL
test_entry_url: /advanced/frontend/web/index-test.php
...@@ -49,7 +49,7 @@ class ContactForm extends Model ...@@ -49,7 +49,7 @@ class ContactForm extends Model
*/ */
public function sendEmail($email) public function sendEmail($email)
{ {
return Yii::$app->mail->compose() return Yii::$app->mailer->compose()
->setTo($email) ->setTo($email)
->setFrom([$this->email => $this->name]) ->setFrom([$this->email => $this->name])
->setSubject($this->subject) ->setSubject($this->subject)
......
...@@ -35,7 +35,7 @@ class PasswordResetRequestForm extends Model ...@@ -35,7 +35,7 @@ class PasswordResetRequestForm extends Model
*/ */
public function sendEmail() public function sendEmail()
{ {
/** @var User $user */ /* @var $user User */
$user = User::findOne([ $user = User::findOne([
'status' => User::STATUS_ACTIVE, 'status' => User::STATUS_ACTIVE,
'email' => $this->email, 'email' => $this->email,
...@@ -44,7 +44,7 @@ class PasswordResetRequestForm extends Model ...@@ -44,7 +44,7 @@ class PasswordResetRequestForm extends Model
if ($user) { if ($user) {
$user->generatePasswordResetToken(); $user->generatePasswordResetToken();
if ($user->save()) { if ($user->save()) {
return \Yii::$app->mail->compose('passwordResetToken', ['user' => $user]) return \Yii::$app->mailer->compose('passwordResetToken', ['user' => $user])
->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot']) ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot'])
->setTo($this->email) ->setTo($this->email)
->setSubject('Password reset for ' . \Yii::$app->name) ->setSubject('Password reset for ' . \Yii::$app->name)
......
<?php <?php
// the entry script URL (without host info) for functional and acceptance tests
// PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL
defined('TEST_ENTRY_URL') or define('TEST_ENTRY_URL', '/advanced/frontend/web/index-test.php');
// the entry script file path for functional and acceptance tests
defined('TEST_ENTRY_FILE') or define('TEST_ENTRY_FILE', dirname(__DIR__) . '/web/index-test.php');
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test'); defined('YII_ENV') or define('YII_ENV', 'test');
...@@ -18,6 +11,8 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php'); ...@@ -18,6 +11,8 @@ require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../../common/config/aliases.php'); require(__DIR__ . '/../../common/config/aliases.php');
// set correct script paths // set correct script paths
$_SERVER['SCRIPT_FILENAME'] = TEST_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = TEST_ENTRY_URL; // the entry script file path for functional and acceptance tests
$_SERVER['SCRIPT_FILENAME'] = dirname(__DIR__) . '/web/index-test.php';
$_SERVER['SCRIPT_NAME'] = \Codeception\Configuration::config()['config']['test_entry_url'];
$_SERVER['SERVER_NAME'] = 'localhost'; $_SERVER['SERVER_NAME'] = 'localhost';
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
return [ return [
'components' => [ 'components' => [
'mail' => [ 'mailer' => [
'useFileTransport' => true, 'useFileTransport' => true,
], ],
'urlManager' => [ 'urlManager' => [
......
<?php
namespace Codeception\Module;
// here you can define custom functions for CodeGuy
class CodeHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for TestGuy
class TestHelper extends \Codeception\Module
{
}
<?php
namespace Codeception\Module;
// here you can define custom functions for WebGuy
class WebHelper extends \Codeception\Module
{
}
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
class_name: WebGuy class_name: WebGuy
modules: modules:
enabled: enabled:
- WebHelper
- PhpBrowser - PhpBrowser
- common\tests\_helpers\FixtureHelper - common\tests\_helpers\FixtureHelper
# you can use WebDriver instead of PhpBrowser to test javascript and ajax. # you can use WebDriver instead of PhpBrowser to test javascript and ajax.
......
<?php <?php
use frontend\tests\_pages\AboutPage; use frontend\tests\_pages\AboutPage;
use frontend\WebGuy;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure that about works'); $I->wantTo('ensure that about works');
......
<?php <?php
use frontend\tests\_pages\ContactPage; use frontend\tests\_pages\ContactPage;
use frontend\WebGuy;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure that contact works'); $I->wantTo('ensure that contact works');
......
<?php <?php
use frontend\WebGuy;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure that home page works'); $I->wantTo('ensure that home page works');
$I->amOnPage(Yii::$app->homeUrl); $I->amOnPage(Yii::$app->homeUrl);
......
<?php <?php
use common\tests\_pages\LoginPage; use common\tests\_pages\LoginPage;
use frontend\WebGuy;
$I = new WebGuy($scenario); $I = new WebGuy($scenario);
$I->wantTo('ensure login page works'); $I->wantTo('ensure login page works');
......
...@@ -10,7 +10,6 @@ class_name: TestGuy ...@@ -10,7 +10,6 @@ class_name: TestGuy
modules: modules:
enabled: enabled:
- Filesystem - Filesystem
- TestHelper
- Yii2 - Yii2
- common\tests\_helpers\FixtureHelper - common\tests\_helpers\FixtureHelper
config: config:
......
<?php <?php
use frontend\tests\_pages\AboutPage; use frontend\tests\_pages\AboutPage;
use frontend\TestGuy;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure that about works'); $I->wantTo('ensure that about works');
......
<?php <?php
use frontend\tests\_pages\ContactPage; use frontend\tests\_pages\ContactPage;
use frontend\TestGuy;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure that contact works'); $I->wantTo('ensure that contact works');
......
<?php <?php
use frontend\TestGuy;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure that home page works'); $I->wantTo('ensure that home page works');
$I->amOnPage(Yii::$app->homeUrl); $I->amOnPage(Yii::$app->homeUrl);
......
<?php <?php
use common\tests\_pages\LoginPage; use common\tests\_pages\LoginPage;
use frontend\TestGuy;
$I = new TestGuy($scenario); $I = new TestGuy($scenario);
$I->wantTo('ensure login page works'); $I->wantTo('ensure login page works');
......
<?php <?php
// set correct script paths // set correct script paths
$_SERVER['SCRIPT_FILENAME'] = TEST_ENTRY_FILE; $_SERVER['SCRIPT_FILENAME'] = dirname(dirname(__DIR__)) . '/web/index-test.php';
$_SERVER['SCRIPT_NAME'] = TEST_ENTRY_URL; $_SERVER['SCRIPT_NAME'] = \Codeception\Configuration::config()['config']['test_entry_url'];;
return yii\helpers\ArrayHelper::merge( return yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../config/main.php'), require(__DIR__ . '/../../config/main.php'),
......
...@@ -4,5 +4,3 @@ ...@@ -4,5 +4,3 @@
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
class_name: CodeGuy class_name: CodeGuy
modules:
enabled: [CodeHelper]
...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge( ...@@ -11,5 +11,12 @@ return yii\helpers\ArrayHelper::merge(
'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit',
], ],
], ],
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => '@frontend/tests/unit/fixtures/data',
'templatePath' => '@common/tests/templates/fixtures'
],
],
] ]
); );
...@@ -5,7 +5,7 @@ return [ ...@@ -5,7 +5,7 @@ return [
'username' => 'okirlin', 'username' => 'okirlin',
'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv', 'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv',
'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi', 'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi',
'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_1391885313', 'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_' . time(),
'created_at' => '1391885313', 'created_at' => '1391885313',
'updated_at' => '1391885313', 'updated_at' => '1391885313',
'email' => 'brady.renner@rutherford.com', 'email' => 'brady.renner@rutherford.com',
...@@ -14,7 +14,7 @@ return [ ...@@ -14,7 +14,7 @@ return [
'username' => 'troy.becker', 'username' => 'troy.becker',
'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp', 'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp',
'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2', 'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2',
'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_1391885313', 'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_' . time(),
'created_at' => '1391885313', 'created_at' => '1391885313',
'updated_at' => '1391885313', 'updated_at' => '1391885313',
'email' => 'nicolas.dianna@hotmail.com', 'email' => 'nicolas.dianna@hotmail.com',
......
...@@ -14,7 +14,7 @@ class ContactFormTest extends TestCase ...@@ -14,7 +14,7 @@ class ContactFormTest extends TestCase
protected function setUp() protected function setUp()
{ {
parent::setUp(); parent::setUp();
Yii::$app->mail->fileTransportCallback = function ($mailer, $message) { Yii::$app->mailer->fileTransportCallback = function ($mailer, $message) {
return 'testing_message.eml'; return 'testing_message.eml';
}; };
} }
...@@ -54,6 +54,6 @@ class ContactFormTest extends TestCase ...@@ -54,6 +54,6 @@ class ContactFormTest extends TestCase
private function getMessageFile() private function getMessageFile()
{ {
return Yii::getAlias(Yii::$app->mail->fileTransportPath) . '/testing_message.eml'; return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';
} }
} }
...@@ -7,15 +7,17 @@ use frontend\tests\unit\DbTestCase; ...@@ -7,15 +7,17 @@ use frontend\tests\unit\DbTestCase;
use frontend\models\PasswordResetRequestForm; use frontend\models\PasswordResetRequestForm;
use common\tests\fixtures\UserFixture; use common\tests\fixtures\UserFixture;
use common\models\User; use common\models\User;
use Codeception\Specify;
class PasswordResetRequestFormTest extends DbTestCase class PasswordResetRequestFormTest extends DbTestCase
{ {
use \Codeception\Specify; use Specify;
protected function setUp() protected function setUp()
{ {
parent::setUp(); parent::setUp();
Yii::$app->mail->fileTransportCallback = function ($mailer, $message) {
Yii::$app->mailer->fileTransportCallback = function ($mailer, $message) {
return 'testing_message.eml'; return 'testing_message.eml';
}; };
} }
...@@ -23,23 +25,28 @@ class PasswordResetRequestFormTest extends DbTestCase ...@@ -23,23 +25,28 @@ class PasswordResetRequestFormTest extends DbTestCase
protected function tearDown() protected function tearDown()
{ {
@unlink($this->getMessageFile()); @unlink($this->getMessageFile());
parent::tearDown(); parent::tearDown();
} }
public function testSendEmailWrongUser() public function testSendEmailWrongUser()
{ {
$this->specify('no user with such email, message should not be send', function () { $this->specify('no user with such email, message should not be send', function () {
$model = new PasswordResetRequestForm(); $model = new PasswordResetRequestForm();
$model->email = 'not-existing-email@example.com'; $model->email = 'not-existing-email@example.com';
expect('email not send', $model->sendEmail())->false(); expect('email not send', $model->sendEmail())->false();
}); });
$this->specify('user is not active, message should not be send', function () { $this->specify('user is not active, message should not be send', function () {
$model = new PasswordResetRequestForm(); $model = new PasswordResetRequestForm();
$model->email = $this->user[1]['email']; $model->email = $this->user[1]['email'];
expect('email not send', $model->sendEmail())->false(); expect('email not send', $model->sendEmail())->false();
}); });
} }
...@@ -53,11 +60,13 @@ class PasswordResetRequestFormTest extends DbTestCase ...@@ -53,11 +60,13 @@ class PasswordResetRequestFormTest extends DbTestCase
expect('user has valid token', $user->password_reset_token)->notNull(); expect('user has valid token', $user->password_reset_token)->notNull();
$this->specify('message has correct format', function () use ($model) { $this->specify('message has correct format', function () use ($model) {
expect('message file exists', file_exists($this->getMessageFile()))->true(); expect('message file exists', file_exists($this->getMessageFile()))->true();
$message = file_get_contents($this->getMessageFile()); $message = file_get_contents($this->getMessageFile());
expect('message "from" is correct', $message)->contains(Yii::$app->params['supportEmail']); expect('message "from" is correct', $message)->contains(Yii::$app->params['supportEmail']);
expect('message "to" is correct', $message)->contains($model->email); expect('message "to" is correct', $message)->contains($model->email);
}); });
} }
...@@ -66,13 +75,14 @@ class PasswordResetRequestFormTest extends DbTestCase ...@@ -66,13 +75,14 @@ class PasswordResetRequestFormTest extends DbTestCase
return [ return [
'user' => [ 'user' => [
'class' => UserFixture::className(), 'class' => UserFixture::className(),
'dataFile' => '@frontend/tests/unit/fixtures/data/user.php' 'dataFile' => '@frontend/tests/unit/fixtures/data/models/user.php'
], ],
]; ];
} }
private function getMessageFile() private function getMessageFile()
{ {
return Yii::getAlias(Yii::$app->mail->fileTransportPath) . '/testing_message.eml'; return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';
} }
} }
...@@ -9,19 +9,26 @@ use frontend\models\ResetPasswordForm; ...@@ -9,19 +9,26 @@ use frontend\models\ResetPasswordForm;
class ResetPasswordFormTest extends DbTestCase class ResetPasswordFormTest extends DbTestCase
{ {
use \Codeception\Specify; /**
* @expectedException yii\base\InvalidParamException
*/
public function testResetWrongToken()
{
new ResetPasswordForm('notexistingtoken_1391882543');
}
/**
* @expectedException yii\base\InvalidParamException
*/
public function testResetEmptyToken()
{
new ResetPasswordForm('');
}
public function testResetPassword() public function testResetCorrectToken()
{ {
$this->specify('wrong reset token', function () { $form = new ResetPasswordForm($this->user[0]['password_reset_token']);
$this->setExpectedException('\Exception', 'Wrong password reset token.'); expect('password should be resetted', $form->resetPassword())->true();
new ResetPasswordForm('notexistingtoken_1391882543');
});
$this->specify('not correct token', function () {
$this->setExpectedException('yii\base\InvalidParamException', 'Password reset token cannot be blank.');
new ResetPasswordForm('');
});
} }
public function fixtures() public function fixtures()
...@@ -29,8 +36,9 @@ class ResetPasswordFormTest extends DbTestCase ...@@ -29,8 +36,9 @@ class ResetPasswordFormTest extends DbTestCase
return [ return [
'user' => [ 'user' => [
'class' => UserFixture::className(), 'class' => UserFixture::className(),
'dataFile' => '@frontend/tests/unit/fixtures/data/user.php' 'dataFile' => '@frontend/tests/unit/fixtures/data/models/user.php'
], ],
]; ];
} }
} }
...@@ -4,23 +4,26 @@ namespace frontend\tests\unit\models; ...@@ -4,23 +4,26 @@ namespace frontend\tests\unit\models;
use frontend\tests\unit\DbTestCase; use frontend\tests\unit\DbTestCase;
use common\tests\fixtures\UserFixture; use common\tests\fixtures\UserFixture;
use Codeception\Specify;
use frontend\models\SignupForm;
class SignupFormTest extends DbTestCase class SignupFormTest extends DbTestCase
{ {
use \Codeception\Specify; use Specify;
public function testCorrectSignup() public function testCorrectSignup()
{ {
$model = $this->getMock('frontend\models\SignupForm', ['validate']); $model = new SignupForm([
$model->expects($this->once())->method('validate')->will($this->returnValue(true)); 'username' => 'some_username',
'email' => 'some_email@example.com',
$model->username = 'some_username'; 'password' => 'some_password',
$model->email = 'some_email@example.com'; ]);
$model->password = 'some_password';
$user = $model->signup(); $user = $model->signup();
$this->assertInstanceOf('common\models\User', $user);
$this->assertInstanceOf('common\models\User', $user, 'user should be valid');
expect('username should be correct', $user->username)->equals('some_username'); expect('username should be correct', $user->username)->equals('some_username');
expect('email should be correct', $user->email)->equals('some_email@example.com'); expect('email should be correct', $user->email)->equals('some_email@example.com');
expect('password should be correct', $user->validatePassword('some_password'))->true(); expect('password should be correct', $user->validatePassword('some_password'))->true();
...@@ -28,10 +31,13 @@ class SignupFormTest extends DbTestCase ...@@ -28,10 +31,13 @@ class SignupFormTest extends DbTestCase
public function testNotCorrectSignup() public function testNotCorrectSignup()
{ {
$model = $this->getMock('frontend\models\SignupForm', ['validate']); $model = new SignupForm([
$model->expects($this->once())->method('validate')->will($this->returnValue(false)); 'username' => 'troy.becker',
'email' => 'nicolas.dianna@hotmail.com',
'password' => 'some_password',
]);
expect('user should not be created', $model->signup())->null(); expect('username and email are in use, user should not be created', $model->signup())->null();
} }
public function fixtures() public function fixtures()
...@@ -39,8 +45,9 @@ class SignupFormTest extends DbTestCase ...@@ -39,8 +45,9 @@ class SignupFormTest extends DbTestCase
return [ return [
'user' => [ 'user' => [
'class' => UserFixture::className(), 'class' => UserFixture::className(),
'dataFile' => false, //do not load test data, only table cleanup 'dataFile' => '@frontend/tests/unit/fixtures/data/models/user.php',
], ],
]; ];
} }
} }
...@@ -6,10 +6,9 @@ use yii\widgets\Breadcrumbs; ...@@ -6,10 +6,9 @@ use yii\widgets\Breadcrumbs;
use frontend\assets\AppAsset; use frontend\assets\AppAsset;
use frontend\widgets\Alert; use frontend\widgets\Alert;
/** /* @var $this \yii\web\View */
* @var \yii\web\View $this /* @var $content string */
* @var string $content
*/
AppAsset::register($this); AppAsset::register($this);
?> ?>
<?php $this->beginPage() ?> <?php $this->beginPage() ?>
...@@ -18,6 +17,7 @@ AppAsset::register($this); ...@@ -18,6 +17,7 @@ AppAsset::register($this);
<head> <head>
<meta charset="<?= Yii::$app->charset ?>"/> <meta charset="<?= Yii::$app->charset ?>"/>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<?= Html::csrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title> <title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?> <?php $this->head() ?>
</head> </head>
......
<?php <?php
use yii\helpers\Html; use yii\helpers\Html;
/** /* @var $this yii\web\View */
* @var yii\web\View $this
*/
$this->title = 'About'; $this->title = 'About';
$this->params['breadcrumbs'][] = $this->title; $this->params['breadcrumbs'][] = $this->title;
?> ?>
......
...@@ -3,11 +3,10 @@ use yii\helpers\Html; ...@@ -3,11 +3,10 @@ use yii\helpers\Html;
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
use yii\captcha\Captcha; use yii\captcha\Captcha;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $form yii\widgets\ActiveForm */
* @var yii\widgets\ActiveForm $form /* @var $model \frontend\models\ContactForm */
* @var \frontend\models\ContactForm $model
*/
$this->title = 'Contact'; $this->title = 'Contact';
$this->params['breadcrumbs'][] = $this->title; $this->params['breadcrumbs'][] = $this->title;
?> ?>
......
...@@ -2,12 +2,10 @@ ...@@ -2,12 +2,10 @@
use yii\helpers\Html; use yii\helpers\Html;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $name string */
* @var string $name /* @var $message string */
* @var string $message /* @var $exception Exception */
* @var Exception $exception
*/
$this->title = $name; $this->title = $name;
?> ?>
......
<?php <?php
/** /* @var $this yii\web\View */
* @var yii\web\View $this
*/
$this->title = 'My Yii Application'; $this->title = 'My Yii Application';
?> ?>
<div class="site-index"> <div class="site-index">
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $form yii\widgets\ActiveForm */
* @var yii\widgets\ActiveForm $form /* @var $model \common\models\LoginForm */
* @var \common\models\LoginForm $model
*/
$this->title = 'Login'; $this->title = 'Login';
$this->params['breadcrumbs'][] = $this->title; $this->params['breadcrumbs'][] = $this->title;
?> ?>
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $form yii\widgets\ActiveForm */
* @var yii\widgets\ActiveForm $form /* @var $model \frontend\models\PasswordResetRequestForm */
* @var \frontend\models\PasswordResetRequestForm $model
*/
$this->title = 'Request password reset'; $this->title = 'Request password reset';
$this->params['breadcrumbs'][] = $this->title; $this->params['breadcrumbs'][] = $this->title;
?> ?>
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $form yii\widgets\ActiveForm */
* @var yii\widgets\ActiveForm $form /* @var $model \frontend\models\ResetPasswordForm */
* @var \frontend\models\ResetPasswordForm $model
*/
$this->title = 'Reset password'; $this->title = 'Reset password';
$this->params['breadcrumbs'][] = $this->title; $this->params['breadcrumbs'][] = $this->title;
?> ?>
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
/** /* @var $this yii\web\View */
* @var yii\web\View $this /* @var $form yii\widgets\ActiveForm */
* @var yii\widgets\ActiveForm $form /* @var $model \frontend\models\SignupForm */
* @var \frontend\models\SignupForm $model
*/
$this->title = 'Signup'; $this->title = 'Signup';
$this->params['breadcrumbs'][] = $this->title; $this->params['breadcrumbs'][] = $this->title;
?> ?>
......
html, html,
body { body {
height: 100%; height: 100%;
} }
.wrap { .wrap {
min-height: 100%; min-height: 100%;
height: auto; height: auto;
margin: 0 auto -60px; margin: 0 auto -60px;
padding: 0 0 60px; padding: 0 0 60px;
} }
.wrap > .container { .wrap > .container {
...@@ -15,61 +15,61 @@ body { ...@@ -15,61 +15,61 @@ body {
} }
.footer { .footer {
height: 60px; height: 60px;
background-color: #f5f5f5; background-color: #f5f5f5;
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
padding-top: 20px; padding-top: 20px;
} }
.jumbotron { .jumbotron {
text-align: center; text-align: center;
background-color: transparent; background-color: transparent;
} }
.jumbotron .btn { .jumbotron .btn {
font-size: 21px; font-size: 21px;
padding: 14px 24px; padding: 14px 24px;
} }
.not-set { .not-set {
color: #c55; color: #c55;
font-style: italic; font-style: italic;
} }
/* add sorting icons to gridview sort links */ /* add sorting icons to gridview sort links */
a.asc:after, a.desc:after { a.asc:after, a.desc:after {
position: relative; position: relative;
top: 1px; top: 1px;
display: inline-block; display: inline-block;
font-family: 'Glyphicons Halflings'; font-family: 'Glyphicons Halflings';
font-style: normal; font-style: normal;
font-weight: normal; font-weight: normal;
line-height: 1; line-height: 1;
padding-left: 5px; padding-left: 5px;
} }
a.asc:after { a.asc:after {
content: /*"\e113"*/ "\e151"; content: /*"\e113"*/ "\e151";
} }
a.desc:after { a.desc:after {
content: /*"\e114"*/ "\e152"; content: /*"\e114"*/ "\e152";
} }
.sort-numerical a.asc:after { .sort-numerical a.asc:after {
content: "\e153"; content: "\e153";
} }
.sort-numerical a.desc:after { .sort-numerical a.desc:after {
content: "\e154"; content: "\e154";
} }
.sort-ordinal a.asc:after { .sort-ordinal a.asc:after {
content: "\e155"; content: "\e155";
} }
.sort-ordinal a.desc:after { .sort-ordinal a.desc:after {
content: "\e156"; content: "\e156";
} }
.grid-view th { .grid-view th {
...@@ -77,15 +77,15 @@ a.desc:after { ...@@ -77,15 +77,15 @@ a.desc:after {
} }
.hint-block { .hint-block {
display: block; display: block;
margin-top: 5px; margin-top: 5px;
color: #999; color: #999;
} }
.error-summary { .error-summary {
color: #a94442; color: #a94442;
background: #fdf7f7; background: #fdf7f7;
border-left: 3px solid #eed3d7; border-left: 3px solid #eed3d7;
padding: 10px 20px; padding: 10px 20px;
margin: 0 0 15px 0; margin: 0 0 15px 0;
} }
...@@ -11,9 +11,17 @@ namespace frontend\widgets; ...@@ -11,9 +11,17 @@ namespace frontend\widgets;
* Alert widget renders a message from session flash. All flash messages are displayed * Alert widget renders a message from session flash. All flash messages are displayed
* in the sequence they were assigned using setFlash. You can set message as following: * in the sequence they were assigned using setFlash. You can set message as following:
* *
* - \Yii::$app->getSession()->setFlash('error', 'This is the message'); * ```php
* - \Yii::$app->getSession()->setFlash('success', 'This is the message'); * \Yii::$app->getSession()->setFlash('error', 'This is the message');
* - \Yii::$app->getSession()->setFlash('info', 'This is the message'); * \Yii::$app->getSession()->setFlash('success', 'This is the message');
* \Yii::$app->getSession()->setFlash('info', 'This is the message');
* ```
*
* Multiple messages could be set as follows:
*
* ```php
* \Yii::$app->getSession()->setFlash('error', ['Error 1', 'Error 2']);
* ```
* *
* @author Kartik Visweswaran <kartikv2@gmail.com> * @author Kartik Visweswaran <kartikv2@gmail.com>
* @author Alexander Makarov <sam@rmcreative.ru> * @author Alexander Makarov <sam@rmcreative.ru>
...@@ -47,19 +55,22 @@ class Alert extends \yii\bootstrap\Widget ...@@ -47,19 +55,22 @@ class Alert extends \yii\bootstrap\Widget
$flashes = $session->getAllFlashes(); $flashes = $session->getAllFlashes();
$appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : ''; $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : '';
foreach ($flashes as $type => $message) { foreach ($flashes as $type => $data) {
if (isset($this->alertTypes[$type])) { if (isset($this->alertTypes[$type])) {
/* initialize css class for each alert box */ $data = (array) $data;
$this->options['class'] = $this->alertTypes[$type] . $appendCss; foreach ($data as $message) {
/* initialize css class for each alert box */
$this->options['class'] = $this->alertTypes[$type] . $appendCss;
/* assign unique id to each alert box */ /* assign unique id to each alert box */
$this->options['id'] = $this->getId() . '-' . $type; $this->options['id'] = $this->getId() . '-' . $type;
echo \yii\bootstrap\Alert::widget([ echo \yii\bootstrap\Alert::widget([
'body' => $message, 'body' => $message,
'closeButton' => $this->closeButton, 'closeButton' => $this->closeButton,
'options' => $this->options, 'options' => $this->options,
]); ]);
}
$session->removeFlash($type); $session->removeFlash($type);
} }
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
* @license http://www.yiiframework.com/license/ * @license http://www.yiiframework.com/license/
*/ */
if (!extension_loaded('mcrypt')) {
die('The mcrypt PHP extension is required by Yii2.');
}
$params = getParams(); $params = getParams();
$root = str_replace('\\', '/', __DIR__); $root = str_replace('\\', '/', __DIR__);
$envs = require("$root/environments/index.php"); $envs = require("$root/environments/index.php");
...@@ -23,147 +27,169 @@ echo "Yii Application Initialization Tool v1.0\n\n"; ...@@ -23,147 +27,169 @@ echo "Yii Application Initialization Tool v1.0\n\n";
$envName = null; $envName = null;
if (empty($params['env']) || $params['env'] === '1') { if (empty($params['env']) || $params['env'] === '1') {
echo "Which environment do you want the application to be initialized in?\n\n"; echo "Which environment do you want the application to be initialized in?\n\n";
foreach ($envNames as $i => $name) { foreach ($envNames as $i => $name) {
echo " [$i] $name\n"; echo " [$i] $name\n";
} }
echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] '; echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
$answer = trim(fgets(STDIN)); $answer = trim(fgets(STDIN));
if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) { if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {
echo "\n Quit initialization.\n"; echo "\n Quit initialization.\n";
exit(0); exit(0);
} }
if (isset($envNames[$answer])) { if (isset($envNames[$answer])) {
$envName = $envNames[$answer]; $envName = $envNames[$answer];
} }
} else { } else {
$envName = $params['env']; $envName = $params['env'];
} }
if (!in_array($envName, $envNames)) { if (!in_array($envName, $envNames)) {
$envsList = implode(', ', $envNames); $envsList = implode(', ', $envNames);
echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n"; echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n";
exit(2); exit(2);
} }
$env = $envs[$envName]; $env = $envs[$envName];
if (empty($params['env'])) { if (empty($params['env'])) {
echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] "; echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
$answer = trim(fgets(STDIN)); $answer = trim(fgets(STDIN));
if (strncasecmp($answer, 'y', 1)) { if (strncasecmp($answer, 'y', 1)) {
echo "\n Quit initialization.\n"; echo "\n Quit initialization.\n";
exit(0); exit(0);
} }
} }
echo "\n Start initialization ...\n\n"; echo "\n Start initialization ...\n\n";
$files = getFileList("$root/environments/{$env['path']}"); $files = getFileList("$root/environments/{$env['path']}");
$all = false; $all = false;
foreach ($files as $file) { foreach ($files as $file) {
if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) { if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) {
break; break;
} }
}
if (isset($env['writable'])) {
foreach ($env['writable'] as $writable) {
echo " chmod 0777 $writable\n";
@chmod("$root/$writable", 0777);
}
} }
if (isset($env['executable'])) { $callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable'];
foreach ($env['executable'] as $executable) { foreach ($callbacks as $callback) {
echo " chmod 0755 $executable\n"; if (!empty($env[$callback])) {
@chmod("$root/$executable", 0755); $callback($root, $env[$callback]);
} }
} }
echo "\n ... initialization completed.\n\n"; echo "\n ... initialization completed.\n\n";
function getFileList($root, $basePath = '') function getFileList($root, $basePath = '')
{ {
$files = []; $files = [];
$handle = opendir($root); $handle = opendir($root);
while (($path = readdir($handle)) !== false) { while (($path = readdir($handle)) !== false) {
if ($path === '.svn' || $path === '.' || $path === '..') { if ($path === '.svn' || $path === '.' || $path === '..') {
continue; continue;
} }
$fullPath = "$root/$path"; $fullPath = "$root/$path";
$relativePath = $basePath === '' ? $path : "$basePath/$path"; $relativePath = $basePath === '' ? $path : "$basePath/$path";
if (is_dir($fullPath)) { if (is_dir($fullPath)) {
$files = array_merge($files, getFileList($fullPath, $relativePath)); $files = array_merge($files, getFileList($fullPath, $relativePath));
} else { } else {
$files[] = $relativePath; $files[] = $relativePath;
} }
} }
closedir($handle); closedir($handle);
return $files; return $files;
} }
function copyFile($root, $source, $target, &$all, $params) function copyFile($root, $source, $target, &$all, $params)
{ {
if (!is_file($root . '/' . $source)) { if (!is_file($root . '/' . $source)) {
echo " skip $target ($source not exist)\n"; echo " skip $target ($source not exist)\n";
return true; return true;
} }
if (is_file($root . '/' . $target)) { if (is_file($root . '/' . $target)) {
if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) { if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
echo " unchanged $target\n"; echo " unchanged $target\n";
return true; return true;
} }
if ($all) { if ($all) {
echo " overwrite $target\n"; echo " overwrite $target\n";
} else { } else {
echo " exist $target\n"; echo " exist $target\n";
echo " ...overwrite? [Yes|No|All|Quit] "; echo " ...overwrite? [Yes|No|All|Quit] ";
$answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN)); $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));
if (!strncasecmp($answer, 'q', 1)) { if (!strncasecmp($answer, 'q', 1)) {
return false; return false;
} else { } else {
if (!strncasecmp($answer, 'y', 1)) { if (!strncasecmp($answer, 'y', 1)) {
echo " overwrite $target\n"; echo " overwrite $target\n";
} else { } else {
if (!strncasecmp($answer, 'a', 1)) { if (!strncasecmp($answer, 'a', 1)) {
echo " overwrite $target\n"; echo " overwrite $target\n";
$all = true; $all = true;
} else { } else {
echo " skip $target\n"; echo " skip $target\n";
return true; return true;
} }
} }
} }
} }
file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
return true; return true;
} }
echo " generate $target\n"; echo " generate $target\n";
@mkdir(dirname($root . '/' . $target), 0777, true); @mkdir(dirname($root . '/' . $target), 0777, true);
file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
return true; return true;
} }
function getParams() function getParams()
{ {
$rawParams = []; $rawParams = [];
if (isset($_SERVER['argv'])) { if (isset($_SERVER['argv'])) {
$rawParams = $_SERVER['argv']; $rawParams = $_SERVER['argv'];
array_shift($rawParams); array_shift($rawParams);
} }
$params = []; $params = [];
foreach ($rawParams as $param) { foreach ($rawParams as $param) {
if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) { if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
$name = $matches[1]; $name = $matches[1];
$params[$name] = isset($matches[3]) ? $matches[3] : true; $params[$name] = isset($matches[3]) ? $matches[3] : true;
} else { } else {
$params[] = $param; $params[] = $param;
} }
} }
return $params; return $params;
}
function setWritable($root, $paths)
{
foreach ($paths as $writable) {
echo " chmod 0777 $writable\n";
@chmod("$root/$writable", 0777);
}
}
function setExecutable($root, $paths)
{
foreach ($paths as $executable) {
echo " chmod 0755 $executable\n";
@chmod("$root/$executable", 0755);
}
}
function setCookieValidationKey($root, $paths)
{
foreach ($paths as $file) {
echo " generate cookie validation key in $file\n";
$file = $root . '/' . $file;
$length = 32;
$bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
$key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
$content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file));
file_put_contents($file, $content);
}
} }
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