├── web ├── files │ └── hello.txt ├── assets │ └── .gitignore ├── robots.txt ├── js │ ├── main-index.js │ └── main.js ├── favicon.ico ├── img │ └── brand.gif ├── .htaccess ├── index.php ├── index-test.php └── css │ ├── main.css │ └── site.css ├── runtime └── .gitignore ├── tests ├── codeception │ ├── unit │ │ ├── fixtures │ │ │ ├── .gitkeep │ │ │ └── data │ │ │ │ └── .gitkeep │ │ ├── templates │ │ │ └── fixtures │ │ │ │ └── .gitkeep │ │ ├── _bootstrap.php │ │ └── models │ │ │ ├── UserTest.php │ │ │ ├── ContactFormTest.php │ │ │ └── LoginFormTest.php │ ├── _output │ │ └── .gitignore │ ├── fixtures │ │ └── .gitignore │ ├── templates │ │ └── .gitignore │ ├── acceptance │ │ ├── _bootstrap.php │ │ ├── AboutCept.php │ │ ├── HomeCept.php │ │ ├── LoginCept.php │ │ └── ContactCept.php │ ├── functional │ │ ├── _bootstrap.php │ │ ├── AboutCept.php │ │ ├── HomeCept.php │ │ ├── LoginCept.php │ │ └── ContactCept.php │ ├── .gitignore │ ├── unit.suite.yml │ ├── config │ │ ├── unit.php │ │ ├── acceptance.php │ │ ├── config.php │ │ └── functional.php │ ├── _pages │ │ ├── AboutPage.php │ │ ├── LoginPage.php │ │ └── ContactPage.php │ ├── functional.suite.yml │ ├── bin │ │ ├── yii.bat │ │ ├── _bootstrap.php │ │ └── yii │ ├── _bootstrap.php │ └── acceptance.suite.yml ├── codeception.yml └── README.md ├── .bowerrc ├── views ├── widget-test │ └── index.php ├── main │ ├── index.php │ ├── search.php │ ├── sendEmail.php │ ├── resetPassword.php │ ├── profile.php │ ├── reg.php │ └── login.php ├── site │ ├── about.php │ ├── error.php │ ├── login.php │ ├── contact.php │ └── index.php └── layouts │ ├── main.php │ └── basic.php ├── components ├── views │ ├── second.php │ └── first.php ├── SecondWidget.php ├── FirstWidget.php ├── MyBehaviors.php └── AlertWidget.php ├── config ├── db.php ├── params.php ├── console.php └── web.php ├── controllers ├── WidgetTestController.php ├── BehaviorsController.php ├── SiteController.php └── MainController.php ├── migrations ├── m150211_193807_drop_post_table.php ├── m150330_153014_drop_user_table.php ├── m150211_165754_create_user_table.php ├── m150211_170614_create_post_table.php ├── m150330_153138_create_user_table.php ├── m150527_004551_drop_user_table.php ├── m150804_021125_add_secret_key_in_user_table.php ├── m150527_004737_create_user_table.php └── m150711_083606_create_profile_table.php ├── mail ├── resetPassword.php ├── activationEmail.php └── layouts │ └── html.php ├── .gitignore ├── yii.bat ├── yii ├── assets └── AppAsset.php ├── commands └── HelloController.php ├── models ├── AccountActivation.php ├── ResetPasswordForm.php ├── SendEmailForm.php ├── ContactForm.php ├── Profile.php ├── LoginForm.php ├── RegForm.php └── User.php ├── LICENSE.md ├── composer.json ├── README.md ├── requirements.php └── composer.lock /web/files/hello.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /tests/codeception/unit/fixtures/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/assets/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /web/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /tests/codeception/unit/fixtures/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/codeception/_output/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /tests/codeception/unit/templates/fixtures/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory" : "vendor/bower" 3 | } 4 | -------------------------------------------------------------------------------- /tests/codeception/fixtures/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /tests/codeception/templates/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /views/widget-test/index.php: -------------------------------------------------------------------------------- 1 | 5 |

main/index

6 | 7 |

8 | 9 |

10 | -------------------------------------------------------------------------------- /tests/codeception/.gitignore: -------------------------------------------------------------------------------- 1 | # these files are auto generated by codeception build 2 | /unit/UnitTester.php 3 | /functional/FunctionalTester.php 4 | /acceptance/AcceptanceTester.php 5 | -------------------------------------------------------------------------------- /views/main/search.php: -------------------------------------------------------------------------------- 1 | 9 |

-------------------------------------------------------------------------------- /tests/codeception/unit.suite.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | 3 | # suite for unit (internal) tests. 4 | # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. 5 | 6 | class_name: UnitTester 7 | -------------------------------------------------------------------------------- /config/db.php: -------------------------------------------------------------------------------- 1 | 'yii\db\Connection', 5 | 'dsn' => 'mysql:host=localhost;dbname=basic', 6 | 'username' => 'root', 7 | 'password' => '', 8 | 'charset' => 'utf8', 9 | ]; 10 | -------------------------------------------------------------------------------- /web/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | 3 | # if a directory or a file exists, use it directly 4 | RewriteCond %{REQUEST_FILENAME} !-f 5 | RewriteCond %{REQUEST_FILENAME} !-d 6 | 7 | # otherwise forward it to index.php 8 | RewriteRule . index.php -------------------------------------------------------------------------------- /tests/codeception/acceptance/AboutCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that about works'); 7 | AboutPage::openBy($I); 8 | $I->see('About', 'h1'); 9 | -------------------------------------------------------------------------------- /tests/codeception/functional/AboutCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that about works'); 7 | AboutPage::openBy($I); 8 | $I->see('About', 'h1'); 9 | -------------------------------------------------------------------------------- /components/views/first.php: -------------------------------------------------------------------------------- 1 | 10 |

Первый виджет

11 |

12 | 13 |

-------------------------------------------------------------------------------- /tests/codeception/config/unit.php: -------------------------------------------------------------------------------- 1 | render( 10 | 'index' 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/codeception/config/acceptance.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that home page works'); 5 | $I->amOnPage(Yii::$app->homeUrl); 6 | $I->see('My Company'); 7 | $I->seeLink('About'); 8 | $I->click('About'); 9 | $I->see('This is the About page.'); 10 | -------------------------------------------------------------------------------- /tests/codeception/functional/HomeCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that home page works'); 5 | $I->amOnPage(Yii::$app->homeUrl); 6 | $I->see('My Company'); 7 | $I->seeLink('About'); 8 | $I->click('About'); 9 | $I->see('This is the About page.'); 10 | -------------------------------------------------------------------------------- /tests/codeception/_pages/AboutPage.php: -------------------------------------------------------------------------------- 1 | run(); 13 | -------------------------------------------------------------------------------- /migrations/m150211_193807_drop_post_table.php: -------------------------------------------------------------------------------- 1 | dropTable('post'); 11 | } 12 | 13 | public function down() 14 | { 15 | echo "m150211_193807_drop_post_table cannot be reverted.\n"; 16 | 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /migrations/m150330_153014_drop_user_table.php: -------------------------------------------------------------------------------- 1 | dropTable('user'); 11 | } 12 | 13 | public function down() 14 | { 15 | echo "m150330_153014_drop_user_table cannot be reverted.\n"; 16 | 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/codeception/unit/models/UserTest.php: -------------------------------------------------------------------------------- 1 | loadFixtures(['user']); 14 | } 15 | 16 | // TODO add test methods here 17 | } 18 | -------------------------------------------------------------------------------- /views/site/about.php: -------------------------------------------------------------------------------- 1 | title = 'About'; 6 | $this->params['breadcrumbs'][] = $this->title; 7 | ?> 8 |
9 |

title) ?>

10 | 11 |

12 | This is the About page. You may modify the following file to customize its content: 13 |

14 | 15 | 16 |
17 | -------------------------------------------------------------------------------- /migrations/m150211_165754_create_user_table.php: -------------------------------------------------------------------------------- 1 | createTable('user',['id'=>'pk','password'=>'string NOT NULL','email'=>'string NOT NULL']); 11 | } 12 | 13 | public function down() 14 | { 15 | $this->dropTable('user'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /config/params.php: -------------------------------------------------------------------------------- 1 | 'admin@example.com', 5 | 'supportEmail' => 'no-reply@phpnt.com', // автоматическая отправка почты с данного емайл 6 | 'secretKeyExpire' => 60 * 60, // время хранения секретного ключа 7 | 'emailActivation' => false, // активация по емайл 8 | 'loginWithEmail' => true, // авторизация по емайл 9 | ]; 10 | -------------------------------------------------------------------------------- /tests/codeception/config/config.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'db' => [ 8 | 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_tests', 9 | ], 10 | 'mailer' => [ 11 | 'useFileTransport' => true, 12 | ], 13 | 'urlManager' => [ 14 | 'showScriptName' => true, 15 | ], 16 | ], 17 | ]; 18 | -------------------------------------------------------------------------------- /mail/resetPassword.php: -------------------------------------------------------------------------------- 1 | username).'. '; 13 | echo Html::a('Для смены пароля перейдите по этой ссылке.', 14 | Yii::$app->urlManager->createAbsoluteUrl( 15 | [ 16 | '/main/reset-password', 17 | 'key' => $user->secret_key 18 | ] 19 | )); -------------------------------------------------------------------------------- /migrations/m150211_170614_create_post_table.php: -------------------------------------------------------------------------------- 1 | createTable('post',['id'=>'pk','post'=>'text','user_id'=>'int']); 11 | $this->addForeignKey('post_user_id','post','user_id','user','id'); 12 | } 13 | 14 | public function safeDown() 15 | { 16 | $this->dropTable('post'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/codeception/functional.suite.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | 3 | # suite for functional (integration) tests. 4 | # emulate web requests and make application process them. 5 | # (tip: better to use with frameworks). 6 | 7 | # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. 8 | #basic/web/index.php 9 | class_name: FunctionalTester 10 | modules: 11 | enabled: 12 | - Filesystem 13 | - Yii2 14 | config: 15 | Yii2: 16 | configFile: 'codeception/config/functional.php' 17 | -------------------------------------------------------------------------------- /mail/activationEmail.php: -------------------------------------------------------------------------------- 1 | username).'.'; 13 | echo Html::a('Для активации аккаунта перейдите по этой ссылке.', 14 | Yii::$app->urlManager->createAbsoluteUrl( 15 | [ 16 | '/main/activate-account', 17 | 'key' => $user->secret_key 18 | ] 19 | )); 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # исключаем db.php 2 | /config/db.php 3 | 4 | # phpstorm файлы проекта 5 | .idea 6 | 7 | # netbeans файлы проекта 8 | nbproject 9 | 10 | # zend studio for eclipse файлы проекта 11 | .buildpath 12 | .project 13 | .settings 14 | 15 | # windows thumbnail cache 16 | Thumbs.db 17 | 18 | # папка приложений, загруженных через Composer 19 | /vendor 20 | 21 | # сам Composer, если он в корне 22 | composer.phar 23 | 24 | # Mac DS_Store Files 25 | .DS_Store 26 | 27 | # файл phpunit тестов 28 | phpunit.phar 29 | 30 | # local phpunit config 31 | /phpunit.xml 32 | -------------------------------------------------------------------------------- /views/main/sendEmail.php: -------------------------------------------------------------------------------- 1 | 10 |
11 | 12 | 13 | 14 | field($model, 'email') ?> 15 | 16 |
17 | 'btn btn-primary']) ?> 18 |
19 | 20 | 21 |
22 | -------------------------------------------------------------------------------- /components/SecondWidget.php: -------------------------------------------------------------------------------- 1 | render( 22 | 'second', 23 | [ 24 | 'content' => $content 25 | ] 26 | ); 27 | } 28 | } -------------------------------------------------------------------------------- /yii.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem ------------------------------------------------------------- 4 | rem Yii command line bootstrap script for Windows. 5 | rem 6 | rem @author Qiang Xue 7 | rem @link http://www.yiiframework.com/ 8 | rem @copyright Copyright (c) 2008 Yii Software LLC 9 | rem @license http://www.yiiframework.com/license/ 10 | rem ------------------------------------------------------------- 11 | 12 | @setlocal 13 | 14 | set YII_PATH=%~dp0 15 | 16 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe 17 | 18 | "%PHP_COMMAND%" "%YII_PATH%yii" %* 19 | 20 | @endlocal 21 | -------------------------------------------------------------------------------- /web/index-test.php: -------------------------------------------------------------------------------- 1 | run(); 17 | -------------------------------------------------------------------------------- /migrations/m150330_153138_create_user_table.php: -------------------------------------------------------------------------------- 1 | createTable( 11 | 'user', 12 | [ 13 | 'id'=>Schema::TYPE_PK, 14 | 'password'=>Schema::TYPE_STRING.' NOT NULL', 15 | 'email'=>Schema::TYPE_STRING.' NOT NULL' 16 | ] 17 | ); 18 | } 19 | 20 | public function down() 21 | { 22 | $this->dropTable('user'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/codeception/bin/yii.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem ------------------------------------------------------------- 4 | rem Yii command line bootstrap script for Windows. 5 | rem 6 | rem @author Qiang Xue 7 | rem @link http://www.yiiframework.com/ 8 | rem @copyright Copyright (c) 2008 Yii Software LLC 9 | rem @license http://www.yiiframework.com/license/ 10 | rem ------------------------------------------------------------- 11 | 12 | @setlocal 13 | 14 | set YII_PATH=%~dp0 15 | 16 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe 17 | 18 | "%PHP_COMMAND%" "%YII_PATH%yii" %* 19 | 20 | @endlocal 21 | -------------------------------------------------------------------------------- /views/main/resetPassword.php: -------------------------------------------------------------------------------- 1 | 10 |
11 | 12 | 13 | 14 | field($model, 'password')->passwordInput() ?> 15 | 16 |
17 | 'btn btn-primary']) ?> 18 |
19 | 20 | 21 |
22 | -------------------------------------------------------------------------------- /tests/codeception/bin/_bootstrap.php: -------------------------------------------------------------------------------- 1 | dropTable('user'); 11 | } 12 | 13 | public function down() 14 | { 15 | echo "m150527_004551_drop_user_table cannot be reverted.\n"; 16 | 17 | return false; 18 | } 19 | 20 | /* 21 | // Use safeUp/safeDown to run migration code within a transaction 22 | public function safeUp() 23 | { 24 | } 25 | 26 | public function safeDown() 27 | { 28 | } 29 | */ 30 | } 31 | -------------------------------------------------------------------------------- /migrations/m150804_021125_add_secret_key_in_user_table.php: -------------------------------------------------------------------------------- 1 | addColumn('user', 'secret_key', Schema::TYPE_STRING); 11 | } 12 | 13 | public function down() 14 | { 15 | $this->dropColumn('user', 'secret_key'); 16 | } 17 | 18 | /* 19 | // Use safeUp/safeDown to run migration code within a transaction 20 | public function safeUp() 21 | { 22 | } 23 | 24 | public function safeDown() 25 | { 26 | } 27 | */ 28 | } 29 | -------------------------------------------------------------------------------- /views/site/error.php: -------------------------------------------------------------------------------- 1 | title = $name; 11 | ?> 12 |
13 | 14 |

title) ?>

15 | 16 |
17 | 18 |
19 | 20 |

21 | The above error occurred while the Web server was processing your request. 22 |

23 |

24 | Please contact us if you think this is a server error. Thank you. 25 |

26 | 27 |
28 | -------------------------------------------------------------------------------- /tests/codeception/_pages/LoginPage.php: -------------------------------------------------------------------------------- 1 | actor->fillField('input[name="LoginForm[username]"]', $username); 22 | $this->actor->fillField('input[name="LoginForm[password]"]', $password); 23 | $this->actor->click('login-button'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /components/FirstWidget.php: -------------------------------------------------------------------------------- 1 | a === null) { 20 | $this->a = 0; 21 | } 22 | if ($this->b === null) { 23 | $this->b = 0; 24 | } 25 | } 26 | 27 | public function run() { 28 | $c = $this->a + $this->b; 29 | 30 | return $this->render( 31 | 'first', 32 | [ 33 | 'c' => $c 34 | ] 35 | ); 36 | } 37 | } -------------------------------------------------------------------------------- /tests/codeception/_pages/ContactPage.php: -------------------------------------------------------------------------------- 1 | $value) { 21 | $inputType = $field === 'body' ? 'textarea' : 'input'; 22 | $this->actor->fillField($inputType . '[name="ContactForm[' . $field . ']"]', $value); 23 | } 24 | $this->actor->click('contact-button'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /views/main/profile.php: -------------------------------------------------------------------------------- 1 | 10 |
11 | 12 | 13 | user) 15 | echo $form->field($model->user, 'username'); 16 | ?> 17 | field($model, 'first_name') ?> 18 | field($model, 'second_name') ?> 19 | field($model, 'middle_name') ?> 20 | 21 |
22 | 'btn btn-primary']) ?> 23 |
24 | 25 | 26 |
27 | -------------------------------------------------------------------------------- /yii: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 24 | exit($exitCode); 25 | -------------------------------------------------------------------------------- /mail/layouts/html.php: -------------------------------------------------------------------------------- 1 | 8 | beginPage() ?> 9 | 10 | 11 | 12 | 13 | <?= Html::encode($this->title) ?> 14 | head() ?> 15 | 16 | 17 | beginBody() ?> 18 | 19 | endBody() ?> 20 | 21 | 22 | endPage() ?> 23 | -------------------------------------------------------------------------------- /assets/AppAsset.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 2.0 15 | */ 16 | class AppAsset extends AssetBundle 17 | { 18 | public $basePath = '@webroot'; 19 | public $baseUrl = '@web'; 20 | public $css = [ 21 | 'css/site.css', 22 | 'css/main.css' 23 | ]; 24 | public $js = [ 25 | 'js/main.js' 26 | ]; 27 | public $jsOptions = [ 28 | 'position' => \yii\web\View::POS_END 29 | ]; 30 | public $depends = [ 31 | 'yii\web\YiiAsset', 32 | 'yii\bootstrap\BootstrapAsset', 33 | ]; 34 | } 35 | -------------------------------------------------------------------------------- /tests/codeception/functional/LoginCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that login works'); 7 | 8 | $loginPage = LoginPage::openBy($I); 9 | 10 | $I->see('Login', 'h1'); 11 | 12 | $I->amGoingTo('try to login with empty credentials'); 13 | $loginPage->login('', ''); 14 | $I->expectTo('see validations errors'); 15 | $I->see('Username cannot be blank.'); 16 | $I->see('Password cannot be blank.'); 17 | 18 | $I->amGoingTo('try to login with wrong credentials'); 19 | $loginPage->login('admin', 'wrong'); 20 | $I->expectTo('see validations errors'); 21 | $I->see('Incorrect username or password.'); 22 | 23 | $I->amGoingTo('try to login with correct credentials'); 24 | $loginPage->login('admin', 'admin'); 25 | $I->expectTo('see user info'); 26 | $I->see('Logout (admin)'); 27 | -------------------------------------------------------------------------------- /commands/HelloController.php: -------------------------------------------------------------------------------- 1 | 18 | * @since 2.0 19 | */ 20 | class HelloController extends Controller 21 | { 22 | /** 23 | * This command echoes what you have entered as the message. 24 | * @param string $message the message to be echoed. 25 | */ 26 | public function actionIndex($message = 'hello world') 27 | { 28 | echo $message . "\n"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /config/console.php: -------------------------------------------------------------------------------- 1 | 'basic-console', 10 | 'basePath' => dirname(__DIR__), 11 | 'bootstrap' => ['log', 'gii'], 12 | 'controllerNamespace' => 'app\commands', 13 | 'modules' => [ 14 | 'gii' => 'yii\gii\Module', 15 | ], 16 | 'components' => [ 17 | 'cache' => [ 18 | 'class' => 'yii\caching\FileCache', 19 | ], 20 | 'log' => [ 21 | 'targets' => [ 22 | [ 23 | 'class' => 'yii\log\FileTarget', 24 | 'levels' => ['error', 'warning'], 25 | ], 26 | ], 27 | ], 28 | 'db' => $db, 29 | ], 30 | 'params' => $params, 31 | ]; 32 | -------------------------------------------------------------------------------- /tests/codeception/config/functional.php: -------------------------------------------------------------------------------- 1 | [ 13 | 'request' => [ 14 | // it's not recommended to run functional tests with CSRF validation enabled 15 | 'enableCsrfValidation' => false, 16 | // but if you absolutely need it set cookie domain to localhost 17 | /* 18 | 'csrfCookie' => [ 19 | 'domain' => 'localhost', 20 | ], 21 | */ 22 | ], 23 | ], 24 | ] 25 | ); 26 | -------------------------------------------------------------------------------- /views/main/reg.php: -------------------------------------------------------------------------------- 1 | 10 |
11 | 12 | 13 | 14 | field($model, 'username') ?> 15 | field($model, 'email') ?> 16 | field($model, 'password')->passwordInput() ?> 17 | 18 |
19 | 'btn btn-primary']) ?> 20 |
21 | 22 | 23 | scenario === 'emailActivation'): 25 | ?> 26 | *На указанный емайл будет отправлено письмо для активации аккаунта. 27 | 30 | 31 |
32 | -------------------------------------------------------------------------------- /views/main/login.php: -------------------------------------------------------------------------------- 1 | 10 | 30 | -------------------------------------------------------------------------------- /tests/codeception/_bootstrap.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'fixture' => [ 19 | 'class' => 'yii\faker\FixtureController', 20 | 'fixtureDataPath' => '@tests/codeception/fixtures', 21 | 'templatePath' => '@tests/codeception/templates', 22 | 'namespace' => 'tests\codeception\fixtures', 23 | ], 24 | ], 25 | ] 26 | ); 27 | 28 | $application = new yii\console\Application($config); 29 | $exitCode = $application->run(); 30 | exit($exitCode); 31 | -------------------------------------------------------------------------------- /migrations/m150527_004737_create_user_table.php: -------------------------------------------------------------------------------- 1 | createTable('user', [ 11 | 'id' => Schema::TYPE_PK, 12 | 'username' => Schema::TYPE_STRING.' NOT NULL', 13 | 'email' => Schema::TYPE_STRING.' NOT NULL', 14 | 'password_hash' => Schema::TYPE_STRING.' NOT NULL', 15 | 'status' => Schema::TYPE_SMALLINT.' NOT NULL', 16 | 'auth_key' => Schema::TYPE_STRING.'(32) NOT NULL', 17 | 'created_at' => Schema::TYPE_INTEGER.' NOT NULL', 18 | 'updated_at' => Schema::TYPE_INTEGER.' NOT NULL', 19 | ]); 20 | } 21 | 22 | public function down() 23 | { 24 | $this->dropTable('user'); 25 | } 26 | 27 | /* 28 | // Use safeUp/safeDown to run migration code within a transaction 29 | public function safeUp() 30 | { 31 | } 32 | 33 | public function safeDown() 34 | { 35 | } 36 | */ 37 | } 38 | -------------------------------------------------------------------------------- /tests/codeception/acceptance/LoginCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that login works'); 7 | 8 | $loginPage = LoginPage::openBy($I); 9 | 10 | $I->see('Login', 'h1'); 11 | 12 | $I->amGoingTo('try to login with empty credentials'); 13 | $loginPage->login('', ''); 14 | if (method_exists($I, 'wait')) { 15 | $I->wait(3); // only for selenium 16 | } 17 | $I->expectTo('see validations errors'); 18 | $I->see('Username cannot be blank.'); 19 | $I->see('Password cannot be blank.'); 20 | 21 | $I->amGoingTo('try to login with wrong credentials'); 22 | $loginPage->login('admin', 'wrong'); 23 | if (method_exists($I, 'wait')) { 24 | $I->wait(3); // only for selenium 25 | } 26 | $I->expectTo('see validations errors'); 27 | $I->see('Incorrect username or password.'); 28 | 29 | $I->amGoingTo('try to login with correct credentials'); 30 | $loginPage->login('admin', 'admin'); 31 | if (method_exists($I, 'wait')) { 32 | $I->wait(3); // only for selenium 33 | } 34 | $I->expectTo('see user info'); 35 | $I->see('Logout (admin)'); 36 | -------------------------------------------------------------------------------- /tests/codeception.yml: -------------------------------------------------------------------------------- 1 | actor: Tester 2 | #coverage: 3 | # #c3_url: http://localhost:8080/index-test.php/ 4 | # enabled: true 5 | # #remote: true 6 | # #remote_config: '../tests/codeception.yml' 7 | # white_list: 8 | # include: 9 | # - ../models/* 10 | # - ../controllers/* 11 | # - ../commands/* 12 | # - ../mail/* 13 | # blacklist: 14 | # include: 15 | # - ../assets/* 16 | # - ../config/* 17 | # - ../runtime/* 18 | # - ../vendor/* 19 | # - ../views/* 20 | # - ../web/* 21 | # - ../tests/* 22 | paths: 23 | tests: codeception 24 | log: codeception/_output 25 | data: codeception/_data 26 | helpers: codeception/_support 27 | settings: 28 | bootstrap: _bootstrap.php 29 | suite_class: \PHPUnit_Framework_TestSuite 30 | memory_limit: 1024M 31 | log: true 32 | colors: true 33 | config: 34 | # the entry script URL (with host info) for functional and acceptance tests 35 | # PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL 36 | test_entry_url: http://localhost:8080/index-test.php -------------------------------------------------------------------------------- /tests/codeception/acceptance.suite.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | 3 | # suite for acceptance tests. 4 | # perform tests in browser using the Selenium-like tools. 5 | # powered by Mink (http://mink.behat.org). 6 | # (tip: that's what your customer will see). 7 | # (tip: test your ajax and javascript by one of Mink drivers). 8 | 9 | # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. 10 | 11 | class_name: AcceptanceTester 12 | modules: 13 | enabled: 14 | - PhpBrowser 15 | # you can use WebDriver instead of PhpBrowser to test javascript and ajax. 16 | # This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium 17 | # "restart" option is used by the WebDriver to start each time per test-file new session and cookies, 18 | # it is useful if you want to login in your app in each test. 19 | # - WebDriver 20 | config: 21 | PhpBrowser: 22 | # PLEASE ADJUST IT TO THE ACTUAL ENTRY POINT WITHOUT PATH INFO 23 | url: http://localhost:8080 24 | # WebDriver: 25 | # url: http://localhost:8080 26 | # browser: firefox 27 | # restart: true 28 | -------------------------------------------------------------------------------- /models/AccountActivation.php: -------------------------------------------------------------------------------- 1 | _user = User::findBySecretKey($key); 27 | if(!$this->_user) 28 | throw new InvalidParamException('Не верный ключ!'); 29 | parent::__construct($config); 30 | } 31 | 32 | public function activateAccount() 33 | { 34 | $user = $this->_user; 35 | $user->status = User::STATUS_ACTIVE; 36 | $user->removeSecretKey(); 37 | return $user->save(); 38 | } 39 | 40 | public function getUsername() 41 | { 42 | $user = $this->_user; 43 | return $user->username; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /migrations/m150711_083606_create_profile_table.php: -------------------------------------------------------------------------------- 1 | createTable( 11 | 'profile', 12 | [ 13 | 'user_id' => Schema::TYPE_PK, 14 | 'avatar' => Schema::TYPE_STRING, 15 | 'first_name' => Schema::TYPE_STRING.'(32)', 16 | 'second_name' => Schema::TYPE_STRING.'(32)', 17 | 'middle_name' => Schema::TYPE_STRING.'(32)', 18 | 'birthday' => Schema::TYPE_INTEGER, 19 | 'gender' => Schema::TYPE_SMALLINT 20 | ] 21 | ); 22 | $this->addForeignKey('profile_user', 'profile', 'user_id', 'user', 'id', 'cascade', 'cascade'); 23 | } 24 | 25 | public function safeDown() 26 | { 27 | $this->dropForeignKey('profile_user', 'profile'); 28 | $this->dropTable('profile'); 29 | } 30 | 31 | /* 32 | // Use safeUp/safeDown to run migration code within a transaction 33 | public function safeUp() 34 | { 35 | } 36 | 37 | public function safeDown() 38 | { 39 | } 40 | */ 41 | } 42 | -------------------------------------------------------------------------------- /models/ResetPasswordForm.php: -------------------------------------------------------------------------------- 1 | 'Пароль' 31 | ]; 32 | } 33 | 34 | public function __construct($key, $config = []) 35 | { 36 | if(empty($key) || !is_string($key)) 37 | throw new InvalidParamException('Ключ не может быть пустым.'); 38 | $this->_user = User::findBySecretKey($key); 39 | if(!$this->_user) 40 | throw new InvalidParamException('Не верный ключ.'); 41 | parent::__construct($config); 42 | } 43 | 44 | public function resetPassword() 45 | { 46 | /* @var $user User */ 47 | $user = $this->_user; 48 | $user->setPassword($this->password); 49 | $user->removeSecretKey(); 50 | return $user->save(); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /components/MyBehaviors.php: -------------------------------------------------------------------------------- 1 | _controller = $value; 23 | } 24 | 25 | public function getController() 26 | { 27 | return $this->_controller; 28 | } 29 | 30 | public function setAction($value) 31 | { 32 | $this->_action = $value; 33 | } 34 | 35 | public function getAction() 36 | { 37 | return $this->_action; 38 | } 39 | 40 | public function setRemoveUnderscore($value) 41 | { 42 | $this->_removeUnderscore = str_replace('_', ' ', $value); 43 | } 44 | 45 | public function getRemoveUnderscore() 46 | { 47 | return $this->_removeUnderscore; 48 | } 49 | 50 | public function events() 51 | { 52 | return [ 53 | Controller::EVENT_BEFORE_ACTION => 'beforeAction' 54 | ]; 55 | } 56 | 57 | public function beforeAction() 58 | { 59 | if($this->controller == 'main' && $this->action == 'search'): 60 | \Yii::$app->session->set('search', $this->removeUnderscore); 61 | endif; 62 | } 63 | } -------------------------------------------------------------------------------- /tests/codeception/functional/ContactCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that contact works'); 7 | 8 | $contactPage = ContactPage::openBy($I); 9 | 10 | $I->see('Contact', 'h1'); 11 | 12 | $I->amGoingTo('submit contact form with no data'); 13 | $contactPage->submit([]); 14 | $I->expectTo('see validations errors'); 15 | $I->see('Contact', 'h1'); 16 | $I->see('Name cannot be blank'); 17 | $I->see('Email cannot be blank'); 18 | $I->see('Subject cannot be blank'); 19 | $I->see('Body cannot be blank'); 20 | $I->see('The verification code is incorrect'); 21 | 22 | $I->amGoingTo('submit contact form with not correct email'); 23 | $contactPage->submit([ 24 | 'name' => 'tester', 25 | 'email' => 'tester.email', 26 | 'subject' => 'test subject', 27 | 'body' => 'test content', 28 | 'verifyCode' => 'testme', 29 | ]); 30 | $I->expectTo('see that email adress is wrong'); 31 | $I->dontSee('Name cannot be blank', '.help-inline'); 32 | $I->see('Email is not a valid email address.'); 33 | $I->dontSee('Subject cannot be blank', '.help-inline'); 34 | $I->dontSee('Body cannot be blank', '.help-inline'); 35 | $I->dontSee('The verification code is incorrect', '.help-inline'); 36 | 37 | $I->amGoingTo('submit contact form with correct data'); 38 | $contactPage->submit([ 39 | 'name' => 'tester', 40 | 'email' => 'tester@example.com', 41 | 'subject' => 'test subject', 42 | 'body' => 'test content', 43 | 'verifyCode' => 'testme', 44 | ]); 45 | $I->dontSeeElement('#contact-form'); 46 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.'); 47 | -------------------------------------------------------------------------------- /views/site/login.php: -------------------------------------------------------------------------------- 1 | title = 'Login'; 10 | $this->params['breadcrumbs'][] = $this->title; 11 | ?> 12 | 47 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The Yii framework is free software. It is released under the terms of 2 | the following BSD License. 3 | 4 | Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | * Neither the name of Yii Software LLC nor the names of its 18 | contributors may be used to endorse or promote products derived 19 | from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /web/css/main.css: -------------------------------------------------------------------------------- 1 | /* pnpNT CSS file */ 2 | @media (max-width: 767px) { 3 | .dropdown-header { 4 | color: #fff; 5 | } 6 | .navbar-default .navbar-nav .open .dropdown-menu > li > a { 7 | color: #fff; 8 | } 9 | .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover { 10 | color: rgba(195, 212, 227, 1); 11 | } 12 | } 13 | #main-menu.navbar-default .navbar-brand { 14 | color: rgba(255, 255, 255, 1); 15 | } 16 | #main-menu.navbar-default { 17 | font-size: 14px; 18 | background-color: rgba(51, 122, 183, 1); 19 | border-width: 0px; 20 | border-radius: 0px; 21 | } 22 | #main-menu.navbar-default .navbar-nav>li>a { 23 | color: rgba(255, 255, 255, 1); 24 | background-color: rgba(51, 122, 183, 1); 25 | } 26 | #main-menu.navbar-default .navbar-nav>li>a:hover, 27 | #main-menu.navbar-default .navbar-nav>li>a:focus { 28 | color: rgba(195, 212, 227, 1); 29 | background-color: rgba(51, 122, 183, 1); 30 | } 31 | #main-menu.navbar-default .navbar-nav>.active>a, 32 | #main-menu.navbar-default .navbar-nav>.active>a:hover, 33 | #main-menu.navbar-default .navbar-nav>.active>a:focus { 34 | color: rgba(255, 255, 255, 1); 35 | background-color: rgba(63, 114, 158, 1); 36 | } 37 | #main-menu.navbar-default .navbar-toggle { 38 | border-color: #fff; 39 | } 40 | #main-menu.navbar-default .navbar-toggle:hover, 41 | #main-menu.navbar-default .navbar-toggle:focus { 42 | background-color: #3f729e; 43 | } 44 | #main-menu.navbar-default .navbar-toggle .icon-bar { 45 | background-color: #fff; 46 | } 47 | #main-menu.navbar-default .navbar-toggle:hover .icon-bar, 48 | #main-menu.navbar-default .navbar-toggle:focus .icon-bar { 49 | background-color: #fff; 50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /models/SendEmailForm.php: -------------------------------------------------------------------------------- 1 | 'trim'], 22 | ['email', 'required'], 23 | ['email', 'email'], 24 | ['email', 'exist', 25 | 'targetClass' => User::className(), 26 | 'filter' => [ 27 | 'status' => User::STATUS_ACTIVE 28 | ], 29 | 'message' => 'Данный емайл не зарегистрирован.' 30 | ], 31 | ]; 32 | } 33 | 34 | public function attributeLabels() 35 | { 36 | return [ 37 | 'email' => 'Емайл' 38 | ]; 39 | } 40 | 41 | public function sendEmail() 42 | { 43 | /* @var $user User */ 44 | $user = User::findOne( 45 | [ 46 | 'status' => User::STATUS_ACTIVE, 47 | 'email' => $this->email 48 | ] 49 | ); 50 | 51 | if($user): 52 | $user->generateSecretKey(); 53 | if($user->save()): 54 | return Yii::$app->mailer->compose('resetPassword', ['user' => $user]) 55 | ->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name.' (отправлено роботом)']) 56 | ->setTo($this->email) 57 | ->setSubject('Сброс пароля для '.Yii::$app->name) 58 | ->send(); 59 | endif; 60 | endif; 61 | 62 | return false; 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /web/css/site.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | .wrap { 7 | min-height: 100%; 8 | height: auto; 9 | margin: 0 auto -60px; 10 | padding: 0 0 60px; 11 | } 12 | 13 | .wrap > .container { 14 | padding: 70px 15px 20px; 15 | } 16 | 17 | .footer { 18 | height: 60px; 19 | background-color: #f5f5f5; 20 | border-top: 1px solid #ddd; 21 | padding-top: 20px; 22 | } 23 | 24 | .jumbotron { 25 | text-align: center; 26 | background-color: transparent; 27 | } 28 | 29 | .jumbotron .btn { 30 | font-size: 21px; 31 | padding: 14px 24px; 32 | } 33 | 34 | .not-set { 35 | color: #c55; 36 | font-style: italic; 37 | } 38 | 39 | /* add sorting icons to gridview sort links */ 40 | a.asc:after, a.desc:after { 41 | position: relative; 42 | top: 1px; 43 | display: inline-block; 44 | font-family: 'Glyphicons Halflings'; 45 | font-style: normal; 46 | font-weight: normal; 47 | line-height: 1; 48 | padding-left: 5px; 49 | } 50 | 51 | a.asc:after { 52 | content: /*"\e113"*/ "\e151"; 53 | } 54 | 55 | a.desc:after { 56 | content: /*"\e114"*/ "\e152"; 57 | } 58 | 59 | .sort-numerical a.asc:after { 60 | content: "\e153"; 61 | } 62 | 63 | .sort-numerical a.desc:after { 64 | content: "\e154"; 65 | } 66 | 67 | .sort-ordinal a.asc:after { 68 | content: "\e155"; 69 | } 70 | 71 | .sort-ordinal a.desc:after { 72 | content: "\e156"; 73 | } 74 | 75 | .grid-view th { 76 | white-space: nowrap; 77 | } 78 | 79 | .hint-block { 80 | display: block; 81 | margin-top: 5px; 82 | color: #999; 83 | } 84 | 85 | .error-summary { 86 | color: #a94442; 87 | background: #fdf7f7; 88 | border-left: 3px solid #eed3d7; 89 | padding: 10px 20px; 90 | margin: 0 0 15px 0; 91 | } 92 | -------------------------------------------------------------------------------- /models/ContactForm.php: -------------------------------------------------------------------------------- 1 | 'Verification Code', 41 | ]; 42 | } 43 | 44 | /** 45 | * Sends an email to the specified email address using the information collected by this model. 46 | * @param string $email the target email address 47 | * @return boolean whether the model passes validation 48 | */ 49 | public function contact($email) 50 | { 51 | if ($this->validate()) { 52 | Yii::$app->mailer->compose() 53 | ->setTo($email) 54 | ->setFrom([$this->email => $this->name]) 55 | ->setSubject($this->subject) 56 | ->setTextBody($this->body) 57 | ->send(); 58 | 59 | return true; 60 | } else { 61 | return false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpnt/our-yii-app", 3 | "description": "Our Yii2 Application", 4 | "keywords": ["yii2", "framework", "basic", "application template"], 5 | "homepage": "http://www.phpnt.com/", 6 | "type": "project", 7 | "license": "BSD-3-Clause", 8 | "support": { 9 | "issues": "https://github.com/yiisoft/yii2/issues?state=open", 10 | "forum": "http://www.yiiframework.com/forum/", 11 | "wiki": "http://www.yiiframework.com/wiki/", 12 | "irc": "irc://irc.freenode.net/yii", 13 | "source": "https://github.com/yiisoft/yii2" 14 | }, 15 | "minimum-stability": "dev", 16 | "require": { 17 | "php": ">=5.4.0", 18 | "yiisoft/yii2": "*", 19 | "yiisoft/yii2-bootstrap": "*", 20 | "yiisoft/yii2-swiftmailer": "*", 21 | "yiisoft/yii2-jui": "~2.0@dev" 22 | }, 23 | "require-dev": { 24 | "yiisoft/yii2-codeception": "*", 25 | "yiisoft/yii2-debug": "*", 26 | "yiisoft/yii2-gii": "*", 27 | "yiisoft/yii2-faker": "*" 28 | }, 29 | "config": { 30 | "process-timeout": 1800 31 | }, 32 | "scripts": { 33 | "post-create-project-cmd": [ 34 | "yii\\composer\\Installer::postCreateProject" 35 | ] 36 | }, 37 | "extra": { 38 | "yii\\composer\\Installer::postCreateProject": { 39 | "setPermission": [ 40 | { 41 | "runtime": "0777", 42 | "web/assets": "0777", 43 | "yii": "0755" 44 | } 45 | ], 46 | "generateCookieValidationKey": [ 47 | "config/web.php" 48 | ] 49 | }, 50 | "asset-installer-paths": { 51 | "npm-asset-library": "vendor/npm", 52 | "bower-asset-library": "vendor/bower" 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/codeception/acceptance/ContactCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that contact works'); 7 | 8 | $contactPage = ContactPage::openBy($I); 9 | 10 | $I->see('Contact', 'h1'); 11 | 12 | $I->amGoingTo('submit contact form with no data'); 13 | $contactPage->submit([]); 14 | if (method_exists($I, 'wait')) { 15 | $I->wait(3); // only for selenium 16 | } 17 | $I->expectTo('see validations errors'); 18 | $I->see('Contact', 'h1'); 19 | $I->see('Name cannot be blank'); 20 | $I->see('Email cannot be blank'); 21 | $I->see('Subject cannot be blank'); 22 | $I->see('Body cannot be blank'); 23 | $I->see('The verification code is incorrect'); 24 | 25 | $I->amGoingTo('submit contact form with not correct email'); 26 | $contactPage->submit([ 27 | 'name' => 'tester', 28 | 'email' => 'tester.email', 29 | 'subject' => 'test subject', 30 | 'body' => 'test content', 31 | 'verifyCode' => 'testme', 32 | ]); 33 | if (method_exists($I, 'wait')) { 34 | $I->wait(3); // only for selenium 35 | } 36 | $I->expectTo('see that email adress is wrong'); 37 | $I->dontSee('Name cannot be blank', '.help-inline'); 38 | $I->see('Email is not a valid email address.'); 39 | $I->dontSee('Subject cannot be blank', '.help-inline'); 40 | $I->dontSee('Body cannot be blank', '.help-inline'); 41 | $I->dontSee('The verification code is incorrect', '.help-inline'); 42 | 43 | $I->amGoingTo('submit contact form with correct data'); 44 | $contactPage->submit([ 45 | 'name' => 'tester', 46 | 'email' => 'tester@example.com', 47 | 'subject' => 'test subject', 48 | 'body' => 'test content', 49 | 'verifyCode' => 'testme', 50 | ]); 51 | if (method_exists($I, 'wait')) { 52 | $I->wait(3); // only for selenium 53 | } 54 | $I->dontSeeElement('#contact-form'); 55 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.'); 56 | -------------------------------------------------------------------------------- /tests/codeception/unit/models/ContactFormTest.php: -------------------------------------------------------------------------------- 1 | mailer->fileTransportCallback = function ($mailer, $message) { 17 | return 'testing_message.eml'; 18 | }; 19 | } 20 | 21 | protected function tearDown() 22 | { 23 | unlink($this->getMessageFile()); 24 | parent::tearDown(); 25 | } 26 | 27 | public function testContact() 28 | { 29 | $model = $this->getMock('app\models\ContactForm', ['validate']); 30 | $model->expects($this->once())->method('validate')->will($this->returnValue(true)); 31 | 32 | $model->attributes = [ 33 | 'name' => 'Tester', 34 | 'email' => 'tester@example.com', 35 | 'subject' => 'very important letter subject', 36 | 'body' => 'body of current message', 37 | ]; 38 | 39 | $model->contact('admin@example.com'); 40 | 41 | $this->specify('email should be send', function () { 42 | expect('email file should exist', file_exists($this->getMessageFile()))->true(); 43 | }); 44 | 45 | $this->specify('message should contain correct data', function () use ($model) { 46 | $emailMessage = file_get_contents($this->getMessageFile()); 47 | 48 | expect('email should contain user name', $emailMessage)->contains($model->name); 49 | expect('email should contain sender email', $emailMessage)->contains($model->email); 50 | expect('email should contain subject', $emailMessage)->contains($model->subject); 51 | expect('email should contain body', $emailMessage)->contains($model->body); 52 | }); 53 | } 54 | 55 | private function getMessageFile() 56 | { 57 | return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml'; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /tests/codeception/unit/models/LoginFormTest.php: -------------------------------------------------------------------------------- 1 | user->logout(); 17 | parent::tearDown(); 18 | } 19 | 20 | public function testLoginNoUser() 21 | { 22 | $model = new LoginForm([ 23 | 'username' => 'not_existing_username', 24 | 'password' => 'not_existing_password', 25 | ]); 26 | 27 | $this->specify('user should not be able to login, when there is no identity', function () use ($model) { 28 | expect('model should not login user', $model->login())->false(); 29 | expect('user should not be logged in', Yii::$app->user->isGuest)->true(); 30 | }); 31 | } 32 | 33 | public function testLoginWrongPassword() 34 | { 35 | $model = new LoginForm([ 36 | 'username' => 'demo', 37 | 'password' => 'wrong_password', 38 | ]); 39 | 40 | $this->specify('user should not be able to login with wrong password', function () use ($model) { 41 | expect('model should not login user', $model->login())->false(); 42 | expect('error message should be set', $model->errors)->hasKey('password'); 43 | expect('user should not be logged in', Yii::$app->user->isGuest)->true(); 44 | }); 45 | } 46 | 47 | public function testLoginCorrect() 48 | { 49 | $model = new LoginForm([ 50 | 'username' => 'demo', 51 | 'password' => 'demo', 52 | ]); 53 | 54 | $this->specify('user should be able to login with correct credentials', function () use ($model) { 55 | expect('model should login user', $model->login())->true(); 56 | expect('error message should not be set', $model->errors)->hasntKey('password'); 57 | expect('user should be logged in', Yii::$app->user->isGuest)->false(); 58 | }); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /models/Profile.php: -------------------------------------------------------------------------------- 1 | 255], 38 | [['first_name', 'second_name', 'middle_name'], 'string', 'max' => 32] 39 | ]; 40 | } 41 | 42 | /** 43 | * @inheritdoc 44 | */ 45 | public function attributeLabels() 46 | { 47 | return [ 48 | 'user_id' => 'User ID', 49 | 'avatar' => 'Аватар', 50 | 'first_name' => 'Имя', 51 | 'second_name' => 'Фамилия', 52 | 'middle_name' => 'Отчество', 53 | 'birthday' => 'Дата рождения', 54 | 'gender' => 'Пол', 55 | ]; 56 | } 57 | 58 | /** 59 | * @return \yii\db\ActiveQuery 60 | */ 61 | public function getUser() 62 | { 63 | return $this->hasOne(User::className(), ['id' => 'user_id']); 64 | } 65 | 66 | public function updateProfile() 67 | { 68 | $profile = ($profile = Profile::findOne(Yii::$app->user->id)) ? $profile : new Profile(); 69 | $profile->user_id = Yii::$app->user->id; 70 | $profile->first_name = $this->first_name; 71 | $profile->second_name = $this->second_name; 72 | $profile->middle_name = $this->middle_name; 73 | if($profile->save()): 74 | $user = $this->user ? $this->user : User::findOne(Yii::$app->user->id); 75 | $username = Yii::$app->request->post('User')['username']; 76 | $user->username = isset($username) ? $username : $user->username; 77 | return $user->save() ? true : false; 78 | endif; 79 | return false; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /views/site/contact.php: -------------------------------------------------------------------------------- 1 | title = 'Contact'; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
14 |

title) ?>

15 | 16 | session->hasFlash('contactFormSubmitted')): ?> 17 | 18 |
19 | Thank you for contacting us. We will respond to you as soon as possible. 20 |
21 | 22 |

23 | Note that if you turn on the Yii debugger, you should be able 24 | to view the mail message on the mail panel of the debugger. 25 | mailer->useFileTransport): ?> 26 | Because the application is in development mode, the email is not sent but saved as 27 | a file under mailer->fileTransportPath) ?>. 28 | Please configure the useFileTransport property of the mail 29 | application component to be false to enable email sending. 30 | 31 |

32 | 33 | 34 | 35 |

36 | If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. 37 |

38 | 39 |
40 |
41 | 'contact-form']); ?> 42 | field($model, 'name') ?> 43 | field($model, 'email') ?> 44 | field($model, 'subject') ?> 45 | field($model, 'body')->textArea(['rows' => 6]) ?> 46 | field($model, 'verifyCode')->widget(Captcha::className(), [ 47 | 'template' => '
{image}
{input}
', 48 | ]) ?> 49 |
50 | 'btn btn-primary', 'name' => 'contact-button']) ?> 51 |
52 | 53 |
54 |
55 | 56 | 57 |
58 | -------------------------------------------------------------------------------- /models/LoginForm.php: -------------------------------------------------------------------------------- 1 | 'default'], 27 | [['email', 'password'], 'required', 'on' => 'loginWithEmail'], 28 | ['email', 'email'], 29 | ['rememberMe', 'boolean'], 30 | ['password', 'validatePassword'] 31 | ]; 32 | } 33 | 34 | public function validatePassword($attribute) 35 | { 36 | if (!$this->hasErrors()): 37 | $user = $this->getUser(); 38 | if (!$user || !$user->validatePassword($this->password)): 39 | $field = ($this->scenario === 'loginWithEmail') ? 'email' : 'username'; 40 | $this->addError($attribute, 'Неправильный '.$field.' или пароль.'); 41 | endif; 42 | endif; 43 | } 44 | 45 | public function getUser() 46 | { 47 | if ($this->_user === false): 48 | if($this->scenario === 'loginWithEmail'): 49 | $this->_user = User::findByEmail($this->email); 50 | else: 51 | $this->_user = User::findByUsername($this->username); 52 | endif; 53 | endif; 54 | return $this->_user; 55 | } 56 | 57 | public function attributeLabels() 58 | { 59 | return [ 60 | 'username' => 'Ник', 61 | 'email' => 'Емайл', 62 | 'password' => 'Пароль', 63 | 'rememberMe' => 'Запомнить меня' 64 | ]; 65 | } 66 | 67 | public function login() 68 | { 69 | if ($this->validate()): 70 | $this->status = ($user = $this->getUser()) ? $user->status : User::STATUS_NOT_ACTIVE; 71 | if ($this->status === User::STATUS_ACTIVE): 72 | return Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0); 73 | else: 74 | return false; 75 | endif; 76 | else: 77 | return false; 78 | endif; 79 | } 80 | } -------------------------------------------------------------------------------- /views/layouts/main.php: -------------------------------------------------------------------------------- 1 | 13 | beginPage() ?> 14 | 15 | 16 | 17 | 18 | 19 | 20 | <?= Html::encode($this->title) ?> 21 | head() ?> 22 | 23 | 24 | 25 | beginBody() ?> 26 |
27 | 'My Company', 30 | 'brandUrl' => Yii::$app->homeUrl, 31 | 'options' => [ 32 | 'class' => 'navbar-inverse navbar-fixed-top', 33 | ], 34 | ]); 35 | echo Nav::widget([ 36 | 'options' => ['class' => 'navbar-nav navbar-right'], 37 | 'items' => [ 38 | ['label' => 'Home', 'url' => ['/site/index']], 39 | ['label' => 'About', 'url' => ['/site/about']], 40 | ['label' => 'Contact', 'url' => ['/site/contact']], 41 | Yii::$app->user->isGuest ? 42 | ['label' => 'Login', 'url' => ['/site/login']] : 43 | ['label' => 'Logout (' . Yii::$app->user->identity->username . ')', 44 | 'url' => ['/site/logout'], 45 | 'linkOptions' => ['data-method' => 'post']], 46 | ], 47 | ]); 48 | NavBar::end(); 49 | ?> 50 | 51 |
52 | isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], 54 | ]) ?> 55 | 56 |
57 |
58 | 59 |
60 |
61 |

© My Company

62 |

63 |
64 |
65 | 66 | endBody() ?> 67 | 68 | 69 | endPage() ?> 70 | -------------------------------------------------------------------------------- /models/RegForm.php: -------------------------------------------------------------------------------- 1 | 'trim'], 24 | [['username', 'email', 'password'],'required'], 25 | ['username', 'string', 'min' => 2, 'max' => 255], 26 | ['password', 'string', 'min' => 6, 'max' => 255], 27 | ['username', 'unique', 28 | 'targetClass' => User::className(), 29 | 'message' => 'Это имя уже занято.'], 30 | ['email', 'email'], 31 | ['email', 'unique', 32 | 'targetClass' => User::className(), 33 | 'message' => 'Эта почта уже занята.'], 34 | ['status', 'default', 'value' => User::STATUS_ACTIVE, 'on' => 'default'], 35 | ['status', 'in', 'range' =>[ 36 | User::STATUS_NOT_ACTIVE, 37 | User::STATUS_ACTIVE 38 | ]], 39 | ['status', 'default', 'value' => User::STATUS_NOT_ACTIVE, 'on' => 'emailActivation'], 40 | ]; 41 | } 42 | 43 | public function attributeLabels() 44 | { 45 | return [ 46 | 'username' => 'Имя пользователя', 47 | 'email' => 'Эл. почта', 48 | 'password' => 'Пароль' 49 | ]; 50 | } 51 | 52 | public function reg() 53 | { 54 | $user = new User(); 55 | $user->username = $this->username; 56 | $user->email = $this->email; 57 | $user->status = $this->status; 58 | $user->setPassword($this->password); 59 | $user->generateAuthKey(); 60 | if($this->scenario === 'emailActivation') 61 | $user->generateSecretKey(); 62 | return $user->save() ? $user : null; 63 | } 64 | 65 | public function sendActivationEmail($user) 66 | { 67 | return Yii::$app->mailer->compose('activationEmail', ['user' => $user]) 68 | ->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name.' (отправлено роботом).']) 69 | ->setTo($this->email) 70 | ->setSubject('Активация для '.Yii::$app->name) 71 | ->send(); 72 | } 73 | } -------------------------------------------------------------------------------- /views/site/index.php: -------------------------------------------------------------------------------- 1 | title = 'My Yii Application'; 4 | ?> 5 |
6 | 7 |
8 |

Congratulations!

9 | 10 |

You have successfully created your Yii-powered application.

11 | 12 |

Get started with Yii

13 |
14 | 15 |
16 | 17 |
18 |
19 |

Heading

20 | 21 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 22 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 23 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 24 | fugiat nulla pariatur.

25 | 26 |

Yii Documentation »

27 |
28 |
29 |

Heading

30 | 31 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 32 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 33 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 34 | fugiat nulla pariatur.

35 | 36 |

Yii Forum »

37 |
38 |
39 |

Heading

40 | 41 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 42 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 43 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 44 | fugiat nulla pariatur.

45 | 46 |

Yii Extensions »

47 |
48 |
49 | 50 |
51 |
52 | -------------------------------------------------------------------------------- /controllers/BehaviorsController.php: -------------------------------------------------------------------------------- 1 | [ 22 | 'class' => AccessControl::className(), 23 | /*'denyCallback' => function ($rule, $action) { 24 | throw new \Exception('Нет доступа.'); 25 | },*/ 26 | 'rules' => [ 27 | [ 28 | 'allow' => true, 29 | 'controllers' => ['main'], 30 | 'actions' => ['reg', 'login', 'activate-account'], 31 | 'verbs' => ['GET', 'POST'], 32 | 'roles' => ['?'] 33 | ], 34 | [ 35 | 'allow' => true, 36 | 'controllers' => ['main'], 37 | 'actions' => ['profile'], 38 | 'verbs' => ['GET', 'POST'], 39 | 'roles' => ['@'] 40 | ], 41 | [ 42 | 'allow' => true, 43 | 'controllers' => ['main'], 44 | 'actions' => ['logout'], 45 | 'verbs' => ['POST'], 46 | 'roles' => ['@'] 47 | ], 48 | [ 49 | 'allow' => true, 50 | 'controllers' => ['main'], 51 | 'actions' => ['index', 'search', 'send-email', 'reset-password'] 52 | ], 53 | [ 54 | 'allow' => true, 55 | 'controllers' => ['widget-test'], 56 | 'actions' => ['index'], 57 | /*'ips' => ['127.1.*'], 58 | 'matchCallback' => function ($rule, $action) { 59 | return date('d-m') === '30-06'; 60 | }*/ 61 | ], 62 | ] 63 | ], 64 | 'removeUnderscore' => [ 65 | 'class' => MyBehaviors::className(), 66 | 'controller' => Yii::$app->controller->id, 67 | 'action' => Yii::$app->controller->action->id, 68 | 'removeUnderscore' => Yii::$app->request->get('search') 69 | ] 70 | ]; 71 | } 72 | } -------------------------------------------------------------------------------- /controllers/SiteController.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'class' => AccessControl::className(), 19 | 'only' => ['logout'], 20 | 'rules' => [ 21 | [ 22 | 'actions' => ['logout'], 23 | 'allow' => true, 24 | 'roles' => ['@'], 25 | ], 26 | ], 27 | ], 28 | 'verbs' => [ 29 | 'class' => VerbFilter::className(), 30 | 'actions' => [ 31 | 'logout' => ['post'], 32 | ], 33 | ], 34 | ]; 35 | } 36 | 37 | public function actions() 38 | { 39 | return [ 40 | 'error' => [ 41 | 'class' => 'yii\web\ErrorAction', 42 | ], 43 | 'captcha' => [ 44 | 'class' => 'yii\captcha\CaptchaAction', 45 | 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, 46 | ], 47 | ]; 48 | } 49 | 50 | public function actionIndex() 51 | { 52 | return $this->render('index'); 53 | } 54 | 55 | public function actionLogin() 56 | { 57 | if (!\Yii::$app->user->isGuest) { 58 | return $this->goHome(); 59 | } 60 | 61 | $model = new LoginForm(); 62 | if ($model->load(Yii::$app->request->post()) && $model->login()) { 63 | return $this->goBack(); 64 | } else { 65 | return $this->render('login', [ 66 | 'model' => $model, 67 | ]); 68 | } 69 | } 70 | 71 | public function actionLogout() 72 | { 73 | Yii::$app->user->logout(); 74 | 75 | return $this->goHome(); 76 | } 77 | 78 | public function actionContact() 79 | { 80 | $model = new ContactForm(); 81 | if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) { 82 | Yii::$app->session->setFlash('contactFormSubmitted'); 83 | 84 | return $this->refresh(); 85 | } else { 86 | return $this->render('contact', [ 87 | 'model' => $model, 88 | ]); 89 | } 90 | } 91 | 92 | public function actionAbout() 93 | { 94 | return $this->render('about'); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /components/AlertWidget.php: -------------------------------------------------------------------------------- 1 | getSession()->setFlash('error', 'This is the message'); 20 | * \Yii::$app->getSession()->setFlash('success', 'This is the message'); 21 | * \Yii::$app->getSession()->setFlash('info', 'This is the message'); 22 | * ``` 23 | * 24 | * Multiple messages could be set as follows: 25 | * 26 | * ```php 27 | * \Yii::$app->getSession()->setFlash('error', ['Error 1', 'Error 2']); 28 | * ``` 29 | * 30 | * @author Kartik Visweswaran 31 | * @author Alexander Makarov 32 | */ 33 | class AlertWidget extends \yii\bootstrap\Widget 34 | { 35 | /** 36 | * @var array the alert types configuration for the flash messages. 37 | * This array is setup as $key => $value, where: 38 | * - $key is the name of the session flash variable 39 | * - $value is the bootstrap alert type (i.e. danger, success, info, warning) 40 | */ 41 | public $alertTypes = [ 42 | 'error' => 'alert-danger', 43 | 'danger' => 'alert-danger', 44 | 'success' => 'alert-success', 45 | 'info' => 'alert-info', 46 | 'warning' => 'alert-warning' 47 | ]; 48 | /** 49 | * @var array the options for rendering the close button tag. 50 | */ 51 | public $closeButton = []; 52 | public function init() 53 | { 54 | parent::init(); 55 | $session = \Yii::$app->getSession(); 56 | $flashes = $session->getAllFlashes(); 57 | $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : ''; 58 | foreach ($flashes as $type => $data) { 59 | if (isset($this->alertTypes[$type])) { 60 | $data = (array) $data; 61 | foreach ($data as $i => $message) { 62 | /* initialize css class for each alert box */ 63 | $this->options['class'] = $this->alertTypes[$type] . $appendCss; 64 | /* assign unique id to each alert box */ 65 | $this->options['id'] = $this->getId() . '-' . $type . '-' . $i; 66 | echo \yii\bootstrap\Alert::widget([ 67 | 'body' => $message, 68 | 'closeButton' => $this->closeButton, 69 | 'options' => $this->options, 70 | ]); 71 | } 72 | $session->removeFlash($type); 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yii 2 Basic Application Template 2 | ================================ 3 | 4 | Yii 2 Basic Application Template is a skeleton Yii 2 application best for 5 | rapidly creating small projects. 6 | 7 | The template contains the basic features including user login/logout and a contact page. 8 | It includes all commonly used configurations that would allow you to focus on adding new 9 | features to your application. 10 | 11 | 12 | DIRECTORY STRUCTURE 13 | ------------------- 14 | 15 | assets/ contains assets definition 16 | commands/ contains console commands (controllers) 17 | config/ contains application configurations 18 | controllers/ contains Web controller classes 19 | mail/ contains view files for e-mails 20 | models/ contains model classes 21 | runtime/ contains files generated during runtime 22 | tests/ contains various tests for the basic application 23 | vendor/ contains dependent 3rd-party packages 24 | views/ contains view files for the Web application 25 | web/ contains the entry script and Web resources 26 | 27 | 28 | 29 | REQUIREMENTS 30 | ------------ 31 | 32 | The minimum requirement by this application template that your Web server supports PHP 5.4.0. 33 | 34 | 35 | INSTALLATION 36 | ------------ 37 | 38 | ### Install from an Archive File 39 | 40 | Extract the archive file downloaded from [yiiframework.com](http://www.yiiframework.com/download/) to 41 | a directory named `basic` that is directly under the Web root. 42 | 43 | You can then access the application through the following URL: 44 | 45 | ~~~ 46 | http://localhost/basic/web/ 47 | ~~~ 48 | 49 | 50 | ### Install via Composer 51 | 52 | If you do not have [Composer](http://getcomposer.org/), you may install it by following the instructions 53 | at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix). 54 | 55 | You can then install this application template using the following command: 56 | 57 | ~~~ 58 | php composer.phar global require "fxp/composer-asset-plugin:1.0.0-beta4" 59 | php composer.phar create-project --prefer-dist --stability=dev phpnt/our-yii-app basic 60 | ~~~ 61 | 62 | Now you should be able to access the application through the following URL, assuming `basic` is the directory 63 | directly under the Web root. 64 | 65 | ~~~ 66 | http://localhost/basic/web/ 67 | ~~~ 68 | 69 | 70 | CONFIGURATION 71 | ------------- 72 | 73 | ### Database 74 | 75 | Edit the file `config/db.php` with real data, for example: 76 | 77 | ```php 78 | return [ 79 | 'class' => 'yii\db\Connection', 80 | 'dsn' => 'mysql:host=localhost;dbname=yii2basic', 81 | 'username' => 'root', 82 | 'password' => '1234', 83 | 'charset' => 'utf8', 84 | ]; 85 | ``` 86 | 87 | **NOTE:** Yii won't create the database for you, this has to be done manually before you can access it. 88 | 89 | Also check and edit the other files in the `config/` directory to customize your application. 90 | -------------------------------------------------------------------------------- /config/web.php: -------------------------------------------------------------------------------- 1 | 'basic', 7 | 'name' => 'Yii2 приложение', 8 | 'basePath' => dirname(__DIR__), 9 | 'bootstrap' => ['log'], 10 | 'layout' => 'basic', 11 | 'defaultRoute' => 'main/index', 12 | 'language' => 'ru_RU', 13 | 'charset' => 'UTF-8', 14 | 'components' => [ 15 | 'request' => [ 16 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 17 | 'cookieValidationKey' => 'MjD6piSCPfhtvTpJX6CrmVLvWXrhjf2t', 18 | ], 19 | 'cache' => [ 20 | 'class' => 'yii\caching\FileCache', 21 | ], 22 | 'user' => [ 23 | 'identityClass' => 'app\models\User', 24 | 'enableAutoLogin' => true, 25 | 'loginUrl' => ['main/login'] 26 | ], 27 | 'errorHandler' => [ 28 | 'errorAction' => 'site/error', 29 | ], 30 | 'mailer' => [ 31 | 'class' => 'yii\swiftmailer\Mailer', 32 | // send all mails to a file by default. You have to set 33 | // 'useFileTransport' to false and configure a transport 34 | // for the mailer to send real emails. 35 | 'useFileTransport' => true, 36 | ], 37 | 'log' => [ 38 | 'traceLevel' => YII_DEBUG ? 3 : 0, 39 | 'targets' => [ 40 | [ 41 | 'class' => 'yii\log\FileTarget', 42 | 'levels' => ['error', 'warning'], 43 | ], 44 | ], 45 | ], 46 | 'db' => require(__DIR__ . '/db.php'), 47 | 'urlManager' => [ 48 | 'enablePrettyUrl' => true, 49 | 'showScriptName' => false, 50 | 'enableStrictParsing' => true, 51 | 'rules' => [ 52 | [ 53 | 'pattern' => '', 54 | 'route' => 'main/index', 55 | 'suffix' => '' 56 | ], 57 | [ 58 | 'pattern' => 'найти--', 59 | 'route' => 'main/search', 60 | 'suffix' => '.html' 61 | ], 62 | [ 63 | 'pattern' => 'найти-', 64 | 'route' => 'main/search', 65 | 'suffix' => '.html' 66 | ], 67 | [ 68 | 'pattern' => '//', 69 | 'route' => '/', 70 | 'suffix' => '' 71 | ], 72 | [ 73 | 'pattern' => '/', 74 | 'route' => '/', 75 | 'suffix' => '.html' 76 | ], 77 | [ 78 | 'pattern' => '///', 79 | 'route' => '//', 80 | 'suffix' => '' 81 | ], 82 | [ 83 | 'pattern' => '//', 84 | 'route' => '//', 85 | 'suffix' => '.html' 86 | ], 87 | ] 88 | ] 89 | ], 90 | 'params' => $params, 91 | ]; 92 | 93 | if (YII_ENV_DEV) { 94 | // configuration adjustments for 'dev' environment 95 | $config['bootstrap'][] = 'debug'; 96 | $config['modules']['debug'] = 'yii\debug\Module'; 97 | 98 | $config['bootstrap'][] = 'gii'; 99 | $config['modules']['gii'] = 'yii\gii\Module'; 100 | } 101 | 102 | return $config; 103 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | This directory contains various tests for the basic application. 2 | 3 | Tests in `codeception` directory are developed with [Codeception PHP Testing Framework](http://codeception.com/). 4 | 5 | After creating the basic application, follow these steps to prepare for the tests: 6 | 7 | 1. Install Codeception if it's not yet installed: 8 | 9 | ``` 10 | composer global require "codeception/codeception=2.0.*" 11 | composer global require "codeception/specify=*" 12 | composer global require "codeception/verify=*" 13 | ``` 14 | 15 | If you've never used Composer for global packages run `composer global status`. It should output: 16 | 17 | ``` 18 | Changed current directory to 19 | ``` 20 | 21 | Then add `/vendor/bin` to you `PATH` environment variable. Now we're able to use `codecept` from command 22 | line globally. 23 | 24 | 2. Install faker extension by running the following from template root directory where `composer.json` is: 25 | 26 | ``` 27 | composer require --dev yiisoft/yii2-faker:* 28 | ``` 29 | 30 | 3. Create `yii2_basic_tests` database and update it by applying migrations: 31 | 32 | ``` 33 | codeception/bin/yii migrate 34 | ``` 35 | 36 | 4. Build the test suites: 37 | 38 | ``` 39 | codecept build 40 | ``` 41 | 42 | 5. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in 43 | webserver. In the `web` directory execute the following: 44 | 45 | ``` 46 | php -S localhost:8080 47 | ``` 48 | 49 | 6. Now you can run the tests with the following commands: 50 | 51 | ``` 52 | # run all available tests 53 | codecept run 54 | # run acceptance tests 55 | codecept run acceptance 56 | # run functional tests 57 | codecept run functional 58 | # run unit tests 59 | codecept run unit 60 | ``` 61 | 62 | Code coverage support 63 | --------------------- 64 | 65 | By default, code coverage is disabled in `codeception.yml` configuration file, you should uncomment needed rows to be able 66 | to collect code coverage. You can run your tests and collect coverage with the following command: 67 | 68 | ``` 69 | #collect coverage for all tests 70 | codecept run --coverage-html --coverage-xml 71 | 72 | #collect coverage only for unit tests 73 | codecept run unit --coverage-html --coverage-xml 74 | 75 | #collect coverage for unit and functional tests 76 | codecept run functional,unit --coverage-html --coverage-xml 77 | ``` 78 | 79 | You can see code coverage output under the `tests/_output` directory. 80 | 81 | ###Remote code coverage 82 | 83 | When you run your tests not in the same process where code coverage is collected, then you should uncomment `remote` option and its 84 | related options, to be able to collect code coverage correctly. To setup remote code coverage you should follow [instructions](http://codeception.com/docs/11-Codecoverage) 85 | from codeception site. 86 | 87 | 1. install `Codeception c3` remote support `composer require "codeception/c3:*"`; 88 | 89 | 2. copy `c3.php` file under your `web` directory; 90 | 91 | 3. include `c3.php` file in your `index-test.php` file before application run, so it can catch needed requests. 92 | 93 | Configuration options that are used by remote code coverage: 94 | 95 | - c3_url: url pointing to entry script that includes `c3.php` file, so `Codeception` will be able to produce code coverage; 96 | - remote: whether to enable remote code coverage or not; 97 | - remote_config: path to the `codeception.yml` configuration file, from the directory where `c3.php` file is located. This is needed 98 | so that `Codeception` can create itself instance and collect code coverage correctly. 99 | 100 | By default `c3_url` and `remote_config` setup correctly, you only need to copy and include `c3.php` file in your `index-test.php` 101 | 102 | After that you should be able to collect code coverage from tests that run through `PhpBrowser` or `WebDriver` with same command 103 | as for other tests: 104 | 105 | ``` 106 | #collect coverage from remote 107 | codecept run acceptance --coverage-html --coverage-xml 108 | ``` 109 | 110 | Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for 111 | more details about writing and running acceptance, functional and unit tests. 112 | -------------------------------------------------------------------------------- /requirements.php: -------------------------------------------------------------------------------- 1 | Error'; 18 | echo '

The path to yii framework seems to be incorrect.

'; 19 | echo '

You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . '.

'; 20 | echo '

Please refer to the README on how to install Yii.

'; 21 | } 22 | 23 | require_once($frameworkPath . '/requirements/YiiRequirementChecker.php'); 24 | $requirementsChecker = new YiiRequirementChecker(); 25 | 26 | $gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.'; 27 | $gdOK = $imagickOK = false; 28 | 29 | if (extension_loaded('imagick')) { 30 | $imagick = new Imagick(); 31 | $imagickFormats = $imagick->queryFormats('PNG'); 32 | if (in_array('PNG', $imagickFormats)) { 33 | $imagickOK = true; 34 | } else { 35 | $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.'; 36 | } 37 | } 38 | 39 | if (extension_loaded('gd')) { 40 | $gdInfo = gd_info(); 41 | if (!empty($gdInfo['FreeType Support'])) { 42 | $gdOK = true; 43 | } else { 44 | $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.'; 45 | } 46 | } 47 | 48 | /** 49 | * Adjust requirements according to your application specifics. 50 | */ 51 | $requirements = array( 52 | // Database : 53 | array( 54 | 'name' => 'PDO extension', 55 | 'mandatory' => true, 56 | 'condition' => extension_loaded('pdo'), 57 | 'by' => 'All DB-related classes', 58 | ), 59 | array( 60 | 'name' => 'PDO SQLite extension', 61 | 'mandatory' => false, 62 | 'condition' => extension_loaded('pdo_sqlite'), 63 | 'by' => 'All DB-related classes', 64 | 'memo' => 'Required for SQLite database.', 65 | ), 66 | array( 67 | 'name' => 'PDO MySQL extension', 68 | 'mandatory' => false, 69 | 'condition' => extension_loaded('pdo_mysql'), 70 | 'by' => 'All DB-related classes', 71 | 'memo' => 'Required for MySQL database.', 72 | ), 73 | array( 74 | 'name' => 'PDO PostgreSQL extension', 75 | 'mandatory' => false, 76 | 'condition' => extension_loaded('pdo_pgsql'), 77 | 'by' => 'All DB-related classes', 78 | 'memo' => 'Required for PostgreSQL database.', 79 | ), 80 | // Cache : 81 | array( 82 | 'name' => 'Memcache extension', 83 | 'mandatory' => false, 84 | 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), 85 | 'by' => 'MemCache', 86 | 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : '' 87 | ), 88 | array( 89 | 'name' => 'APC extension', 90 | 'mandatory' => false, 91 | 'condition' => extension_loaded('apc'), 92 | 'by' => 'ApcCache', 93 | ), 94 | // CAPTCHA: 95 | array( 96 | 'name' => 'GD PHP extension with FreeType support', 97 | 'mandatory' => false, 98 | 'condition' => $gdOK, 99 | 'by' => 'Captcha', 100 | 'memo' => $gdMemo, 101 | ), 102 | array( 103 | 'name' => 'ImageMagick PHP extension with PNG support', 104 | 'mandatory' => false, 105 | 'condition' => $imagickOK, 106 | 'by' => 'Captcha', 107 | 'memo' => $imagickMemo, 108 | ), 109 | // PHP ini : 110 | 'phpExposePhp' => array( 111 | 'name' => 'Expose PHP', 112 | 'mandatory' => false, 113 | 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), 114 | 'by' => 'Security reasons', 115 | 'memo' => '"expose_php" should be disabled at php.ini', 116 | ), 117 | 'phpAllowUrlInclude' => array( 118 | 'name' => 'PHP allow url include', 119 | 'mandatory' => false, 120 | 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), 121 | 'by' => 'Security reasons', 122 | 'memo' => '"allow_url_include" should be disabled at php.ini', 123 | ), 124 | 'phpSmtp' => array( 125 | 'name' => 'PHP mail SMTP', 126 | 'mandatory' => false, 127 | 'condition' => strlen(ini_get('SMTP'))>0, 128 | 'by' => 'Email sending', 129 | 'memo' => 'PHP mail SMTP server required', 130 | ), 131 | ); 132 | $requirementsChecker->checkYii()->check($requirements)->render(); 133 | -------------------------------------------------------------------------------- /models/User.php: -------------------------------------------------------------------------------- 1 | 'trim'], 46 | [['username', 'email', 'status'], 'required'], 47 | ['email', 'email'], 48 | ['username', 'string', 'min' => 2, 'max' => 255], 49 | ['password', 'required', 'on' => 'create'], 50 | ['username', 'unique', 'message' => 'Это имя занято.'], 51 | ['email', 'unique', 'message' => 'Эта почта уже зарегистрирована.'], 52 | ['secret_key', 'unique'] 53 | ]; 54 | } 55 | 56 | /** 57 | * @inheritdoc 58 | */ 59 | public function attributeLabels() 60 | { 61 | return [ 62 | 'id' => 'ID', 63 | 'username' => 'Ник', 64 | 'email' => 'Email', 65 | 'password' => 'Password Hash', 66 | 'status' => 'Статус', 67 | 'auth_key' => 'Auth Key', 68 | 'created_at' => 'Дата создания', 69 | 'updated_at' => 'Дата изменения', 70 | ]; 71 | } 72 | 73 | /* Связи */ 74 | public function getProfile() 75 | { 76 | return $this->hasOne(Profile::className(), ['user_id' => 'id']); 77 | } 78 | 79 | /* Поведения */ 80 | public function behaviors() 81 | { 82 | return [ 83 | TimestampBehavior::className() 84 | ]; 85 | } 86 | 87 | /* Поиск */ 88 | 89 | /** Находит пользователя по имени и возвращает объект найденного пользователя. 90 | * Вызываеться из модели LoginForm. 91 | */ 92 | public static function findByUsername($username) 93 | { 94 | return static::findOne([ 95 | 'username' => $username 96 | ]); 97 | } 98 | 99 | /* Находит пользователя по емайл */ 100 | public static function findByEmail($email) 101 | { 102 | return static::findOne([ 103 | 'email' => $email 104 | ]); 105 | } 106 | 107 | public static function findBySecretKey($key) 108 | { 109 | if (!static::isSecretKeyExpire($key)) 110 | { 111 | return null; 112 | } 113 | return static::findOne([ 114 | 'secret_key' => $key, 115 | ]); 116 | } 117 | 118 | /* Хелперы */ 119 | public function generateSecretKey() 120 | { 121 | $this->secret_key = Yii::$app->security->generateRandomString().'_'.time(); 122 | } 123 | 124 | public function removeSecretKey() 125 | { 126 | $this->secret_key = null; 127 | } 128 | 129 | public static function isSecretKeyExpire($key) 130 | { 131 | if (empty($key)) 132 | { 133 | return false; 134 | } 135 | $expire = Yii::$app->params['secretKeyExpire']; 136 | $parts = explode('_', $key); 137 | $timestamp = (int) end($parts); 138 | 139 | return $timestamp + $expire >= time(); 140 | } 141 | 142 | /** 143 | * Генерирует хеш из введенного пароля и присваивает (при записи) полученное значение полю password_hash таблицы user для 144 | * нового пользователя. 145 | * Вызываеться из модели RegForm. 146 | */ 147 | public function setPassword($password) 148 | { 149 | $this->password_hash = Yii::$app->security->generatePasswordHash($password); 150 | } 151 | 152 | /** 153 | * Генерирует случайную строку из 32 шестнадцатеричных символов и присваивает (при записи) полученное значение полю auth_key 154 | * таблицы user для нового пользователя. 155 | * Вызываеться из модели RegForm. 156 | */ 157 | public function generateAuthKey(){ 158 | $this->auth_key = Yii::$app->security->generateRandomString(); 159 | } 160 | 161 | /** 162 | * Сравнивает полученный пароль с паролем в поле password_hash, для текущего пользователя, в таблице user. 163 | * Вызываеться из модели LoginForm. 164 | */ 165 | public function validatePassword($password) 166 | { 167 | return Yii::$app->security->validatePassword($password, $this->password_hash); 168 | } 169 | 170 | /* Аутентификация пользователей */ 171 | public static function findIdentity($id) 172 | { 173 | return static::findOne([ 174 | 'id' => $id, 175 | 'status' => self::STATUS_ACTIVE 176 | ]); 177 | } 178 | 179 | public static function findIdentityByAccessToken($token, $type = null) 180 | { 181 | return static::findOne(['access_token' => $token]); 182 | } 183 | 184 | public function getId() 185 | { 186 | return $this->id; 187 | } 188 | 189 | public function getAuthKey() 190 | { 191 | return $this->auth_key; 192 | } 193 | 194 | public function validateAuthKey($authKey) 195 | { 196 | return $this->auth_key === $authKey; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /views/layouts/basic.php: -------------------------------------------------------------------------------- 1 | beginPage(); 20 | ?> 21 | 22 | 23 | 24 | 25 | 26 | registerMetaTag(['name' => 'viewport', 'content' => 'width=device-width, initial-scale=1']); ?> 27 | <?= Yii::$app->name ?> 28 | head() ?> 29 | 30 | 31 | beginBody(); ?> 32 | 33 |
34 | [ 38 | 'class' => 'navbar navbar-default', 39 | 'id' => 'main-menu' 40 | ], 41 | 'renderInnerContainer' => true, 42 | 'innerContainerOptions' => [ 43 | 'class' => 'container' 44 | ], 45 | 'brandLabel' => '', 46 | 'brandUrl' => [ 47 | '/main/index' 48 | ], 49 | 'brandOptions' => [ 50 | 'class' => 'navbar-brand' 51 | ] 52 | ] 53 | ); 54 | if (!Yii::$app->user->isGuest): 55 | ?> 56 | 70 | 'Из коробки ', 75 | 'items' => [ 76 | '', 77 | '
  • ', 78 | [ 79 | 'label' => 'Перейти к просмотру', 80 | 'url' => ['/widget-test/index'] 81 | ] 82 | ] 83 | ], 84 | [ 85 | 'label' => 'О проекте ', 86 | 'url' => [ 87 | '#' 88 | ], 89 | 'linkOptions' => [ 90 | 'data-toggle' => 'modal', 91 | 'data-target' => '#modal', 92 | 'style' => 'cursor: pointer; outline: none;' 93 | ], 94 | ], 95 | ]; 96 | 97 | if (Yii::$app->user->isGuest): 98 | $menuItems[] = [ 99 | 'label' => 'Регистрация', 100 | 'url' => ['/main/reg'] 101 | ]; 102 | $menuItems[] = [ 103 | 'label' => 'Войти', 104 | 'url' => ['/main/login'] 105 | ]; 106 | endif; 107 | 108 | echo Nav::widget([ 109 | 'items' => $menuItems, 110 | 'activateParents' => true, 111 | 'encodeLabels' => false, 112 | 'options' => [ 113 | 'class' => 'navbar-nav navbar-right' 114 | ] 115 | ]); 116 | 117 | Modal::begin([ 118 | 'header' => '

    phpNT

    ', 119 | 'id' => 'modal' 120 | ]); 121 | echo 'Проект для продвинутых PHP разработчиков.'; 122 | Modal::end(); 123 | 124 | ActiveForm::begin( 125 | [ 126 | 'action' => ['/найти'], 127 | 'method' => 'get', 128 | 'options' => [ 129 | 'class' => 'navbar-form navbar-right' 130 | ] 131 | ] 132 | ); 133 | echo '
    '; 134 | echo Html::input( 135 | 'type: text', 136 | 'search', 137 | '', 138 | [ 139 | 'placeholder' => 'Найти ...', 140 | 'class' => 'form-control' 141 | ] 142 | ); 143 | echo ''; 144 | echo Html::submitButton( 145 | '', 146 | [ 147 | 'class' => 'btn btn-success', 148 | 'onClick' => 'window.location.href = this.form.action + "-" + this.form.search.value.replace(/[^\w\а-яё\А-ЯЁ]+/g, "_") + ".html";' 149 | ] 150 | ); 151 | echo '
    '; 152 | ActiveForm::end(); 153 | 154 | NavBar::end(); 155 | ?> 156 |
    157 | 158 | 159 |
    160 |
    161 | 162 |
    163 |
    164 | 165 | phpNT 166 | 167 |
    168 |
    169 | 170 | endBody(); ?> 171 | 172 | 173 | endPage(); -------------------------------------------------------------------------------- /controllers/MainController.php: -------------------------------------------------------------------------------- 1 | render( 27 | 'index', 28 | [ 29 | 'hello' => $hello 30 | ]); 31 | } 32 | 33 | public function actionProfile() 34 | { 35 | $model = ($model = Profile::findOne(Yii::$app->user->id)) ? $model : new Profile(); 36 | 37 | if($model->load(Yii::$app->request->post()) && $model->validate()): 38 | if($model->updateProfile()): 39 | Yii::$app->session->setFlash('success', 'Профиль изменен'); 40 | else: 41 | Yii::$app->session->setFlash('error', 'Профиль не изменен'); 42 | Yii::error('Ошибка записи. Профиль не изменен'); 43 | return $this->refresh(); 44 | endif; 45 | endif; 46 | 47 | return $this->render( 48 | 'profile', 49 | [ 50 | 'model' => $model 51 | ] 52 | ); 53 | } 54 | 55 | public function actionReg() 56 | { 57 | $emailActivation = Yii::$app->params['emailActivation']; 58 | $model = $emailActivation ? new RegForm(['scenario' => 'emailActivation']) : new RegForm(); 59 | 60 | if ($model->load(Yii::$app->request->post()) && $model->validate()): 61 | if ($user = $model->reg()): 62 | if ($user->status === User::STATUS_ACTIVE): 63 | if (Yii::$app->getUser()->login($user)): 64 | return $this->goHome(); 65 | endif; 66 | else: 67 | if($model->sendActivationEmail($user)): 68 | Yii::$app->session->setFlash('success', 'Письмо с активацией отправлено на емайл '.Html::encode($user->email).' (проверьте папку спам).'); 69 | else: 70 | Yii::$app->session->setFlash('error', 'Ошибка. Письмо не отправлено.'); 71 | Yii::error('Ошибка отправки письма.'); 72 | endif; 73 | return $this->refresh(); 74 | endif; 75 | else: 76 | Yii::$app->session->setFlash('error', 'Возникла ошибка при регистрации.'); 77 | Yii::error('Ошибка при регистрации'); 78 | return $this->refresh(); 79 | endif; 80 | endif; 81 | 82 | return $this->render( 83 | 'reg', 84 | [ 85 | 'model' => $model 86 | ] 87 | ); 88 | } 89 | 90 | public function actionActivateAccount($key) 91 | { 92 | try { 93 | $user = new AccountActivation($key); 94 | } 95 | catch(InvalidParamException $e) { 96 | throw new BadRequestHttpException($e->getMessage()); 97 | } 98 | 99 | if($user->activateAccount()): 100 | Yii::$app->session->setFlash('success', 'Активация прошла успешно. '.Html::encode($user->username).' вы теперь с phpNT!!!'); 101 | else: 102 | Yii::$app->session->setFlash('error', 'Ошибка активации.'); 103 | Yii::error('Ошибка при активации.'); 104 | endif; 105 | 106 | return $this->redirect(Url::to(['/main/login'])); 107 | } 108 | 109 | public function actionLogout() 110 | { 111 | Yii::$app->user->logout(); 112 | return $this->redirect(['/main/index']); 113 | } 114 | 115 | public function actionLogin() 116 | { 117 | if (!Yii::$app->user->isGuest): 118 | return $this->goHome(); 119 | endif; 120 | 121 | $loginWithEmail = Yii::$app->params['loginWithEmail']; 122 | 123 | $model = $loginWithEmail ? new LoginForm(['scenario' => 'loginWithEmail']) : new LoginForm(); 124 | 125 | if ($model->load(Yii::$app->request->post()) && $model->login()): 126 | return $this->goBack(); 127 | endif; 128 | 129 | return $this->render( 130 | 'login', 131 | [ 132 | 'model' => $model 133 | ] 134 | ); 135 | } 136 | 137 | public function actionSearch() 138 | { 139 | $search = Yii::$app->session->get('search'); 140 | Yii::$app->session->remove('search'); 141 | 142 | if ($search): 143 | Yii::$app->session->setFlash( 144 | 'success', 145 | 'Результат поиска' 146 | ); 147 | else: 148 | Yii::$app->session->setFlash( 149 | 'error', 150 | 'Не заполнена форма поиска' 151 | ); 152 | endif; 153 | 154 | return $this->render( 155 | 'search', 156 | [ 157 | 'search' => $search 158 | ] 159 | ); 160 | } 161 | 162 | public function actionSendEmail() 163 | { 164 | $model = new SendEmailForm(); 165 | 166 | if ($model->load(Yii::$app->request->post())) { 167 | if ($model->validate()) { 168 | if($model->sendEmail()): 169 | Yii::$app->getSession()->setFlash('warning', 'Проверьте емайл.'); 170 | return $this->goHome(); 171 | else: 172 | Yii::$app->getSession()->setFlash('error', 'Нельзя сбросить пароль.'); 173 | endif; 174 | } 175 | } 176 | 177 | return $this->render('sendEmail', [ 178 | 'model' => $model, 179 | ]); 180 | } 181 | 182 | public function actionResetPassword($key) 183 | { 184 | try { 185 | $model = new ResetPasswordForm($key); 186 | } 187 | catch (InvalidParamException $e) { 188 | throw new BadRequestHttpException($e->getMessage()); 189 | } 190 | 191 | if ($model->load(Yii::$app->request->post())) { 192 | if ($model->validate() && $model->resetPassword()) { 193 | Yii::$app->getSession()->setFlash('warning', 'Пароль изменен.'); 194 | return $this->redirect(['/main/login']); 195 | } 196 | } 197 | 198 | return $this->render('resetPassword', [ 199 | 'model' => $model, 200 | ]); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "0f9b2ac8c3dbc5f37342e568b48ffedd", 8 | "packages": [ 9 | { 10 | "name": "bower-asset/bootstrap", 11 | "version": "v3.3.4", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/twbs/bootstrap.git", 15 | "reference": "a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/twbs/bootstrap/zipball/a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f", 20 | "reference": "a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "bower-asset/jquery": ">=1.9.1" 25 | }, 26 | "type": "bower-asset-library", 27 | "extra": { 28 | "bower-asset-main": [ 29 | "less/bootstrap.less", 30 | "dist/css/bootstrap.css", 31 | "dist/js/bootstrap.js", 32 | "dist/fonts/glyphicons-halflings-regular.eot", 33 | "dist/fonts/glyphicons-halflings-regular.svg", 34 | "dist/fonts/glyphicons-halflings-regular.ttf", 35 | "dist/fonts/glyphicons-halflings-regular.woff", 36 | "dist/fonts/glyphicons-halflings-regular.woff2" 37 | ], 38 | "bower-asset-ignore": [ 39 | "/.*", 40 | "_config.yml", 41 | "CNAME", 42 | "composer.json", 43 | "CONTRIBUTING.md", 44 | "docs", 45 | "js/tests", 46 | "test-infra" 47 | ] 48 | }, 49 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 50 | "keywords": [ 51 | "css", 52 | "framework", 53 | "front-end", 54 | "js", 55 | "less", 56 | "mobile-first", 57 | "responsive", 58 | "web" 59 | ] 60 | }, 61 | { 62 | "name": "bower-asset/jquery", 63 | "version": "2.1.3", 64 | "source": { 65 | "type": "git", 66 | "url": "https://github.com/jquery/jquery.git", 67 | "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0" 68 | }, 69 | "dist": { 70 | "type": "zip", 71 | "url": "https://api.github.com/repos/jquery/jquery/zipball/8f2a9d9272d6ed7f32d3a484740ab342c02541e0", 72 | "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0", 73 | "shasum": "" 74 | }, 75 | "require-dev": { 76 | "bower-asset/qunit": "1.14.0", 77 | "bower-asset/requirejs": "2.1.10", 78 | "bower-asset/sinon": "1.8.1", 79 | "bower-asset/sizzle": "2.1.1-patch2" 80 | }, 81 | "type": "bower-asset-library", 82 | "extra": { 83 | "bower-asset-main": "dist/jquery.js", 84 | "bower-asset-ignore": [ 85 | "**/.*", 86 | "build", 87 | "speed", 88 | "test", 89 | "*.md", 90 | "AUTHORS.txt", 91 | "Gruntfile.js", 92 | "package.json" 93 | ] 94 | }, 95 | "license": [ 96 | "MIT" 97 | ], 98 | "keywords": [ 99 | "javascript", 100 | "jquery", 101 | "library" 102 | ] 103 | }, 104 | { 105 | "name": "bower-asset/jquery-ui", 106 | "version": "1.11.4", 107 | "source": { 108 | "type": "git", 109 | "url": "https://github.com/components/jqueryui.git", 110 | "reference": "c34f8dbf3ba57b3784b93f26119f436c0e8288e1" 111 | }, 112 | "dist": { 113 | "type": "zip", 114 | "url": "https://api.github.com/repos/components/jqueryui/zipball/c34f8dbf3ba57b3784b93f26119f436c0e8288e1", 115 | "reference": "c34f8dbf3ba57b3784b93f26119f436c0e8288e1", 116 | "shasum": "" 117 | }, 118 | "require": { 119 | "bower-asset/jquery": ">=1.6" 120 | }, 121 | "type": "bower-asset-library", 122 | "extra": { 123 | "bower-asset-main": [ 124 | "jquery-ui.js" 125 | ], 126 | "bower-asset-ignore": [] 127 | } 128 | }, 129 | { 130 | "name": "bower-asset/jquery.inputmask", 131 | "version": "3.1.62", 132 | "source": { 133 | "type": "git", 134 | "url": "https://github.com/RobinHerbots/jquery.inputmask.git", 135 | "reference": "da1a274cefa18a52a0519ac7ffe8e8d31e950eae" 136 | }, 137 | "dist": { 138 | "type": "zip", 139 | "url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/da1a274cefa18a52a0519ac7ffe8e8d31e950eae", 140 | "reference": "da1a274cefa18a52a0519ac7ffe8e8d31e950eae", 141 | "shasum": "" 142 | }, 143 | "require": { 144 | "bower-asset/jquery": ">=1.7" 145 | }, 146 | "type": "bower-asset-library", 147 | "extra": { 148 | "bower-asset-main": [ 149 | "./dist/inputmask/jquery.inputmask.js", 150 | "./dist/inputmask/jquery.inputmask.extensions.js", 151 | "./dist/inputmask/jquery.inputmask.date.extensions.js", 152 | "./dist/inputmask/jquery.inputmask.numeric.extensions.js", 153 | "./dist/inputmask/jquery.inputmask.phone.extensions.js", 154 | "./dist/inputmask/jquery.inputmask.regex.extensions.js" 155 | ], 156 | "bower-asset-ignore": [ 157 | "**/.*", 158 | "qunit/", 159 | "nuget/", 160 | "tools/", 161 | "js/", 162 | "*.md", 163 | "build.properties", 164 | "build.xml", 165 | "jquery.inputmask.jquery.json" 166 | ] 167 | }, 168 | "license": [ 169 | "http://opensource.org/licenses/mit-license.php" 170 | ], 171 | "description": "jquery.inputmask is a jquery plugin which create an input mask.", 172 | "keywords": [ 173 | "form", 174 | "input", 175 | "inputmask", 176 | "jquery", 177 | "mask", 178 | "plugins" 179 | ] 180 | }, 181 | { 182 | "name": "bower-asset/punycode", 183 | "version": "v1.3.2", 184 | "source": { 185 | "type": "git", 186 | "url": "https://github.com/bestiejs/punycode.js.git", 187 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" 188 | }, 189 | "dist": { 190 | "type": "zip", 191 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", 192 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", 193 | "shasum": "" 194 | }, 195 | "type": "bower-asset-library", 196 | "extra": { 197 | "bower-asset-main": "punycode.js", 198 | "bower-asset-ignore": [ 199 | "coverage", 200 | "tests", 201 | ".*", 202 | "component.json", 203 | "Gruntfile.js", 204 | "node_modules", 205 | "package.json" 206 | ] 207 | } 208 | }, 209 | { 210 | "name": "bower-asset/yii2-pjax", 211 | "version": "dev-master", 212 | "source": { 213 | "type": "git", 214 | "url": "https://github.com/yiisoft/jquery-pjax.git", 215 | "reference": "3f20897307cca046fca5323b318475ae9dac0ca0" 216 | }, 217 | "dist": { 218 | "type": "zip", 219 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/3f20897307cca046fca5323b318475ae9dac0ca0", 220 | "reference": "3f20897307cca046fca5323b318475ae9dac0ca0", 221 | "shasum": "" 222 | }, 223 | "require": { 224 | "bower-asset/jquery": ">=1.8" 225 | }, 226 | "type": "bower-asset-library", 227 | "extra": { 228 | "bower-asset-main": "./jquery.pjax.js", 229 | "bower-asset-ignore": [ 230 | ".travis.yml", 231 | "Gemfile", 232 | "Gemfile.lock", 233 | "vendor/", 234 | "script/", 235 | "test/" 236 | ], 237 | "branch-alias": { 238 | "dev-master": "2.0.3-dev" 239 | } 240 | }, 241 | "license": [ 242 | "MIT" 243 | ] 244 | }, 245 | { 246 | "name": "cebe/markdown", 247 | "version": "dev-master", 248 | "source": { 249 | "type": "git", 250 | "url": "https://github.com/cebe/markdown.git", 251 | "reference": "e14d3da8f84eefa3792fd22b5b5ecba9c98d2e18" 252 | }, 253 | "dist": { 254 | "type": "zip", 255 | "url": "https://api.github.com/repos/cebe/markdown/zipball/e14d3da8f84eefa3792fd22b5b5ecba9c98d2e18", 256 | "reference": "e14d3da8f84eefa3792fd22b5b5ecba9c98d2e18", 257 | "shasum": "" 258 | }, 259 | "require": { 260 | "lib-pcre": "*", 261 | "php": ">=5.4.0" 262 | }, 263 | "require-dev": { 264 | "cebe/indent": "*", 265 | "facebook/xhprof": "*@dev", 266 | "phpunit/phpunit": "4.1.*" 267 | }, 268 | "bin": [ 269 | "bin/markdown" 270 | ], 271 | "type": "library", 272 | "extra": { 273 | "branch-alias": { 274 | "dev-master": "1.1.x-dev" 275 | } 276 | }, 277 | "autoload": { 278 | "psr-4": { 279 | "cebe\\markdown\\": "" 280 | } 281 | }, 282 | "notification-url": "https://packagist.org/downloads/", 283 | "license": [ 284 | "MIT" 285 | ], 286 | "authors": [ 287 | { 288 | "name": "Carsten Brandt", 289 | "email": "mail@cebe.cc", 290 | "homepage": "http://cebe.cc/", 291 | "role": "Creator" 292 | } 293 | ], 294 | "description": "A super fast, highly extensible markdown parser for PHP", 295 | "homepage": "https://github.com/cebe/markdown#readme", 296 | "keywords": [ 297 | "extensible", 298 | "fast", 299 | "gfm", 300 | "markdown", 301 | "markdown-extra" 302 | ], 303 | "time": "2015-03-20 11:07:08" 304 | }, 305 | { 306 | "name": "ezyang/htmlpurifier", 307 | "version": "v4.6.0", 308 | "source": { 309 | "type": "git", 310 | "url": "https://github.com/ezyang/htmlpurifier.git", 311 | "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd" 312 | }, 313 | "dist": { 314 | "type": "zip", 315 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd", 316 | "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd", 317 | "shasum": "" 318 | }, 319 | "require": { 320 | "php": ">=5.2" 321 | }, 322 | "type": "library", 323 | "autoload": { 324 | "psr-0": { 325 | "HTMLPurifier": "library/" 326 | }, 327 | "files": [ 328 | "library/HTMLPurifier.composer.php" 329 | ] 330 | }, 331 | "notification-url": "https://packagist.org/downloads/", 332 | "license": [ 333 | "LGPL" 334 | ], 335 | "authors": [ 336 | { 337 | "name": "Edward Z. Yang", 338 | "email": "admin@htmlpurifier.org", 339 | "homepage": "http://ezyang.com" 340 | } 341 | ], 342 | "description": "Standards compliant HTML filter written in PHP", 343 | "homepage": "http://htmlpurifier.org/", 344 | "keywords": [ 345 | "html" 346 | ], 347 | "time": "2013-11-30 08:25:19" 348 | }, 349 | { 350 | "name": "swiftmailer/swiftmailer", 351 | "version": "5.x-dev", 352 | "source": { 353 | "type": "git", 354 | "url": "https://github.com/swiftmailer/swiftmailer.git", 355 | "reference": "728eba28e355e081b0729b4c18cb9c13abe12560" 356 | }, 357 | "dist": { 358 | "type": "zip", 359 | "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/728eba28e355e081b0729b4c18cb9c13abe12560", 360 | "reference": "728eba28e355e081b0729b4c18cb9c13abe12560", 361 | "shasum": "" 362 | }, 363 | "require": { 364 | "php": ">=5.3.3" 365 | }, 366 | "require-dev": { 367 | "mockery/mockery": "~0.9.1" 368 | }, 369 | "type": "library", 370 | "extra": { 371 | "branch-alias": { 372 | "dev-master": "5.4-dev" 373 | } 374 | }, 375 | "autoload": { 376 | "files": [ 377 | "lib/swift_required.php" 378 | ] 379 | }, 380 | "notification-url": "https://packagist.org/downloads/", 381 | "license": [ 382 | "MIT" 383 | ], 384 | "authors": [ 385 | { 386 | "name": "Chris Corbyn" 387 | }, 388 | { 389 | "name": "Fabien Potencier", 390 | "email": "fabien@symfony.com" 391 | } 392 | ], 393 | "description": "Swiftmailer, free feature-rich PHP mailer", 394 | "homepage": "http://swiftmailer.org", 395 | "keywords": [ 396 | "mail", 397 | "mailer" 398 | ], 399 | "time": "2015-03-30 15:09:02" 400 | }, 401 | { 402 | "name": "yiisoft/yii2", 403 | "version": "dev-master", 404 | "source": { 405 | "type": "git", 406 | "url": "https://github.com/yiisoft/yii2-framework.git", 407 | "reference": "ef6543e4d1554d9277c8510ec7fa1de8484cf62e" 408 | }, 409 | "dist": { 410 | "type": "zip", 411 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/ef6543e4d1554d9277c8510ec7fa1de8484cf62e", 412 | "reference": "ef6543e4d1554d9277c8510ec7fa1de8484cf62e", 413 | "shasum": "" 414 | }, 415 | "require": { 416 | "bower-asset/jquery": "2.1.*@stable | 1.11.*@stable", 417 | "bower-asset/jquery.inputmask": "3.1.*", 418 | "bower-asset/punycode": "1.3.*", 419 | "bower-asset/yii2-pjax": ">=2.0.1", 420 | "cebe/markdown": "~1.0.0 | ~1.1.0", 421 | "ext-mbstring": "*", 422 | "ezyang/htmlpurifier": "4.6.*", 423 | "lib-pcre": "*", 424 | "php": ">=5.4.0", 425 | "yiisoft/yii2-composer": "*" 426 | }, 427 | "bin": [ 428 | "yii" 429 | ], 430 | "type": "library", 431 | "extra": { 432 | "branch-alias": { 433 | "dev-master": "2.0.x-dev" 434 | } 435 | }, 436 | "autoload": { 437 | "psr-4": { 438 | "yii\\": "" 439 | } 440 | }, 441 | "notification-url": "https://packagist.org/downloads/", 442 | "license": [ 443 | "BSD-3-Clause" 444 | ], 445 | "authors": [ 446 | { 447 | "name": "Qiang Xue", 448 | "email": "qiang.xue@gmail.com", 449 | "homepage": "http://www.yiiframework.com/", 450 | "role": "Founder and project lead" 451 | }, 452 | { 453 | "name": "Alexander Makarov", 454 | "email": "sam@rmcreative.ru", 455 | "homepage": "http://rmcreative.ru/", 456 | "role": "Core framework development" 457 | }, 458 | { 459 | "name": "Maurizio Domba", 460 | "homepage": "http://mdomba.info/", 461 | "role": "Core framework development" 462 | }, 463 | { 464 | "name": "Carsten Brandt", 465 | "email": "mail@cebe.cc", 466 | "homepage": "http://cebe.cc/", 467 | "role": "Core framework development" 468 | }, 469 | { 470 | "name": "Timur Ruziev", 471 | "email": "resurtm@gmail.com", 472 | "homepage": "http://resurtm.com/", 473 | "role": "Core framework development" 474 | }, 475 | { 476 | "name": "Paul Klimov", 477 | "email": "klimov.paul@gmail.com", 478 | "role": "Core framework development" 479 | } 480 | ], 481 | "description": "Yii PHP Framework Version 2", 482 | "homepage": "http://www.yiiframework.com/", 483 | "keywords": [ 484 | "framework", 485 | "yii2" 486 | ], 487 | "time": "2015-04-26 02:01:50" 488 | }, 489 | { 490 | "name": "yiisoft/yii2-bootstrap", 491 | "version": "dev-master", 492 | "source": { 493 | "type": "git", 494 | "url": "https://github.com/yiisoft/yii2-bootstrap.git", 495 | "reference": "72da96e3af490bbb240fd04c32bb445dcb5421ae" 496 | }, 497 | "dist": { 498 | "type": "zip", 499 | "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap/zipball/72da96e3af490bbb240fd04c32bb445dcb5421ae", 500 | "reference": "72da96e3af490bbb240fd04c32bb445dcb5421ae", 501 | "shasum": "" 502 | }, 503 | "require": { 504 | "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*", 505 | "yiisoft/yii2": "*" 506 | }, 507 | "type": "yii2-extension", 508 | "extra": { 509 | "branch-alias": { 510 | "dev-master": "2.0.x-dev" 511 | }, 512 | "asset-installer-paths": { 513 | "npm-asset-library": "vendor/npm", 514 | "bower-asset-library": "vendor/bower" 515 | } 516 | }, 517 | "autoload": { 518 | "psr-4": { 519 | "yii\\bootstrap\\": "" 520 | } 521 | }, 522 | "notification-url": "https://packagist.org/downloads/", 523 | "license": [ 524 | "BSD-3-Clause" 525 | ], 526 | "authors": [ 527 | { 528 | "name": "Qiang Xue", 529 | "email": "qiang.xue@gmail.com" 530 | } 531 | ], 532 | "description": "The Twitter Bootstrap extension for the Yii framework", 533 | "keywords": [ 534 | "bootstrap", 535 | "yii2" 536 | ], 537 | "time": "2015-04-23 14:50:19" 538 | }, 539 | { 540 | "name": "yiisoft/yii2-composer", 541 | "version": "dev-master", 542 | "source": { 543 | "type": "git", 544 | "url": "https://github.com/yiisoft/yii2-composer.git", 545 | "reference": "24f53b745b6517258aedcff4f7dda7459aae503b" 546 | }, 547 | "dist": { 548 | "type": "zip", 549 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/24f53b745b6517258aedcff4f7dda7459aae503b", 550 | "reference": "24f53b745b6517258aedcff4f7dda7459aae503b", 551 | "shasum": "" 552 | }, 553 | "require": { 554 | "composer-plugin-api": "1.0.0" 555 | }, 556 | "type": "composer-plugin", 557 | "extra": { 558 | "class": "yii\\composer\\Plugin", 559 | "branch-alias": { 560 | "dev-master": "2.0.x-dev" 561 | } 562 | }, 563 | "autoload": { 564 | "psr-4": { 565 | "yii\\composer\\": "" 566 | } 567 | }, 568 | "notification-url": "https://packagist.org/downloads/", 569 | "license": [ 570 | "BSD-3-Clause" 571 | ], 572 | "authors": [ 573 | { 574 | "name": "Qiang Xue", 575 | "email": "qiang.xue@gmail.com" 576 | } 577 | ], 578 | "description": "The composer plugin for Yii extension installer", 579 | "keywords": [ 580 | "composer", 581 | "extension installer", 582 | "yii2" 583 | ], 584 | "time": "2015-03-23 18:34:13" 585 | }, 586 | { 587 | "name": "yiisoft/yii2-jui", 588 | "version": "dev-master", 589 | "source": { 590 | "type": "git", 591 | "url": "https://github.com/yiisoft/yii2-jui.git", 592 | "reference": "3a92b5eaa4e3d07940437552ee86450a20bc908c" 593 | }, 594 | "dist": { 595 | "type": "zip", 596 | "url": "https://api.github.com/repos/yiisoft/yii2-jui/zipball/3a92b5eaa4e3d07940437552ee86450a20bc908c", 597 | "reference": "3a92b5eaa4e3d07940437552ee86450a20bc908c", 598 | "shasum": "" 599 | }, 600 | "require": { 601 | "bower-asset/jquery-ui": "1.11.*@stable", 602 | "yiisoft/yii2": "*" 603 | }, 604 | "type": "yii2-extension", 605 | "extra": { 606 | "branch-alias": { 607 | "dev-master": "2.0.x-dev" 608 | }, 609 | "asset-installer-paths": { 610 | "npm-asset-library": "vendor/npm", 611 | "bower-asset-library": "vendor/bower" 612 | } 613 | }, 614 | "autoload": { 615 | "psr-4": { 616 | "yii\\jui\\": "" 617 | } 618 | }, 619 | "notification-url": "https://packagist.org/downloads/", 620 | "license": [ 621 | "BSD-3-Clause" 622 | ], 623 | "authors": [ 624 | { 625 | "name": "Qiang Xue", 626 | "email": "qiang.xue@gmail.com" 627 | } 628 | ], 629 | "description": "The Jquery UI extension for the Yii framework", 630 | "keywords": [ 631 | "jQuery UI", 632 | "yii2" 633 | ], 634 | "time": "2015-04-12 00:10:29" 635 | }, 636 | { 637 | "name": "yiisoft/yii2-swiftmailer", 638 | "version": "dev-master", 639 | "source": { 640 | "type": "git", 641 | "url": "https://github.com/yiisoft/yii2-swiftmailer.git", 642 | "reference": "a30c1ce8487d12c81af0aec177ad5d77bc1692ee" 643 | }, 644 | "dist": { 645 | "type": "zip", 646 | "url": "https://api.github.com/repos/yiisoft/yii2-swiftmailer/zipball/a30c1ce8487d12c81af0aec177ad5d77bc1692ee", 647 | "reference": "a30c1ce8487d12c81af0aec177ad5d77bc1692ee", 648 | "shasum": "" 649 | }, 650 | "require": { 651 | "swiftmailer/swiftmailer": "~5.0", 652 | "yiisoft/yii2": "*" 653 | }, 654 | "type": "yii2-extension", 655 | "extra": { 656 | "branch-alias": { 657 | "dev-master": "2.0.x-dev" 658 | } 659 | }, 660 | "autoload": { 661 | "psr-4": { 662 | "yii\\swiftmailer\\": "" 663 | } 664 | }, 665 | "notification-url": "https://packagist.org/downloads/", 666 | "license": [ 667 | "BSD-3-Clause" 668 | ], 669 | "authors": [ 670 | { 671 | "name": "Paul Klimov", 672 | "email": "klimov.paul@gmail.com" 673 | } 674 | ], 675 | "description": "The SwiftMailer integration for the Yii framework", 676 | "keywords": [ 677 | "email", 678 | "mail", 679 | "mailer", 680 | "swift", 681 | "swiftmailer", 682 | "yii2" 683 | ], 684 | "time": "2015-04-02 14:59:17" 685 | } 686 | ], 687 | "packages-dev": [ 688 | { 689 | "name": "bower-asset/typeahead.js", 690 | "version": "v0.10.5", 691 | "source": { 692 | "type": "git", 693 | "url": "https://github.com/twitter/typeahead.js.git", 694 | "reference": "5f198b87d1af845da502ea9df93a5e84801ce742" 695 | }, 696 | "dist": { 697 | "type": "zip", 698 | "url": "https://api.github.com/repos/twitter/typeahead.js/zipball/5f198b87d1af845da502ea9df93a5e84801ce742", 699 | "reference": "5f198b87d1af845da502ea9df93a5e84801ce742", 700 | "shasum": "" 701 | }, 702 | "require": { 703 | "bower-asset/jquery": ">=1.7" 704 | }, 705 | "require-dev": { 706 | "bower-asset/jasmine-ajax": "~1.3.1", 707 | "bower-asset/jasmine-jquery": "~1.5.2", 708 | "bower-asset/jquery": "~1.7" 709 | }, 710 | "type": "bower-asset-library", 711 | "extra": { 712 | "bower-asset-main": "dist/typeahead.bundle.js" 713 | } 714 | }, 715 | { 716 | "name": "fzaninotto/faker", 717 | "version": "dev-master", 718 | "source": { 719 | "type": "git", 720 | "url": "https://github.com/fzaninotto/Faker.git", 721 | "reference": "901bde792eddf6907f33634ff8aafb2dfddd4784" 722 | }, 723 | "dist": { 724 | "type": "zip", 725 | "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/901bde792eddf6907f33634ff8aafb2dfddd4784", 726 | "reference": "901bde792eddf6907f33634ff8aafb2dfddd4784", 727 | "shasum": "" 728 | }, 729 | "require": { 730 | "php": ">=5.3.3" 731 | }, 732 | "require-dev": { 733 | "phpunit/phpunit": "~4.0", 734 | "squizlabs/php_codesniffer": "~1.5" 735 | }, 736 | "suggest": { 737 | "ext-intl": "*" 738 | }, 739 | "type": "library", 740 | "extra": { 741 | "branch-alias": { 742 | "dev-master": "1.5.x-dev" 743 | } 744 | }, 745 | "autoload": { 746 | "psr-4": { 747 | "Faker\\": "src/Faker/" 748 | } 749 | }, 750 | "notification-url": "https://packagist.org/downloads/", 751 | "license": [ 752 | "MIT" 753 | ], 754 | "authors": [ 755 | { 756 | "name": "Francois Zaninotto" 757 | } 758 | ], 759 | "description": "Faker is a PHP library that generates fake data for you.", 760 | "keywords": [ 761 | "data", 762 | "faker", 763 | "fixtures" 764 | ], 765 | "time": "2015-04-14 13:37:56" 766 | }, 767 | { 768 | "name": "phpspec/php-diff", 769 | "version": "dev-master", 770 | "source": { 771 | "type": "git", 772 | "url": "https://github.com/phpspec/php-diff.git", 773 | "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a" 774 | }, 775 | "dist": { 776 | "type": "zip", 777 | "url": "https://api.github.com/repos/phpspec/php-diff/zipball/30e103d19519fe678ae64a60d77884ef3d71b28a", 778 | "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a", 779 | "shasum": "" 780 | }, 781 | "type": "library", 782 | "autoload": { 783 | "psr-0": { 784 | "Diff": "lib/" 785 | } 786 | }, 787 | "notification-url": "https://packagist.org/downloads/", 788 | "license": [ 789 | "BSD-3-Clause" 790 | ], 791 | "authors": [ 792 | { 793 | "name": "Chris Boulton", 794 | "homepage": "http://github.com/chrisboulton", 795 | "role": "Original developer" 796 | } 797 | ], 798 | "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", 799 | "time": "2013-11-01 13:02:21" 800 | }, 801 | { 802 | "name": "yiisoft/yii2-codeception", 803 | "version": "dev-master", 804 | "source": { 805 | "type": "git", 806 | "url": "https://github.com/yiisoft/yii2-codeception.git", 807 | "reference": "71bde805b9e063215114dd4ff9b9978ec1505283" 808 | }, 809 | "dist": { 810 | "type": "zip", 811 | "url": "https://api.github.com/repos/yiisoft/yii2-codeception/zipball/71bde805b9e063215114dd4ff9b9978ec1505283", 812 | "reference": "71bde805b9e063215114dd4ff9b9978ec1505283", 813 | "shasum": "" 814 | }, 815 | "require": { 816 | "yiisoft/yii2": "*" 817 | }, 818 | "type": "yii2-extension", 819 | "extra": { 820 | "branch-alias": { 821 | "dev-master": "2.0.x-dev" 822 | } 823 | }, 824 | "autoload": { 825 | "psr-4": { 826 | "yii\\codeception\\": "" 827 | } 828 | }, 829 | "notification-url": "https://packagist.org/downloads/", 830 | "license": [ 831 | "BSD-3-Clause" 832 | ], 833 | "authors": [ 834 | { 835 | "name": "Mark Jebri", 836 | "email": "mark.github@yandex.ru" 837 | } 838 | ], 839 | "description": "The Codeception integration for the Yii framework", 840 | "keywords": [ 841 | "codeception", 842 | "yii2" 843 | ], 844 | "time": "2015-04-02 21:46:21" 845 | }, 846 | { 847 | "name": "yiisoft/yii2-debug", 848 | "version": "dev-master", 849 | "source": { 850 | "type": "git", 851 | "url": "https://github.com/yiisoft/yii2-debug.git", 852 | "reference": "14ef93a0b75bd1c2d6b6eac69ffe33ff3df47560" 853 | }, 854 | "dist": { 855 | "type": "zip", 856 | "url": "https://api.github.com/repos/yiisoft/yii2-debug/zipball/14ef93a0b75bd1c2d6b6eac69ffe33ff3df47560", 857 | "reference": "14ef93a0b75bd1c2d6b6eac69ffe33ff3df47560", 858 | "shasum": "" 859 | }, 860 | "require": { 861 | "yiisoft/yii2": "*", 862 | "yiisoft/yii2-bootstrap": "*" 863 | }, 864 | "type": "yii2-extension", 865 | "extra": { 866 | "branch-alias": { 867 | "dev-master": "2.0.x-dev" 868 | } 869 | }, 870 | "autoload": { 871 | "psr-4": { 872 | "yii\\debug\\": "" 873 | } 874 | }, 875 | "notification-url": "https://packagist.org/downloads/", 876 | "license": [ 877 | "BSD-3-Clause" 878 | ], 879 | "authors": [ 880 | { 881 | "name": "Qiang Xue", 882 | "email": "qiang.xue@gmail.com" 883 | } 884 | ], 885 | "description": "The debugger extension for the Yii framework", 886 | "keywords": [ 887 | "debug", 888 | "debugger", 889 | "yii2" 890 | ], 891 | "time": "2015-04-12 08:53:46" 892 | }, 893 | { 894 | "name": "yiisoft/yii2-faker", 895 | "version": "dev-master", 896 | "source": { 897 | "type": "git", 898 | "url": "https://github.com/yiisoft/yii2-faker.git", 899 | "reference": "8f9beea41bc47c8d3100edc822f589fb2b6cdc71" 900 | }, 901 | "dist": { 902 | "type": "zip", 903 | "url": "https://api.github.com/repos/yiisoft/yii2-faker/zipball/8f9beea41bc47c8d3100edc822f589fb2b6cdc71", 904 | "reference": "8f9beea41bc47c8d3100edc822f589fb2b6cdc71", 905 | "shasum": "" 906 | }, 907 | "require": { 908 | "fzaninotto/faker": "~1.4", 909 | "yiisoft/yii2": "*" 910 | }, 911 | "type": "yii2-extension", 912 | "extra": { 913 | "branch-alias": { 914 | "dev-master": "2.0.x-dev" 915 | } 916 | }, 917 | "autoload": { 918 | "psr-4": { 919 | "yii\\faker\\": "" 920 | } 921 | }, 922 | "notification-url": "https://packagist.org/downloads/", 923 | "license": [ 924 | "BSD-3-Clause" 925 | ], 926 | "authors": [ 927 | { 928 | "name": "Mark Jebri", 929 | "email": "mark.github@yandex.ru" 930 | } 931 | ], 932 | "description": "Fixture generator. The Faker integration for the Yii framework.", 933 | "keywords": [ 934 | "Fixture", 935 | "faker", 936 | "yii2" 937 | ], 938 | "time": "2015-04-09 22:05:50" 939 | }, 940 | { 941 | "name": "yiisoft/yii2-gii", 942 | "version": "dev-master", 943 | "source": { 944 | "type": "git", 945 | "url": "https://github.com/yiisoft/yii2-gii.git", 946 | "reference": "b0ed0ad42de3f9539c935b36794b880f78f9c39b" 947 | }, 948 | "dist": { 949 | "type": "zip", 950 | "url": "https://api.github.com/repos/yiisoft/yii2-gii/zipball/b0ed0ad42de3f9539c935b36794b880f78f9c39b", 951 | "reference": "b0ed0ad42de3f9539c935b36794b880f78f9c39b", 952 | "shasum": "" 953 | }, 954 | "require": { 955 | "bower-asset/typeahead.js": "0.10.*", 956 | "phpspec/php-diff": ">=1.0.2", 957 | "yiisoft/yii2": "~2.0", 958 | "yiisoft/yii2-bootstrap": "~2.0" 959 | }, 960 | "type": "yii2-extension", 961 | "extra": { 962 | "branch-alias": { 963 | "dev-master": "2.0.x-dev" 964 | }, 965 | "asset-installer-paths": { 966 | "npm-asset-library": "vendor/npm", 967 | "bower-asset-library": "vendor/bower" 968 | } 969 | }, 970 | "autoload": { 971 | "psr-4": { 972 | "yii\\gii\\": "" 973 | } 974 | }, 975 | "notification-url": "https://packagist.org/downloads/", 976 | "license": [ 977 | "BSD-3-Clause" 978 | ], 979 | "authors": [ 980 | { 981 | "name": "Qiang Xue", 982 | "email": "qiang.xue@gmail.com" 983 | } 984 | ], 985 | "description": "The Gii extension for the Yii framework", 986 | "keywords": [ 987 | "code generator", 988 | "gii", 989 | "yii2" 990 | ], 991 | "time": "2015-04-24 15:35:21" 992 | } 993 | ], 994 | "aliases": [], 995 | "minimum-stability": "dev", 996 | "stability-flags": { 997 | "yiisoft/yii2-jui": 20 998 | }, 999 | "prefer-stable": false, 1000 | "prefer-lowest": false, 1001 | "platform": { 1002 | "php": ">=5.4.0" 1003 | }, 1004 | "platform-dev": [] 1005 | } 1006 | --------------------------------------------------------------------------------