This commit is contained in:
dongpd 2020-02-01 16:47:12 +07:00
commit 4c619ad6e6
16739 changed files with 3329170 additions and 0 deletions

14
.htaccess Normal file
View File

@ -0,0 +1,14 @@
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
</IfModule>
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_URI} ^/.*
RewriteRule ^(.*)$ web/$1 [L]
RewriteCond %{REQUEST_URI} !^/web/
RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ web/index.php
</IfModule>

32
LICENSE.md Normal file
View File

@ -0,0 +1,32 @@
The Yii framework is free software. It is released under the terms of
the following BSD License.
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.

233
README.md Normal file
View File

@ -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](http://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 Status](https://travis-ci.org/yiisoft/yii2-app-basic.svg?branch=master)](https://travis-ci.org/yiisoft/yii2-app-basic)
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 5.4.0.
INSTALLATION
------------
### Install via Composer
If you do not have [Composer](http://getcomposer.org/), you may install it by following the instructions
at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix).
You can then install this project template using the following command:
~~~
php composer.phar create-project --prefer-dist --stability=dev 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](http://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](http://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](http://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 `yii2_basic_tests` 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-html --coverage-xml
#collect coverage only for unit tests
vendor/bin/codecept run unit -- --coverage-html --coverage-xml
#collect coverage for unit and functional tests
vendor/bin/codecept run functional,unit -- --coverage-html --coverage-xml
```
You can see code coverage output under the `tests/_output` directory.

81
Vagrantfile vendored Normal file
View File

@ -0,0 +1,81 @@
require 'yaml'
require 'fileutils'
required_plugins = %w( vagrant-hostmanager vagrant-vbguest )
required_plugins.each do |plugin|
exec "vagrant plugin install #{plugin}" unless Vagrant.has_plugin? plugin
end
domains = {
app: 'yii2basic.dev'
}
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-16.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']]
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

44
assets/AppAsset.php Normal file
View File

@ -0,0 +1,44 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://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',
'ajaxFileUpload/ajaxFilesUpload.css',
'datetimepicker/bootstrap-datetimepicker.css',
'icheck/skins/all.css'
];
public $js = [
'icheck/icheck.min.js',
'ajaxFileUpload/ajaxFilesUpload.js',
'datetimepicker/moment-with-locales.js',
'datetimepicker/bootstrap-datetimepicker.js',
'js/boostrap-notify.min.js',
'js/socket.io.min.js',
'js/editor.js',
'js/common.js'
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}

23
assets/LogsAsset.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace app\assets;
use yii\web\AssetBundle;
class LogsAsset extends AssetBundle {
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
];
public $js = [
'js/logs.js'
];
public $depends = [
'yii\web\YiiAsset',
'app\assets\AppAsset',
// 'yii\jui\JuiAsset',
'yii\bootstrap\BootstrapAsset',
];
}

28
assets/UserAsset.php Normal file
View File

@ -0,0 +1,28 @@
<?php
namespace app\assets;
use yii\web\AssetBundle;
class UserAsset extends AssetBundle {
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'select2/css/select2.min.css',
'ajaxFileUpload/ajaxFilesUpload.css'
];
public $js = [
'js/md5.min.js',
'select2/js/select2.min.js',
'ajaxFileUpload/ajaxFilesUpload.js',
'js/user.js'
];
public $depends = [
'yii\web\YiiAsset',
'app\assets\AppAsset',
// 'yii\jui\JuiAsset',
'yii\bootstrap\BootstrapAsset',
];
}

23
assets/VehicleAsset.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace app\assets;
use yii\web\AssetBundle;
class VehicleAsset extends AssetBundle {
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
];
public $js = [
'js/vehicle.js'
];
public $depends = [
'yii\web\YiiAsset',
'app\assets\AppAsset',
// 'yii\jui\JuiAsset',
'yii\bootstrap\BootstrapAsset',
];
}

37
codeception.yml Normal file
View File

@ -0,0 +1,37 @@
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
helpers: tests/_support
settings:
bootstrap: _bootstrap.php
memory_limit: 1024M
colors: true
modules:
config:
Yii2:
configFile: 'config/test.php'
cleanup: false
# 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/*
# blacklist:
# include:
# - assets/*
# - config/*
# - runtime/*
# - vendor/*
# - views/*
# - web/*
# - tests/*

View File

@ -0,0 +1,135 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace app\commands;
use yii\console\Controller;
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 AssignController extends Controller {
public $pharse = [
1 => "Phân cảnh",
2 => "Vẽ background",
3 => "Vẽ động",
4 => "Đọc thoại",
5 => "Sạch xen",
6 => "Kỹ thuật"
];
/**
* 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() {
$config = \app\models\Config::findOne(['config_key' => 'auto_assign'])->config;
$time = \app\models\Config::findOne(['config_key' => 'time_auto_assign'])->config * 60;
if ($config === '1') {
$query = \app\models\Projects::find();
$query->andFilterWhere(["OR", ['p1' => 0], ['p2' => 0], ['p3' => 0], ['p4' => 0], ['p5' => 0], ['p6' => 0]]);
$projects = $query->all();
foreach ($projects as $k => $project) {
if ($project->p1 == 0) {
$this->assign($time, $project, 1);
} else {
if ($project->p2 == 0) {
$this->assign($time, $project, 2);
} else {
if ($project->p5 == 0) {
$this->assign($time, $project, 5);
} elseif ($project->p6 == 0) {
$this->assign($time, $project, 6);
}
}
if ($project->p3 == 0) {
$this->assign($time, $project, 3);
}
if ($project->p4 == 0) {
$this->assign($time, $project, 4);
}
}
}
}
return;
}
public function assign($time, $project, $pid) {
$project_id = $project->id;
$role = '';
if ($pid == 1) {
$role = 'hoa_sy_phan_canh';
}
if (in_array($pid, [2, 3, 4])) {
if ($pid == 2) {
$role = 'hoa_sy_to_mau';
}
if ($pid == 3) {
$role = 'hoa_sy_ve_dong';
}
if ($pid == 4) {
$role = 'doc_thoai';
}
$timeConfig = time() - $time;
$check = \app\models\Results::find()->andWhere(['project_id' => $project_id, 'p_id' => 1, 'status' => 1])->andWhere(["<", "modified_at", $timeConfig])->count();
if ($check == 0) {
return;
}
}
if ($pid == 5) {
$role = 'hoa_sy_sach_xen';
$timeConfig = time() - $time;
$check = \app\models\Results::find()->andWhere(['project_id' => $project_id, 'p_id' => 2, 'status' => 1])->andWhere(["<", "modified_at", $timeConfig])->count();
if ($check == 0) {
return;
}
}
if ($pid == 6) {
$role = 'ky_thuat';
$timeConfig = time() - $time;
$check = \app\models\Results::find()->andWhere(['project_id' => $project_id, 'p_id' => 5, 'status' => 1])->andWhere(["<", "modified_at", $timeConfig])->count();
if ($check == 0) {
return;
}
}
$authors = \app\models\AuthAssignment::find()->andWhere(['item_name' => $role])->all();
foreach ($authors as $k => $v) {
$currentProjects = \app\models\Results::find()->andWhere(['u_id' => $v->user_id, 'content' => null])->count();
if (\app\models\User::findOne($v->user_id)->quota > $currentProjects) {
\app\models\Projects::updateAll(['p' . $pid => $v->user_id], ['id' => $project_id]);
$model = new \app\models\Results();
$check = $model->create(['project_id' => $project_id, 'p_id' => $pid, 'u_id' => $v->user_id]);
if ($check) {
$notification = new \app\models\Notification();
$content = "<b>Hệ thống</b> đã tự động giao quy trình " . $this->pharse[$pid] . " cho bạn trong dự án <b>" . $project->name . "</b>";
$notif_id = $notification->create([
'content' => $content,
'from_user' => 0,
'to_user' => $v->user_id,
'url' => \yii\helpers\Url::to(['/projects/view', 'id' => $project_id, 'p' => $pid]),
'time' => time()
]);
if ($notif_id) {
$notification->sendEmail($notif_id, $v->user_id, $content);
}
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,34 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace app\commands;
use yii\console\Controller;
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;
}
}

View File

@ -0,0 +1,147 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace app\components;
use yii\helpers\ArrayHelper;
/**
* Description of CacheRbacManager
*
* @author Kdg
*/
class CacheRbacDbManager extends \yii\rbac\DbManager {
/**
* @var string the ID of the cache application component that is used to cache rbac.
* Defaults to 'cache' which refers to the primary cache application component.
*/
public $cache = 'cache';
/**
* @var integer Lifetime of cached data in seconds
*/
public $cacheDuration = 3600;
/**
* @var string cache key name
*/
public $cacheKeyName = 'RbacCached';
/**
* @var array php cache
*/
protected $cachedData = [];
/**
* @inheritdoc
*/
public function checkAccess($userId, $permissionName, $params = []) {
if (!empty($params))
return parent::checkAccess($userId, $permissionName, $params);
$cacheKey = 'checkAccess:' . $userId . ':' . $permissionName;
$cached = $this->getValue($cacheKey);
if (empty($cached)) {
$cached = parent::checkAccess($userId, $permissionName);
$this->setValue($cacheKey, $cached);
}
return $cached;
}
/**
* @inheritdoc
*/
protected function checkAccessRecursive($user, $itemName, $params, $assignments) {
$cacheKey = 'checkAccessRecursive:' . $user . ':' . $itemName;
if (!empty($params))
$cacheKey .= ':' . current($params)->primaryKey;
$cached = $this->getValue($cacheKey);
if (empty($cached)) {
$cached = parent::checkAccessRecursive($user, $itemName, $params, $assignments);
$this->setValue($cacheKey, $cached);
}
return $cached;
}
/**
* @inheritdoc
*/
protected function getItem($name) {
$cacheKey = 'Item:' . $name;
$cached = $this->getValue($cacheKey);
if (empty($cached)) {
$cached = parent::getItem($name);
$this->setValue($cacheKey, $cached);
}
return $cached;
}
/**
* @inheritdoc
*/
public function getAssignments($userId) {
if (empty($userId))
return parent::getAssignments($userId);
$cacheKey = 'Assignments:' . $userId;
$cached = $this->getValue($cacheKey);
if (empty($cached)) {
$cached = parent::getAssignments($userId);
$this->setValue($cacheKey, $cached);
}
return $cached;
}
/**
* Set a value in cache
* @param $key
* @param $value
* @return mixed
*/
protected function setValue($key, $value) {
$this->cachedData = $this->getCache()->get($this->cacheKeyName);
if (empty($this->cachedData))
$this->cachedData = [];
$this->cachedData[$key] = $value;
return $this->getCache()->set($this->cacheKeyName, $this->cachedData, $this->cacheDuration);
}
/**
* Get cached value
* @param $key
* @return mixed
*/
protected function getValue($key) {
$cached = ArrayHelper::getValue($this->cachedData, $key);
if (!isset($cached)) {
$cacheData = $this->getCache()->get($this->cacheKeyName);
$cached = $this->cachedData[$key] = ArrayHelper::getValue($cacheData, $key);
}
return $cached;
}
/**
* Get cached value
* @param $key
* @return mixed
*/
public function deleteAllCache() {
return $this->getCache()->delete($this->cacheKeyName);
}
/**
*
* @return \yii\caching\Cache
*/
private function getCache() {
if (is_string($this->cache)) {
$this->cache = \Yii::$app->get($this->cache);
}
return $this->cache;
}
}

73
composer.json Normal file
View File

@ -0,0 +1,73 @@
{
"name": "yiisoft/yii2-app-basic",
"description": "Yii 2 Basic Project Template",
"keywords": ["yii2", "framework", "basic", "project template"],
"homepage": "http://www.yiiframework.com/",
"type": "project",
"license": "BSD-3-Clause",
"support": {
"issues": "https://github.com/yiisoft/yii2/issues?state=open",
"forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"minimum-stability": "stable",
"require": {
"php": ">=5.4.0",
"yiisoft/yii2": "~2.0.14",
"yiisoft/yii2-bootstrap": "~2.0.0",
"yiisoft/yii2-swiftmailer": "~2.0.0",
"dmstr/yii2-adminlte-asset": "^2.1",
"yiisoft/yii2-smarty": "^2.0",
"yii2mod/yii2-rbac": "*",
"linslin/yii2-curl": "*",
"phpoffice/phpexcel": "*"
},
"require-dev": {
"yiisoft/yii2-debug": "~2.0.0",
"yiisoft/yii2-gii": "~2.0.0",
"yiisoft/yii2-faker": "~2.0.0",
"codeception/base": "^2.2.3",
"codeception/verify": "~0.3.1",
"codeception/specify": "~0.4.3"
},
"config": {
"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"
}
]
}

4361
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

4
config/aliases.php Normal file
View File

@ -0,0 +1,4 @@
<?php
\Yii::setAlias('images_folder', '/data/uploads');

56
config/console.php Normal file
View File

@ -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',
],
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',
'defaultRoles' => ['guest', 'user'],
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'log' => [
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'urlManager' => [
'showScriptName' => false,
'class' => 'yii\web\UrlManager',
'scriptUrl' => "/index.php"
],
'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',
];
}
return $config;

14
config/db.php Normal file
View File

@ -0,0 +1,14 @@
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=intops',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
// Schema cache options (for production environment)
//'enableSchemaCache' => true,
//'schemaCacheDuration' => 60,
//'schemaCache' => 'cache',
];

5
config/params.php Normal file
View File

@ -0,0 +1,5 @@
<?php
return [
'adminEmail' => 'admin@example.com',
];

42
config/test.php Normal file
View File

@ -0,0 +1,42 @@
<?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' => [
'useFileTransport' => true,
],
'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,
];

6
config/test_db.php Normal file
View File

@ -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=yii2_basic_tests';
return $db;

152
config/web.php Normal file
View File

@ -0,0 +1,152 @@
<?php
$params = require __DIR__ . '/params.php';
$db = require __DIR__ . '/db.php';
$config = [
'id' => 'basic',
'homeUrl' => ['/dashboard'],
'name' => 'BeetInnovators ANPR',
'defaultRoute' => 'dashboard',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'timeZone' => 'Asia/Ho_Chi_Minh',
'language' => 'vi-VN',
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
'modules' => [
'rbac' => [
'class' => 'yii2mod\rbac\Module',
],
],
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager', //'app\components\CacheRbacDbManager',
'defaultRoles' => ['guest', 'user'],
],
'mongodb' => [
'class' => '\yii\mongodb\Connection',
'dsn' => 'mongodb://localhost:27017/human',
],
'view' => [
'theme' => [
'pathMap' => [
'@app/views' => '@vendor/dmstr/yii2-adminlte-asset/example-views/yiisoft/yii2-app'
],
],
'defaultExtension' => 'tpl',
'renderers' => [
'tpl' => [
'class' => 'yii\smarty\ViewRenderer',
//'cachePath' => '@runtime/Smarty/cache',
],
],
],
'assetManager' => [
'bundles' => [
'dmstr\web\AdminLteAsset' => [
'skin' => 'skin-blue',
],
],
],
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'eqHsmuZKxCrVYfeBbpt5suJvVHafnK7O',
'enableCsrfValidation' => false,
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'view' => [
'defaultExtension' => 'tpl',
'renderers' => [
'tpl' => [
'class' => 'yii\smarty\ViewRenderer',
'cachePath' => '@runtime/Smarty/cache',
],
],
],
'viewPath' => '@app/mail',
'transport' => [
'class' => 'Swift_SmtpTransport',
'host' => 'smtp.gmail.com',
'username' => 'sunrise.media.apps@gmail.com',
'password' => 'admin@123456',
'port' => '587',
'encryption' => 'tls', //ssl use post 465
],
'useFileTransport' => false,
],
'i18n' => [
'translations' => [
'app*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '@app/messages',
//'sourceLanguage' => 'en-US',
'fileMap' => []
],
],
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => $db,
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
],
],
],
'params' => $params,
];
if (YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
// 'allowedIPs' => ['127.0.0.1', '::1'],
'allowedIPs' => ['*'],
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
// 'allowedIPs' => ['127.0.0.1', '::1'],
'allowedIPs' => ['*'],
'generators' => [
'crud' => [
'class' => 'yii\gii\generators\crud\Generator',
'templates' => [
'adminlte' => '@vendor/dmstr/yii2-adminlte-asset/gii/templates/crud/simple',
]
]
],
];
}
return $config;

View File

@ -0,0 +1,353 @@
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\helpers\Url;
use yii\helpers\FileHelper;
use app\models\User;
use app\models\Gate;
use app\models\Camera;
use app\models\Card;
use app\models\Logs;
/**
* CardController implements the CRUD actions for Card model.
*/
class ApiController extends Controller {
/**
* {@inheritdoc}
*/
public function behaviors() {
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
];
}
public function actionLogin() {
if (Yii::$app->request->post()) {
$post = Yii::$app->request->bodyParams;
$user = User::findOne([
'username' => $post['username'],
'password' => md5($post['password'])
]);
Yii::$app->response->format = "json";
if ($user) {
$gate = Gate::findOne(['user_id' => $user->id]);
if (!$gate) {
return [
'status' => false,
'data' => "Tài khoản chưa được cấu hình phân quyền"
];
} else {
if ($gate->api_config == null || $gate->api_config === "") {
return [
'status' => false,
'data' => "Cổng chưa được cấu hình API"
];
}
}
$cameras = Camera::find()->andWhere(['gate' => $gate->id])->all();
if (count($cameras) == 0) {
return [
'status' => false,
'data' => "Cổng chưa được cấu hình camera"
];
}
return [
'status' => true,
'data' => [
"userID" => $user->id,
"name" => $user->first_name,
"api" => json_decode($gate->api_config, true),
"score" => 8,
"scoreLong" => 6,
"camera1" => $gate->getCameraInfo(1),
"camera2" => $gate->getCameraInfo(2),
"camera3" => $gate->getCameraInfo(3),
"camera4" => $gate->getCameraInfo(4),
"camera5" => $gate->getCameraInfo(5),
"camera6" => $gate->getCameraInfo(6),
"camera7" => $gate->getCameraInfo(7),
"camera8" => $gate->getCameraInfo(8),
"statistic" => Logs::statistics(),
"cascadeConfig" => json_decode($gate->cascade_config, true),
"laneConfig" => json_decode($gate->lane_config, true)
]
];
} else {
return [
'status' => false,
'data' => "Tên tài khoản hoặc mật khẩu không đúng"
];
}
}
}
public function actionCheckCard() {
if (Yii::$app->request->post()) {
$post = Yii::$app->request->bodyParams;
$cardInfo = Card::findOne(['code' => $post['card']]);
Yii::$app->response->format = "json";
if ($cardInfo) {
$lastLog = Logs::find()->andWhere(['card_id' => $cardInfo->id])->orderBy(['time_in' => SORT_DESC])->one();
if ($lastLog) {
if ($lastLog->type == "in") {
return [
'status' => true,
'type' => "out",
'cardID' => sprintf("%06d", $cardInfo->id),
'cardRealID' => $cardInfo->id,
'log_id' => $lastLog->id,
'cardType' => $cardInfo->cardType,
'vehicleType' => $cardInfo->vehicleType,
'plate' => $lastLog->plate_in,
'time' => date("H:i:s d/m/Y", $lastLog->time_in),
'plateImage' => base64_encode(file_get_contents(Yii::getAlias('@webroot') . "/data/uploads/" . $lastLog->plate_image_in)),
'frameImage' => base64_encode(file_get_contents(Yii::getAlias('@webroot') . "/data/uploads/" . $lastLog->frame_image_in)),
'faceImage' => $lastLog->face_image_in === "" ? "" : base64_encode(file_get_contents(Yii::getAlias('@webroot') . "/data/uploads/" . $lastLog->face_image_in)),
'name' => $lastLog->name_in,
'plate' => $cardInfo->plate
];
} else {
return [
'status' => true,
'type' => "in",
'cardID' => sprintf("%06d", $cardInfo->id),
'cardRealID' => $cardInfo->id,
'cardType' => $cardInfo->cardType,
'vehicleType' => $cardInfo->vehicleType,
'plate' => $cardInfo->plate
];
}
} else {
return [
'status' => true,
'type' => "in",
'cardID' => sprintf("%06d", $cardInfo->id),
'cardRealID' => $cardInfo->id,
'cardType' => $cardInfo->cardType,
'vehicleType' => $cardInfo->vehicleType,
'plate' => $cardInfo->plate
];
}
} else {
return [
'status' => false
];
}
}
}
public function actionSaveLogs() {
if (Yii::$app->request->post()) {
$post = Yii::$app->request->bodyParams;
$RootFolder = Yii::getAlias('@webroot') . "/data/uploads";
$temp = $post['time'];
$temp = explode(" ", $temp);
$DateFolder = str_replace("/", "_", $temp[1]);
$time = date_format(date_create_from_format('H:i:s d/m/Y', $post['time']), 'U');
$targetPathFrame = $RootFolder . "/" . $DateFolder . "/frame/" . $post['type'];
FileHelper::createDirectory($targetPathFrame, 0777);
$FrameFileName = "frame_" . $time . ".png";
file_put_contents($targetPathFrame . "/" . $FrameFileName, base64_decode($post['frameImage']));
$post['frameImage'] = $DateFolder . "/frame/" . $post['type'] . "/" . $FrameFileName;
if ($post['plateImage'] !== "") {
$targetPathPlate = $RootFolder . "/" . $DateFolder . "/plate/" . $post['type'];
FileHelper::createDirectory($targetPathPlate, 0777);
$PlateFileName = "plate_" . $time . ".png";
file_put_contents($targetPathPlate . "/" . $PlateFileName, base64_decode($post['plateImage']));
$post['plateImage'] = $DateFolder . "/plate/" . $post['type'] . "/" . $PlateFileName;
} else {
$post['plateImage'] = null;
}
if (isset($post['faceImage'])) {
$targetPathFace = $RootFolder . "/" . $DateFolder . "/face/" . $post['type'];
FileHelper::createDirectory($targetPathFace, 0777);
$FaceFileName = "face_" . $time . ".png";
file_put_contents($targetPathFace . "/" . $FaceFileName, base64_decode($post['faceImage']));
$post['faceImage'] = $DateFolder . "/face/" . $post['type'] . "/" . $FaceFileName;
}
$post['time'] = $time;
if ($post['type'] === "in") {
$model = new Logs();
Yii::$app->response->format = "json";
$id = $model->create($post);
if ($id) {
return [
'status' => true,
'logID' => $id,
"cost" => "0"
];
} else {
return [
'status' => false
];
}
} else {
$model = Logs::findOne($post['log_id']);
$model->plate_out = $post['plate'];
$model->plate_image_out = $post['plateImage'];
$model->frame_image_out = $post['frameImage'];
$model->face_image_out = isset($post['faceImage']) ? $post['faceImage'] : "";
$model->name_out = isset($post['name']) ? $post['name'] : "";
$model->time_out = $time;
$model->camera_out = $post['camera'];
$model->mod_out = $post['mod'];
Yii::$app->response->format = "json";
if ($model->save()) {
return [
'status' => true,
'logID' => $model->id,
'cost' => $model->cost
];
} else {
return [
'status' => false
];
}
}
}
}
public function actionUpdateLogs() {
if (Yii::$app->request->post()) {
$post = Yii::$app->request->bodyParams;
$model = Logs::findOne($post['logID']);
$model->plate_in = $post['plate_in'];
$model->plate_out = $post['plate_out'];
$model->save();
return true;
}
}
public function actionStatistics() {
Yii::$app->response->format = "json";
return Logs::statistics();
}
public function convert($code) {
$temp = explode("-", $code)[0];
$hex = dechex($temp);
$t = [];
for ($i = 0; $i < strlen($hex) / 2; $i++) {
$t[] = substr($hex, $i * 2, 2);
}
$t = array_reverse($t);
$t = implode("", $t);
return hexdec($t);
}
public function actionImport() {
$file_type = \PHPExcel_IOFactory::identify("data/test.xlsx");
$objReader = \PHPExcel_IOFactory::createReader($file_type);
$objPHPExcel = $objReader->load("data/test.xlsx");
$sheet_data = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
$objPHPExcel = new \PHPExcel();
$count = 1;
$objPHPExcel->setActiveSheetIndex(0);
$toExcelFile[] = [
"Mã NV",
"Họ tên",
"Đơn vị",
"Mã thẻ gốc",
"Giới tính",
"Mã thẻ đã chuyển đổi"
];
$cards = Card::find()->all();
foreach ($sheet_data as $k => $row) {
$ExportData[] = $row["A"];
$ExportData[] = $row["B"];
$ExportData[] = $row["C"];
$ExportData[] = $row["D"];
$ExportData[] = $row["E"];
$ExportData[] = $this->convert($row["D"]);
$toExcelFile[] = $ExportData;
unset($ExportData);
}
$activeSheet = $objPHPExcel->getActiveSheet();
$activeSheet->getColumnDimension('B')->setWidth(30);
$rowCount = 1;
for ($i = 0; $i < count($toExcelFile); $i++) {
$column = 'A';
$row = $toExcelFile[$i];
for ($j = 0; $j < count($row); $j++) {
if (!isset($row[$j]))
$value = NULL;
elseif ($row[$j] != "")
$value = strip_tags($row[$j]);
else
$value = "";
$activeSheet->setCellValue($column . $rowCount, $value);
$column = chr(ord($column) + 1);
}
$rowCount++;
}
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
ob_end_clean();
header('Content-type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="ket-qua.xlsx"');
header('Cache-Control: max-age=0');
$objWriter->save('php://output');
exit();
}
public function actionExport() {
$objPHPExcel = new \PHPExcel();
$count = 1;
$objPHPExcel->setActiveSheetIndex(0);
$toExcelFile[] = [
"STT",
"Mã thẻ"
];
$cards = Card::find()->all();
foreach ($cards as $k => $v) {
$ExportData[] = $v->id;
$ExportData[] = $v->code;
$toExcelFile[] = $ExportData;
unset($ExportData);
}
$activeSheet = $objPHPExcel->getActiveSheet();
$activeSheet->getColumnDimension('B')->setWidth(30);
$rowCount = 1;
for ($i = 0; $i < count($toExcelFile); $i++) {
$column = 'A';
$row = $toExcelFile[$i];
for ($j = 0; $j < count($row); $j++) {
if (!isset($row[$j]))
$value = NULL;
elseif ($row[$j] != "")
$value = strip_tags($row[$j]);
else
$value = "";
$activeSheet->setCellValue($column . $rowCount, $value);
$column = chr(ord($column) + 1);
}
$rowCount++;
}
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
ob_end_clean();
header('Content-type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="ket-qua.xlsx"');
header('Cache-Control: max-age=0');
$objWriter->save('php://output');
exit();
}
}

View File

@ -0,0 +1,141 @@
<?php
namespace app\controllers;
use Yii;
use app\models\Logs;
use app\models\LogsSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
/**
* LogsController implements the CRUD actions for Logs model.
*/
class LogsController extends Controller {
public function init() {
parent::init();
if (Yii::$app->user->isGuest) {
return $this->redirect(['/site/login']);
}
}
/**
* {@inheritdoc}
*/
public function behaviors() {
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
];
}
/**
* Lists all Logs models.
* @return mixed
*/
public function actionIndex($from = "", $to = "") {
if ($from === "") {
$from = "00:00 " . date("d/m/Y");
}
if ($to === "") {
$to = "23:59 " . date("d/m/Y");
}
$this->view->title = "Thống kê";
$searchModel = new LogsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$f = date_format(date_create_from_format('H:i d/m/Y', $from), 'U');
$t = date_format(date_create_from_format('H:i d/m/Y', $to), 'U');
$dataProvider->query->andWhere(["OR", ["BETWEEN", 'time_in', $f, $t], ["BETWEEN", 'time_out', $f, $t]]);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'from' => $from,
'to' => $to
]);
}
/**
* Displays a single Logs model.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionView($id) {
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
/**
* Creates a new Logs model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate() {
$model = new Logs();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('create', [
'model' => $model,
]);
}
/**
* Updates an existing Logs model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('update', [
'model' => $model,
]);
}
/**
* Deletes an existing Logs model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionDelete($id) {
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
/**
* Finds the Logs model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param integer $id
* @return Logs the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id) {
if (($model = Logs::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
}

View File

@ -0,0 +1,122 @@
<?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::className(),
'only' => ['logout'],
'rules' => [
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'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->redirect(["/dashboard"]);
}
$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');
}
}

View File

@ -0,0 +1,289 @@
<?php
namespace app\controllers;
use Yii;
use app\models\User;
use app\models\UserSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\helpers\Url;
use app\models\AuthItem;
use app\models\AuthAssignment;
/**
* UserController implements the CRUD actions for User model.
*/
class UserController extends Controller {
public function init() {
parent::init();
if (Yii::$app->user->isGuest) {
return $this->redirect(['/site/login']);
}
if (!Yii::$app->user->can("administrator")) {
return $this->redirect(["/dashboard"]);
}
}
/**
* {@inheritdoc}
*/
public function behaviors() {
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
];
}
/**
* Lists all User models.
* @return mixed
*/
public function actionIndex() {
$this->view->title = "Người dùng";
$this->view->params['breadcrumbs'][] = "Hệ thống";
$this->view->params['breadcrumbs'][] = $this->view->title;
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
/**
* Displays a single User model.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionView($id) {
if (!Yii::$app->user->can("administrator")) {
Yii::$app->response->format = "json";
return [
"title" => "403",
"form" => Yii::t("app", "Bạn không có quyền truy cập!")
];
}
$model = $this->findModel($id);
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = "json";
return [
"title" => "<i class='fa fa-user'></i> " . Yii::t("app", "Thông tin người dùng"),
"form" => $this->renderPartial("view", [
"model" => $model
])
];
}
}
/**
* Creates a new User model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate() {
if (!Yii::$app->user->can("administrator")) {
Yii::$app->response->format = "json";
return [
"title" => "403",
"form" => Yii::t("app", "Bạn không có quyền truy cập!")
];
}
$model = new User();
if (Yii::$app->request->post()) {
$post = Yii::$app->request->post();
Yii::$app->response->format = "json";
$check = User::findOne(["username" => $post['Username']]);
if ($check) {
return [
'stt' => false,
"reason" => 'username'
];
}
$check2 = User::findOne(['email' => $post['Email']]);
if ($check2) {
return [
'stt' => false,
"reason" => 'email'
];
}
$user_id = $model->create($post);
$auth = Yii::$app->authManager;
foreach ($post['Role'] as $key => $value) {
$role = $auth->getRole($value);
if ($role != null) {
$auth->assign($role, $user_id);
}
}
return [
'stt' => true
];
} else {
Yii::$app->response->format = "json";
return [
"title" => "<i class='fa fa-plus-circle'></i> " . Yii::t("app", "Tạo người dùng mới"),
"form" => $this->renderPartial("form", [
"model" => $model,
"roles" => AuthItem::roleArray(),
"url" => Url::to(['/user/create'])
])
];
}
}
/**
* Updates an existing User model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionUpdate($id) {
if (!Yii::$app->user->can("administrator")) {
Yii::$app->response->format = "json";
return [
"title" => "403",
"form" => Yii::t("app", "Bạn không có quyền truy cập!")
];
}
$model = $this->findModel($id);
if (Yii::$app->request->post()) {
$post = Yii::$app->request->post();
if ($post['Username'] !== $model->username) {
$check = User::findOne(["username" => $post['Username']]);
if ($check)
return false;
}
if ($post['Password'] !== "") {
$model->password = md5($post['Password']);
}
$model->first_name = $post['Name'];
$model->username = $post['Username'];
$model->phone_number = $post['PhoneNumber'];
$model->email = $post['Email'];
$model->quota = $post['Quota'];
$model->save();
AuthAssignment::deleteAll(['user_id' => $id]);
$auth = Yii::$app->authManager;
foreach ($post['Role'] as $key => $value) {
$role = $auth->getRole($value);
if ($role != null) {
$auth->assign($role, $id);
}
}
return true;
} else {
Yii::$app->response->format = "json";
return [
"title" => "<i class='fa fa-edit'></i> " . Yii::t("app", "Sửa thông tin người dùng"),
"form" => $this->renderPartial("form", [
"model" => $model,
"roles" => AuthItem::roleArray(),
"url" => Url::to(['/user/update', 'id' => $id])
])
];
}
}
/**
* Deletes an existing User model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionDelete($id) {
if (!Yii::$app->user->can("administrator")) {
throw new \yii\web\ForbiddenHttpException(Yii::t("app", "Bạn không có quyền truy cập!"));
}
$this->findModel($id)->delete();
AuthAssignment::deleteAll(['user_id' => $id]);
return $this->redirect(['index']);
}
/**
* Finds the User model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param integer $id
* @return User the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id) {
if (($model = User::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
public function actionProfiles() {
if (Yii::$app->user->isGuest) {
return $this->redirect(['/site/login']);
}
$model = $this->findModel(Yii::$app->user->id);
$this->view->title = Yii::t("app", "Thông tin cá nhân");
$this->view->params['breadcrumbs'][] = $this->view->title;
return $this->render('profiles', [
"model" => $model
]);
}
public function actionInfo($id) {
if (Yii::$app->request->post()) {
$model = $this->findModel($id);
$post = Yii::$app->request->post();
$model->first_name = $post['Name'];
$model->phone_number = $post['PhoneNumber'];
$model->email = $post['Email'];
return $model->save();
}
}
public function actionChangePassword() {
$model = $this->findModel(Yii::$app->user->id);
if (Yii::$app->request->post()) {
$post = Yii::$app->request->post();
$model->password = md5($post['NewPassword']);
$model->save();
return true;
} else {
if (Yii::$app->user->isGuest) {
return $this->redirect(['/site/login']);
}
$this->view->title = Yii::t("app", "Đổi mật khẩu");
$this->view->params['breadcrumbs'][] = $this->view->title;
return $this->render('password', [
"model" => $model
]);
}
}
public function actionAvatar() {
if (Yii::$app->request->post()) {
$model = new \app\models\UploadForm();
$path = "avatar/" . Yii::$app->user->id;
$url = $model->UploadGlobal("image", ["PNG", "JPG", "JPEG", "GIF"], $path);
$UserInfo = User::findOne(Yii::$app->user->id);
$UserInfo->user_image = $url;
$UserInfo->save();
return $url;
}
}
}

View File

@ -0,0 +1,190 @@
<?php
namespace app\controllers;
use Yii;
use app\models\Vehicle;
use app\models\VehicleSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\helpers\Url;
/**
* VehicleController implements the CRUD actions for Vehicle model.
*/
class VehicleController extends Controller {
public function init() {
parent::init();
if (Yii::$app->user->isGuest) {
return $this->redirect(['/site/login']);
}
}
/**
* {@inheritdoc}
*/
public function behaviors() {
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
];
}
/**
* Lists all Vehicle models.
* @return mixed
*/
public function actionIndex() {
$this->view->title = "Danh sách xe";
$this->view->params['breadcrumbs'][] = $this->view->title;
$searchModel = new VehicleSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->orderBy(['id' => SORT_DESC]);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
/**
* Displays a single Vehicle model.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionView($id) {
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
/**
* Creates a new Vehicle model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate() {
$model = new Vehicle();
if (Yii::$app->request->post()) {
$post = Yii::$app->request->post();
return $model->create([
'plate' => $this->format($post['plate']),
'type' => $post['type'],
'company' => $post['company'],
'vehicle_type' => $post['vehicleType'],
'driver' => $post['driver'],
'telephone' => $this->format($post['telephone']),
'indentity_card' => $post['cmt']
]);
} else {
Yii::$app->response->format = "json";
return [
"title" => "Thêm xe mới",
"form" => $this->renderPartial("form", [
"model" => $model,
"url" => Url::to(['create'])
])
];
}
}
/**
* Updates an existing Vehicle model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionUpdate($id) {
$model = $this->findModel($id);
if (Yii::$app->request->post()) {
$post = Yii::$app->request->post();
$model->plate = $this->format($post['plate']);
$model->type = $post['type'];
$model->company = $post['company'];
$model->vehicle_type = $post['vehicleType'];
$model->driver = $post['driver'];
$model->telephone = $this->format($post['telephone']);
$model->indentity_card = $post['cmt'];
$model->modified_at = time();
return $model->save();
} else {
Yii::$app->response->format = "json";
return [
"title" => "Sửa thông tin xe",
"form" => $this->renderPartial("form", [
"model" => $model,
"url" => Url::to(['update', 'id' => $id])
])
];
}
}
/**
* Deletes an existing Vehicle model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionDelete($id) {
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
/**
* Finds the Vehicle model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param integer $id
* @return Vehicle the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id) {
if (($model = Vehicle::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
// public function actionImport() {
// $file_type = \PHPExcel_IOFactory::identify("data/data.xlsx");
// $objReader = \PHPExcel_IOFactory::createReader($file_type);
// $objPHPExcel = $objReader->load("data/data.xlsx");
// $sheet_data = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
// $kq = [];
// foreach ($sheet_data as $k => $row) {
// if ($k > 1) {
// $model = new Vehicle();
// $kq[] = $model->create([
// 'plate' => $this->formatPlate($row["B"]),
// 'type' => $row["C"],
// 'company' => $row["D"],
// 'vehicle_type' => $row["E"],
// 'driver' => $row["F"],
// 'telephone' => $this->formatPlate($row["G"]),
// 'indentity_card' => strval($row["H"])
// ]);
// }
// }
// echo "<pre>";
// var_dump($kq);
// echo "</pre>";
// exit();
// }
//
public function format($plate) {
$p1 = str_replace("-", "", $plate);
$p2 = str_replace(".", "", $p1);
return str_replace(" ", "", $p2);
}
}

9
docker-compose.yml Normal file
View File

@ -0,0 +1,9 @@
version: '2'
services:
php:
image: yiisoftware/yii2-php:7.1-apache
volumes:
- ~/.composer-docker/cache:/root/.composer/cache:delegated
- ./:/app:delegated
ports:
- '8000:80'

94
helpers/LogsGrid.php Normal file
View File

@ -0,0 +1,94 @@
<?php
namespace app\helpers;
use Yii;
use yii\helpers\Html;
use yii\helpers\Url;
use app\models\common;
class LogsGrid {
public static function engineNameFunc() {
return function ($data) {
return $data->app->app_name;
};
}
public static function getLayout() {
return "{items}<div class='row'><div class='col-md-4'>{summary}</div><div class='col-md-8 text-right'>{pager}</div></div>";
}
public static function actionTemplate() {
return "{update} {delete}";
}
public static function plateIn() {
return function($model) {
$style = "width:50px";
if ($model->mod_in == 1) {
$style = "width:100%";
}
$image = $model->plate_image_in;
if (!$image) {
$image = $model->frame_image_in;
$style = "width:100%";
}
return Html::img(Yii::$app->request->hostInfo . "/data/uploads/" . $image, [
'class' => "img-thumbnail",
"style" => $style
]);
};
}
public static function cardId() {
return function($model) {
if ($model->card_id != 0) {
return sprintf("%06d", $model->card_id);
} else {
return "<i class='text-red'>Thẻ đã bị xóa!</i>";
}
};
}
public static function plateOut() {
return function($model) {
if ($model->time_out) {
$style = "width:50px";
if ($model->mod_out == 1) {
$style = "width:100%";
}
$image = $model->plate_image_out;
if (!$image) {
$image = $model->frame_image_out;
$style = "width:100%";
}
return Html::img(Yii::$app->request->hostInfo . "/data/uploads/" . $image, [
'class' => "img-thumbnail",
"style" => $style
]);
} else {
return "";
}
};
}
public static function timeIn() {
return function($model) {
$common = new common();
return $common->formatTime($model->time_in, "H:i:s d/m/Y");
};
}
public static function timeOut() {
return function($model) {
if ($model->time_out) {
$common = new common();
return $common->formatTime($model->time_out, "H:i:s d/m/Y");
} else {
return "";
}
};
}
}

88
helpers/UserGrid.php Normal file
View File

@ -0,0 +1,88 @@
<?php
namespace app\helpers;
use Yii;
use yii\helpers\Html;
use yii\helpers\Url;
class UserGrid {
public static function engineNameFunc() {
return function ($data) {
return $data->app->app_name;
};
}
public static function getLayout() {
return "{items}<div class='row'><div class='col-md-4'>{summary}</div><div class='col-md-8 text-right'>{pager}</div></div>";
}
public static function actionTemplate() {
return "{view} {update} {delete}";
}
public static function avatar() {
return function($model) {
return "23432";
};
}
public static function roles() {
return function($model) {
return $model->roleName;
};
}
public static function view() {
return function($url, $model) {
if (\Yii::$app->user->can("administrator")) {
return Html::button("<i class='fa fa-search'></i>", [
"class" => "btn btn-info btn-xs",
"data" => [
"toggle" => "tooltip",
"href" => Url::to(['/user/view', 'id' => $model->id])
],
"title" => Yii::t("app", "View"),
"onclick" => "user.form(this);"
]);
}
return "";
};
}
public static function update() {
return function($url, $model) {
if (\Yii::$app->user->can("administrator")) {
return Html::button("<i class='fa fa-pencil'></i>", [
"class" => "btn btn-success btn-xs",
"data" => [
"toggle" => "tooltip",
"href" => Url::to(['/user/update', 'id' => $model->id])
],
"title" => Yii::t("app", "Edit"),
"onclick" => "user.form(this);"
]);
}
return "";
};
}
public static function delete() {
return function($url, $model) {
if (\Yii::$app->user->can("administrator")) {
return Html::a('<i class="fa fa-trash"></i>', ['/user/delete', 'id' => $model->id], [
'class' => 'btn btn-danger btn-xs',
'title' => Yii::t("app", "Delete"),
'data' => [
'toggle' => 'tooltip',
'confirm' => "Bạn có chắc chắn muốn xóa người dùng này không?",
'method' => 'post'
]
]);
}
return "";
};
}
}

74
helpers/VehicleGrid.php Normal file
View File

@ -0,0 +1,74 @@
<?php
namespace app\helpers;
use Yii;
use yii\helpers\Html;
use yii\helpers\Url;
class VehicleGrid {
public static function engineNameFunc() {
return function ($data) {
return $data->app->app_name;
};
}
public static function getLayout() {
return "{items}<div class='row'><div class='col-md-4'>{summary}</div><div class='col-md-8 text-right'>{pager}</div></div>";
}
public static function actionTemplate() {
return "{update} {delete}";
}
public static function driver() {
return function($model) {
$ls = explode("/", $model->driver);
return implode("</br>", $ls);
};
}
public static function telephone() {
return function($model) {
$ls = explode("/", $model->telephone);
return implode("</br>", $ls);
};
}
public static function card() {
return function($model) {
$ls = explode("/", $model->indentity_card);
return implode("</br>", $ls);
};
}
public static function update() {
return function($url, $model) {
return Html::button("<i class='fa fa-pencil'></i>", [
"class" => "btn btn-success btn-xs",
"data" => [
"toggle" => "tooltip",
"href" => Url::to(['update', 'id' => $model->id])
],
"title" => "Chỉnh sửa",
"onclick" => "_form(this);"
]);
};
}
public static function delete() {
return function($url, $model) {
return Html::a('<i class="fa fa-trash"></i>', ['delete', 'id' => $model->id], [
'class' => 'btn btn-danger btn-xs',
'title' => "Xóa",
'data' => [
'toggle' => 'tooltip',
'confirm' => "Bạn có chắc chắn muốn xóa thông tin xe này không?",
'method' => 'post'
]
]);
};
}
}

1322
intops.sql Normal file

File diff suppressed because it is too large Load Diff

22
mail/layouts/html.php Normal file
View File

@ -0,0 +1,22 @@
<?php
use yii\helpers\Html;
/* @var $this \yii\web\View view component instance */
/* @var $message \yii\mail\MessageInterface the message being composed */
/* @var $content string 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() ?>

17
mail/layouts/html.tpl Normal file
View File

@ -0,0 +1,17 @@
{use class="yii\helpers\Html"}
{$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={$app->charset}" />
<title>{$this->title|escape}</title>
{$this->head()}
</head>
<body>
{$this->beginBody()}
{$content}
{$this->endBody()}
</body>
</html>
{$this->endPage()}

7
mail/layouts/text.tpl Normal file
View File

@ -0,0 +1,7 @@
{use class="yii\helpers\Html"}
{$this->beginPage()}
{$this->beginBody()}
{$content}
{$this->endBody()}
{$this->endPage()}

3
mail/mailContent.tpl Normal file
View File

@ -0,0 +1,3 @@
{$content}
<br>
Click vào <a href="{$url}"><b>ĐÂY</b></a> để xem chi tiết

9
messages/vi/app.php Normal file
View File

@ -0,0 +1,9 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
return [];

48
models/AuthAssignment.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "auth_assignment".
*
* @property string $item_name
* @property string $user_id
* @property int $created_at
*/
class AuthAssignment extends \yii\db\ActiveRecord
{
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'auth_assignment';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['item_name', 'user_id'], 'required'],
[['created_at'], 'integer'],
[['item_name', 'user_id'], 'string', 'max' => 64],
[['item_name', 'user_id'], 'unique', 'targetAttribute' => ['item_name', 'user_id']],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'item_name' => 'Item Name',
'user_id' => 'User ID',
'created_at' => 'Created At',
];
}
}

98
models/AuthItem.php Normal file
View File

@ -0,0 +1,98 @@
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "auth_item".
*
* @property string $name
* @property int $type
* @property string $description
* @property string $rule_name
* @property resource $data
* @property int $created_at
* @property int $updated_at
*
* @property AuthItemChild[] $authItemChildren
* @property AuthItemChild[] $authItemChildren0
* @property AuthItem[] $children
* @property AuthItem[] $parents
*/
class AuthItem extends \yii\db\ActiveRecord {
/**
* {@inheritdoc}
*/
public static function tableName() {
return 'auth_item';
}
/**
* {@inheritdoc}
*/
public function rules() {
return [
[['name', 'type'], 'required'],
[['type', 'created_at', 'updated_at'], 'integer'],
[['description', 'data'], 'string'],
[['name', 'rule_name'], 'string', 'max' => 64],
[['name'], 'unique'],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels() {
return [
'name' => 'Name',
'type' => 'Type',
'description' => 'Description',
'rule_name' => 'Rule Name',
'data' => 'Data',
'created_at' => 'Created At',
'updated_at' => 'Updated At',
];
}
/**
* @return \yii\db\ActiveQuery
*/
public function getAuthItemChildren() {
return $this->hasMany(AuthItemChild::className(), ['parent' => 'name']);
}
/**
* @return \yii\db\ActiveQuery
*/
public function getAuthItemChildren0() {
return $this->hasMany(AuthItemChild::className(), ['child' => 'name']);
}
/**
* @return \yii\db\ActiveQuery
*/
public function getChildren() {
return $this->hasMany(AuthItem::className(), ['name' => 'child'])->viaTable('auth_item_child', ['parent' => 'name']);
}
/**
* @return \yii\db\ActiveQuery
*/
public function getParents() {
return $this->hasMany(AuthItem::className(), ['name' => 'parent'])->viaTable('auth_item_child', ['child' => 'name']);
}
public static function roleArray() {
$ls = self::find()->all();
$re = [];
foreach ($ls as $key => $value) {
if (!in_array($value->name, ['hoa_sy', 'kiem_duyet', 'quy_trinh_cu', 'kiem_duyet_kich_ban', 'kiem_duyet_phan_canh', 'kiem_duyet_to_mau', 'kiem_duyet_ve_dong', 'kiem_duyet_sach_xen', 'kiem_duyet_ky_thuat']))
$re[$value->name] = Yii::t("app", $value->description);
}
return $re;
}
}

64
models/ContactForm.php Normal file
View File

@ -0,0 +1,64 @@
<?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([$this->email => $this->name])
->setSubject($this->subject)
->setTextBody($this->body)
->send();
return true;
}
return false;
}
}

75
models/LoginForm.php Normal file
View File

@ -0,0 +1,75 @@
<?php
namespace app\models;
use Yii;
use yii\base\Model;
/**
* LoginForm is the model behind the login form.
*
* @property User|null $user This property is read-only.
*
*/
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;
}
}

67
models/Logs.php Normal file
View File

@ -0,0 +1,67 @@
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "logs".
*
* @property int $id
* @property int $vehicle_id
* @property string $plate_image_in
* @property string $frame_image_in
* @property int $time_in
* @property string $plate_image_out
* @property string $frame_image_out
* @property int $time_out
* @property string $seal_no
* @property string $note
* @property string $factory
*/
class Logs extends \yii\db\ActiveRecord {
/**
* {@inheritdoc}
*/
public static function tableName() {
return 'logs';
}
/**
* {@inheritdoc}
*/
public function rules() {
return [
[['vehicle_id'], 'required'],
[['vehicle_id', 'time_in', 'time_out'], 'integer'],
[['plate_image_in', 'frame_image_in', 'plate_image_out', 'frame_image_out', 'seal_no', 'note'], 'string'],
[['factory'], 'string', 'max' => 100],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels() {
return [
'id' => 'ID',
'vehicle_id' => 'Vehicle ID',
'plate_image_in' => 'Ảnh biển vào',
'frame_image_in' => 'Frame Image In',
'time_in' => 'Thời gian vào',
'plate_image_out' => 'Ảnh biển ra',
'frame_image_out' => 'Frame Image Out',
'time_out' => 'Thời gian ra',
'seal_no' => 'SEAL_NO',
'note' => 'Nội dung khác',
'factory' => 'Factory',
'plate' => "Biển số"
];
}
public function getVehicle() {
return $this->hasOne(Vehicle::className(), ["id" => "vehicle_id"]);
}
}

78
models/LogsSearch.php Normal file
View File

@ -0,0 +1,78 @@
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Logs;
/**
* LogsSearch represents the model behind the search form of `app\models\Logs`.
*/
class LogsSearch extends Logs {
/**
* {@inheritdoc}
*/
public function rules() {
return [
[['id', 'vehicle_id'], 'integer'],
[['frame_image_in', 'frame_image_out', 'seal_no', 'note', 'factory'], 'safe'],
];
}
/**
* {@inheritdoc}
*/
public function scenarios() {
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* @param array $params
*
* @return ActiveDataProvider
*/
public function search($params) {
$query = Logs::find();
$query->joinWith("vehicle");
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'vehicle_id' => $this->vehicle_id,
'time_in' => $this->time_in,
'time_out' => $this->time_out,
]);
$query->andFilterWhere(['like', 'plate_image_in', $this->plate_image_in])
->andFilterWhere(['like', 'frame_image_in', $this->frame_image_in])
->andFilterWhere(['like', 'plate_image_out', $this->plate_image_out])
->andFilterWhere(['like', 'frame_image_out', $this->frame_image_out])
->andFilterWhere(['like', 'seal_no', $this->seal_no])
->andFilterWhere(['like', 'note', $this->note])
->andFilterWhere(['like', 'factory', $this->factory])
->andFilterWhere(['like', 'vehicle.plate', $this->vehicle_id]);
return $dataProvider;
}
}

65
models/LogsUnknow.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "logs_unknow".
*
* @property int $id
* @property string $plate
* @property string $plate_image_in
* @property string $frame_image_in
* @property int $time_in
* @property string $plate_image_out
* @property string $frame_image_out
* @property int $time_out
* @property string $seal_no
* @property string $note
* @property string $factory
*/
class LogsUnknow extends \yii\db\ActiveRecord
{
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'logs_unknow';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['plate'], 'required'],
[['plate_image_in', 'frame_image_in', 'plate_image_out', 'frame_image_out', 'seal_no', 'note'], 'string'],
[['time_in', 'time_out'], 'integer'],
[['plate'], 'string', 'max' => 50],
[['factory'], 'string', 'max' => 100],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'plate' => 'Plate',
'plate_image_in' => 'Plate Image In',
'frame_image_in' => 'Frame Image In',
'time_in' => 'Time In',
'plate_image_out' => 'Plate Image Out',
'frame_image_out' => 'Frame Image Out',
'time_out' => 'Time Out',
'seal_no' => 'Seal No',
'note' => 'Note',
'factory' => 'Factory',
];
}
}

204
models/User.php Normal file
View File

@ -0,0 +1,204 @@
<?php
namespace app\models;
use Yii;
use yii\db\ActiveRecord;
class User extends ActiveRecord implements \yii\web\IdentityInterface {
public static function tableName() {
return 'user';
}
/**
* @inheritdoc
*/
public function rules() {
return [
[['username', 'password'], 'required'],
[['email'], 'email'],
[['username', 'email'], 'unique'],
[['phone_number'], 'string', 'max' => 30],
[['username', 'password', 'password_reset_token', 'first_name', 'last_name'], 'string', 'max' => 250],
[['user_image', 'email'], 'string', 'max' => 500],
[['quota'], 'integer']
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels() {
return [
'first_name' => "Tên đăng nhập",
'last_name' => 'Last Name',
'username' => "Họ tên",
'phone_number' => "Điện thoại",
'email' => "Email",
'roleName' => "Phân quyền"
];
}
public static function findIdentity($id) {
$user = self::find()
->where([
"id" => $id
])
->one();
if ($user == null) {
return null;
}
return new static($user);
}
/**
* @inheritdoc
*/
public static function findIdentityByAccessToken($token, $userType = null) {
$user = self::find()
->where(["accessToken" => $token])
->one();
if (!count($user)) {
return null;
}
return new static($user);
}
/**
* Finds user by username
*
* @param string $username
* @return static|null
*/
public static function findByUsername($username) {
$user = self::find()
->where([
"username" => $username
])
->one();
if ($user == null) {
return null;
}
return new static($user);
}
public static function findByUser($username) {
$user = self::find()
->where([
"username" => $username
])
->one();
if ($user == null) {
return null;
}
return $user;
}
/**
* @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 boolean if password provided is valid for current user
*/
public function validatePassword($password) {
return $this->password === md5($password);
}
public function create($data) {
$r = $this->load([
'first_name' => $data['Name'],
'username' => $data['Username'],
'password' => $data['Password'] !== "" ? md5($data['Password']) : md5('123456a@'),
'phone_number' => $data['PhoneNumber'],
'email' => $data['Email']
], '');
if ($r) {
try {
$this->save();
return $this->id;
} catch (\Exception $ex) {
return false;
}
}
}
public function getRole() {
return AuthAssignment::findOne(['user_id' => $this->id])->item_name;
}
public function getRoleName() {
$roles = $this->roles;
$lists = "";
foreach ($roles as $key => $value) {
$lists .= \yii\helpers\Html::label(Yii::t("app", AuthItem::findOne(['name' => $value])->description), "", ["class" => "label label-info"]) . " ";
}
return $lists;
}
public function getRoleNameLists() {
$roles = $this->roles;
$lists = [];
foreach ($roles as $key => $value) {
$lists[] = AuthItem::findOne(['name' => $value])->description;
}
return implode(",", $lists);
}
public function getRoles() {
$roleArray = [];
$roles = AuthAssignment::find()->andWhere(['user_id' => $this->id])->all();
foreach ($roles as $key => $value) {
$roleArray[] = $value->item_name;
}
return $roleArray;
}
public static function securityArray($all = false) {
$ls = AuthAssignment::find()->andWhere(['IN', 'item_name', ["security"]])->all();
$temp = [];
foreach ($ls as $key => $value) {
$temp[] = $value->user_id;
}
$lsID = array_unique($temp);
$re = [];
foreach ($lsID as $key => $value) {
if ($all) {
$re[$value] = self::findOne($value)->first_name;
} else {
$check = Gate::findOne(['user_id' => $value]);
if (!$check)
$re[$value] = self::findOne($value)->first_name;
}
}
return $re;
}
public function getAvatar() {
$directoryAsset = Yii::$app->assetManager->getPublishedUrl('@vendor/almasaeed2010/adminlte/dist');
return $this->user_image == null ? $directoryAsset . "/img/user2-160x160.jpg" : Yii::getAlias("@images_folder") . $this->user_image;
}
}

77
models/UserSearch.php Normal file
View File

@ -0,0 +1,77 @@
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\User;
/**
* UserSearch represents the model behind the search form of `app\models\User`.
*/
class UserSearch extends User
{
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['id'], 'integer'],
[['first_name', 'last_name', 'phone_number', 'username', 'email', 'password', 'authKey', 'password_reset_token', 'user_image'], 'safe'],
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* @param array $params
*
* @return ActiveDataProvider
*/
public function search($params)
{
$query = User::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'phone_number', $this->phone_number])
->andFilterWhere(['like', 'username', $this->username])
->andFilterWhere(['like', 'email', $this->email])
->andFilterWhere(['like', 'password', $this->password])
->andFilterWhere(['like', 'authKey', $this->authKey])
->andFilterWhere(['like', 'password_reset_token', $this->password_reset_token])
->andFilterWhere(['like', 'user_image', $this->user_image]);
return $dataProvider;
}
}

81
models/Vehicle.php Normal file
View File

@ -0,0 +1,81 @@
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "vehicle".
*
* @property int $id
* @property string $plate
* @property string $type
* @property string $company
* @property string $vehicle_type
* @property string $driver
* @property string $telephone
* @property string $indentity_card
* @property int $created_at
* @property int $modified_at
*/
class Vehicle extends \yii\db\ActiveRecord {
/**
* {@inheritdoc}
*/
public static function tableName() {
return 'vehicle';
}
/**
* {@inheritdoc}
*/
public function rules() {
return [
[['plate', 'type'], 'required'],
[['company', 'vehicle_type'], 'string'],
[['plate', 'type'], 'string', 'max' => 20],
[['driver', 'telephone', 'indentity_card'], 'string', 'max' => 200],
[['created_at', 'modified_at'], 'integer']
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels() {
return [
'id' => 'ID',
'plate' => 'Biển số xe',
'type' => 'Loại xe',
'company' => 'Tên công ty',
'vehicle_type' => 'Kiểu xe',
'driver' => 'Lái xe',
'telephone' => 'Điện thoại',
'indentity_card' => 'CMT',
];
}
public function create($data) {
$r = $this->load([
'plate' => $data['plate'],
'type' => $data['type'],
'company' => $data['company'],
'vehicle_type' => $data['vehicle_type'],
'driver' => $data['driver'],
'telephone' => $data['telephone'],
'indentity_card' => $data['indentity_card'],
'created_at' => time(),
'modified_at' => time()
], '');
if ($r) {
try {
$this->save();
return $this->id;
} catch (\Exception $ex) {
return false;
}
}
}
}

75
models/VehicleSearch.php Normal file
View File

@ -0,0 +1,75 @@
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Vehicle;
/**
* VehicleSearch represents the model behind the search form of `app\models\Vehicle`.
*/
class VehicleSearch extends Vehicle
{
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['id'], 'integer'],
[['plate', 'type', 'company', 'vehicle_type', 'driver', 'telephone', 'indentity_card'], 'safe'],
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* @param array $params
*
* @return ActiveDataProvider
*/
public function search($params)
{
$query = Vehicle::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
]);
$query->andFilterWhere(['like', 'plate', $this->plate])
->andFilterWhere(['like', 'type', $this->type])
->andFilterWhere(['like', 'company', $this->company])
->andFilterWhere(['like', 'vehicle_type', $this->vehicle_type])
->andFilterWhere(['like', 'driver', $this->driver])
->andFilterWhere(['like', 'telephone', $this->telephone])
->andFilterWhere(['like', 'indentity_card', $this->indentity_card]);
return $dataProvider;
}
}

174
models/common.php Normal file
View File

@ -0,0 +1,174 @@
<?php
namespace app\models;
use Yii;
class common extends \yii\db\ActiveRecord {
public function formatName($name) {
return preg_replace('/[^a-zA-Z0-9 _-]/', '', $this->vn2latin($name, true));
}
public function vn2latin($cs, $tolower = false) {
/* Mảng chứa tất cả ký tự có dấu trong Tiếng Việt */
$marTViet = array("à", "á", "", "", "ã", "â", "", "", "", "", "", "ă",
"", "", "", "", "", "è", "é", "", "", "", "ê", "",
"ế", "", "", "",
"ì", "í", "", "", "ĩ",
"ò", "ó", "", "", "õ", "ô", "", "", "", "", "", "ơ",
"", "", "", "", "",
"ù", "ú", "", "", "ũ", "ư", "", "", "", "", "",
"", "ý", "", "", "",
"đ",
"À", "Á", "", "", "Ã", "Â", "", "", "", "", "", "Ă",
"", "", "", "", "",
"È", "É", "", "", "", "Ê", "", "", "", "", "",
"Ì", "Í", "", "", "Ĩ",
"Ò", "Ó", "", "", "Õ", "Ô", "", "", "", "", "", "Ơ", "", "", "", "", "",
"Ù", "Ú", "", "", "Ũ", "Ư", "", "", "", "", "",
"", "Ý", "", "", "",
"Đ", " ");
/* Mảng chứa tất cả ký tự không dấu tương ứng với mảng $marTViet bên trên */
$marKoDau = array("a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a",
"a", "a", "a", "a", "a", "a",
"e", "e", "e", "e", "e", "e", "e", "e", "e", "e", "e",
"i", "i", "i", "i", "i",
"o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o",
"o", "o", "o", "o", "o",
"u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u",
"y", "y", "y", "y", "y",
"d",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"A", "A", "A", "A", "A",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"I", "I", "I", "I", "I",
"O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O",
"U", "U", "U", "U", "U", "U", "U", "U", "U", "U", "U",
"Y", "Y", "Y", "Y", "Y",
"D", "-");
if ($tolower) {
return strtolower(str_replace($marTViet, $marKoDau, $cs));
}
return str_replace($marTViet, $marKoDau, $cs);
}
public function formatTime($time, $format = "d/m/Y") {
// $now = time();
// $range = $now - $time;
// if ($range > 60 * 60 * 12) {
return date($format, $time);
// } else {
// return Yii::$app->formatter->asRelativeTime($time);
// }
}
//Upload
public function UploadFile($file, $fileTypes, $dir) {
$LocalPath = "data/" . $dir;
$RootFolder = Yii::getAlias('@webroot') . "/" . $LocalPath;
$name = $_FILES[$file]["name"];
$array = explode(".", $name);
$nr = count($array);
$ext = $array[$nr - 1];
$fileName = preg_replace('/[^a-zA-Z0-9 _-]/', '', $this->vn2latin($array[0], true));
$destfile = time() . "_" . $fileName . "." . $ext;
if (!empty($_FILES)) {
$tempFile = $_FILES[$file]['tmp_name'];
$targetPath = $RootFolder;
if (!file_exists($targetPath)) {
@mkdir($targetPath, 0777, true);
}
$targetFile = $targetPath . '/' . $destfile;
$targetFileLocal = $LocalPath . '/' . $destfile;
// Validate the file type
$fileParts = pathinfo($_FILES[$file]['name']);
if (in_array(strtoupper($fileParts['extension']), $fileTypes)) {
move_uploaded_file($tempFile, $targetFile);
if (file_exists($targetFile)) {
return $targetFileLocal;
} else {
return false;
}
} else {
return 2;
}
}
}
//Move file
public function MoveFile($file, $folder) {
$exp = explode("/", $file);
$t = [];
foreach ($exp as $key => $value) {
if ($key < count($exp) - 1) {
$t[] = $value;
}
}
$folderOld = implode("/", $t);
$root = \Yii::getAlias('@app') . '/web/data/uploads' . trim($folderOld);
chdir($root);
$nameArr = explode(".", basename($file));
$name = $this->formatName($nameArr[0]);
$ext = $nameArr[count($nameArr) - 1];
rename(basename($file), $name . "." . $ext);
$tempdir = $root . "/" . $name . "." . $ext;
if (file_exists($tempdir)) {
$destfile = basename($tempdir);
$dir = Yii::getAlias('@webroot') . "/data/uploads" . $folder;
$file_dir = $dir . '/' . $destfile;
if (!file_exists($dir)) {
@mkdir($dir, 0777, true);
}
$output = shell_exec("mv {$tempdir} {$file_dir}");
$link = $folder . "/" . $destfile;
} else {
$link = $file;
}
return $link;
}
//File size
public function filesize_formatted($path) {
$size = filesize($path);
$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
$power = $size > 0 ? floor(log($size, 1024)) : 0;
return number_format($size / pow(1024, $power), 2, '.', ',') . " " . $units[$power];
}
public function getExtension($file) {
$f = basename($file);
$ls = explode(".", $file);
return strtolower($ls[count($ls) - 1]);
}
public function convertIntToTime($seconds) {
$hours = floor($seconds / 3600);
$mins = floor($seconds / 60 % 60);
$secs = floor($seconds % 60);
if ($hours > 0) {
return sprintf('%02d:%02d:%02d', $hours, $mins, $secs);
} else {
return sprintf('%02d:%02d', $mins, $secs);
}
}
public function visiblePharse($stt, $tab, $pharse) {
$visible = false;
if ($stt != 0) {
if ($stt == -1) {
if ($tab == $pharse) {
$visible = true;
}
} else {
$visible = true;
}
} else {
$visible = true;
}
return $visible;
}
}

View File

View File

@ -0,0 +1,8 @@
copy.src.files=false
copy.src.on.open=false
copy.src.target=
remote.connection=BI-9f36c2
remote.directory=/anpr
remote.upload=ON_SAVE
run.as=LOCAL
url=http://localhost/

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
</project-private>

View File

@ -0,0 +1,7 @@
include.path=${php.global.include.path}
php.version=PHP_70
source.encoding=UTF-8
src.dir=.
tags.asp=false
tags.short=false
web.root=.

9
nbproject/project.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.php.project</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/php-project/1">
<name>intops</name>
</data>
</configuration>
</project>

160
requirements.php Normal file
View File

@ -0,0 +1,160 @@
<?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 = [
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="http://www.yiiframework.com/doc-2.0/yii-caching-memcache.html">MemCache</a>',
'memo' => extension_loaded('memcached') ? 'To use memcached set <a href="http://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="http://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="http://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="http://www.yiiframework.com/doc-2.0/yii-caching-apccache.html">ApcCache</a>',
);
}
$requirementsChecker->checkYii()->check($requirements)->render();

View File

@ -0,0 +1,88 @@
<?php
/* Smarty version 3.1.32, created on 2020-02-01 16:42:09
from 'C:\xampp\htdocs\intops\views\logs\index.tpl' */
/* @var Smarty_Internal_Template $_smarty_tpl */
if ($_smarty_tpl->_decodeProperties($_smarty_tpl, array (
'version' => '3.1.32',
'unifunc' => 'content_5e3547f1864524_18781299',
'has_nocache_code' => false,
'file_dependency' =>
array (
'20236a3e8180e4db3a06fbb10df331cc13b7b539' =>
array (
0 => 'C:\\xampp\\htdocs\\intops\\views\\logs\\index.tpl',
1 => 1580550113,
2 => 'file',
),
),
'includes' =>
array (
),
),false)) {
function content_5e3547f1864524_18781299 (Smarty_Internal_Template $_smarty_tpl) {
$_smarty_tpl->_loadInheritance();
$_smarty_tpl->inheritance->init($_smarty_tpl, true);
?>
<?php echo call_user_func_array($_smarty_tpl->registered_plugins[ 'modifier' ][ 'void' ][ 0 ], array( app\assets\LogsAsset::register($_smarty_tpl->tpl_vars['this']->value) ));?>
<?php
$_smarty_tpl->inheritance->instanceBlock($_smarty_tpl, 'Block_12812370875e3547f184cb78_94057328', 'content');
$_smarty_tpl->inheritance->endChild($_smarty_tpl, (dirname($_smarty_tpl->source->filepath)).('/../extends.tpl'));
}
/* {block 'content'} */
class Block_12812370875e3547f184cb78_94057328 extends Smarty_Internal_Block
{
public $subBlocks = array (
'content' =>
array (
0 => 'Block_12812370875e3547f184cb78_94057328',
),
);
public function callBlock(Smarty_Internal_Template $_smarty_tpl) {
?>
<div class="row">
<div class="col-md-2">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">Từ</div>
<input type='text' value="<?php echo $_smarty_tpl->tpl_vars['from']->value;?>
" class="form-control" id='from' name='FromTime' readonly="">
</div>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">Đến</div>
<input type='text' value="<?php echo $_smarty_tpl->tpl_vars['to']->value;?>
" class="form-control" id='to' name='ToTime' readonly="">
</div>
</div>
</div>
<div class="col-md-1">
<button class="btn btn-primary btn-block" onclick="search(this);" data-href='<?php echo yii\helpers\Url::to(array('index'));?>
'>
<i class="fa fa-search"></i> Search
</button>
</div>
<div class="col-md-2">
<button class="btn btn-success" onclick="_export(this);" data-href='<?php echo yii\helpers\Url::to(array('export'));?>
'>
<i class="fa fa-download"></i> Xuất báo cáo
</button>
</div>
</div>
<br>
<?php echo yii\grid\GridView::widget(array('dataProvider'=>$_smarty_tpl->tpl_vars['dataProvider']->value,'filterModel'=>$_smarty_tpl->tpl_vars['searchModel']->value,'layout'=>\app\helpers\LogsGrid::getLayout(),'tableOptions'=>array('class'=>'table table-striped table-bordered','style'=>'background:#fff;min-width:700px;'),'columns'=>array(array('class'=>'yii\grid\SerialColumn'),array('attribute'=>'vehicle_id','value'=>'vehicle.plate'),'factory','seal_no',array('attribute'=>"plate_image_in",'format'=>'raw','contentOptions'=>array('class'=>'text-center'),'headerOptions'=>array('style'=>'width:10%'),'value'=>\app\helpers\LogsGrid::plateIn()),array('attribute'=>"time_in",'format'=>'raw','contentOptions'=>array('class'=>'text-center'),'headerOptions'=>array('style'=>'width:18%'),'value'=>\app\helpers\LogsGrid::timeIn()),array('attribute'=>"plate_image_out",'format'=>'raw','contentOptions'=>array('class'=>'text-center'),'headerOptions'=>array('style'=>'width:10%'),'value'=>\app\helpers\LogsGrid::plateOut()),array('attribute'=>"time_out",'format'=>'raw','contentOptions'=>array('class'=>'text-center'),'headerOptions'=>array('style'=>'width:18%'),'value'=>\app\helpers\LogsGrid::timeOut()),'note')));?>
<?php
}
}
/* {/block 'content'} */
}

View File

@ -0,0 +1,121 @@
<?php
/* Smarty version 3.1.32, created on 2020-02-01 16:42:09
from 'C:\xampp\htdocs\intops\views\extends.tpl' */
/* @var Smarty_Internal_Template $_smarty_tpl */
if ($_smarty_tpl->_decodeProperties($_smarty_tpl, array (
'version' => '3.1.32',
'unifunc' => 'content_5e3547f197a168_13113435',
'has_nocache_code' => false,
'file_dependency' =>
array (
'82f09dda666f85f4e6bdd96739becd21dab9a07a' =>
array (
0 => 'C:\\xampp\\htdocs\\intops\\views\\extends.tpl',
1 => 1576056501,
2 => 'file',
),
),
'includes' =>
array (
),
),false)) {
function content_5e3547f197a168_13113435 (Smarty_Internal_Template $_smarty_tpl) {
$_smarty_tpl->_loadInheritance();
$_smarty_tpl->inheritance->init($_smarty_tpl, false);
?>
<div class="body-extend">
<?php
$_smarty_tpl->inheritance->instanceBlock($_smarty_tpl, 'Block_14548772005e3547f1976ec8_28995603', "content");
?>
</div>
<div id="blocking" class="fade modal" role="dialog" tabindex="-1">
<div class="modal-dialog" style="top: 50%;margin-top: -45px;">
<div class="modal-content" style="background-color: transparent;box-shadow: none;">
<div class="modal-body">
<div id='modelContent' class="text-center">
<i class="fa fa-spinner fa-pulse fa-5x fa-fw" style="color: #fff;"></i>
</div>
</div>
</div>
</div>
</div>
<div id="uploadBlock" class="fade modal" role="dialog" tabindex="-1">
<div class="modal-dialog" style="top: 50%;margin-top: -45px;">
<div class="modal-content" style="background-color: transparent;box-shadow: none;">
<div class="modal-body">
<div class="text-center">
<i class="fa fa-spinner fa-pulse fa-5x fa-fw" style="color: #fff;"></i>
<div class="text-bold" style="color: white;font-size: 20px;" id="upload-percent">0 %</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header" id="modalHeader">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel"></h4>
</div>
<div class="modal-body" id="myModalContent">
...
</div>
<div class="modal-footer" id='myModalFooter'>
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="fa fa-remove"></span> Đóng lại</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="myModalFullScreen" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document" style="width: 90%;">
<div class="modal-content">
<div class="modal-header" id="modalFullScreenHeader">
<input type="hidden" name="ReLoadFullScreen" value="false">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalFullScreenLabel"></h4>
</div>
<div class="modal-body" id="myModalFullScreenContent">
...
</div>
</div>
</div>
</div>
<div class="modal fade" id="alertModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" id="alertModalDialog" role="document">
<div class="modal-content">
<div class="modal-header" id="alertModalHeader" style="background-color: #ffcc66;color: green;">
<h4 class="modal-title" id="alertModalLabel" style="color: #fff;">
<span class="fa fa-info-circle"></span> <b>Thông báo</b>
</h4>
</div>
<div class="modal-body c-red" id="alertModalContent" style="font-weight: bold;">
...
</div>
<div class="modal-footer" id="alertModalFooter">
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="fa fa-remove"></span> Đồng ý</button>
</div>
</div>
</div>
</div><?php }
/* {block "content"} */
class Block_14548772005e3547f1976ec8_28995603 extends Smarty_Internal_Block
{
public $subBlocks = array (
'content' =>
array (
0 => 'Block_14548772005e3547f1976ec8_28995603',
),
);
public function callBlock(Smarty_Internal_Template $_smarty_tpl) {
?>
<?php
}
}
/* {/block "content"} */
}

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

1
runtime/debug/index.data Normal file
View File

@ -0,0 +1 @@
a:1:{s:13:"5e3547f1719e4";a:9:{s:3:"tag";s:13:"5e3547f1719e4";s:3:"url";s:32:"http://localhost/intops/web/logs";s:4:"ajax";i:0;s:6:"method";s:3:"GET";s:2:"ip";s:3:"::1";s:4:"time";d:1580550129.335;s:10:"statusCode";i:200;s:8:"sqlCount";i:8;s:9:"mailCount";i:0;}}

6
tests/_bootstrap.php Normal file
View File

@ -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';

1
tests/_data/.gitkeep Normal file
View File

@ -0,0 +1 @@

2
tests/_output/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -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
*/
}

View File

@ -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;
}

View File

@ -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
*/
}

View File

@ -0,0 +1,10 @@
class_name: AcceptanceTester
modules:
enabled:
- WebDriver:
url: http://127.0.0.1:8080/
browser: firefox
- Yii2:
part: orm
entryScript: index-test.php
cleanup: false

View File

@ -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');
}
}

View File

@ -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.');
}
}

View File

@ -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.');
}
}

View File

@ -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');
}
}

View File

@ -0,0 +1 @@
<?php

29
tests/bin/yii Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env php
<?php
/**
* Yii console bootstrap file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://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);

20
tests/bin/yii.bat Normal file
View File

@ -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 http://www.yiiframework.com/
rem @copyright Copyright (c) 2008 Yii Software LLC
rem @license http://www.yiiframework.com/license/
rem -------------------------------------------------------------
@setlocal
set YII_PATH=%~dp0
if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
"%PHP_COMMAND%" "%YII_PATH%yii" %*
@endlocal

View File

@ -0,0 +1,13 @@
# 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
class_name: FunctionalTester
modules:
enabled:
- Filesystem
- Yii2

View File

@ -0,0 +1,57 @@
<?php
class ContactFormCest
{
public function _before(\FunctionalTester $I)
{
$I->amOnPage(['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.');
}
}

View File

@ -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');
}
}

View File

@ -0,0 +1 @@
<?php

11
tests/unit.suite.yml Normal file
View File

@ -0,0 +1,11 @@
# Codeception Test Suite Configuration
# suite for unit (internal) tests.
# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
class_name: UnitTester
modules:
enabled:
- Asserts
- Yii2:
part: [orm, email]

View File

@ -0,0 +1,3 @@
<?php
// add unit testing specific bootstrap code here

View File

@ -0,0 +1,43 @@
<?php
namespace tests\models;
class ContactFormTest extends \Codeception\Test\Unit
{
private $model;
/**
* @var \UnitTester
*/
public $tester;
public function testEmailIsSentOnContact()
{
/** @var ContactForm $model */
$this->model = $this->getMockBuilder('app\models\ContactForm')
->setMethods(['validate'])
->getMock();
$this->model->expects($this->once())
->method('validate')
->will($this->returnValue(true));
$this->model->attributes = [
'name' => 'Tester',
'email' => 'tester@example.com',
'subject' => 'very important letter subject',
'body' => 'body of current message',
];
expect_that($this->model->contact('admin@example.com'));
// using Yii2 module actions to check email was sent
$this->tester->seeEmailIsSent();
$emailMessage = $this->tester->grabLastSentEmail();
expect('valid email is sent', $emailMessage)->isInstanceOf('yii\mail\MessageInterface');
expect($emailMessage->getTo())->hasKey('admin@example.com');
expect($emailMessage->getFrom())->hasKey('tester@example.com');
expect($emailMessage->getSubject())->equals('very important letter subject');
expect($emailMessage->toString())->contains('body of current message');
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace tests\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',
]);
expect_not($this->model->login());
expect_that(\Yii::$app->user->isGuest);
}
public function testLoginWrongPassword()
{
$this->model = new LoginForm([
'username' => 'demo',
'password' => 'wrong_password',
]);
expect_not($this->model->login());
expect_that(\Yii::$app->user->isGuest);
expect($this->model->errors)->hasKey('password');
}
public function testLoginCorrect()
{
$this->model = new LoginForm([
'username' => 'demo',
'password' => 'demo',
]);
expect_that($this->model->login());
expect_not(\Yii::$app->user->isGuest);
expect($this->model->errors)->hasntKey('password');
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace tests\models;
use app\models\User;
class UserTest extends \Codeception\Test\Unit
{
public function testFindUserById()
{
expect_that($user = User::findIdentity(100));
expect($user->username)->equals('admin');
expect_not(User::findIdentity(999));
}
public function testFindUserByAccessToken()
{
expect_that($user = User::findIdentityByAccessToken('100-token'));
expect($user->username)->equals('admin');
expect_not(User::findIdentityByAccessToken('non-existing'));
}
public function testFindUserByUsername()
{
expect_that($user = User::findByUsername('admin'));
expect_not(User::findByUsername('not-admin'));
}
/**
* @depends testFindUserByUsername
*/
public function testValidateUser($user)
{
$user = User::findByUsername('admin');
expect_that($user->validateAuthKey('test100key'));
expect_not($user->validateAuthKey('test102key'));
expect_that($user->validatePassword('admin'));
expect_not($user->validatePassword('123456'));
}
}

2
vagrant/config/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# local configuration
vagrant-local.yml

View File

@ -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

38
vagrant/nginx/app.conf Normal file
View File

@ -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.dev;
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.0-fpm.sock;
try_files $uri =404;
}
location ~ /\.(ht|svn|git) {
deny all;
}
}

3
vagrant/nginx/log/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
#nginx logs
yii2basic.access.log
yii2basic.error.log

View File

@ -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.0-fpm restart
service nginx restart
service mysql restart

View File

@ -0,0 +1,71 @@
#!/usr/bin/env bash
#== Import script args ==
timezone=$(echo "$1")
#== 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 "Prepare root password for MySQL"
debconf-set-selections <<< "mariadb-server-10.0 mysql-server/root_password password \"''\""
debconf-set-selections <<< "mariadb-server-10.0 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.0-curl php7.0-cli php7.0-intl php7.0-mysqlnd php7.0-gd php7.0-fpm php7.0-mbstring php7.0-xml unzip nginx mariadb-server-10.0 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 -uroot <<< "CREATE USER 'root'@'%' IDENTIFIED BY ''"
mysql -uroot <<< "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'"
mysql -uroot <<< "DROP USER 'root'@'localhost'"
mysql -uroot <<< "FLUSH PRIVILEGES"
echo "Done!"
info "Configure PHP-FPM"
sed -i 's/user = www-data/user = vagrant/g' /etc/php/7.0/fpm/pool.d/www.conf
sed -i 's/group = www-data/group = vagrant/g' /etc/php/7.0/fpm/pool.d/www.conf
sed -i 's/owner = www-data/owner = vagrant/g' /etc/php/7.0/fpm/pool.d/www.conf
cat << EOF > /etc/php/7.0/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 "Initailize databases for MySQL"
mysql -uroot <<< "CREATE DATABASE yii2basic"
mysql -uroot <<< "CREATE DATABASE yii2basic_test"
echo "Done!"
info "Install composer"
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

View File

@ -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

View File

@ -0,0 +1,33 @@
<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
;
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules(array(
'@PSR2' => true,
'array_syntax' => array('syntax' => 'short'),
'combine_consecutive_unsets' => true,
// 'header_comment' => array('header' => $header),
'no_extra_consecutive_blank_lines' => array(
'break',
'continue',
'extra',
'return',
'throw',
'use',
'parenthesis_brace_block',
'square_brace_block',
'curly_brace_block'
),
'no_useless_else' => true,
'no_useless_return' => true,
'ordered_class_elements' => true,
'ordered_imports' => true,
'phpdoc_add_missing_param_annotation' => true,
'psr4' => true,
'strict_comparison' => true,
))
->setFinder($finder)
;

View File

@ -0,0 +1,16 @@
# Changelog
## 1.0.1 - 2015-03-04
## Changed
- Added CONTRIBUTING.md file
## 1.0.0 - 2015-03-04
## Changed
- Refactored extension to follow new 2amigOS! extension standards based on
[yii2-extension-skeleton](https://github.com/2amigos/yii2-extension-skeleton)
- Updated tests
## Fixed
- Fixed bug when checking "or" conditions

View File

@ -0,0 +1,32 @@
# Contributing
Contributions are **welcome** and will be fully **credited**.
We accept contributions via Pull Requests on [Github](https://github.com/2amigos/yii2-arrayquery-component).
## Pull Requests
- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
- **Create feature branches** - Don't ask us to pull from your master branch.
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
## Running Tests
``` bash
$ phpunit
```
**Happy coding**!

View File

@ -0,0 +1,28 @@
# The BSD License (BSD)
Copyright (c) 2013-2015, 2amigOS! Consulting Group LLC.
> 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 2amigOS! Consulting Group, 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 HOLDER 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.

View File

@ -0,0 +1,79 @@
ArrayQuery Component for Yii2
=============================
[![Latest Version](https://img.shields.io/github/tag/2amigos/yii2-arrayquery-component.svg?style=flat-square&label=release)](https://github.com/2amigos/yii2-arrayquery-component/tags)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
[![Build Status](https://img.shields.io/travis/2amigos/yii2-arrayquery-component/master.svg?style=flat-square)](https://travis-ci.org/2amigos/yii2-arrayquery-component)
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/2amigos/yii2-arrayquery-component.svg?style=flat-square)](https://scrutinizer-ci.com/g/2amigos/yii2-arrayquery-component/code-structure)
[![Quality Score](https://img.shields.io/scrutinizer/g/2amigos/yii2-arrayquery-component.svg?style=flat-square)](https://scrutinizer-ci.com/g/2amigos/yii2-arrayquery-component)
[![Total Downloads](https://img.shields.io/packagist/dt/2amigos/yii2-arrayquery-component.svg?style=flat-square)](https://packagist.org/packages/2amigos/yii2-arrayquery-component)
Allows searching/filtering of an array. This component is very useful when displaying array data in GridViews with an
ArrayDataProvider.
Installation
------------
The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
Either run
```
php composer.phar require "2amigos/yii2-arrayquery-component" "*"
```
or add
```
"2amigos/yii2-arrayquery-component" : "*"
```
to the require section of your application's `composer.json` file.
Usage
-----
```
\\ $models is the array elements to used with ArrayDataProvider
$query = new ArrayQuery($models);
$models = $query
->addCondition('name', '~2amigos')
->addCondition('name', 'cebe/yii2-gravatar', 'or')
->find();
$dataProvider = new ArrayDataProvider([
'allModels' => $models,
'pagination' => [
'pageSize' => 50,
],
'sort' => [
'attributes' => [], // to be specified
],
]);
```
## Testing
``` bash
$ phpunit
```
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
## Credits
- [Antonio Ramirez](https://github.com/tonydspaniard)
- [All Contributors](../../contributors)
## License
The BSD License (BSD). Please see [License File](LICENSE.md) for more information.
> [![2amigOS!](http://www.gravatar.com/avatar/55363394d72945ff7ed312556ec041e0.png)](http://www.2amigos.us)
<i>Custom Software | Web & Mobile Software Development</i>
[www.2amigos.us](http://www.2amigos.us)

View File

@ -0,0 +1,46 @@
{
"name": "2amigos/yii2-arrayquery-component",
"description": "Yii2 component that allows for searching/filtering the elements of an array.",
"type": "yii2-extension",
"keywords": [
"2amigos",
"yii",
"yii2",
"yii 2",
"extension",
"component",
"arrayquery"
],
"homepage": "http://yiiwheels.com/extension/arrayquery-component",
"license": "BSD-3-Clause",
"authors": [
{
"name": "2amigOS! Consulting Group",
"email": "hola@2amigos.us",
"homepage": "http://2amigos.us",
"role": "Developer"
}
],
"support": {
"issues": "https://github.com/dosamigos/yii2-arrayquery-component/issues",
"source": "https://github.com/dosamigos/yii2-arrayquery-component"
},
"require": {
"yiisoft/yii2": "~2.0.11"
},
"require-dev": {
"phpunit/phpunit": "~5.6",
"friendsofphp/php-cs-fixer": "^2.0",
"scrutinizer/ocular": "~1.1"
},
"autoload": {
"psr-4": {
"dosamigos\\arrayquery\\": "src"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
}
}

View File

@ -0,0 +1,208 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigos! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery;
use dosamigos\arrayquery\conditions\Equal;
use dosamigos\arrayquery\conditions\GreaterThan;
use dosamigos\arrayquery\conditions\GreaterThanOrEqual;
use dosamigos\arrayquery\conditions\LessThan;
use dosamigos\arrayquery\conditions\LessThanOrEqual;
use dosamigos\arrayquery\conditions\Like;
use dosamigos\arrayquery\conditions\NotLike;
/**
* ArrayQuery allows to filter an array by apply conditions.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery
*/
class ArrayQuery
{
/**
* @var array the data to search, filter.
*/
private $data;
/**
* @var array the array tokenized so user can search multidimensional array by key paths -ie `parentkey.child`
*/
private $tokens;
/**
* @var array the conditions to apply
*/
private $conditions = [];
/**
* @param array $array
*/
public function __construct(array $array)
{
$this->data = $array;
foreach ($array as $k => $item) {
$this->tokens[$k] = $this->tokenize($item, '', false);
}
}
/**
* Adds a condition to apply the array
*
* @param string $key the key to search in the array
* @param mixed $value the value to search. It supports SQL like operator plus some custom ones:
* - `~` or `like` : like `%value%` in SQL
* - `n~` or `nlike` : like `NOT LIKE` in SQL
* @param string $operator the operator. It can be `and` or `or`. If any of `or` matches it will be added to the
* successful results.
*
* @return static
*/
public function addCondition($key, $value, $operator = 'and')
{
if ($value != null) { // not accepting null values
$operation = null;
$operator = strcasecmp($operator, 'or') !== 0 ? 'and' : 'or';
if (preg_match('/^(?:\s*(<>|<=|>=|<|>|=|~|n~|like|nlike))?(.*)$/i', $value, $matches)) {
$operation = $matches[1];
$value = trim($matches[2]);
}
if (empty($operation) || strlen($operation) > 5) {
$operation = '=';
}
switch ($operation) {
case '<':
$condition = new LessThan($value);
break;
case '>':
$condition = new GreaterThan($value);
break;
case '<>':
$condition = new Equal($value);
$condition->reverse();
break;
case '<=':
$condition = new LessThanOrEqual($value);
break;
case '>=':
$condition = new GreaterThanOrEqual($value);
break;
case '~':
case 'like':
$condition = new Like($value);
break;
case 'n~':
case 'nlike':
$condition = new NotLike($value);
break;
case '=':
default:
$condition = new Equal($value);
}
$this->conditions[$operator][] = ['condition' => $condition, 'key' => $key];
}
return $this;
}
/**
* Returns the first matched result.
* @return array the first matched result, empty array if none found.
*/
public function one()
{
foreach ($this->tokens as $key => $token) {
if (!$this->matches($token)) {
continue;
}
return $this->data[$key];
}
return [];
}
/**
* Returns array of matched results.
* @return array the matched results.
*/
public function find()
{
if (empty($this->conditions)) {
return $this->data;
}
$results = [];
foreach ($this->tokens as $key => $token) {
if (!$this->matches($token)) {
continue;
}
$results[$key] = $this->data[$key];
}
return $results;
}
/**
* Tokenizes the array to ease the search in multidimensional arrays.
*
* @param array $array the array to tokenize
* @param string $prefix the key prefix
* @param bool $addParent whether to add parent value anyway. False
*
* @return array
*/
public function tokenize($array, $prefix = '', $addParent = true)
{
$paths = [];
$px = empty($prefix) ? null : $prefix . ".";
foreach ($array as $key => $items) {
if (is_array($items)) {
$addParent && $paths[$px . $key] = $items;
foreach ($this->tokenize($items, $px . $key) as $k => $path) {
$paths[$k] = $path;
}
} elseif (is_object($items)) {
$addParent && $paths[$px . $key] = $items;
foreach ($this->tokenize(get_object_vars($items), $px . $key) as $k => $path) {
$paths[$k] = $path;
}
} else {
$paths[$px . $key] = $items;
}
}
return $paths;
}
/**
* Checks data against conditions
*
* @param mixed $data the data to match against.
*
* @return bool true if matches condition
*/
private function matches($data)
{
$matches = true;
$conditions = isset($this->conditions['and']) ? $this->conditions['and'] : [];
foreach ($conditions as $condition) {
$key = $condition['key'];
$condition = $condition['condition'];
if (!array_key_exists($key, $data) || !$condition->matches($data[$key])) {
$matches = false;
break;
}
}
$conditions = isset($this->conditions['or']) ? $this->conditions['or'] : [];
foreach ($conditions as $condition) {
$key = $condition['key'];
$condition = $condition['condition'];
if (array_key_exists($key, $data) && $condition->matches($data[$key])) {
$matches = true;
break;
}
}
return $matches;
}
}

View File

@ -0,0 +1,77 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* Condition abstract base class where all conditions extend from
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
abstract class Condition
{
/**
* @var mixed the value to match against
*/
protected $value;
/**
* @var bool whether to reverse or not
*/
protected $negate = false;
/**
* @param mixed $value the value to match against
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* Reverses the condition
* @return $this
*/
public function reverse()
{
$this->negate = !$this->negate;
return $this;
}
/**
* Checks whether the value passes condition
*
* @param mixed $data the data to match
*
* @return mixed
*/
abstract public function matches($data);
/**
* Checks whether the value and the data are of same type
*
* @param mixed $value
* @param mixed $against
*
* @return bool true if both are of same type
*/
protected function checkType($value, $against)
{
if (is_numeric($value) && is_numeric($against)) {
$value = filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT);
$against = filter_var($against, FILTER_SANITIZE_NUMBER_FLOAT);
}
if (gettype($value) != gettype($against)) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* Equal checks if value is equal to the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class Equal extends Condition
{
/**
* @inheritdoc
*/
public function matches($data)
{
return (($this->checkType($data, $this->value) && strcmp($data, $this->value) === 0) xor $this->negate);
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* @copyright Copyright (c) 2013-2017 2amigOS! Consulting Group LLC
* @link http://2amigos.us
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
namespace dosamigos\arrayquery\conditions;
/**
* GreaterThan checks if value is greater than the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class GreaterThan extends Condition
{
/**
* Returns [[LessThan]] condition
* @return LessThan
*/
public function reverse()
{
return new LessThan($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
return ($this->checkType($data, $this->value) && $data > $this->value);
}
}

Some files were not shown because too many files have changed in this diff Show More