Jiangmenger
12 months ago
commit
2ea7e9a718
76 changed files with 3102 additions and 0 deletions
-
3.bowerrc
-
36.gitignore
-
29LICENSE.md
-
233README.md
-
92Vagrantfile
-
31assets/AppAsset.php
-
27codeception.yml
-
34commands/HelloController.php
-
90commands/PhonebookController.php
-
32commands/PostController.php
-
75composer.json
-
33config/__autocomplete.php
-
56config/console.php
-
14config/db.php
-
7config/params.php
-
46config/test.php
-
6config/test_db.php
-
74config/web.php
-
128controllers/SiteController.php
-
42data/contract.json
-
9docker-compose.yml
-
22mail/layouts/html.php
-
13mail/layouts/text.php
-
65models/ContactForm.php
-
81models/LoginForm.php
-
104models/User.php
-
162requirements.php
-
2runtime/.gitignore
-
6tests/_bootstrap.php
-
1tests/_data/.gitkeep
-
2tests/_output/.gitignore
-
26tests/_support/AcceptanceTester.php
-
23tests/_support/FunctionalTester.php
-
26tests/_support/UnitTester.php
-
10tests/acceptance.suite.yml.example
-
12tests/acceptance/AboutCest.php
-
34tests/acceptance/ContactCest.php
-
18tests/acceptance/HomeCest.php
-
21tests/acceptance/LoginCest.php
-
1tests/acceptance/_bootstrap.php
-
29tests/bin/yii
-
20tests/bin/yii.bat
-
14tests/functional.suite.yml
-
57tests/functional/ContactFormCest.php
-
59tests/functional/LoginFormCest.php
-
1tests/functional/_bootstrap.php
-
11tests/unit.suite.yml
-
3tests/unit/_bootstrap.php
-
41tests/unit/models/ContactFormTest.php
-
51tests/unit/models/LoginFormTest.php
-
44tests/unit/models/UserTest.php
-
261tests/unit/widgets/AlertTest.php
-
2vagrant/config/.gitignore
-
22vagrant/config/vagrant-local.example.yml
-
38vagrant/nginx/app.conf
-
3vagrant/nginx/log/.gitignore
-
18vagrant/provision/always-as-root.sh
-
79vagrant/provision/once-as-root.sh
-
31vagrant/provision/once-as-vagrant.sh
-
50vagrant/provision/provision.awk
-
83views/layouts/main.php
-
18views/site/about.php
-
68views/site/contact.php
-
27views/site/error.php
-
53views/site/index.php
-
55views/site/login.php
-
4web/.htaccess
-
2web/assets/.gitignore
-
88web/css/site.css
-
BINweb/favicon.ico
-
16web/index-test.php
-
12web/index.php
-
2web/robots.txt
-
73widgets/Alert.php
-
21yii
-
20yii.bat
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"directory" : "vendor/bower-asset" |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
# phpstorm project files |
||||
|
.idea |
||||
|
|
||||
|
# netbeans project files |
||||
|
nbproject |
||||
|
|
||||
|
# zend studio for eclipse project files |
||||
|
.buildpath |
||||
|
.project |
||||
|
.settings |
||||
|
|
||||
|
# windows thumbnail cache |
||||
|
Thumbs.db |
||||
|
|
||||
|
# composer vendor dir |
||||
|
/vendor |
||||
|
|
||||
|
# composer itself is not needed |
||||
|
composer.phar |
||||
|
|
||||
|
# composer lock |
||||
|
composer.lock |
||||
|
|
||||
|
# Mac DS_Store Files |
||||
|
.DS_Store |
||||
|
|
||||
|
# phpunit itself is not needed |
||||
|
phpunit.phar |
||||
|
# local phpunit config |
||||
|
/phpunit.xml |
||||
|
|
||||
|
tests/_output/* |
||||
|
tests/_support/_generated |
||||
|
|
||||
|
#vagrant folder |
||||
|
/.vagrant |
@ -0,0 +1,29 @@ |
|||||
|
Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) |
||||
|
All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions |
||||
|
are met: |
||||
|
|
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
* Redistributions in binary form must reproduce the above copyright |
||||
|
notice, this list of conditions and the following disclaimer in |
||||
|
the documentation and/or other materials provided with the |
||||
|
distribution. |
||||
|
* Neither the name of Yii Software LLC nor the names of its |
||||
|
contributors may be used to endorse or promote products derived |
||||
|
from this software without specific prior written permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
|
POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,233 @@ |
|||||
|
<p align="center"> |
||||
|
<a href="https://github.com/yiisoft" target="_blank"> |
||||
|
<img src="https://avatars0.githubusercontent.com/u/993323" height="100px"> |
||||
|
</a> |
||||
|
<h1 align="center">Yii 2 Basic Project Template</h1> |
||||
|
<br> |
||||
|
</p> |
||||
|
|
||||
|
Yii 2 Basic Project Template is a skeleton [Yii 2](https://www.yiiframework.com/) application best for |
||||
|
rapidly creating small projects. |
||||
|
|
||||
|
The template contains the basic features including user login/logout and a contact page. |
||||
|
It includes all commonly used configurations that would allow you to focus on adding new |
||||
|
features to your application. |
||||
|
|
||||
|
[![Latest Stable Version](https://img.shields.io/packagist/v/yiisoft/yii2-app-basic.svg)](https://packagist.org/packages/yiisoft/yii2-app-basic) |
||||
|
[![Total Downloads](https://img.shields.io/packagist/dt/yiisoft/yii2-app-basic.svg)](https://packagist.org/packages/yiisoft/yii2-app-basic) |
||||
|
[![build](https://github.com/yiisoft/yii2-app-basic/workflows/build/badge.svg)](https://github.com/yiisoft/yii2-app-basic/actions?query=workflow%3Abuild) |
||||
|
|
||||
|
DIRECTORY STRUCTURE |
||||
|
------------------- |
||||
|
|
||||
|
assets/ contains assets definition |
||||
|
commands/ contains console commands (controllers) |
||||
|
config/ contains application configurations |
||||
|
controllers/ contains Web controller classes |
||||
|
mail/ contains view files for e-mails |
||||
|
models/ contains model classes |
||||
|
runtime/ contains files generated during runtime |
||||
|
tests/ contains various tests for the basic application |
||||
|
vendor/ contains dependent 3rd-party packages |
||||
|
views/ contains view files for the Web application |
||||
|
web/ contains the entry script and Web resources |
||||
|
|
||||
|
|
||||
|
|
||||
|
REQUIREMENTS |
||||
|
------------ |
||||
|
|
||||
|
The minimum requirement by this project template that your Web server supports PHP 7.4. |
||||
|
|
||||
|
|
||||
|
INSTALLATION |
||||
|
------------ |
||||
|
|
||||
|
### Install via Composer |
||||
|
|
||||
|
If you do not have [Composer](https://getcomposer.org/), you may install it by following the instructions |
||||
|
at [getcomposer.org](https://getcomposer.org/doc/00-intro.md#installation-nix). |
||||
|
|
||||
|
You can then install this project template using the following command: |
||||
|
|
||||
|
~~~ |
||||
|
composer create-project --prefer-dist yiisoft/yii2-app-basic basic |
||||
|
~~~ |
||||
|
|
||||
|
Now you should be able to access the application through the following URL, assuming `basic` is the directory |
||||
|
directly under the Web root. |
||||
|
|
||||
|
~~~ |
||||
|
http://localhost/basic/web/ |
||||
|
~~~ |
||||
|
|
||||
|
### Install from an Archive File |
||||
|
|
||||
|
Extract the archive file downloaded from [yiiframework.com](https://www.yiiframework.com/download/) to |
||||
|
a directory named `basic` that is directly under the Web root. |
||||
|
|
||||
|
Set cookie validation key in `config/web.php` file to some random secret string: |
||||
|
|
||||
|
```php |
||||
|
'request' => [ |
||||
|
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation |
||||
|
'cookieValidationKey' => '<secret random string goes here>', |
||||
|
], |
||||
|
``` |
||||
|
|
||||
|
You can then access the application through the following URL: |
||||
|
|
||||
|
~~~ |
||||
|
http://localhost/basic/web/ |
||||
|
~~~ |
||||
|
|
||||
|
|
||||
|
### Install with Docker |
||||
|
|
||||
|
Update your vendor packages |
||||
|
|
||||
|
docker-compose run --rm php composer update --prefer-dist |
||||
|
|
||||
|
Run the installation triggers (creating cookie validation code) |
||||
|
|
||||
|
docker-compose run --rm php composer install |
||||
|
|
||||
|
Start the container |
||||
|
|
||||
|
docker-compose up -d |
||||
|
|
||||
|
You can then access the application through the following URL: |
||||
|
|
||||
|
http://127.0.0.1:8000 |
||||
|
|
||||
|
**NOTES:** |
||||
|
- Minimum required Docker engine version `17.04` for development (see [Performance tuning for volume mounts](https://docs.docker.com/docker-for-mac/osxfs-caching/)) |
||||
|
- The default configuration uses a host-volume in your home directory `.docker-composer` for composer caches |
||||
|
|
||||
|
|
||||
|
CONFIGURATION |
||||
|
------------- |
||||
|
|
||||
|
### Database |
||||
|
|
||||
|
Edit the file `config/db.php` with real data, for example: |
||||
|
|
||||
|
```php |
||||
|
return [ |
||||
|
'class' => 'yii\db\Connection', |
||||
|
'dsn' => 'mysql:host=localhost;dbname=yii2basic', |
||||
|
'username' => 'root', |
||||
|
'password' => '1234', |
||||
|
'charset' => 'utf8', |
||||
|
]; |
||||
|
``` |
||||
|
|
||||
|
**NOTES:** |
||||
|
- Yii won't create the database for you, this has to be done manually before you can access it. |
||||
|
- Check and edit the other files in the `config/` directory to customize your application as required. |
||||
|
- Refer to the README in the `tests` directory for information specific to basic application tests. |
||||
|
|
||||
|
|
||||
|
TESTING |
||||
|
------- |
||||
|
|
||||
|
Tests are located in `tests` directory. They are developed with [Codeception PHP Testing Framework](https://codeception.com/). |
||||
|
By default, there are 3 test suites: |
||||
|
|
||||
|
- `unit` |
||||
|
- `functional` |
||||
|
- `acceptance` |
||||
|
|
||||
|
Tests can be executed by running |
||||
|
|
||||
|
``` |
||||
|
vendor/bin/codecept run |
||||
|
``` |
||||
|
|
||||
|
The command above will execute unit and functional tests. Unit tests are testing the system components, while functional |
||||
|
tests are for testing user interaction. Acceptance tests are disabled by default as they require additional setup since |
||||
|
they perform testing in real browser. |
||||
|
|
||||
|
|
||||
|
### Running acceptance tests |
||||
|
|
||||
|
To execute acceptance tests do the following: |
||||
|
|
||||
|
1. Rename `tests/acceptance.suite.yml.example` to `tests/acceptance.suite.yml` to enable suite configuration |
||||
|
|
||||
|
2. Replace `codeception/base` package in `composer.json` with `codeception/codeception` to install full-featured |
||||
|
version of Codeception |
||||
|
|
||||
|
3. Update dependencies with Composer |
||||
|
|
||||
|
``` |
||||
|
composer update |
||||
|
``` |
||||
|
|
||||
|
4. Download [Selenium Server](https://www.seleniumhq.org/download/) and launch it: |
||||
|
|
||||
|
``` |
||||
|
java -jar ~/selenium-server-standalone-x.xx.x.jar |
||||
|
``` |
||||
|
|
||||
|
In case of using Selenium Server 3.0 with Firefox browser since v48 or Google Chrome since v53 you must download [GeckoDriver](https://github.com/mozilla/geckodriver/releases) or [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) and launch Selenium with it: |
||||
|
|
||||
|
``` |
||||
|
# for Firefox |
||||
|
java -jar -Dwebdriver.gecko.driver=~/geckodriver ~/selenium-server-standalone-3.xx.x.jar |
||||
|
|
||||
|
# for Google Chrome |
||||
|
java -jar -Dwebdriver.chrome.driver=~/chromedriver ~/selenium-server-standalone-3.xx.x.jar |
||||
|
``` |
||||
|
|
||||
|
As an alternative way you can use already configured Docker container with older versions of Selenium and Firefox: |
||||
|
|
||||
|
``` |
||||
|
docker run --net=host selenium/standalone-firefox:2.53.0 |
||||
|
``` |
||||
|
|
||||
|
5. (Optional) Create `yii2basic_test` database and update it by applying migrations if you have them. |
||||
|
|
||||
|
``` |
||||
|
tests/bin/yii migrate |
||||
|
``` |
||||
|
|
||||
|
The database configuration can be found at `config/test_db.php`. |
||||
|
|
||||
|
|
||||
|
6. Start web server: |
||||
|
|
||||
|
``` |
||||
|
tests/bin/yii serve |
||||
|
``` |
||||
|
|
||||
|
7. Now you can run all available tests |
||||
|
|
||||
|
``` |
||||
|
# run all available tests |
||||
|
vendor/bin/codecept run |
||||
|
|
||||
|
# run acceptance tests |
||||
|
vendor/bin/codecept run acceptance |
||||
|
|
||||
|
# run only unit and functional tests |
||||
|
vendor/bin/codecept run unit,functional |
||||
|
``` |
||||
|
|
||||
|
### Code coverage support |
||||
|
|
||||
|
By default, code coverage is disabled in `codeception.yml` configuration file, you should uncomment needed rows to be able |
||||
|
to collect code coverage. You can run your tests and collect coverage with the following command: |
||||
|
|
||||
|
``` |
||||
|
#collect coverage for all tests |
||||
|
vendor/bin/codecept run --coverage --coverage-html --coverage-xml |
||||
|
|
||||
|
#collect coverage only for unit tests |
||||
|
vendor/bin/codecept run unit --coverage --coverage-html --coverage-xml |
||||
|
|
||||
|
#collect coverage for unit and functional tests |
||||
|
vendor/bin/codecept run functional,unit --coverage --coverage-html --coverage-xml |
||||
|
``` |
||||
|
|
||||
|
You can see code coverage output under the `tests/_output` directory. |
@ -0,0 +1,92 @@ |
|||||
|
require 'yaml' |
||||
|
require 'fileutils' |
||||
|
|
||||
|
required_plugins_installed = nil |
||||
|
required_plugins = %w( vagrant-hostmanager vagrant-vbguest ) |
||||
|
required_plugins.each do |plugin| |
||||
|
unless Vagrant.has_plugin? plugin |
||||
|
system "vagrant plugin install #{plugin}" |
||||
|
required_plugins_installed = true |
||||
|
end |
||||
|
end |
||||
|
|
||||
|
# IF plugin[s] was just installed - restart required |
||||
|
if required_plugins_installed |
||||
|
# Get CLI command[s] and call again |
||||
|
system 'vagrant' + ARGV.to_s.gsub(/\[\"|\", \"|\"\]/, ' ') |
||||
|
exit |
||||
|
end |
||||
|
|
||||
|
domains = { |
||||
|
app: 'yii2basic.test' |
||||
|
} |
||||
|
|
||||
|
vagrantfile_dir_path = File.dirname(__FILE__) |
||||
|
|
||||
|
config = { |
||||
|
local: vagrantfile_dir_path + '/vagrant/config/vagrant-local.yml', |
||||
|
example: vagrantfile_dir_path + '/vagrant/config/vagrant-local.example.yml' |
||||
|
} |
||||
|
|
||||
|
# copy config from example if local config not exists |
||||
|
FileUtils.cp config[:example], config[:local] unless File.exist?(config[:local]) |
||||
|
# read config |
||||
|
options = YAML.load_file config[:local] |
||||
|
|
||||
|
# check github token |
||||
|
if options['github_token'].nil? || options['github_token'].to_s.length != 40 |
||||
|
puts "You must place REAL GitHub token into configuration:\n/yii2-app-basic/vagrant/config/vagrant-local.yml" |
||||
|
exit |
||||
|
end |
||||
|
|
||||
|
# vagrant configurate |
||||
|
Vagrant.configure(2) do |config| |
||||
|
# select the box |
||||
|
config.vm.box = 'bento/ubuntu-18.04' |
||||
|
|
||||
|
# should we ask about box updates? |
||||
|
config.vm.box_check_update = options['box_check_update'] |
||||
|
|
||||
|
config.vm.provider 'virtualbox' do |vb| |
||||
|
# machine cpus count |
||||
|
vb.cpus = options['cpus'] |
||||
|
# machine memory size |
||||
|
vb.memory = options['memory'] |
||||
|
# machine name (for VirtualBox UI) |
||||
|
vb.name = options['machine_name'] |
||||
|
end |
||||
|
|
||||
|
# machine name (for vagrant console) |
||||
|
config.vm.define options['machine_name'] |
||||
|
|
||||
|
# machine name (for guest machine console) |
||||
|
config.vm.hostname = options['machine_name'] |
||||
|
|
||||
|
# network settings |
||||
|
config.vm.network 'private_network', ip: options['ip'] |
||||
|
|
||||
|
# sync: folder 'yii2-app-advanced' (host machine) -> folder '/app' (guest machine) |
||||
|
config.vm.synced_folder './', '/app', owner: 'vagrant', group: 'vagrant' |
||||
|
|
||||
|
# disable folder '/vagrant' (guest machine) |
||||
|
config.vm.synced_folder '.', '/vagrant', disabled: true |
||||
|
|
||||
|
# hosts settings (host machine) |
||||
|
config.vm.provision :hostmanager |
||||
|
config.hostmanager.enabled = true |
||||
|
config.hostmanager.manage_host = true |
||||
|
config.hostmanager.ignore_private_ip = false |
||||
|
config.hostmanager.include_offline = true |
||||
|
config.hostmanager.aliases = domains.values |
||||
|
|
||||
|
# quick fix for failed guest additions installations |
||||
|
# config.vbguest.auto_update = false |
||||
|
|
||||
|
# provisioners |
||||
|
config.vm.provision 'shell', path: './vagrant/provision/once-as-root.sh', args: [options['timezone'], options['ip']] |
||||
|
config.vm.provision 'shell', path: './vagrant/provision/once-as-vagrant.sh', args: [options['github_token']], privileged: false |
||||
|
config.vm.provision 'shell', path: './vagrant/provision/always-as-root.sh', run: 'always' |
||||
|
|
||||
|
# post-install message (vagrant console) |
||||
|
config.vm.post_up_message = "App URL: http://#{domains[:app]}" |
||||
|
end |
@ -0,0 +1,31 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @link https://www.yiiframework.com/ |
||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
|
* @license https://www.yiiframework.com/license/ |
||||
|
*/ |
||||
|
|
||||
|
namespace app\assets; |
||||
|
|
||||
|
use yii\web\AssetBundle; |
||||
|
|
||||
|
/** |
||||
|
* Main application asset bundle. |
||||
|
* |
||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
|
* @since 2.0 |
||||
|
*/ |
||||
|
class AppAsset extends AssetBundle |
||||
|
{ |
||||
|
public $basePath = '@webroot'; |
||||
|
public $baseUrl = '@web'; |
||||
|
public $css = [ |
||||
|
'css/site.css', |
||||
|
]; |
||||
|
public $js = [ |
||||
|
]; |
||||
|
public $depends = [ |
||||
|
'yii\web\YiiAsset', |
||||
|
'yii\bootstrap5\BootstrapAsset' |
||||
|
]; |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
actor: Tester |
||||
|
bootstrap: _bootstrap.php |
||||
|
paths: |
||||
|
tests: tests |
||||
|
output: tests/_output |
||||
|
data: tests/_data |
||||
|
helpers: tests/_support |
||||
|
settings: |
||||
|
memory_limit: 1024M |
||||
|
colors: true |
||||
|
modules: |
||||
|
config: |
||||
|
Yii2: |
||||
|
configFile: 'config/test.php' |
||||
|
|
||||
|
# To enable code coverage: |
||||
|
#coverage: |
||||
|
# #c3_url: http://localhost:8080/index-test.php/ |
||||
|
# enabled: true |
||||
|
# #remote: true |
||||
|
# #remote_config: '../codeception.yml' |
||||
|
# whitelist: |
||||
|
# include: |
||||
|
# - models/* |
||||
|
# - controllers/* |
||||
|
# - commands/* |
||||
|
# - mail/* |
@ -0,0 +1,34 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @link https://www.yiiframework.com/ |
||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
|
* @license https://www.yiiframework.com/license/ |
||||
|
*/ |
||||
|
|
||||
|
namespace app\commands; |
||||
|
|
||||
|
use yii\console\Controller; |
||||
|
use yii\console\ExitCode; |
||||
|
|
||||
|
/** |
||||
|
* This command echoes the first argument that you have entered. |
||||
|
* |
||||
|
* This command is provided as an example for you to learn how to create console commands. |
||||
|
* |
||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
|
* @since 2.0 |
||||
|
*/ |
||||
|
class HelloController extends Controller |
||||
|
{ |
||||
|
/** |
||||
|
* This command echoes what you have entered as the message. |
||||
|
* @param string $message the message to be echoed. |
||||
|
* @return int Exit code |
||||
|
*/ |
||||
|
public function actionIndex($message = 'hello world') |
||||
|
{ |
||||
|
echo $message . "\n"; |
||||
|
|
||||
|
return ExitCode::OK; |
||||
|
} |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
<?php |
||||
|
namespace app\commands; |
||||
|
|
||||
|
use yii\console\Controller; |
||||
|
|
||||
|
class PhonebookController extends Controller |
||||
|
{ |
||||
|
// 读取和保存文件
|
||||
|
private function loadContacts() |
||||
|
{ |
||||
|
$file = '/opt/phonebook/data/contract.json'; |
||||
|
if (!file_exists($file)) { |
||||
|
return []; |
||||
|
} |
||||
|
|
||||
|
return json_decode(file_get_contents($file), true); |
||||
|
} |
||||
|
|
||||
|
private function saveContacts($contacts) |
||||
|
{ |
||||
|
file_put_contents('/opt/phonebook/data/contract.json', json_encode($contacts, JSON_PRETTY_PRINT)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
//增添联系人 (actionAdd)
|
||||
|
public function actionAdd($name, $phone) |
||||
|
{ |
||||
|
$contacts = $this->loadContacts(); |
||||
|
$contacts[] = ['id' => count($contacts) + 1, 'name' => $name, 'phone' => $phone]; |
||||
|
$this->saveContacts($contacts); |
||||
|
|
||||
|
echo "Contact added successfully.\n"; |
||||
|
} |
||||
|
//搜索联系人 (actionSearch)
|
||||
|
public function actionSearch($name) |
||||
|
{ |
||||
|
$contacts = $this->loadContacts(); |
||||
|
$found = array_filter($contacts, function ($contact) use ($name) { |
||||
|
return strpos(strtolower($contact['name']), strtolower($name)) !== false; |
||||
|
}); |
||||
|
|
||||
|
if (empty($found)) { |
||||
|
echo "No contacts found.\n"; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach ($found as $contact) { |
||||
|
echo "ID: {$contact['id']}, Name: {$contact['name']}, Phone: {$contact['phone']}\n"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//删除联系人 (actionDelete)
|
||||
|
public function actionDelete($id) |
||||
|
{ |
||||
|
$contacts = $this->loadContacts(); |
||||
|
foreach ($contacts as $i => $contact) { |
||||
|
if ($contact['id'] == $id) { |
||||
|
array_splice($contacts, $i, 1); |
||||
|
$this->saveContacts($contacts); |
||||
|
echo "Contact deleted successfully.\n"; |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
echo "Contact not found.\n"; |
||||
|
} |
||||
|
//修改联系人 (actionUpdate)
|
||||
|
public function actionUpdate($id, $name, $phone) |
||||
|
{ |
||||
|
$contacts = $this->loadContacts(); |
||||
|
foreach ($contacts as &$contact) { |
||||
|
if ($contact['id'] == $id) { |
||||
|
$contact['name'] = $name; |
||||
|
$contact['phone'] = $phone; |
||||
|
$this->saveContacts($contacts); |
||||
|
echo "Contact updated successfully.\n"; |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
echo "Contact not found.\n"; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
?>
|
@ -0,0 +1,32 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace app\controllers; |
||||
|
|
||||
|
use Yii; |
||||
|
use app\models\Post; |
||||
|
use yii\web\Controller; |
||||
|
use yii\web\NotFoundHttpException; |
||||
|
|
||||
|
class PostController extends Controller{ |
||||
|
public function actionView($id){ |
||||
|
$model = Post::findOne($id); |
||||
|
if( $model === null){ |
||||
|
throw new NotFoundHttpException; |
||||
|
} |
||||
|
|
||||
|
return $this->render('view', [ |
||||
|
'model' => $model, |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
public function actionCreate(){ |
||||
|
$model = new Post; |
||||
|
if($model->load(Yii::$app->request->post())&& $model->save()){ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
?>
|
@ -0,0 +1,75 @@ |
|||||
|
{ |
||||
|
"name": "yiisoft/yii2-app-basic", |
||||
|
"description": "Yii 2 Basic Project Template", |
||||
|
"keywords": ["yii2", "framework", "basic", "project template"], |
||||
|
"homepage": "https://www.yiiframework.com/", |
||||
|
"type": "project", |
||||
|
"license": "BSD-3-Clause", |
||||
|
"support": { |
||||
|
"issues": "https://github.com/yiisoft/yii2/issues?state=open", |
||||
|
"forum": "https://www.yiiframework.com/forum/", |
||||
|
"wiki": "https://www.yiiframework.com/wiki/", |
||||
|
"irc": "ircs://irc.libera.chat:6697/yii", |
||||
|
"source": "https://github.com/yiisoft/yii2" |
||||
|
}, |
||||
|
"minimum-stability": "stable", |
||||
|
"require": { |
||||
|
"php": ">=7.4.0", |
||||
|
"yiisoft/yii2": "~2.0.45", |
||||
|
"yiisoft/yii2-bootstrap5": "~2.0.2", |
||||
|
"yiisoft/yii2-symfonymailer": "~2.0.3" |
||||
|
}, |
||||
|
"require-dev": { |
||||
|
"yiisoft/yii2-debug": "~2.1.0", |
||||
|
"yiisoft/yii2-gii": "~2.2.0", |
||||
|
"yiisoft/yii2-faker": "~2.0.0", |
||||
|
"phpunit/phpunit": "~9.5.0", |
||||
|
"codeception/codeception": "^5.0.0 || ^4.0", |
||||
|
"codeception/lib-innerbrowser": "^4.0 || ^3.0 || ^1.1", |
||||
|
"codeception/module-asserts": "^3.0 || ^1.1", |
||||
|
"codeception/module-yii2": "^1.1", |
||||
|
"codeception/module-filesystem": "^3.0 || ^2.0 || ^1.1", |
||||
|
"codeception/verify": "^3.0 || ^2.2", |
||||
|
"symfony/browser-kit": "^6.0 || >=2.7 <=4.2.4" |
||||
|
}, |
||||
|
"config": { |
||||
|
"allow-plugins": { |
||||
|
"yiisoft/yii2-composer" : true |
||||
|
}, |
||||
|
"process-timeout": 1800, |
||||
|
"fxp-asset": { |
||||
|
"enabled": false |
||||
|
} |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"post-install-cmd": [ |
||||
|
"yii\\composer\\Installer::postInstall" |
||||
|
], |
||||
|
"post-create-project-cmd": [ |
||||
|
"yii\\composer\\Installer::postCreateProject", |
||||
|
"yii\\composer\\Installer::postInstall" |
||||
|
] |
||||
|
}, |
||||
|
"extra": { |
||||
|
"yii\\composer\\Installer::postCreateProject": { |
||||
|
"setPermission": [ |
||||
|
{ |
||||
|
"runtime": "0777", |
||||
|
"web/assets": "0777", |
||||
|
"yii": "0755" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"yii\\composer\\Installer::postInstall": { |
||||
|
"generateCookieValidationKey": [ |
||||
|
"config/web.php" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"repositories": [ |
||||
|
{ |
||||
|
"type": "composer", |
||||
|
"url": "https://asset-packagist.org" |
||||
|
} |
||||
|
] |
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** |
||||
|
* This class only exists here for IDE (PHPStorm/Netbeans/...) autocompletion. |
||||
|
* This file is never included anywhere. |
||||
|
* Adjust this file to match classes configured in your application config, to enable IDE autocompletion for custom components. |
||||
|
* Example: A property phpdoc can be added in `__Application` class as `@property \vendor\package\Rollbar|__Rollbar $rollbar` and adding a class in this file |
||||
|
* ```php |
||||
|
* // @property of \vendor\package\Rollbar goes here
|
||||
|
* class __Rollbar { |
||||
|
* } |
||||
|
* ``` |
||||
|
*/ |
||||
|
class Yii { |
||||
|
/** |
||||
|
* @var \yii\web\Application|\yii\console\Application|__Application |
||||
|
*/ |
||||
|
public static $app; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @property yii\rbac\DbManager $authManager |
||||
|
* @property \yii\web\User|__WebUser $user |
||||
|
* |
||||
|
*/ |
||||
|
class __Application { |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @property app\models\User $identity |
||||
|
*/ |
||||
|
class __WebUser { |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
<?php |
||||
|
|
||||
|
$params = require __DIR__ . '/params.php'; |
||||
|
$db = require __DIR__ . '/db.php'; |
||||
|
|
||||
|
$config = [ |
||||
|
'id' => 'basic-console', |
||||
|
'basePath' => dirname(__DIR__), |
||||
|
'bootstrap' => ['log'], |
||||
|
'controllerNamespace' => 'app\commands', |
||||
|
'aliases' => [ |
||||
|
'@bower' => '@vendor/bower-asset', |
||||
|
'@npm' => '@vendor/npm-asset', |
||||
|
'@tests' => '@app/tests', |
||||
|
], |
||||
|
'components' => [ |
||||
|
'cache' => [ |
||||
|
'class' => 'yii\caching\FileCache', |
||||
|
], |
||||
|
'log' => [ |
||||
|
'targets' => [ |
||||
|
[ |
||||
|
'class' => 'yii\log\FileTarget', |
||||
|
'levels' => ['error', 'warning'], |
||||
|
], |
||||
|
], |
||||
|
], |
||||
|
'db' => $db, |
||||
|
], |
||||
|
'params' => $params, |
||||
|
/* |
||||
|
'controllerMap' => [ |
||||
|
'fixture' => [ // Fixture generation command line.
|
||||
|
'class' => 'yii\faker\FixtureController', |
||||
|
], |
||||
|
], |
||||
|
*/ |
||||
|
]; |
||||
|
|
||||
|
if (YII_ENV_DEV) { |
||||
|
// configuration adjustments for 'dev' environment
|
||||
|
$config['bootstrap'][] = 'gii'; |
||||
|
$config['modules']['gii'] = [ |
||||
|
'class' => 'yii\gii\Module', |
||||
|
]; |
||||
|
// configuration adjustments for 'dev' environment
|
||||
|
// requires version `2.1.21` of yii2-debug module
|
||||
|
$config['bootstrap'][] = 'debug'; |
||||
|
$config['modules']['debug'] = [ |
||||
|
'class' => 'yii\debug\Module', |
||||
|
// uncomment the following to add your IP if you are not connecting from localhost.
|
||||
|
//'allowedIPs' => ['127.0.0.1', '::1'],
|
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
return $config; |
@ -0,0 +1,14 @@ |
|||||
|
<?php |
||||
|
|
||||
|
return [ |
||||
|
'class' => 'yii\db\Connection', |
||||
|
'dsn' => 'mysql:host=localhost;dbname=yii2basic', |
||||
|
'username' => 'root', |
||||
|
'password' => 'deep123', |
||||
|
'charset' => 'utf8', |
||||
|
|
||||
|
// Schema cache options (for production environment)
|
||||
|
//'enableSchemaCache' => true,
|
||||
|
//'schemaCacheDuration' => 60,
|
||||
|
//'schemaCache' => 'cache',
|
||||
|
]; |
@ -0,0 +1,7 @@ |
|||||
|
<?php |
||||
|
|
||||
|
return [ |
||||
|
'adminEmail' => 'admin@example.com', |
||||
|
'senderEmail' => 'noreply@example.com', |
||||
|
'senderName' => 'Example.com mailer', |
||||
|
]; |
@ -0,0 +1,46 @@ |
|||||
|
<?php |
||||
|
$params = require __DIR__ . '/params.php'; |
||||
|
$db = require __DIR__ . '/test_db.php'; |
||||
|
|
||||
|
/** |
||||
|
* Application configuration shared by all test types |
||||
|
*/ |
||||
|
return [ |
||||
|
'id' => 'basic-tests', |
||||
|
'basePath' => dirname(__DIR__), |
||||
|
'aliases' => [ |
||||
|
'@bower' => '@vendor/bower-asset', |
||||
|
'@npm' => '@vendor/npm-asset', |
||||
|
], |
||||
|
'language' => 'en-US', |
||||
|
'components' => [ |
||||
|
'db' => $db, |
||||
|
'mailer' => [ |
||||
|
'class' => \yii\symfonymailer\Mailer::class, |
||||
|
'viewPath' => '@app/mail', |
||||
|
// send all mails to a file by default.
|
||||
|
'useFileTransport' => true, |
||||
|
'messageClass' => 'yii\symfonymailer\Message' |
||||
|
], |
||||
|
'assetManager' => [ |
||||
|
'basePath' => __DIR__ . '/../web/assets', |
||||
|
], |
||||
|
'urlManager' => [ |
||||
|
'showScriptName' => true, |
||||
|
], |
||||
|
'user' => [ |
||||
|
'identityClass' => 'app\models\User', |
||||
|
], |
||||
|
'request' => [ |
||||
|
'cookieValidationKey' => 'test', |
||||
|
'enableCsrfValidation' => false, |
||||
|
// but if you absolutely need it set cookie domain to localhost
|
||||
|
/* |
||||
|
'csrfCookie' => [ |
||||
|
'domain' => 'localhost', |
||||
|
], |
||||
|
*/ |
||||
|
], |
||||
|
], |
||||
|
'params' => $params, |
||||
|
]; |
@ -0,0 +1,6 @@ |
|||||
|
<?php |
||||
|
$db = require __DIR__ . '/db.php'; |
||||
|
// test database! Important not to run tests on production or development databases
|
||||
|
$db['dsn'] = 'mysql:host=localhost;dbname=yii2basic_test'; |
||||
|
|
||||
|
return $db; |
@ -0,0 +1,74 @@ |
|||||
|
<?php |
||||
|
|
||||
|
$params = require __DIR__ . '/params.php'; |
||||
|
$db = require __DIR__ . '/db.php'; |
||||
|
|
||||
|
$config = [ |
||||
|
'id' => 'basic', |
||||
|
'basePath' => dirname(__DIR__), |
||||
|
'bootstrap' => ['log'], |
||||
|
'aliases' => [ |
||||
|
'@bower' => '@vendor/bower-asset', |
||||
|
'@npm' => '@vendor/npm-asset', |
||||
|
], |
||||
|
'components' => [ |
||||
|
'request' => [ |
||||
|
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
|
||||
|
'cookieValidationKey' => 'hovIi5cjCDE92evC_zPUv3332pNJ7sIC', |
||||
|
], |
||||
|
'cache' => [ |
||||
|
'class' => 'yii\caching\FileCache', |
||||
|
], |
||||
|
'user' => [ |
||||
|
'identityClass' => 'app\models\User', |
||||
|
'enableAutoLogin' => true, |
||||
|
], |
||||
|
'errorHandler' => [ |
||||
|
'errorAction' => 'site/error', |
||||
|
], |
||||
|
'mailer' => [ |
||||
|
'class' => \yii\symfonymailer\Mailer::class, |
||||
|
'viewPath' => '@app/mail', |
||||
|
// send all mails to a file by default.
|
||||
|
'useFileTransport' => true, |
||||
|
], |
||||
|
'log' => [ |
||||
|
'traceLevel' => YII_DEBUG ? 3 : 0, |
||||
|
'targets' => [ |
||||
|
[ |
||||
|
'class' => 'yii\log\FileTarget', |
||||
|
'levels' => ['error', 'warning'], |
||||
|
], |
||||
|
], |
||||
|
], |
||||
|
'db' => $db, |
||||
|
/* |
||||
|
'urlManager' => [ |
||||
|
'enablePrettyUrl' => true, |
||||
|
'showScriptName' => false, |
||||
|
'rules' => [ |
||||
|
], |
||||
|
], |
||||
|
*/ |
||||
|
], |
||||
|
'params' => $params, |
||||
|
]; |
||||
|
|
||||
|
if (YII_ENV_DEV) { |
||||
|
// configuration adjustments for 'dev' environment
|
||||
|
$config['bootstrap'][] = 'debug'; |
||||
|
$config['modules']['debug'] = [ |
||||
|
'class' => 'yii\debug\Module', |
||||
|
// uncomment the following to add your IP if you are not connecting from localhost.
|
||||
|
//'allowedIPs' => ['127.0.0.1', '::1'],
|
||||
|
]; |
||||
|
|
||||
|
$config['bootstrap'][] = 'gii'; |
||||
|
$config['modules']['gii'] = [ |
||||
|
'class' => 'yii\gii\Module', |
||||
|
// uncomment the following to add your IP if you are not connecting from localhost.
|
||||
|
//'allowedIPs' => ['127.0.0.1', '::1'],
|
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
return $config; |
@ -0,0 +1,128 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace app\controllers; |
||||
|
|
||||
|
use Yii; |
||||
|
use yii\filters\AccessControl; |
||||
|
use yii\web\Controller; |
||||
|
use yii\web\Response; |
||||
|
use yii\filters\VerbFilter; |
||||
|
use app\models\LoginForm; |
||||
|
use app\models\ContactForm; |
||||
|
|
||||
|
class SiteController extends Controller |
||||
|
{ |
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public function behaviors() |
||||
|
{ |
||||
|
return [ |
||||
|
'access' => [ |
||||
|
'class' => AccessControl::class, |
||||
|
'only' => ['logout'], |
||||
|
'rules' => [ |
||||
|
[ |
||||
|
'actions' => ['logout'], |
||||
|
'allow' => true, |
||||
|
'roles' => ['@'], |
||||
|
], |
||||
|
], |
||||
|
], |
||||
|
'verbs' => [ |
||||
|
'class' => VerbFilter::class, |
||||
|
'actions' => [ |
||||
|
'logout' => ['post'], |
||||
|
], |
||||
|
], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public function actions() |
||||
|
{ |
||||
|
return [ |
||||
|
'error' => [ |
||||
|
'class' => 'yii\web\ErrorAction', |
||||
|
], |
||||
|
'captcha' => [ |
||||
|
'class' => 'yii\captcha\CaptchaAction', |
||||
|
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, |
||||
|
], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Displays homepage. |
||||
|
* |
||||
|
* @return string |
||||
|
*/ |
||||
|
public function actionIndex() |
||||
|
{ |
||||
|
return $this->render('index'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Login action. |
||||
|
* |
||||
|
* @return Response|string |
||||
|
*/ |
||||
|
public function actionLogin() |
||||
|
{ |
||||
|
if (!Yii::$app->user->isGuest) { |
||||
|
return $this->goHome(); |
||||
|
} |
||||
|
|
||||
|
$model = new LoginForm(); |
||||
|
if ($model->load(Yii::$app->request->post()) && $model->login()) { |
||||
|
return $this->goBack(); |
||||
|
} |
||||
|
|
||||
|
$model->password = ''; |
||||
|
return $this->render('login', [ |
||||
|
'model' => $model, |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Logout action. |
||||
|
* |
||||
|
* @return Response |
||||
|
*/ |
||||
|
public function actionLogout() |
||||
|
{ |
||||
|
Yii::$app->user->logout(); |
||||
|
|
||||
|
return $this->goHome(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Displays contact page. |
||||
|
* |
||||
|
* @return Response|string |
||||
|
*/ |
||||
|
public function actionContact() |
||||
|
{ |
||||
|
$model = new ContactForm(); |
||||
|
if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) { |
||||
|
Yii::$app->session->setFlash('contactFormSubmitted'); |
||||
|
|
||||
|
return $this->refresh(); |
||||
|
} |
||||
|
return $this->render('contact', [ |
||||
|
'model' => $model, |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Displays about page. |
||||
|
* |
||||
|
* @return string |
||||
|
*/ |
||||
|
public function actionAbout() |
||||
|
{ |
||||
|
return $this->render('about'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
[ |
||||
|
{ |
||||
|
"id": 1, |
||||
|
"name": "jiang", |
||||
|
"phone": "19866827739" |
||||
|
}, |
||||
|
{ |
||||
|
"id": 2, |
||||
|
"name": "zhang", |
||||
|
"phone": "001" |
||||
|
}, |
||||
|
{ |
||||
|
"id": 3, |
||||
|
"name": "chen", |
||||
|
"phone": "002" |
||||
|
}, |
||||
|
{ |
||||
|
"id": 4, |
||||
|
"name": "chen", |
||||
|
"phone": "002" |
||||
|
}, |
||||
|
{ |
||||
|
"id": 5, |
||||
|
"name": "li", |
||||
|
"phone": "003" |
||||
|
}, |
||||
|
{ |
||||
|
"id": 6, |
||||
|
"name": "guan", |
||||
|
"phone": "004" |
||||
|
}, |
||||
|
{ |
||||
|
"id": 7, |
||||
|
"name": "huang", |
||||
|
"phone": "005" |
||||
|
}, |
||||
|
{ |
||||
|
"id": 8, |
||||
|
"name": "zeng", |
||||
|
"phone": "006" |
||||
|
} |
||||
|
] |
@ -0,0 +1,9 @@ |
|||||
|
version: '2' |
||||
|
services: |
||||
|
php: |
||||
|
image: yiisoftware/yii2-php:7.4-apache |
||||
|
volumes: |
||||
|
- ~/.composer-docker/cache:/root/.composer/cache:delegated |
||||
|
- ./:/app:delegated |
||||
|
ports: |
||||
|
- '8000:80' |
@ -0,0 +1,22 @@ |
|||||
|
<?php |
||||
|
use yii\helpers\Html; |
||||
|
|
||||
|
/** @var \yii\web\View $this view component instance */ |
||||
|
/** @var \yii\mail\MessageInterface $message the message being composed */ |
||||
|
/** @var string $content main view render result */ |
||||
|
?>
|
||||
|
<?php $this->beginPage() ?>
|
||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
||||
|
<html xmlns="http://www.w3.org/1999/xhtml"> |
||||
|
<head> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" /> |
||||
|
<title><?= Html::encode($this->title) ?></title>
|
||||
|
<?php $this->head() ?>
|
||||
|
</head> |
||||
|
<body> |
||||
|
<?php $this->beginBody() ?>
|
||||
|
<?= $content ?>
|
||||
|
<?php $this->endBody() ?>
|
||||
|
</body> |
||||
|
</html> |
||||
|
<?php $this->endPage() ?>
|
@ -0,0 +1,13 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** |
||||
|
* @var yii\web\View $this view component instance |
||||
|
* @var yii\mail\BaseMessage $message the message being composed |
||||
|
* @var string $content main view render result |
||||
|
*/ |
||||
|
|
||||
|
$this->beginPage(); |
||||
|
$this->beginBody(); |
||||
|
echo $content; |
||||
|
$this->endBody(); |
||||
|
$this->endPage(); |
@ -0,0 +1,65 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace app\models; |
||||
|
|
||||
|
use Yii; |
||||
|
use yii\base\Model; |
||||
|
|
||||
|
/** |
||||
|
* ContactForm is the model behind the contact form. |
||||
|
*/ |
||||
|
class ContactForm extends Model |
||||
|
{ |
||||
|
public $name; |
||||
|
public $email; |
||||
|
public $subject; |
||||
|
public $body; |
||||
|
public $verifyCode; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @return array the validation rules. |
||||
|
*/ |
||||
|
public function rules() |
||||
|
{ |
||||
|
return [ |
||||
|
// name, email, subject and body are required
|
||||
|
[['name', 'email', 'subject', 'body'], 'required'], |
||||
|
// email has to be a valid email address
|
||||
|
['email', 'email'], |
||||
|
// verifyCode needs to be entered correctly
|
||||
|
['verifyCode', 'captcha'], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @return array customized attribute labels |
||||
|
*/ |
||||
|
public function attributeLabels() |
||||
|
{ |
||||
|
return [ |
||||
|
'verifyCode' => 'Verification Code', |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Sends an email to the specified email address using the information collected by this model. |
||||
|
* @param string $email the target email address |
||||
|
* @return bool whether the model passes validation |
||||
|
*/ |
||||
|
public function contact($email) |
||||
|
{ |
||||
|
if ($this->validate()) { |
||||
|
Yii::$app->mailer->compose() |
||||
|
->setTo($email) |
||||
|
->setFrom([Yii::$app->params['senderEmail'] => Yii::$app->params['senderName']]) |
||||
|
->setReplyTo([$this->email => $this->name]) |
||||
|
->setSubject($this->subject) |
||||
|
->setTextBody($this->body) |
||||
|
->send(); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
@ -0,0 +1,81 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace app\models; |
||||
|
|
||||
|
use Yii; |
||||
|
use yii\base\Model; |
||||
|
|
||||
|
/** |
||||
|
* LoginForm is the model behind the login form. |
||||
|
* |
||||
|
* @property-read User|null $user |
||||
|
* |
||||
|
*/ |
||||
|
class LoginForm extends Model |
||||
|
{ |
||||
|
public $username; |
||||
|
public $password; |
||||
|
public $rememberMe = true; |
||||
|
|
||||
|
private $_user = false; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @return array the validation rules. |
||||
|
*/ |
||||
|
public function rules() |
||||
|
{ |
||||
|
return [ |
||||
|
// username and password are both required
|
||||
|
[['username', 'password'], 'required'], |
||||
|
// rememberMe must be a boolean value
|
||||
|
['rememberMe', 'boolean'], |
||||
|
// password is validated by validatePassword()
|
||||
|
['password', 'validatePassword'], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Validates the password. |
||||
|
* This method serves as the inline validation for password. |
||||
|
* |
||||
|
* @param string $attribute the attribute currently being validated |
||||
|
* @param array $params the additional name-value pairs given in the rule |
||||
|
*/ |
||||
|
public function validatePassword($attribute, $params) |
||||
|
{ |
||||
|
if (!$this->hasErrors()) { |
||||
|
$user = $this->getUser(); |
||||
|
|
||||
|
if (!$user || !$user->validatePassword($this->password)) { |
||||
|
$this->addError($attribute, 'Incorrect username or password.'); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Logs in a user using the provided username and password. |
||||
|
* @return bool whether the user is logged in successfully |
||||
|
*/ |
||||
|
public function login() |
||||
|
{ |
||||
|
if ($this->validate()) { |
||||
|
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Finds user by [[username]] |
||||
|
* |
||||
|
* @return User|null |
||||
|
*/ |
||||
|
public function getUser() |
||||
|
{ |
||||
|
if ($this->_user === false) { |
||||
|
$this->_user = User::findByUsername($this->username); |
||||
|
} |
||||
|
|
||||
|
return $this->_user; |
||||
|
} |
||||
|
} |
@ -0,0 +1,104 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace app\models; |
||||
|
|
||||
|
class User extends \yii\base\BaseObject implements \yii\web\IdentityInterface |
||||
|
{ |
||||
|
public $id; |
||||
|
public $username; |
||||
|
public $password; |
||||
|
public $authKey; |
||||
|
public $accessToken; |
||||
|
|
||||
|
private static $users = [ |
||||
|
'100' => [ |
||||
|
'id' => '100', |
||||
|
'username' => 'admin', |
||||
|
'password' => 'admin', |
||||
|
'authKey' => 'test100key', |
||||
|
'accessToken' => '100-token', |
||||
|
], |
||||
|
'101' => [ |
||||
|
'id' => '101', |
||||
|
'username' => 'demo', |
||||
|
'password' => 'demo', |
||||
|
'authKey' => 'test101key', |
||||
|
'accessToken' => '101-token', |
||||
|
], |
||||
|
]; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public static function findIdentity($id) |
||||
|
{ |
||||
|
return isset(self::$users[$id]) ? new static(self::$users[$id]) : null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public static function findIdentityByAccessToken($token, $type = null) |
||||
|
{ |
||||
|
foreach (self::$users as $user) { |
||||
|
if ($user['accessToken'] === $token) { |
||||
|
return new static($user); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Finds user by username |
||||
|
* |
||||
|
* @param string $username |
||||
|
* @return static|null |
||||
|
*/ |
||||
|
public static function findByUsername($username) |
||||
|
{ |
||||
|
foreach (self::$users as $user) { |
||||
|
if (strcasecmp($user['username'], $username) === 0) { |
||||
|
return new static($user); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public function getId() |
||||
|
{ |
||||
|
return $this->id; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public function getAuthKey() |
||||
|
{ |
||||
|
return $this->authKey; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public function validateAuthKey($authKey) |
||||
|
{ |
||||
|
return $this->authKey === $authKey; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Validates password |
||||
|
* |
||||
|
* @param string $password password to validate |
||||
|
* @return bool if password provided is valid for current user |
||||
|
*/ |
||||
|
public function validatePassword($password) |
||||
|
{ |
||||
|
return $this->password === $password; |
||||
|
} |
||||
|
} |
@ -0,0 +1,162 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* Application requirement checker script. |
||||
|
* |
||||
|
* In order to run this script use the following console command: |
||||
|
* php requirements.php |
||||
|
* |
||||
|
* In order to run this script from the web, you should copy it to the web root. |
||||
|
* If you are using Linux you can create a hard link instead, using the following command: |
||||
|
* ln ../requirements.php requirements.php |
||||
|
*/ |
||||
|
|
||||
|
// you may need to adjust this path to the correct Yii framework path
|
||||
|
// uncomment and adjust the following line if Yii is not located at the default path
|
||||
|
//$frameworkPath = dirname(__FILE__) . '/vendor/yiisoft/yii2';
|
||||
|
|
||||
|
|
||||
|
if (!isset($frameworkPath)) { |
||||
|
$searchPaths = array( |
||||
|
dirname(__FILE__) . '/vendor/yiisoft/yii2', |
||||
|
dirname(__FILE__) . '/../vendor/yiisoft/yii2', |
||||
|
); |
||||
|
foreach ($searchPaths as $path) { |
||||
|
if (is_dir($path)) { |
||||
|
$frameworkPath = $path; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!isset($frameworkPath) || !is_dir($frameworkPath)) { |
||||
|
$message = "<h1>Error</h1>\n\n" |
||||
|
. "<p><strong>The path to yii framework seems to be incorrect.</strong></p>\n" |
||||
|
. '<p>You need to install Yii framework via composer or adjust the framework path in file <abbr title="' . __FILE__ . '">' . basename(__FILE__) . "</abbr>.</p>\n" |
||||
|
. '<p>Please refer to the <abbr title="' . dirname(__FILE__) . "/README.md\">README</abbr> on how to install Yii.</p>\n"; |
||||
|
|
||||
|
if (!empty($_SERVER['argv'])) { |
||||
|
// do not print HTML when used in console mode
|
||||
|
echo strip_tags($message); |
||||
|
} else { |
||||
|
echo $message; |
||||
|
} |
||||
|
exit(1); |
||||
|
} |
||||
|
|
||||
|
require_once($frameworkPath . '/requirements/YiiRequirementChecker.php'); |
||||
|
$requirementsChecker = new YiiRequirementChecker(); |
||||
|
|
||||
|
$gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.'; |
||||
|
$gdOK = $imagickOK = false; |
||||
|
|
||||
|
if (extension_loaded('imagick')) { |
||||
|
$imagick = new Imagick(); |
||||
|
$imagickFormats = $imagick->queryFormats('PNG'); |
||||
|
if (in_array('PNG', $imagickFormats)) { |
||||
|
$imagickOK = true; |
||||
|
} else { |
||||
|
$imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (extension_loaded('gd')) { |
||||
|
$gdInfo = gd_info(); |
||||
|
if (!empty($gdInfo['FreeType Support'])) { |
||||
|
$gdOK = true; |
||||
|
} else { |
||||
|
$gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Adjust requirements according to your application specifics. |
||||
|
*/ |
||||
|
$requirements = array( |
||||
|
// Database :
|
||||
|
array( |
||||
|
'name' => 'PDO extension', |
||||
|
'mandatory' => true, |
||||
|
'condition' => extension_loaded('pdo'), |
||||
|
'by' => 'All DB-related classes', |
||||
|
), |
||||
|
array( |
||||
|
'name' => 'PDO SQLite extension', |
||||
|
'mandatory' => false, |
||||
|
'condition' => extension_loaded('pdo_sqlite'), |
||||
|
'by' => 'All DB-related classes', |
||||
|
'memo' => 'Required for SQLite database.', |
||||
|
), |
||||
|
array( |
||||
|
'name' => 'PDO MySQL extension', |
||||
|
'mandatory' => false, |
||||
|
'condition' => extension_loaded('pdo_mysql'), |
||||
|
'by' => 'All DB-related classes', |
||||
|
'memo' => 'Required for MySQL database.', |
||||
|
), |
||||
|
array( |
||||
|
'name' => 'PDO PostgreSQL extension', |
||||
|
'mandatory' => false, |
||||
|
'condition' => extension_loaded('pdo_pgsql'), |
||||
|
'by' => 'All DB-related classes', |
||||
|
'memo' => 'Required for PostgreSQL database.', |
||||
|
), |
||||
|
// Cache :
|
||||
|
array( |
||||
|
'name' => 'Memcache extension', |
||||
|
'mandatory' => false, |
||||
|
'condition' => extension_loaded('memcache') || extension_loaded('memcached'), |
||||
|
'by' => '<a href="https://www.yiiframework.com/doc-2.0/yii-caching-memcache.html">MemCache</a>', |
||||
|
'memo' => extension_loaded('memcached') ? 'To use memcached set <a href="https://www.yiiframework.com/doc-2.0/yii-caching-memcache.html#$useMemcached-detail">MemCache::useMemcached</a> to <code>true</code>.' : '' |
||||
|
), |
||||
|
// CAPTCHA:
|
||||
|
array( |
||||
|
'name' => 'GD PHP extension with FreeType support', |
||||
|
'mandatory' => false, |
||||
|
'condition' => $gdOK, |
||||
|
'by' => '<a href="https://www.yiiframework.com/doc-2.0/yii-captcha-captcha.html">Captcha</a>', |
||||
|
'memo' => $gdMemo, |
||||
|
), |
||||
|
array( |
||||
|
'name' => 'ImageMagick PHP extension with PNG support', |
||||
|
'mandatory' => false, |
||||
|
'condition' => $imagickOK, |
||||
|
'by' => '<a href="https://www.yiiframework.com/doc-2.0/yii-captcha-captcha.html">Captcha</a>', |
||||
|
'memo' => $imagickMemo, |
||||
|
), |
||||
|
// PHP ini :
|
||||
|
'phpExposePhp' => array( |
||||
|
'name' => 'Expose PHP', |
||||
|
'mandatory' => false, |
||||
|
'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), |
||||
|
'by' => 'Security reasons', |
||||
|
'memo' => '"expose_php" should be disabled at php.ini', |
||||
|
), |
||||
|
'phpAllowUrlInclude' => array( |
||||
|
'name' => 'PHP allow url include', |
||||
|
'mandatory' => false, |
||||
|
'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), |
||||
|
'by' => 'Security reasons', |
||||
|
'memo' => '"allow_url_include" should be disabled at php.ini', |
||||
|
), |
||||
|
'phpSmtp' => array( |
||||
|
'name' => 'PHP mail SMTP', |
||||
|
'mandatory' => false, |
||||
|
'condition' => strlen(ini_get('SMTP')) > 0, |
||||
|
'by' => 'Email sending', |
||||
|
'memo' => 'PHP mail SMTP server required', |
||||
|
), |
||||
|
); |
||||
|
|
||||
|
// OPcache check
|
||||
|
if (!version_compare(phpversion(), '5.5', '>=')) { |
||||
|
$requirements[] = array( |
||||
|
'name' => 'APC extension', |
||||
|
'mandatory' => false, |
||||
|
'condition' => extension_loaded('apc'), |
||||
|
'by' => '<a href="https://www.yiiframework.com/doc-2.0/yii-caching-apccache.html">ApcCache</a>', |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
$result = $requirementsChecker->checkYii()->check($requirements)->getResult(); |
||||
|
$requirementsChecker->render(); |
||||
|
exit($result['summary']['errors'] === 0 ? 0 : 1); |
@ -0,0 +1,2 @@ |
|||||
|
* |
||||
|
!.gitignore |
@ -0,0 +1,6 @@ |
|||||
|
<?php |
||||
|
define('YII_ENV', 'test'); |
||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
|
|
||||
|
require_once __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; |
||||
|
require __DIR__ .'/../vendor/autoload.php'; |
@ -0,0 +1 @@ |
|||||
|
|
@ -0,0 +1,2 @@ |
|||||
|
* |
||||
|
!.gitignore |
@ -0,0 +1,26 @@ |
|||||
|
<?php |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Inherited Methods |
||||
|
* @method void wantToTest($text) |
||||
|
* @method void wantTo($text) |
||||
|
* @method void execute($callable) |
||||
|
* @method void expectTo($prediction) |
||||
|
* @method void expect($prediction) |
||||
|
* @method void amGoingTo($argumentation) |
||||
|
* @method void am($role) |
||||
|
* @method void lookForwardTo($achieveValue) |
||||
|
* @method void comment($description) |
||||
|
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) |
||||
|
* |
||||
|
* @SuppressWarnings(PHPMD) |
||||
|
*/ |
||||
|
class AcceptanceTester extends \Codeception\Actor |
||||
|
{ |
||||
|
use _generated\AcceptanceTesterActions; |
||||
|
|
||||
|
/** |
||||
|
* Define custom actions here |
||||
|
*/ |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
<?php |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Inherited Methods |
||||
|
* @method void wantToTest($text) |
||||
|
* @method void wantTo($text) |
||||
|
* @method void execute($callable) |
||||
|
* @method void expectTo($prediction) |
||||
|
* @method void expect($prediction) |
||||
|
* @method void amGoingTo($argumentation) |
||||
|
* @method void am($role) |
||||
|
* @method void lookForwardTo($achieveValue) |
||||
|
* @method void comment($description) |
||||
|
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) |
||||
|
* |
||||
|
* @SuppressWarnings(PHPMD) |
||||
|
*/ |
||||
|
class FunctionalTester extends \Codeception\Actor |
||||
|
{ |
||||
|
use _generated\FunctionalTesterActions; |
||||
|
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
<?php |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Inherited Methods |
||||
|
* @method void wantToTest($text) |
||||
|
* @method void wantTo($text) |
||||
|
* @method void execute($callable) |
||||
|
* @method void expectTo($prediction) |
||||
|
* @method void expect($prediction) |
||||
|
* @method void amGoingTo($argumentation) |
||||
|
* @method void am($role) |
||||
|
* @method void lookForwardTo($achieveValue) |
||||
|
* @method void comment($description) |
||||
|
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL) |
||||
|
* |
||||
|
* @SuppressWarnings(PHPMD) |
||||
|
*/ |
||||
|
class UnitTester extends \Codeception\Actor |
||||
|
{ |
||||
|
use _generated\UnitTesterActions; |
||||
|
|
||||
|
/** |
||||
|
* Define custom actions here |
||||
|
*/ |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
actor: AcceptanceTester |
||||
|
modules: |
||||
|
enabled: |
||||
|
- WebDriver: |
||||
|
url: http://127.0.0.1:8080/ |
||||
|
browser: firefox |
||||
|
- Yii2: |
||||
|
part: orm |
||||
|
entryScript: index-test.php |
||||
|
cleanup: false |
@ -0,0 +1,12 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use yii\helpers\Url; |
||||
|
|
||||
|
class AboutCest |
||||
|
{ |
||||
|
public function ensureThatAboutWorks(AcceptanceTester $I) |
||||
|
{ |
||||
|
$I->amOnPage(Url::toRoute('/site/about')); |
||||
|
$I->see('About', 'h1'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use yii\helpers\Url; |
||||
|
|
||||
|
class ContactCest |
||||
|
{ |
||||
|
public function _before(\AcceptanceTester $I) |
||||
|
{ |
||||
|
$I->amOnPage(Url::toRoute('/site/contact')); |
||||
|
} |
||||
|
|
||||
|
public function contactPageWorks(AcceptanceTester $I) |
||||
|
{ |
||||
|
$I->wantTo('ensure that contact page works'); |
||||
|
$I->see('Contact', 'h1'); |
||||
|
} |
||||
|
|
||||
|
public function contactFormCanBeSubmitted(AcceptanceTester $I) |
||||
|
{ |
||||
|
$I->amGoingTo('submit contact form with correct data'); |
||||
|
$I->fillField('#contactform-name', 'tester'); |
||||
|
$I->fillField('#contactform-email', 'tester@example.com'); |
||||
|
$I->fillField('#contactform-subject', 'test subject'); |
||||
|
$I->fillField('#contactform-body', 'test content'); |
||||
|
$I->fillField('#contactform-verifycode', 'testme'); |
||||
|
|
||||
|
$I->click('contact-button'); |
||||
|
|
||||
|
$I->wait(2); // wait for button to be clicked
|
||||
|
|
||||
|
$I->dontSeeElement('#contact-form'); |
||||
|
$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use yii\helpers\Url; |
||||
|
|
||||
|
class HomeCest |
||||
|
{ |
||||
|
public function ensureThatHomePageWorks(AcceptanceTester $I) |
||||
|
{ |
||||
|
$I->amOnPage(Url::toRoute('/site/index')); |
||||
|
$I->see('My Company'); |
||||
|
|
||||
|
$I->seeLink('About'); |
||||
|
$I->click('About'); |
||||
|
$I->wait(2); // wait for page to be opened
|
||||
|
|
||||
|
$I->see('This is the About page.'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use yii\helpers\Url; |
||||
|
|
||||
|
class LoginCest |
||||
|
{ |
||||
|
public function ensureThatLoginWorks(AcceptanceTester $I) |
||||
|
{ |
||||
|
$I->amOnPage(Url::toRoute('/site/login')); |
||||
|
$I->see('Login', 'h1'); |
||||
|
|
||||
|
$I->amGoingTo('try to login with correct credentials'); |
||||
|
$I->fillField('input[name="LoginForm[username]"]', 'admin'); |
||||
|
$I->fillField('input[name="LoginForm[password]"]', 'admin'); |
||||
|
$I->click('login-button'); |
||||
|
$I->wait(2); // wait for button to be clicked
|
||||
|
|
||||
|
$I->expectTo('see user info'); |
||||
|
$I->see('Logout'); |
||||
|
} |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
<?php |
@ -0,0 +1,29 @@ |
|||||
|
#!/usr/bin/env php |
||||
|
<?php |
||||
|
/** |
||||
|
* Yii console bootstrap file. |
||||
|
* |
||||
|
* @link https://www.yiiframework.com/ |
||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
|
* @license https://www.yiiframework.com/license/ |
||||
|
*/ |
||||
|
|
||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
|
defined('YII_ENV') or define('YII_ENV', 'test'); |
||||
|
|
||||
|
require __DIR__ . '/../../vendor/autoload.php'; |
||||
|
require __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php'; |
||||
|
|
||||
|
$config = yii\helpers\ArrayHelper::merge( |
||||
|
require __DIR__ . '/../../config/console.php', |
||||
|
[ |
||||
|
'components' => [ |
||||
|
'db' => require __DIR__ . '/../../config/test_db.php' |
||||
|
] |
||||
|
] |
||||
|
); |
||||
|
|
||||
|
|
||||
|
$application = new yii\console\Application($config); |
||||
|
$exitCode = $application->run(); |
||||
|
exit($exitCode); |
@ -0,0 +1,20 @@ |
|||||
|
@echo off |
||||
|
|
||||
|
rem ------------------------------------------------------------- |
||||
|
rem Yii command line bootstrap script for Windows. |
||||
|
rem |
||||
|
rem @author Qiang Xue <qiang.xue@gmail.com> |
||||
|
rem @link https://www.yiiframework.com/ |
||||
|
rem @copyright Copyright (c) 2008 Yii Software LLC |
||||
|
rem @license https://www.yiiframework.com/license/ |
||||
|
rem ------------------------------------------------------------- |
||||
|
|
||||
|
@setlocal |
||||
|
|
||||
|
set YII_PATH=%~dp0 |
||||
|
|
||||
|
if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe |
||||
|
|
||||
|
"%PHP_COMMAND%" "%YII_PATH%yii" %* |
||||
|
|
||||
|
@endlocal |
@ -0,0 +1,14 @@ |
|||||
|
# Codeception Test Suite Configuration |
||||
|
|
||||
|
# suite for functional (integration) tests. |
||||
|
# emulate web requests and make application process them. |
||||
|
# (tip: better to use with frameworks). |
||||
|
|
||||
|
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. |
||||
|
#basic/web/index.php |
||||
|
actor: FunctionalTester |
||||
|
modules: |
||||
|
enabled: |
||||
|
- Filesystem |
||||
|
- Yii2 |
||||
|
- Asserts |
@ -0,0 +1,57 @@ |
|||||
|
<?php |
||||
|
|
||||
|
class ContactFormCest |
||||
|
{ |
||||
|
public function _before(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->amOnRoute('site/contact'); |
||||
|
} |
||||
|
|
||||
|
public function openContactPage(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->see('Contact', 'h1'); |
||||
|
} |
||||
|
|
||||
|
public function submitEmptyForm(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->submitForm('#contact-form', []); |
||||
|
$I->expectTo('see validations errors'); |
||||
|
$I->see('Contact', 'h1'); |
||||
|
$I->see('Name cannot be blank'); |
||||
|
$I->see('Email cannot be blank'); |
||||
|
$I->see('Subject cannot be blank'); |
||||
|
$I->see('Body cannot be blank'); |
||||
|
$I->see('The verification code is incorrect'); |
||||
|
} |
||||
|
|
||||
|
public function submitFormWithIncorrectEmail(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->submitForm('#contact-form', [ |
||||
|
'ContactForm[name]' => 'tester', |
||||
|
'ContactForm[email]' => 'tester.email', |
||||
|
'ContactForm[subject]' => 'test subject', |
||||
|
'ContactForm[body]' => 'test content', |
||||
|
'ContactForm[verifyCode]' => 'testme', |
||||
|
]); |
||||
|
$I->expectTo('see that email address is wrong'); |
||||
|
$I->dontSee('Name cannot be blank', '.help-inline'); |
||||
|
$I->see('Email is not a valid email address.'); |
||||
|
$I->dontSee('Subject cannot be blank', '.help-inline'); |
||||
|
$I->dontSee('Body cannot be blank', '.help-inline'); |
||||
|
$I->dontSee('The verification code is incorrect', '.help-inline'); |
||||
|
} |
||||
|
|
||||
|
public function submitFormSuccessfully(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->submitForm('#contact-form', [ |
||||
|
'ContactForm[name]' => 'tester', |
||||
|
'ContactForm[email]' => 'tester@example.com', |
||||
|
'ContactForm[subject]' => 'test subject', |
||||
|
'ContactForm[body]' => 'test content', |
||||
|
'ContactForm[verifyCode]' => 'testme', |
||||
|
]); |
||||
|
$I->seeEmailIsSent(); |
||||
|
$I->dontSeeElement('#contact-form'); |
||||
|
$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,59 @@ |
|||||
|
<?php |
||||
|
|
||||
|
class LoginFormCest |
||||
|
{ |
||||
|
public function _before(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->amOnRoute('site/login'); |
||||
|
} |
||||
|
|
||||
|
public function openLoginPage(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->see('Login', 'h1'); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// demonstrates `amLoggedInAs` method
|
||||
|
public function internalLoginById(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->amLoggedInAs(100); |
||||
|
$I->amOnPage('/'); |
||||
|
$I->see('Logout (admin)'); |
||||
|
} |
||||
|
|
||||
|
// demonstrates `amLoggedInAs` method
|
||||
|
public function internalLoginByInstance(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->amLoggedInAs(\app\models\User::findByUsername('admin')); |
||||
|
$I->amOnPage('/'); |
||||
|
$I->see('Logout (admin)'); |
||||
|
} |
||||
|
|
||||
|
public function loginWithEmptyCredentials(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->submitForm('#login-form', []); |
||||
|
$I->expectTo('see validations errors'); |
||||
|
$I->see('Username cannot be blank.'); |
||||
|
$I->see('Password cannot be blank.'); |
||||
|
} |
||||
|
|
||||
|
public function loginWithWrongCredentials(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->submitForm('#login-form', [ |
||||
|
'LoginForm[username]' => 'admin', |
||||
|
'LoginForm[password]' => 'wrong', |
||||
|
]); |
||||
|
$I->expectTo('see validations errors'); |
||||
|
$I->see('Incorrect username or password.'); |
||||
|
} |
||||
|
|
||||
|
public function loginSuccessfully(\FunctionalTester $I) |
||||
|
{ |
||||
|
$I->submitForm('#login-form', [ |
||||
|
'LoginForm[username]' => 'admin', |
||||
|
'LoginForm[password]' => 'admin', |
||||
|
]); |
||||
|
$I->see('Logout (admin)'); |
||||
|
$I->dontSeeElement('form#login-form'); |
||||
|
} |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
<?php |
@ -0,0 +1,11 @@ |
|||||
|
# Codeception Test Suite Configuration |
||||
|
|
||||
|
# suite for unit (internal) tests. |
||||
|
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. |
||||
|
|
||||
|
actor: UnitTester |
||||
|
modules: |
||||
|
enabled: |
||||
|
- Asserts |
||||
|
- Yii2: |
||||
|
part: [orm, email, fixtures] |
@ -0,0 +1,3 @@ |
|||||
|
<?php |
||||
|
|
||||
|
// add unit testing specific bootstrap code here
|
@ -0,0 +1,41 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace tests\unit\models; |
||||
|
|
||||
|
use app\models\ContactForm; |
||||
|
use yii\mail\MessageInterface; |
||||
|
|
||||
|
class ContactFormTest extends \Codeception\Test\Unit |
||||
|
{ |
||||
|
/** |
||||
|
* @var \UnitTester |
||||
|
*/ |
||||
|
public $tester; |
||||
|
|
||||
|
public function testEmailIsSentOnContact() |
||||
|
{ |
||||
|
$model = new ContactForm(); |
||||
|
|
||||
|
$model->attributes = [ |
||||
|
'name' => 'Tester', |
||||
|
'email' => 'tester@example.com', |
||||
|
'subject' => 'very important letter subject', |
||||
|
'body' => 'body of current message', |
||||
|
'verifyCode' => 'testme', |
||||
|
]; |
||||
|
|
||||
|
verify($model->contact('admin@example.com'))->notEmpty(); |
||||
|
|
||||
|
// using Yii2 module actions to check email was sent
|
||||
|
$this->tester->seeEmailIsSent(); |
||||
|
|
||||
|
/** @var MessageInterface $emailMessage */ |
||||
|
$emailMessage = $this->tester->grabLastSentEmail(); |
||||
|
verify($emailMessage)->instanceOf('yii\mail\MessageInterface'); |
||||
|
verify($emailMessage->getTo())->arrayHasKey('admin@example.com'); |
||||
|
verify($emailMessage->getFrom())->arrayHasKey('noreply@example.com'); |
||||
|
verify($emailMessage->getReplyTo())->arrayHasKey('tester@example.com'); |
||||
|
verify($emailMessage->getSubject())->equals('very important letter subject'); |
||||
|
verify($emailMessage->toString())->stringContainsString('body of current message'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace tests\unit\models; |
||||
|
|
||||
|
use app\models\LoginForm; |
||||
|
|
||||
|
class LoginFormTest extends \Codeception\Test\Unit |
||||
|
{ |
||||
|
private $model; |
||||
|
|
||||
|
protected function _after() |
||||
|
{ |
||||
|
\Yii::$app->user->logout(); |
||||
|
} |
||||
|
|
||||
|
public function testLoginNoUser() |
||||
|
{ |
||||
|
$this->model = new LoginForm([ |
||||
|
'username' => 'not_existing_username', |
||||
|
'password' => 'not_existing_password', |
||||
|
]); |
||||
|
|
||||
|
verify($this->model->login())->false(); |
||||
|
verify(\Yii::$app->user->isGuest)->true(); |
||||
|
} |
||||
|
|
||||
|
public function testLoginWrongPassword() |
||||
|
{ |
||||
|
$this->model = new LoginForm([ |
||||
|
'username' => 'demo', |
||||
|
'password' => 'wrong_password', |
||||
|
]); |
||||
|
|
||||
|
verify($this->model->login())->false(); |
||||
|
verify(\Yii::$app->user->isGuest)->true(); |
||||
|
verify($this->model->errors)->arrayHasKey('password'); |
||||
|
} |
||||
|
|
||||
|
public function testLoginCorrect() |
||||
|
{ |
||||
|
$this->model = new LoginForm([ |
||||
|
'username' => 'demo', |
||||
|
'password' => 'demo', |
||||
|
]); |
||||
|
|
||||
|
verify($this->model->login())->true(); |
||||
|
verify(\Yii::$app->user->isGuest)->false(); |
||||
|
verify($this->model->errors)->arrayHasNotKey('password'); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace tests\unit\models; |
||||
|
|
||||
|
use app\models\User; |
||||
|
|
||||
|
class UserTest extends \Codeception\Test\Unit |
||||
|
{ |
||||
|
public function testFindUserById() |
||||
|
{ |
||||
|
verify($user = User::findIdentity(100))->notEmpty(); |
||||
|
verify($user->username)->equals('admin'); |
||||
|
|
||||
|
verify(User::findIdentity(999))->empty(); |
||||
|
} |
||||
|
|
||||
|
public function testFindUserByAccessToken() |
||||
|
{ |
||||
|
verify($user = User::findIdentityByAccessToken('100-token'))->notEmpty(); |
||||
|
verify($user->username)->equals('admin'); |
||||
|
|
||||
|
verify(User::findIdentityByAccessToken('non-existing'))->empty(); |
||||
|
} |
||||
|
|
||||
|
public function testFindUserByUsername() |
||||
|
{ |
||||
|
verify($user = User::findByUsername('admin'))->notEmpty(); |
||||
|
verify(User::findByUsername('not-admin'))->empty(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @depends testFindUserByUsername |
||||
|
*/ |
||||
|
public function testValidateUser() |
||||
|
{ |
||||
|
$user = User::findByUsername('admin'); |
||||
|
verify($user->validateAuthKey('test100key'))->notEmpty(); |
||||
|
verify($user->validateAuthKey('test102key'))->empty(); |
||||
|
|
||||
|
verify($user->validatePassword('admin'))->notEmpty(); |
||||
|
verify($user->validatePassword('123456'))->empty(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,261 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace tests\unit\widgets; |
||||
|
|
||||
|
use app\widgets\Alert; |
||||
|
use Yii; |
||||
|
|
||||
|
class AlertTest extends \Codeception\Test\Unit |
||||
|
{ |
||||
|
public function testSingleErrorMessage() |
||||
|
{ |
||||
|
$message = 'This is an error message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('error', $message); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($message); |
||||
|
verify($renderingResult)->stringContainsString('alert-danger'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testMultipleErrorMessages() |
||||
|
{ |
||||
|
$firstMessage = 'This is the first error message'; |
||||
|
$secondMessage = 'This is the second error message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('error', [$firstMessage, $secondMessage]); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($firstMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondMessage); |
||||
|
verify($renderingResult)->stringContainsString('alert-danger'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testSingleDangerMessage() |
||||
|
{ |
||||
|
$message = 'This is a danger message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('danger', $message); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($message); |
||||
|
verify($renderingResult)->stringContainsString('alert-danger'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testMultipleDangerMessages() |
||||
|
{ |
||||
|
$firstMessage = 'This is the first danger message'; |
||||
|
$secondMessage = 'This is the second danger message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('danger', [$firstMessage, $secondMessage]); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($firstMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondMessage); |
||||
|
verify($renderingResult)->stringContainsString('alert-danger'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testSingleSuccessMessage() |
||||
|
{ |
||||
|
$message = 'This is a success message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('success', $message); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($message); |
||||
|
verify($renderingResult)->stringContainsString('alert-success'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testMultipleSuccessMessages() |
||||
|
{ |
||||
|
$firstMessage = 'This is the first danger message'; |
||||
|
$secondMessage = 'This is the second danger message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('success', [$firstMessage, $secondMessage]); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($firstMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondMessage); |
||||
|
verify($renderingResult)->stringContainsString('alert-success'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testSingleInfoMessage() |
||||
|
{ |
||||
|
$message = 'This is an info message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('info', $message); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($message); |
||||
|
verify($renderingResult)->stringContainsString('alert-info'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testMultipleInfoMessages() |
||||
|
{ |
||||
|
$firstMessage = 'This is the first info message'; |
||||
|
$secondMessage = 'This is the second info message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('info', [$firstMessage, $secondMessage]); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($firstMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondMessage); |
||||
|
verify($renderingResult)->stringContainsString('alert-info'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testSingleWarningMessage() |
||||
|
{ |
||||
|
$message = 'This is a warning message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('warning', $message); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($message); |
||||
|
verify($renderingResult)->stringContainsString('alert-warning'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
} |
||||
|
|
||||
|
public function testMultipleWarningMessages() |
||||
|
{ |
||||
|
$firstMessage = 'This is the first warning message'; |
||||
|
$secondMessage = 'This is the second warning message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('warning', [$firstMessage, $secondMessage]); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($firstMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondMessage); |
||||
|
verify($renderingResult)->stringContainsString('alert-warning'); |
||||
|
|
||||
|
verify($renderingResult)->stringNotContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringNotContainsString('alert-info'); |
||||
|
} |
||||
|
|
||||
|
public function testSingleMixedMessages() { |
||||
|
$errorMessage = 'This is an error message'; |
||||
|
$dangerMessage = 'This is a danger message'; |
||||
|
$successMessage = 'This is a success message'; |
||||
|
$infoMessage = 'This is a info message'; |
||||
|
$warningMessage = 'This is a warning message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('error', $errorMessage); |
||||
|
Yii::$app->session->setFlash('danger', $dangerMessage); |
||||
|
Yii::$app->session->setFlash('success', $successMessage); |
||||
|
Yii::$app->session->setFlash('info', $infoMessage); |
||||
|
Yii::$app->session->setFlash('warning', $warningMessage); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($errorMessage); |
||||
|
verify($renderingResult)->stringContainsString($dangerMessage); |
||||
|
verify($renderingResult)->stringContainsString($successMessage); |
||||
|
verify($renderingResult)->stringContainsString($infoMessage); |
||||
|
verify($renderingResult)->stringContainsString($warningMessage); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testMultipleMixedMessages() { |
||||
|
$firstErrorMessage = 'This is the first error message'; |
||||
|
$secondErrorMessage = 'This is the second error message'; |
||||
|
$firstDangerMessage = 'This is the first danger message'; |
||||
|
$secondDangerMessage = 'This is the second'; |
||||
|
$firstSuccessMessage = 'This is the first success message'; |
||||
|
$secondSuccessMessage = 'This is the second success message'; |
||||
|
$firstInfoMessage = 'This is the first info message'; |
||||
|
$secondInfoMessage = 'This is the second info message'; |
||||
|
$firstWarningMessage = 'This is the first warning message'; |
||||
|
$secondWarningMessage = 'This is the second warning message'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('error', [$firstErrorMessage, $secondErrorMessage]); |
||||
|
Yii::$app->session->setFlash('danger', [$firstDangerMessage, $secondDangerMessage]); |
||||
|
Yii::$app->session->setFlash('success', [$firstSuccessMessage, $secondSuccessMessage]); |
||||
|
Yii::$app->session->setFlash('info', [$firstInfoMessage, $secondInfoMessage]); |
||||
|
Yii::$app->session->setFlash('warning', [$firstWarningMessage, $secondWarningMessage]); |
||||
|
|
||||
|
$renderingResult = Alert::widget(); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString($firstErrorMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondErrorMessage); |
||||
|
verify($renderingResult)->stringContainsString($firstDangerMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondDangerMessage); |
||||
|
verify($renderingResult)->stringContainsString($firstSuccessMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondSuccessMessage); |
||||
|
verify($renderingResult)->stringContainsString($firstInfoMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondInfoMessage); |
||||
|
verify($renderingResult)->stringContainsString($firstWarningMessage); |
||||
|
verify($renderingResult)->stringContainsString($secondWarningMessage); |
||||
|
|
||||
|
verify($renderingResult)->stringContainsString('alert-danger'); |
||||
|
verify($renderingResult)->stringContainsString('alert-success'); |
||||
|
verify($renderingResult)->stringContainsString('alert-info'); |
||||
|
verify($renderingResult)->stringContainsString('alert-warning'); |
||||
|
} |
||||
|
|
||||
|
public function testFlashIntegrity() |
||||
|
{ |
||||
|
$errorMessage = 'This is an error message'; |
||||
|
$unrelatedMessage = 'This is a message that is not related to the alert widget'; |
||||
|
|
||||
|
Yii::$app->session->setFlash('error', $errorMessage); |
||||
|
Yii::$app->session->setFlash('unrelated', $unrelatedMessage); |
||||
|
|
||||
|
Alert::widget(); |
||||
|
|
||||
|
// Simulate redirect
|
||||
|
Yii::$app->session->close(); |
||||
|
Yii::$app->session->open(); |
||||
|
|
||||
|
verify(Yii::$app->session->getFlash('error'))->empty(); |
||||
|
verify(Yii::$app->session->getFlash('unrelated'))->equals($unrelatedMessage); |
||||
|
} |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
# local configuration |
||||
|
vagrant-local.yml |
@ -0,0 +1,22 @@ |
|||||
|
# Your personal GitHub token |
||||
|
github_token: <your-personal-github-token> |
||||
|
# Read more: https://github.com/blog/1509-personal-api-tokens |
||||
|
# You can generate it here: https://github.com/settings/tokens |
||||
|
|
||||
|
# Guest OS timezone |
||||
|
timezone: Europe/London |
||||
|
|
||||
|
# Are we need check box updates for every 'vagrant up'? |
||||
|
box_check_update: false |
||||
|
|
||||
|
# Virtual machine name |
||||
|
machine_name: yii2basic |
||||
|
|
||||
|
# Virtual machine IP |
||||
|
ip: 192.168.83.137 |
||||
|
|
||||
|
# Virtual machine CPU cores number |
||||
|
cpus: 1 |
||||
|
|
||||
|
# Virtual machine RAM |
||||
|
memory: 1024 |
@ -0,0 +1,38 @@ |
|||||
|
server { |
||||
|
charset utf-8; |
||||
|
client_max_body_size 128M; |
||||
|
sendfile off; |
||||
|
|
||||
|
listen 80; ## listen for ipv4 |
||||
|
#listen [::]:80 default_server ipv6only=on; ## listen for ipv6 |
||||
|
|
||||
|
server_name yii2basic.test; |
||||
|
root /app/web/; |
||||
|
index index.php; |
||||
|
|
||||
|
access_log /app/vagrant/nginx/log/yii2basic.access.log; |
||||
|
error_log /app/vagrant/nginx/log/yii2basic.error.log; |
||||
|
|
||||
|
location / { |
||||
|
# Redirect everything that isn't a real file to index.php |
||||
|
try_files $uri $uri/ /index.php$is_args$args; |
||||
|
} |
||||
|
|
||||
|
# uncomment to avoid processing of calls to non-existing static files by Yii |
||||
|
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ { |
||||
|
# try_files $uri =404; |
||||
|
#} |
||||
|
#error_page 404 /404.html; |
||||
|
|
||||
|
location ~ \.php$ { |
||||
|
include fastcgi_params; |
||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; |
||||
|
#fastcgi_pass 127.0.0.1:9000; |
||||
|
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; |
||||
|
try_files $uri =404; |
||||
|
} |
||||
|
|
||||
|
location ~ /\.(ht|svn|git) { |
||||
|
deny all; |
||||
|
} |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
#nginx logs |
||||
|
yii2basic.access.log |
||||
|
yii2basic.error.log |
@ -0,0 +1,18 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
|
||||
|
#== Bash helpers == |
||||
|
|
||||
|
function info { |
||||
|
echo " " |
||||
|
echo "--> $1" |
||||
|
echo " " |
||||
|
} |
||||
|
|
||||
|
#== Provision script == |
||||
|
|
||||
|
info "Provision-script user: `whoami`" |
||||
|
|
||||
|
info "Restart web-stack" |
||||
|
service php7.2-fpm restart |
||||
|
service nginx restart |
||||
|
service mysql restart |
@ -0,0 +1,79 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
|
||||
|
#== Import script args == |
||||
|
|
||||
|
timezone=$(echo "$1") |
||||
|
readonly IP=$2 |
||||
|
|
||||
|
#== Bash helpers == |
||||
|
|
||||
|
function info { |
||||
|
echo " " |
||||
|
echo "--> $1" |
||||
|
echo " " |
||||
|
} |
||||
|
|
||||
|
#== Provision script == |
||||
|
|
||||
|
info "Provision-script user: `whoami`" |
||||
|
|
||||
|
export DEBIAN_FRONTEND=noninteractive |
||||
|
|
||||
|
info "Configure timezone" |
||||
|
timedatectl set-timezone ${timezone} --no-ask-password |
||||
|
|
||||
|
info "Add the VM IP to the list of allowed IPs" |
||||
|
awk -v ip=$IP -f /app/vagrant/provision/provision.awk /app/config/web.php |
||||
|
|
||||
|
info "Prepare root password for MySQL" |
||||
|
debconf-set-selections <<< 'mariadb-server mysql-server/root_password password' |
||||
|
debconf-set-selections <<< 'mariadb-server mysql-server/root_password_again password' |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Update OS software" |
||||
|
apt-get update |
||||
|
apt-get upgrade -y |
||||
|
|
||||
|
info "Install additional software" |
||||
|
apt-get install -y php7.2-curl php7.2-cli php7.2-intl php7.2-mysqlnd php7.2-gd php7.2-fpm php7.2-mbstring php7.2-xml unzip nginx mariadb-server-10.1 php.xdebug |
||||
|
|
||||
|
info "Configure MySQL" |
||||
|
sed -i 's/.*bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mariadb.conf.d/50-server.cnf |
||||
|
mysql <<< "CREATE USER 'root'@'%' IDENTIFIED BY ''" |
||||
|
mysql <<< "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'" |
||||
|
mysql <<< "DROP USER 'root'@'localhost'" |
||||
|
mysql <<< 'FLUSH PRIVILEGES' |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Configure PHP-FPM" |
||||
|
sed -i 's/user = www-data/user = vagrant/g' /etc/php/7.2/fpm/pool.d/www.conf |
||||
|
sed -i 's/group = www-data/group = vagrant/g' /etc/php/7.2/fpm/pool.d/www.conf |
||||
|
sed -i 's/owner = www-data/owner = vagrant/g' /etc/php/7.2/fpm/pool.d/www.conf |
||||
|
cat << EOF > /etc/php/7.2/mods-available/xdebug.ini |
||||
|
zend_extension=xdebug.so |
||||
|
xdebug.remote_enable=1 |
||||
|
xdebug.remote_connect_back=1 |
||||
|
xdebug.remote_port=9000 |
||||
|
xdebug.remote_autostart=1 |
||||
|
EOF |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Configure NGINX" |
||||
|
sed -i 's/user www-data/user vagrant/g' /etc/nginx/nginx.conf |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Enabling site configuration" |
||||
|
ln -s /app/vagrant/nginx/app.conf /etc/nginx/sites-enabled/app.conf |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Removing default site configuration" |
||||
|
rm /etc/nginx/sites-enabled/default |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Initialize databases for MySQL" |
||||
|
mysql <<< 'CREATE DATABASE yii2basic' |
||||
|
mysql <<< 'CREATE DATABASE yii2basic_test' |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Install composer" |
||||
|
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer |
@ -0,0 +1,31 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
|
||||
|
#== Import script args == |
||||
|
|
||||
|
github_token=$(echo "$1") |
||||
|
|
||||
|
#== Bash helpers == |
||||
|
|
||||
|
function info { |
||||
|
echo " " |
||||
|
echo "--> $1" |
||||
|
echo " " |
||||
|
} |
||||
|
|
||||
|
#== Provision script == |
||||
|
|
||||
|
info "Provision-script user: `whoami`" |
||||
|
|
||||
|
info "Configure composer" |
||||
|
composer config --global github-oauth.github.com ${github_token} |
||||
|
echo "Done!" |
||||
|
|
||||
|
info "Install project dependencies" |
||||
|
cd /app |
||||
|
composer --no-progress --prefer-dist install |
||||
|
|
||||
|
info "Create bash-alias 'app' for vagrant user" |
||||
|
echo 'alias app="cd /app"' | tee /home/vagrant/.bash_aliases |
||||
|
|
||||
|
info "Enabling colorized prompt for guest console" |
||||
|
sed -i "s/#force_color_prompt=yes/force_color_prompt=yes/" /home/vagrant/.bashrc |
@ -0,0 +1,50 @@ |
|||||
|
### |
||||
|
# Modifying Yii2's files for Vagrant VM |
||||
|
# |
||||
|
# @author HA3IK <golubha3ik@gmail.com> |
||||
|
# @version 1.0.0 |
||||
|
|
||||
|
BEGIN { |
||||
|
print "AWK BEGINs its work:" |
||||
|
IGNORECASE = 1 |
||||
|
|
||||
|
# Correct IP - wildcard last octet |
||||
|
match(ip, /(([0-9]+\.)+)/, arr) |
||||
|
ip = arr[1] "*" |
||||
|
} |
||||
|
# BODY |
||||
|
{ |
||||
|
# Check if it's the same file |
||||
|
if (FILENAME != isFile["same"]){ |
||||
|
msg = "- Work with: " FILENAME |
||||
|
# Close a previous file |
||||
|
close(isFile["same"]) |
||||
|
# Delete previous data |
||||
|
delete isFile |
||||
|
# Save current file |
||||
|
isFile["same"] = FILENAME |
||||
|
# Define array index for the file |
||||
|
switch (FILENAME){ |
||||
|
case /config\/web\.php$/: |
||||
|
isFile["IsConfWeb"] = 1 |
||||
|
msg = msg " - add allowed IP: " ip |
||||
|
break |
||||
|
} |
||||
|
# Print the concatenated message for the file |
||||
|
print msg |
||||
|
} |
||||
|
|
||||
|
# IF config/web.php |
||||
|
if (isFile["IsConfWeb"]){ |
||||
|
# IF line has "allowedIPs" and doesn't has our IP |
||||
|
if (match($0, "allowedIPs") && !match($0, ip)){ |
||||
|
match($0, /([^\]]+)(.+)/, arr) |
||||
|
$0 = sprintf("%s, '%s'%s", arr[1], ip, arr[2]) |
||||
|
} |
||||
|
# Rewrite the file |
||||
|
print $0 > FILENAME |
||||
|
} |
||||
|
} |
||||
|
END { |
||||
|
print "AWK ENDs its work." |
||||
|
} |
@ -0,0 +1,83 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** @var yii\web\View $this */ |
||||
|
/** @var string $content */ |
||||
|
|
||||
|
use app\assets\AppAsset; |
||||
|
use app\widgets\Alert; |
||||
|
use yii\bootstrap5\Breadcrumbs; |
||||
|
use yii\bootstrap5\Html; |
||||
|
use yii\bootstrap5\Nav; |
||||
|
use yii\bootstrap5\NavBar; |
||||
|
|
||||
|
AppAsset::register($this); |
||||
|
|
||||
|
$this->registerCsrfMetaTags(); |
||||
|
$this->registerMetaTag(['charset' => Yii::$app->charset], 'charset'); |
||||
|
$this->registerMetaTag(['name' => 'viewport', 'content' => 'width=device-width, initial-scale=1, shrink-to-fit=no']); |
||||
|
$this->registerMetaTag(['name' => 'description', 'content' => $this->params['meta_description'] ?? '']); |
||||
|
$this->registerMetaTag(['name' => 'keywords', 'content' => $this->params['meta_keywords'] ?? '']); |
||||
|
$this->registerLinkTag(['rel' => 'icon', 'type' => 'image/x-icon', 'href' => Yii::getAlias('@web/favicon.ico')]); |
||||
|
?>
|
||||
|
<?php $this->beginPage() ?>
|
||||
|
<!DOCTYPE html> |
||||
|
<html lang="<?= Yii::$app->language ?>" class="h-100"> |
||||
|
<head> |
||||
|
<title><?= Html::encode($this->title) ?></title>
|
||||
|
<?php $this->head() ?>
|
||||
|
</head> |
||||
|
<body class="d-flex flex-column h-100"> |
||||
|
<?php $this->beginBody() ?>
|
||||
|
|
||||
|
<header id="header"> |
||||
|
<?php |
||||
|
NavBar::begin([ |
||||
|
'brandLabel' => Yii::$app->name, |
||||
|
'brandUrl' => Yii::$app->homeUrl, |
||||
|
'options' => ['class' => 'navbar-expand-md navbar-dark bg-dark fixed-top'] |
||||
|
]); |
||||
|
echo Nav::widget([ |
||||
|
'options' => ['class' => 'navbar-nav'], |
||||
|
'items' => [ |
||||
|
['label' => 'Home', 'url' => ['/site/index']], |
||||
|
['label' => 'About', 'url' => ['/site/about']], |
||||
|
['label' => 'Contact', 'url' => ['/site/contact']], |
||||
|
Yii::$app->user->isGuest |
||||
|
? ['label' => 'Login', 'url' => ['/site/login']] |
||||
|
: '<li class="nav-item">' |
||||
|
. Html::beginForm(['/site/logout']) |
||||
|
. Html::submitButton( |
||||
|
'Logout (' . Yii::$app->user->identity->username . ')', |
||||
|
['class' => 'nav-link btn btn-link logout'] |
||||
|
) |
||||
|
. Html::endForm() |
||||
|
. '</li>' |
||||
|
] |
||||
|
]); |
||||
|
NavBar::end(); |
||||
|
?>
|
||||
|
</header> |
||||
|
|
||||
|
<main id="main" class="flex-shrink-0" role="main"> |
||||
|
<div class="container"> |
||||
|
<?php if (!empty($this->params['breadcrumbs'])): ?>
|
||||
|
<?= Breadcrumbs::widget(['links' => $this->params['breadcrumbs']]) ?>
|
||||
|
<?php endif ?>
|
||||
|
<?= Alert::widget() ?>
|
||||
|
<?= $content ?>
|
||||
|
</div> |
||||
|
</main> |
||||
|
|
||||
|
<footer id="footer" class="mt-auto py-3 bg-light"> |
||||
|
<div class="container"> |
||||
|
<div class="row text-muted"> |
||||
|
<div class="col-md-6 text-center text-md-start">© My Company <?= date('Y') ?></div>
|
||||
|
<div class="col-md-6 text-center text-md-end"><?= Yii::powered() ?></div>
|
||||
|
</div> |
||||
|
</div> |
||||
|
</footer> |
||||
|
|
||||
|
<?php $this->endBody() ?>
|
||||
|
</body> |
||||
|
</html> |
||||
|
<?php $this->endPage() ?>
|
@ -0,0 +1,18 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** @var yii\web\View $this */ |
||||
|
|
||||
|
use yii\helpers\Html; |
||||
|
|
||||
|
$this->title = 'About'; |
||||
|
$this->params['breadcrumbs'][] = $this->title; |
||||
|
?>
|
||||
|
<div class="site-about"> |
||||
|
<h1><?= Html::encode($this->title) ?></h1>
|
||||
|
|
||||
|
<p> |
||||
|
This is the About page. You may modify the following file to customize its content: |
||||
|
</p> |
||||
|
|
||||
|
<code><?= __FILE__ ?></code>
|
||||
|
</div> |
@ -0,0 +1,68 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** @var yii\web\View $this */ |
||||
|
/** @var yii\bootstrap5\ActiveForm $form */ |
||||
|
/** @var app\models\ContactForm $model */ |
||||
|
|
||||
|
use yii\bootstrap5\ActiveForm; |
||||
|
use yii\bootstrap5\Html; |
||||
|
use yii\captcha\Captcha; |
||||
|
|
||||
|
$this->title = 'Contact'; |
||||
|
$this->params['breadcrumbs'][] = $this->title; |
||||
|
?>
|
||||
|
<div class="site-contact"> |
||||
|
<h1><?= Html::encode($this->title) ?></h1>
|
||||
|
|
||||
|
<?php if (Yii::$app->session->hasFlash('contactFormSubmitted')): ?>
|
||||
|
|
||||
|
<div class="alert alert-success"> |
||||
|
Thank you for contacting us. We will respond to you as soon as possible. |
||||
|
</div> |
||||
|
|
||||
|
<p> |
||||
|
Note that if you turn on the Yii debugger, you should be able |
||||
|
to view the mail message on the mail panel of the debugger. |
||||
|
<?php if (Yii::$app->mailer->useFileTransport): ?>
|
||||
|
Because the application is in development mode, the email is not sent but saved as |
||||
|
a file under <code><?= Yii::getAlias(Yii::$app->mailer->fileTransportPath) ?></code>.
|
||||
|
Please configure the <code>useFileTransport</code> property of the <code>mail</code> |
||||
|
application component to be false to enable email sending. |
||||
|
<?php endif; ?>
|
||||
|
</p> |
||||
|
|
||||
|
<?php else: ?>
|
||||
|
|
||||
|
<p> |
||||
|
If you have business inquiries or other questions, please fill out the following form to contact us. |
||||
|
Thank you. |
||||
|
</p> |
||||
|
|
||||
|
<div class="row"> |
||||
|
<div class="col-lg-5"> |
||||
|
|
||||
|
<?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'name')->textInput(['autofocus' => true]) ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'email') ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'subject') ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'body')->textarea(['rows' => 6]) ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'verifyCode')->widget(Captcha::class, [ |
||||
|
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>', |
||||
|
]) ?>
|
||||
|
|
||||
|
<div class="form-group"> |
||||
|
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
|
||||
|
</div> |
||||
|
|
||||
|
<?php ActiveForm::end(); ?>
|
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<?php endif; ?>
|
||||
|
</div> |
@ -0,0 +1,27 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** @var yii\web\View $this */ |
||||
|
/** @var string $name */ |
||||
|
/** @var string $message */ |
||||
|
/** @var Exception$exception */ |
||||
|
|
||||
|
use yii\helpers\Html; |
||||
|
|
||||
|
$this->title = $name; |
||||
|
?>
|
||||
|
<div class="site-error"> |
||||
|
|
||||
|
<h1><?= Html::encode($this->title) ?></h1>
|
||||
|
|
||||
|
<div class="alert alert-danger"> |
||||
|
<?= nl2br(Html::encode($message)) ?>
|
||||
|
</div> |
||||
|
|
||||
|
<p> |
||||
|
The above error occurred while the Web server was processing your request. |
||||
|
</p> |
||||
|
<p> |
||||
|
Please contact us if you think this is a server error. Thank you. |
||||
|
</p> |
||||
|
|
||||
|
</div> |
@ -0,0 +1,53 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** @var yii\web\View $this */ |
||||
|
|
||||
|
$this->title = 'My Yii Application'; |
||||
|
?>
|
||||
|
<div class="site-index"> |
||||
|
|
||||
|
<div class="jumbotron text-center bg-transparent mt-5 mb-5"> |
||||
|
<h1 class="display-4">Congratulations!</h1> |
||||
|
|
||||
|
<p class="lead">You have successfully created your Yii-powered application.</p> |
||||
|
|
||||
|
<p><a class="btn btn-lg btn-success" href="https://www.yiiframework.com">Get started with Yii</a></p> |
||||
|
</div> |
||||
|
|
||||
|
<div class="body-content"> |
||||
|
|
||||
|
<div class="row"> |
||||
|
<div class="col-lg-4 mb-3"> |
||||
|
<h2>Heading</h2> |
||||
|
|
||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et |
||||
|
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip |
||||
|
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu |
||||
|
fugiat nulla pariatur.</p> |
||||
|
|
||||
|
<p><a class="btn btn-outline-secondary" href="https://www.yiiframework.com/doc/">Yii Documentation »</a></p> |
||||
|
</div> |
||||
|
<div class="col-lg-4 mb-3"> |
||||
|
<h2>Heading</h2> |
||||
|
|
||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et |
||||
|
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip |
||||
|
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu |
||||
|
fugiat nulla pariatur.</p> |
||||
|
|
||||
|
<p><a class="btn btn-outline-secondary" href="https://www.yiiframework.com/forum/">Yii Forum »</a></p> |
||||
|
</div> |
||||
|
<div class="col-lg-4"> |
||||
|
<h2>Heading</h2> |
||||
|
|
||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et |
||||
|
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip |
||||
|
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu |
||||
|
fugiat nulla pariatur.</p> |
||||
|
|
||||
|
<p><a class="btn btn-outline-secondary" href="https://www.yiiframework.com/extensions/">Yii Extensions »</a></p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</div> |
@ -0,0 +1,55 @@ |
|||||
|
<?php |
||||
|
|
||||
|
/** @var yii\web\View $this */ |
||||
|
/** @var yii\bootstrap5\ActiveForm $form */ |
||||
|
|
||||
|
/** @var app\models\LoginForm $model */ |
||||
|
|
||||
|
use yii\bootstrap5\ActiveForm; |
||||
|
use yii\bootstrap5\Html; |
||||
|
|
||||
|
$this->title = 'Login'; |
||||
|
$this->params['breadcrumbs'][] = $this->title; |
||||
|
?>
|
||||
|
<div class="site-login"> |
||||
|
<h1><?= Html::encode($this->title) ?></h1>
|
||||
|
|
||||
|
<p>Please fill out the following fields to login:</p> |
||||
|
|
||||
|
<div class="row"> |
||||
|
<div class="col-lg-5"> |
||||
|
|
||||
|
<?php $form = ActiveForm::begin([ |
||||
|
'id' => 'login-form', |
||||
|
'fieldConfig' => [ |
||||
|
'template' => "{label}\n{input}\n{error}", |
||||
|
'labelOptions' => ['class' => 'col-lg-1 col-form-label mr-lg-3'], |
||||
|
'inputOptions' => ['class' => 'col-lg-3 form-control'], |
||||
|
'errorOptions' => ['class' => 'col-lg-7 invalid-feedback'], |
||||
|
], |
||||
|
]); ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'password')->passwordInput() ?>
|
||||
|
|
||||
|
<?= $form->field($model, 'rememberMe')->checkbox([ |
||||
|
'template' => "<div class=\"custom-control custom-checkbox\">{input} {label}</div>\n<div class=\"col-lg-8\">{error}</div>", |
||||
|
]) ?>
|
||||
|
|
||||
|
<div class="form-group"> |
||||
|
<div> |
||||
|
<?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
|
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<?php ActiveForm::end(); ?>
|
||||
|
|
||||
|
<div style="color:#999;"> |
||||
|
You may login with <strong>admin/admin</strong> or <strong>demo/demo</strong>.<br> |
||||
|
To modify the username/password, please check out the code <code>app\models\User::$users</code>. |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
@ -0,0 +1,4 @@ |
|||||
|
RewriteEngine on |
||||
|
RewriteCond %{REQUEST_FILENAME} !-d |
||||
|
RewriteCond %{REQUEST_FILENAME} !-f |
||||
|
RewriteRule . index.php [L] |
@ -0,0 +1,2 @@ |
|||||
|
* |
||||
|
!.gitignore |
@ -0,0 +1,88 @@ |
|||||
|
main > .container { |
||||
|
padding: 70px 15px 20px; |
||||
|
} |
||||
|
|
||||
|
.footer { |
||||
|
background-color: #f5f5f5; |
||||
|
font-size: .9em; |
||||
|
height: 60px; |
||||
|
} |
||||
|
|
||||
|
.footer > .container { |
||||
|
padding-right: 15px; |
||||
|
padding-left: 15px; |
||||
|
} |
||||
|
|
||||
|
.not-set { |
||||
|
color: #c55; |
||||
|
font-style: italic; |
||||
|
} |
||||
|
|
||||
|
/* add sorting icons to gridview sort links */ |
||||
|
a.asc:after, a.desc:after { |
||||
|
content: ''; |
||||
|
left: 3px; |
||||
|
display: inline-block; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
border: solid 5px transparent; |
||||
|
margin: 4px 4px 2px 4px; |
||||
|
background: transparent; |
||||
|
} |
||||
|
|
||||
|
a.asc:after { |
||||
|
border-bottom: solid 7px #212529; |
||||
|
border-top-width: 0; |
||||
|
} |
||||
|
|
||||
|
a.desc:after { |
||||
|
border-top: solid 7px #212529; |
||||
|
border-bottom-width: 0; |
||||
|
} |
||||
|
|
||||
|
.grid-view th { |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
.hint-block { |
||||
|
display: block; |
||||
|
margin-top: 5px; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.error-summary { |
||||
|
color: #a94442; |
||||
|
background: #fdf7f7; |
||||
|
border-left: 3px solid #eed3d7; |
||||
|
padding: 10px 20px; |
||||
|
margin: 0 0 15px 0; |
||||
|
} |
||||
|
|
||||
|
/* align the logout "link" (button in form) of the navbar */ |
||||
|
.nav li > form > button.logout { |
||||
|
padding-top: 7px; |
||||
|
color: rgba(255, 255, 255, 0.5); |
||||
|
} |
||||
|
|
||||
|
@media(max-width:767px) { |
||||
|
.nav li > form > button.logout { |
||||
|
display:block; |
||||
|
text-align: left; |
||||
|
width: 100%; |
||||
|
padding: 10px 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.nav > li > form > button.logout:focus, |
||||
|
.nav > li > form > button.logout:hover { |
||||
|
text-decoration: none; |
||||
|
color: rgba(255, 255, 255, 0.75); |
||||
|
} |
||||
|
|
||||
|
.nav > li > form > button.logout:focus { |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
.form-group { |
||||
|
margin-bottom: 1rem; |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
<?php |
||||
|
|
||||
|
// NOTE: Make sure this file is not accessible when deployed to production
|
||||
|
if (!in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) { |
||||
|
die('You are not allowed to access this file.'); |
||||
|
} |
||||
|
|
||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
|
defined('YII_ENV') or define('YII_ENV', 'test'); |
||||
|
|
||||
|
require __DIR__ . '/../vendor/autoload.php'; |
||||
|
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; |
||||
|
|
||||
|
$config = require __DIR__ . '/../config/test.php'; |
||||
|
|
||||
|
(new yii\web\Application($config))->run(); |
@ -0,0 +1,12 @@ |
|||||
|
<?php |
||||
|
|
||||
|
// comment out the following two lines when deployed to production
|
||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true);//定義兩個常量,查看你當前是運行環境還是開發環境
|
||||
|
defined('YII_ENV') or define('YII_ENV', 'dev'); |
||||
|
|
||||
|
require __DIR__ . '/../vendor/autoload.php'; |
||||
|
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; |
||||
|
|
||||
|
$config = require __DIR__ . '/../config/web.php'; |
||||
|
|
||||
|
(new yii\web\Application($config))->run(); |
@ -0,0 +1,2 @@ |
|||||
|
User-agent: * |
||||
|
Disallow: |
@ -0,0 +1,73 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace app\widgets; |
||||
|
|
||||
|
use Yii; |
||||
|
|
||||
|
/** |
||||
|
* Alert widget renders a message from session flash. All flash messages are displayed |
||||
|
* in the sequence they were assigned using setFlash. You can set message as following: |
||||
|
* |
||||
|
* ```php |
||||
|
* Yii::$app->session->setFlash('error', 'This is the message'); |
||||
|
* Yii::$app->session->setFlash('success', 'This is the message'); |
||||
|
* Yii::$app->session->setFlash('info', 'This is the message'); |
||||
|
* ``` |
||||
|
* |
||||
|
* Multiple messages could be set as follows: |
||||
|
* |
||||
|
* ```php |
||||
|
* Yii::$app->session->setFlash('error', ['Error 1', 'Error 2']); |
||||
|
* ``` |
||||
|
* |
||||
|
* @author Kartik Visweswaran <kartikv2@gmail.com> |
||||
|
* @author Alexander Makarov <sam@rmcreative.ru> |
||||
|
*/ |
||||
|
class Alert extends \yii\bootstrap5\Widget |
||||
|
{ |
||||
|
/** |
||||
|
* @var array the alert types configuration for the flash messages. |
||||
|
* This array is setup as $key => $value, where: |
||||
|
* - key: the name of the session flash variable |
||||
|
* - value: the bootstrap alert type (i.e. danger, success, info, warning) |
||||
|
*/ |
||||
|
public $alertTypes = [ |
||||
|
'error' => 'alert-danger', |
||||
|
'danger' => 'alert-danger', |
||||
|
'success' => 'alert-success', |
||||
|
'info' => 'alert-info', |
||||
|
'warning' => 'alert-warning' |
||||
|
]; |
||||
|
/** |
||||
|
* @var array the options for rendering the close button tag. |
||||
|
* Array will be passed to [[\yii\bootstrap\Alert::closeButton]]. |
||||
|
*/ |
||||
|
public $closeButton = []; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* {@inheritdoc} |
||||
|
*/ |
||||
|
public function run() |
||||
|
{ |
||||
|
$session = Yii::$app->session; |
||||
|
$appendClass = isset($this->options['class']) ? ' ' . $this->options['class'] : ''; |
||||
|
|
||||
|
foreach (array_keys($this->alertTypes) as $type) { |
||||
|
$flash = $session->getFlash($type); |
||||
|
|
||||
|
foreach ((array) $flash as $i => $message) { |
||||
|
echo \yii\bootstrap5\Alert::widget([ |
||||
|
'body' => $message, |
||||
|
'closeButton' => $this->closeButton, |
||||
|
'options' => array_merge($this->options, [ |
||||
|
'id' => $this->getId() . '-' . $type . '-' . $i, |
||||
|
'class' => $this->alertTypes[$type] . $appendClass, |
||||
|
]), |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
$session->removeFlash($type); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
#!/usr/bin/env php |
||||
|
<?php |
||||
|
/** |
||||
|
* Yii console bootstrap file. |
||||
|
* |
||||
|
* @link https://www.yiiframework.com/ |
||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
|
* @license https://www.yiiframework.com/license/ |
||||
|
*/ |
||||
|
|
||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
|
defined('YII_ENV') or define('YII_ENV', 'dev'); |
||||
|
|
||||
|
require __DIR__ . '/vendor/autoload.php'; |
||||
|
require __DIR__ . '/vendor/yiisoft/yii2/Yii.php'; |
||||
|
|
||||
|
$config = require __DIR__ . '/config/console.php'; |
||||
|
|
||||
|
$application = new yii\console\Application($config); |
||||
|
$exitCode = $application->run(); |
||||
|
exit($exitCode); |
@ -0,0 +1,20 @@ |
|||||
|
@echo off |
||||
|
|
||||
|
rem ------------------------------------------------------------- |
||||
|
rem Yii command line bootstrap script for Windows. |
||||
|
rem |
||||
|
rem @author Qiang Xue <qiang.xue@gmail.com> |
||||
|
rem @link https://www.yiiframework.com/ |
||||
|
rem @copyright Copyright (c) 2008 Yii Software LLC |
||||
|
rem @license https://www.yiiframework.com/license/ |
||||
|
rem ------------------------------------------------------------- |
||||
|
|
||||
|
@setlocal |
||||
|
|
||||
|
set YII_PATH=%~dp0 |
||||
|
|
||||
|
if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe |
||||
|
|
||||
|
"%PHP_COMMAND%" "%YII_PATH%yii" %* |
||||
|
|
||||
|
@endlocal |
Write
Preview
Loading…
Cancel
Save
Reference in new issue