This commit is contained in:
dongpd 2020-03-27 10:13:51 +07:00
commit da1024a5b3
16614 changed files with 3274273 additions and 0 deletions

0
.gitignore vendored Normal file
View File

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

47
assets/AppAsset.php Normal file
View File

@ -0,0 +1,47 @@
<?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',
'select2/css/select2.min.css'
];
public $js = [
'js/md5.min.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',
'select2/js/select2.min.js',
'js/editor.js',
'js/common.js'
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}

23
assets/DashboardAsset.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace app\assets;
use yii\web\AssetBundle;
class DashboardAsset extends AssetBundle {
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
];
public $js = [
'js/user.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',
];
}

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,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=khuvuichoi',
'dsn' => 'sqlite:@app/db/app.db',
'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;

143
config/web.php Normal file
View File

@ -0,0 +1,143 @@
<?php
$params = require __DIR__ . '/params.php';
$db = require __DIR__ . '/db.php';
$config = [
'id' => 'basic',
'homeUrl' => ['/dashboard'],
'name' => 'AIParking Server',
'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
],
'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,43 @@
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\helpers\FileHelper;
use app\models\User;
use app\models\Gate;
use app\models\Camera;
use app\models\Card;
use app\models\CardGroup;
use app\models\Logs;
use app\models\Config;
/**
* 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;
}
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace app\controllers;
use Yii;
use app\models\Logs;
use app\models\LogsSearch;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\helpers\Url;
/**
* ScriptController implements the CRUD actions for Script model.
*/
class DashboardController 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 Script models.
* @return mixed
*/
public function actionIndex() {
$this->view->title = "Bảng tổng hợp";
return $this->render('index', [
]);
}
}

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,272 @@
<?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']);
}
}
/**
* {@inheritdoc}
*/
public function behaviors() {
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
];
}
/**
* Lists all User models.
* @return mixed
*/
public function actionIndex() {
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->renderAjax("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() {
$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,
'url' => Url::to(['/user'])
];
} 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) {
$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->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);
}
}
Yii::$app->response->format = "json";
return [
'stt' => true,
'url' => Url::to(['/user'])
];
} 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->request->isAjax) {
$this->findModel($id)->delete();
AuthAssignment::deleteAll(['user_id' => $id]);
Yii::$app->response->format = "json";
return ["url" => Url::to(['/user'])];
}
}
/**
* 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() {
$model = $this->findModel(Yii::$app->user->id);
if (Yii::$app->request->post()) {
$post = Yii::$app->request->post();
$model->first_name = $post['Name'];
$model->phone_number = $post['PhoneNumber'];
$model->email = $post['Email'];
return $model->save();
} else {
Yii::$app->response->format = "json";
if (Yii::$app->user->isGuest) {
return [
"title" => "Lỗi",
"form" => "Bạn chưa đăng nhập hệ thống"
];
}
return [
"title" => "Thông tin cá nhân",
"form" => $this->renderPartial('profiles', [
"model" => $model
])
];
}
}
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 {
Yii::$app->response->format = "json";
if (Yii::$app->user->isGuest) {
return [
"title" => "Lỗi",
"form" => "Bạn chưa đăng nhập hệ thống"
];
}
return [
"title" => "Đổi mật khẩu",
"form" => $this->renderPartial('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;
}
}
}

BIN
db/app.db Normal file

Binary file not shown.

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'

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::button("<i class='fa fa-trash'></i>", [
"class" => "btn btn-danger btn-xs",
"data" => [
"toggle" => "tooltip",
"href" => Url::to(['/user/delete', 'id' => $model->id])
],
"title" => Yii::t("app", "Delete"),
"onclick" => "user.delete(this);"
]);
}
return "";
};
}
}

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

160
models/UploadForm.php Normal file
View File

@ -0,0 +1,160 @@
<?php
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model {
/**
* @var UploadedFile[]
*/
public $imageFiles;
public function rules() {
return [
[['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, jpeg, pdf, rar, zip', 'maxFiles' => 70],
];
}
public function upload($params) {
if ($this->validate()) {
$currentStorage = Storage::findOne(['stt' => 1])->folder;
// $root = \Yii::getAlias('@app') . '/web/data/uploads/';
$root = $currentStorage . "/uploads/";
$folder = $root . $params['project_type'] . "/" . $params['project_id'] . "/" . $params['p_id'];
if (!file_exists($folder))
mkdir($folder, 0777, true);
$files = [];
foreach ($this->imageFiles as $file) {
$file->saveAs($folder . "/" . $file->baseName . '.' . $file->extension);
$files[] = $file->baseName . '.' . $file->extension;
}
$model = new Images();
$model->create($params, $files);
$results = Results::findOne(['project_id' => $params['project_id_raw'], 'p_id' => $params['p_id_raw']]);
$results->content = "yes";
if ($results->create_at == $results->modified_at) {
$results->modified_at = time();
}
$results->save();
return true;
} else {
var_dump($this->errors);
return false;
}
}
public function uploadZip($params) {
return $this->UploadFile('file' . $params["name"], ["RAR", "ZIP", "MPG", "MXF"], $params);
}
public function uploadDoc($params) {
return $this->UploadFile('file' . $params["name"], ["DOC", "DOCX", "XLS", "XLSX"], $params);
}
public function uploadWord($params) {
return $this->UploadFile('file' . $params["name"], ["DOC", "DOCX", "RAR", "ZIP"], $params);
}
public function uploadMp3($params) {
return $this->UploadFile('file' . $params["name"], ["MP3", "WAV", "RAR", "ZIP"], $params);
}
public function UploadFile($file, $fileTypes, $params) {
$currentStorage = Storage::findOne(['stt' => 1])->folder;
// $root = \Yii::getAlias('@app') . '/web/data/uploads';
$root = $currentStorage . "/uploads";
$LocalPath = "/" . $params['project_type'] . "/" . $params['project_id'] . "/" . $params['p_id'];
$RootFolder = $root . $LocalPath;
// $name = $_FILES[$file]["name"];
// $array = explode(".", $name);
// $nr = count($array);
// $ext = $array[$nr - 1];
// $fileName = md5($params['project_type'] . "/" . $params['project_id'] . "/" . $params['p_id']);
$destfile = $_FILES[$file]["name"];
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;
}
}
}
public function UploadGlobal($file, $fileTypes, $path) {
$root = \Yii::getAlias('@app') . '/web/data/uploads';
$LocalPath = "/" . $path;
$RootFolder = $root . $LocalPath;
// $name = $_FILES[$file]["name"];
// $array = explode(".", $name);
// $nr = count($array);
// $ext = $array[$nr - 1];
// $fileName = md5($path);
$destfile = time() . "_" . $_FILES[$file]["name"]; // 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) {
$currentStorage = Storage::findOne(['stt' => 1])->folder;
$root = $currentStorage . "/uploads";
// $root = \Yii::getAlias('@app') . '/web/data/uploads/';
$tempdir = $file;
if (trim($tempdir) !== "") {
$tempdir = $root . trim($tempdir);
} else {
$tempdir = "/dddddddddddddddddddddeeeeeeeeeeeee";
}
if (file_exists($tempdir)) {
$destfile = basename($tempdir);
$dir = $root . $folder;
$file_dir = $dir . '/' . $destfile;
$link = $destfile;
if (!file_exists($dir)) {
@mkdir($dir, 0777, true);
}
$output = shell_exec("mv {$tempdir} {$file_dir}");
} else {
$link = $file;
}
return $link;
}
}

203
models/User.php Normal file
View File

@ -0,0 +1,203 @@
<?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]
];
}
/**
* {@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;
}
}

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

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();

0
runtime/temp.txt Normal file
View File

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

View File

@ -0,0 +1,40 @@
<?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;
/**
* GreaterThanOrEqual checks if value is greater or 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 GreaterThanOrEqual extends Condition
{
/**
* Returns [[LessThanOrEqual]] condition
* @return LessThanOrEqual
*/
public function reverse()
{
return new LessThanOrEqual($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
$gt = new GreaterThan($this->value);
$e = new Equal($this->value);
return $gt->matches($data) || $e->matches($data);
}
}

View File

@ -0,0 +1,39 @@
<?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;
/**
* LessThan checks if value is less than 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 LessThan extends Condition
{
/**
* Returns [[GreaterThan]] condition
* @return GreaterThan
*/
public function reverse()
{
return new GreaterThan($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
return ($this->checkType($data, $this->value) && $data < $this->value);
}
}

View File

@ -0,0 +1,41 @@
<?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;
/**
* LessThanOrEqual checks if value is less than or 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 LessThanOrEqual extends Condition
{
/**
* Returns [[GreaterThanOrEqual]] condition
* @return GreaterThanOrEqual
*/
public function reverse()
{
return new GreaterThanOrEqual($this->value);
}
/**
* @inheritdoc
*/
public function matches($data)
{
$gt = new LessThan($this->value);
$e = new Equal($this->value);
return $gt->matches($data) || $e->matches($data);
}
}

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;
/**
* Like checks if value is matches any words in theå data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class Like extends Condition
{
/**
* @inheritdoc
*/
public function matches($data)
{
return is_string($data) && mb_stripos($data, $this->value) !== false;
}
}

View File

@ -0,0 +1,27 @@
<?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;
/**
* NotLike checks if value is not within the data searched.
*
* @author Antonio Ramirez <hola@2amigos.us>
* @link http://www.ramirezcobos.com/
* @link http://www.2amigos.us/
* @package dosamigos\arrayquery\conditions
*/
class NotLike extends Like
{
/**
* @inheritdoc
*/
public function matches($data)
{
return !parent::matches($data);
}
}

View File

@ -0,0 +1,34 @@
<!--
Before opening a new issue, please search through the existing issues to
see if your topic has already been addressed. Note that you may need to
remove the "is:open" filter from the search bar to include closed issues.
Check the appropriate type for your issue below by placing an x between the
brackets.
Please note that issues which do not fall under any of the below categories
will be closed.
--->
### Issue type:
- [ ] Feature request <!-- Requesting the implementation of a new feature -->
- [ ] Bug report <!-- Reporting unexpected or erroneous behavior -->
- [ ] Documentation <!-- Proposing a modification to the documentation -->
<!--
Please describe the environment.
-->
### Environment:
* AdminLTE Version: <!-- Example: 2.4 -->
* Operating System: <!-- Example: OSX/Android -->
* Browser (Version): <!-- Example: Chrome (Latest) -->
<!--
BUG REPORTS must include:
* Steps or URL needed to reproduce the bug/issue
* Any relevant error messages (screenshots may also help)
* A snippet of your markup (where applicable)
FEATURE REQUESTS must include:
* A detailed description of the proposed functionality
-->
### Description:

View File

@ -0,0 +1,11 @@
*.DS_Store
*.log
*.zip
.idea
.sass-cache/
/nbproject/
/nbproject/private/
/node_modules/
ad.js
TODO
test.html

View File

@ -0,0 +1,2 @@
documentation/
composer.json

View File

@ -0,0 +1,311 @@
// AdminLTE Gruntfile
module.exports = function (grunt) { // jshint ignore:line
'use strict';
grunt.initConfig({
pkg : grunt.file.readJSON('package.json'),
watch : {
less : {
// Compiles less files upon saving
files: ['build/less/*.less'],
tasks: ['less:development', 'less:production', 'replace', 'notify:less']
},
js : {
// Compile js files upon saving
files: ['build/js/*.js'],
tasks: ['js', 'notify:js']
},
skins: {
// Compile any skin less files upon saving
files: ['build/less/skins/*.less'],
tasks: ['less:skins', 'less:minifiedSkins', 'notify:less']
}
},
// Notify end of tasks
notify: {
less: {
options: {
title : 'AdminLTE',
message: 'LESS finished running'
}
},
js : {
options: {
title : 'AdminLTE',
message: 'JS bundler finished running'
}
}
},
// 'less'-task configuration
// This task will compile all less files upon saving to create both AdminLTE.css and AdminLTE.min.css
less : {
// Development not compressed
development : {
files: {
// compilation.css : source.less
'dist/css/AdminLTE.css' : 'build/less/AdminLTE.less',
// AdminLTE without plugins
'dist/css/alt/AdminLTE-without-plugins.css' : 'build/less/AdminLTE-without-plugins.less',
// Separate plugins
'dist/css/alt/AdminLTE-select2.css' : 'build/less/select2.less',
'dist/css/alt/AdminLTE-fullcalendar.css' : 'build/less/fullcalendar.less',
'dist/css/alt/AdminLTE-bootstrap-social.css': 'build/less/bootstrap-social.less'
}
},
// Production compressed version
production : {
options: {
compress: true
},
files : {
// compilation.css : source.less
'dist/css/AdminLTE.min.css' : 'build/less/AdminLTE.less',
// AdminLTE without plugins
'dist/css/alt/AdminLTE-without-plugins.min.css' : 'build/less/AdminLTE-without-plugins.less',
// Separate plugins
'dist/css/alt/AdminLTE-select2.min.css' : 'build/less/select2.less',
'dist/css/alt/AdminLTE-fullcalendar.min.css' : 'build/less/fullcalendar.less',
'dist/css/alt/AdminLTE-bootstrap-social.min.css': 'build/less/bootstrap-social.less'
}
},
// Non minified skin files
skins : {
files: {
'dist/css/skins/skin-blue.css' : 'build/less/skins/skin-blue.less',
'dist/css/skins/skin-black.css' : 'build/less/skins/skin-black.less',
'dist/css/skins/skin-yellow.css' : 'build/less/skins/skin-yellow.less',
'dist/css/skins/skin-green.css' : 'build/less/skins/skin-green.less',
'dist/css/skins/skin-red.css' : 'build/less/skins/skin-red.less',
'dist/css/skins/skin-purple.css' : 'build/less/skins/skin-purple.less',
'dist/css/skins/skin-blue-light.css' : 'build/less/skins/skin-blue-light.less',
'dist/css/skins/skin-black-light.css' : 'build/less/skins/skin-black-light.less',
'dist/css/skins/skin-yellow-light.css': 'build/less/skins/skin-yellow-light.less',
'dist/css/skins/skin-green-light.css' : 'build/less/skins/skin-green-light.less',
'dist/css/skins/skin-red-light.css' : 'build/less/skins/skin-red-light.less',
'dist/css/skins/skin-purple-light.css': 'build/less/skins/skin-purple-light.less',
'dist/css/skins/_all-skins.css' : 'build/less/skins/_all-skins.less'
}
},
// Skins minified
minifiedSkins: {
options: {
compress: true
},
files : {
'dist/css/skins/skin-blue.min.css' : 'build/less/skins/skin-blue.less',
'dist/css/skins/skin-black.min.css' : 'build/less/skins/skin-black.less',
'dist/css/skins/skin-yellow.min.css' : 'build/less/skins/skin-yellow.less',
'dist/css/skins/skin-green.min.css' : 'build/less/skins/skin-green.less',
'dist/css/skins/skin-red.min.css' : 'build/less/skins/skin-red.less',
'dist/css/skins/skin-purple.min.css' : 'build/less/skins/skin-purple.less',
'dist/css/skins/skin-blue-light.min.css' : 'build/less/skins/skin-blue-light.less',
'dist/css/skins/skin-black-light.min.css' : 'build/less/skins/skin-black-light.less',
'dist/css/skins/skin-yellow-light.min.css': 'build/less/skins/skin-yellow-light.less',
'dist/css/skins/skin-green-light.min.css' : 'build/less/skins/skin-green-light.less',
'dist/css/skins/skin-red-light.min.css' : 'build/less/skins/skin-red-light.less',
'dist/css/skins/skin-purple-light.min.css': 'build/less/skins/skin-purple-light.less',
'dist/css/skins/_all-skins.min.css' : 'build/less/skins/_all-skins.less'
}
}
},
// Uglify task info. Compress the js files.
uglify: {
options : {
mangle : true,
preserveComments: 'some'
},
production: {
files: {
'dist/js/adminlte.min.js': ['dist/js/adminlte.js']
}
}
},
// Concatenate JS Files
concat: {
options: {
separator: '\n\n',
banner : '/*! AdminLTE app.js\n'
+ '* ================\n'
+ '* Main JS application file for AdminLTE v2. This file\n'
+ '* should be included in all pages. It controls some layout\n'
+ '* options and implements exclusive AdminLTE plugins.\n'
+ '*\n'
+ '* @Author Almsaeed Studio\n'
+ '* @Support <https://www.almsaeedstudio.com>\n'
+ '* @Email <abdullah@almsaeedstudio.com>\n'
+ '* @version <%= pkg.version %>\n'
+ '* @repository <%= pkg.repository.url %>\n'
+ '* @license MIT <http://opensource.org/licenses/MIT>\n'
+ '*/\n\n'
+ '// Make sure jQuery has been loaded\n'
+ 'if (typeof jQuery === \'undefined\') {\n'
+ 'throw new Error(\'AdminLTE requires jQuery\')\n'
+ '}\n\n'
},
dist : {
src : [
'build/js/BoxRefresh.js',
'build/js/BoxWidget.js',
'build/js/ControlSidebar.js',
'build/js/DirectChat.js',
'build/js/Layout.js',
'build/js/PushMenu.js',
'build/js/TodoList.js',
'build/js/Tree.js'
],
dest: 'dist/js/adminlte.js'
}
},
// Replace image paths in AdminLTE without plugins
replace: {
withoutPlugins : {
src : ['dist/css/alt/AdminLTE-without-plugins.css'],
dest : 'dist/css/alt/AdminLTE-without-plugins.css',
replacements: [
{
from: '../img',
to : '../../img'
}
]
},
withoutPluginsMin: {
src : ['dist/css/alt/AdminLTE-without-plugins.min.css'],
dest : 'dist/css/alt/AdminLTE-without-plugins.min.css',
replacements: [
{
from: '../img',
to : '../../img'
}
]
}
},
// Build the documentation files
includes: {
build: {
src : ['*.html'], // Source files
dest : 'documentation/', // Destination directory
flatten: true,
cwd : 'documentation/build',
options: {
silent : true,
includePath: 'documentation/build/include'
}
}
},
// Optimize images
image: {
dynamic: {
files: [
{
expand: true,
cwd : 'build/img/',
src : ['**/*.{png,jpg,gif,svg,jpeg}'],
dest : 'dist/img/'
}
]
}
},
// Validate JS code
jshint: {
options: {
jshintrc: 'build/js/.jshintrc'
},
grunt : {
options: {
jshintrc: 'build/grunt/.jshintrc'
},
src : 'Gruntfile.js'
},
core : {
src: 'build/js/*.js'
},
demo : {
src: 'dist/js/demo.js'
},
pages : {
src: 'dist/js/pages/*.js'
}
},
jscs: {
options: {
config: 'build/js/.jscsrc'
},
core : {
src: '<%= jshint.core.src %>'
},
pages : {
src: '<%= jshint.pages.src %>'
}
},
// Validate CSS files
csslint: {
options: {
csslintrc: 'build/less/.csslintrc'
},
dist : [
'dist/css/AdminLTE.css'
]
},
// Validate Bootstrap HTML
bootlint: {
options: {
relaxerror: ['W005']
},
files : ['pages/**/*.html', '*.html']
},
// Delete images in build directory
// After compressing the images in the build/img dir, there is no need
// for them
clean: {
build: ['build/img/*']
}
});
// Load all grunt tasks
// LESS Compiler
grunt.loadNpmTasks('grunt-contrib-less');
// Watch File Changes
grunt.loadNpmTasks('grunt-contrib-watch');
// Compress JS Files
grunt.loadNpmTasks('grunt-contrib-uglify');
// Include Files Within HTML
grunt.loadNpmTasks('grunt-includes');
// Optimize images
grunt.loadNpmTasks('grunt-image');
// Validate JS code
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-jscs');
// Delete not needed files
grunt.loadNpmTasks('grunt-contrib-clean');
// Lint CSS
grunt.loadNpmTasks('grunt-contrib-csslint');
// Lint Bootstrap
grunt.loadNpmTasks('grunt-bootlint');
// Concatenate JS files
grunt.loadNpmTasks('grunt-contrib-concat');
// Notify
grunt.loadNpmTasks('grunt-notify');
// Replace
grunt.loadNpmTasks('grunt-text-replace');
// Linting task
grunt.registerTask('lint', ['jshint', 'csslint', 'bootlint']);
// JS task
grunt.registerTask('js', ['concat', 'uglify']);
// CSS Task
grunt.registerTask('css', ['less:development', 'less:production', 'replace']);
// The default task (running 'grunt' in console) is 'watch'
grunt.registerTask('default', ['watch']);
};

20
vendor/almasaeed2010/adminlte/LICENSE vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2014-2017 Abdullah Almsaeed
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

57
vendor/almasaeed2010/adminlte/README.md vendored Normal file
View File

@ -0,0 +1,57 @@
Introduction
============
![Bower version](https://img.shields.io/bower/v/adminlte.svg)
[![npm version](https://img.shields.io/npm/v/admin-lte.svg)](https://www.npmjs.com/package/admin-lte)
[![Packagist](https://img.shields.io/packagist/v/almasaeed2010/adminlte.svg)](https://packagist.org/packages/almasaeed2010/adminlte)
[![CDNJS](https://img.shields.io/cdnjs/v/admin-lte.svg)](https://cdnjs.com/libraries/admin-lte)
**AdminLTE** -- is a fully responsive admin template. Based on **[Bootstrap 3](https://github.com/twbs/bootstrap)** framework. Highly customizable and easy to use. Fits many screen resolutions from small mobile devices to large desktops. Check out the live preview now and see for yourself.
**Download & Preview on [AdminLTE.IO](https://adminlte.io)**
### Looking for Premium Templates?
**AdminLTE.IO just opened a new premium templates website. Hand picked to ensure the best quality and the most affordable prices. Visit https://themequarry.com for more information.**
## Documentation & Installation Guide
Visit the [online documentation](https://adminlte.io/docs) for the most
updated guide.
!["AdminLTE Presentation"](https://adminlte.io/AdminLTE2.png "AdminLTE Presentation")
### Contribution
Contribution are always **welcome and recommended**! Here is how:
- Fork the repository ([here is the guide](https://help.github.com/articles/fork-a-repo/)).
- Clone to your machine ```git clone https://github.com/YOUR_USERNAME/AdminLTE.git```
- Make your changes
- Create a pull request
#### Contribution Requirements:
- When you contribute, you agree to give a non-exclusive license to AdminLTE.IO to use that contribution in any context as we (AdminLTE.IO) see appropriate.
- If you use content provided by another party, it must be appropriately licensed using an [open source](http://opensource.org/licenses) license.
- Contributions are only accepted through Github pull requests.
- Finally, contributed code must work in all supported browsers (see above for browser support).
### License
AdminLTE is an open source project by [AdminLTE.IO](https://adminlte.io) that is licensed under [MIT](http://opensource.org/licenses/MIT). AdminLTE.IO
reserves the right to change the license of future releases. Wondering what you can or can't do? View the [license guide](https://adminlte.io/docs/license).
### Legacy Releases
AdminLTE 1.x can be easily upgraded to 2.x using [this guide](https://adminlte.io/themes/AdminLTE/documentation/index.html#upgrade), but if you intend to keep using AdminLTE 1.x, you can download the latest release from the [releases](https://github.com/almasaeed2010/AdminLTE/releases) section above.
### Change log
**For the most recent change log, visit the [releases page](https://github.com/almasaeed2010/AdminLTE/releases) or the [changelog file](https://github.com/almasaeed2010/AdminLTE/blob/master/changelog.md).** We will add detailed release notes to each new release.
### Image Credits
- [Pixeden](http://www.pixeden.com/psd-web-elements/flat-responsive-showcase-psd)
- [Graphicsfuel](http://www.graphicsfuel.com/2013/02/13-high-resolution-blur-backgrounds/)
- [Pickaface](http://pickaface.net/)
- [Unsplash](https://unsplash.com/)
- [Uifaces](http://uifaces.com/)
### Donations
Donations are **greatly appreciated!**
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif "AdminLTE Presentation")](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=629XCUSXBHCBC "Donate")

View File

@ -0,0 +1,65 @@
{
"name": "admin-lte",
"homepage": "https://adminlte.io",
"authors": [
"Abdullah Almsaeed <abdullah@almsaeedstudio.com>"
],
"description": "Admin dashboard and control panel template",
"main": [
"index2.html",
"dist/css/AdminLTE.css",
"dist/js/adminlte.js",
"build/less/AdminLTE.less"
],
"keywords": [
"css",
"js",
"html",
"template",
"admin",
"bootstrap",
"theme",
"backend",
"responsive"
],
"license": "MIT",
"ignore": [
"/.*",
"node_modules",
"bower_components",
"composer.json",
"documentation"
],
"dependencies": {
"bootstrap-slider": "*",
"chart.js": "1.0.*",
"ckeditor": "^4.7.0",
"bootstrap-colorpicker": "^2.5.1",
"bootstrap": "^3.3.7",
"jquery": "^3.2.1",
"datatables.net": "^1.10.15",
"datatables.net-bs": "^2.1.1",
"bootstrap-datepicker": "^1.7.0",
"bootstrap-daterangepicker": "^2.1.25",
"moment": "^2.18.1",
"fastclick": "^1.0.6",
"Flot": "flot#^0.8.3",
"fullcalendar": "^3.4.0",
"inputmask": "jquery.inputmask#^3.3.7",
"ion.rangeSlider": "ionrangeslider#^2.2.0",
"jvectormap": "^1.2.2",
"jquery-knob": "^1.2.13",
"morris.js": "^0.5.1",
"PACE": "pace#^1.0.2",
"select2": "^4.0.3",
"jquery-slimscroll": "slimscroll#^1.3.8",
"bootstrap-timepicker": "^0.5.2",
"jquery-sparkline": "^2.1.3",
"font-awesome": "^4.7.0",
"Ionicons": "ionicons#^2.0.1",
"jquery-ui": "1.11.4"
},
"resolutions": {
"jquery": "^3.2.1"
}
}

View File

@ -0,0 +1,18 @@
{
"name": "Flot",
"version": "0.8.3",
"main": "jquery.flot.js",
"dependencies": {
"jquery": ">= 1.2.6"
},
"homepage": "https://github.com/flot/flot",
"_release": "0.8.3",
"_resolution": {
"type": "version",
"tag": "v0.8.3",
"commit": "453b017cc5acfd75e252b93e8635f57f4196d45d"
},
"_source": "https://github.com/flot/flot.git",
"_target": "^0.8.3",
"_originalSource": "flot"
}

View File

@ -0,0 +1,3 @@
*.min.js
!excanvas.min.js
node_modules/

View File

@ -0,0 +1,3 @@
language: node_js
node_js:
- 0.8

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
## Contributing to Flot ##
We welcome all contributions, but following these guidelines results in less
work for us, and a faster and better response.
### Issues ###
Issues are not a way to ask general questions about Flot. If you see unexpected
behavior but are not 100% certain that it is a bug, please try posting to the
[forum](http://groups.google.com/group/flot-graphs) first, and confirm that
what you see is really a Flot problem before creating a new issue for it. When
reporting a bug, please include a working demonstration of the problem, if
possible, or at least a clear description of the options you're using and the
environment (browser and version, jQuery version, other libraries) that you're
running under.
If you have suggestions for new features, or changes to existing ones, we'd
love to hear them! Please submit each suggestion as a separate new issue.
If you would like to work on an existing issue, please make sure it is not
already assigned to someone else. If an issue is assigned to someone, that
person has already started working on it. So, pick unassigned issues to prevent
duplicated effort.
### Pull Requests ###
To make merging as easy as possible, please keep these rules in mind:
1. Submit new features or architectural changes to the *&lt;version&gt;-work*
branch for the next major release. Submit bug fixes to the master branch.
2. Divide larger changes into a series of small, logical commits with
descriptive messages.
3. Rebase, if necessary, before submitting your pull request, to reduce the
work we need to do to merge it.
4. Format your code according to the style guidelines below.
### Flot Style Guidelines ###
Flot follows the [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines),
with the following updates and exceptions:
#### Spacing ####
Use four-space indents, no tabs. Do not add horizontal space around parameter
lists, loop definitions, or array/object indices. For example:
```js
for ( var i = 0; i < data.length; i++ ) { // This block is wrong!
if ( data[ i ] > 1 ) {
data[ i ] = 2;
}
}
for (var i = 0; i < data.length; i++) { // This block is correct!
if (data[i] > 1) {
data[i] = 2;
}
}
```
#### Comments ####
Use [jsDoc](http://usejsdoc.org) comments for all file and function headers.
Use // for all inline and block comments, regardless of length.
All // comment blocks should have an empty line above *and* below them. For
example:
```js
var a = 5;
// We're going to loop here
// TODO: Make this loop faster, better, stronger!
for (var x = 0; x < 10; x++) {}
```
#### Wrapping ####
Block comments should be wrapped at 80 characters.
Code should attempt to wrap at 80 characters, but may run longer if wrapping
would hurt readability more than having to scroll horizontally. This is a
judgement call made on a situational basis.
Statements containing complex logic should not be wrapped arbitrarily if they
do not exceed 80 characters. For example:
```js
if (a == 1 && // This block is wrong!
b == 2 &&
c == 3) {}
if (a == 1 && b == 2 && c == 3) {} // This block is correct!
```

View File

@ -0,0 +1,75 @@
## Frequently asked questions ##
#### How much data can Flot cope with? ####
Flot will happily draw everything you send to it so the answer
depends on the browser. The excanvas emulation used for IE (built with
VML) makes IE by far the slowest browser so be sure to test with that
if IE users are in your target group (for large plots in IE, you can
also check out Flashcanvas which may be faster).
1000 points is not a problem, but as soon as you start having more
points than the pixel width, you should probably start thinking about
downsampling/aggregation as this is near the resolution limit of the
chart anyway. If you downsample server-side, you also save bandwidth.
#### Flot isn't working when I'm using JSON data as source! ####
Actually, Flot loves JSON data, you just got the format wrong.
Double check that you're not inputting strings instead of numbers,
like [["0", "-2.13"], ["5", "4.3"]]. This is most common mistake, and
the error might not show up immediately because Javascript can do some
conversion automatically.
#### Can I export the graph? ####
You can grab the image rendered by the canvas element used by Flot
as a PNG or JPEG (remember to set a background). Note that it won't
include anything not drawn in the canvas (such as the legend). And it
doesn't work with excanvas which uses VML, but you could try
Flashcanvas.
#### The bars are all tiny in time mode? ####
It's not really possible to determine the bar width automatically.
So you have to set the width with the barWidth option which is NOT in
pixels, but in the units of the x axis (or the y axis for horizontal
bars). For time mode that's milliseconds so the default value of 1
makes the bars 1 millisecond wide.
#### Can I use Flot with libraries like Mootools or Prototype? ####
Yes, Flot supports it out of the box and it's easy! Just use jQuery
instead of $, e.g. call jQuery.plot instead of $.plot and use
jQuery(something) instead of $(something). As a convenience, you can
put in a DOM element for the graph placeholder where the examples and
the API documentation are using jQuery objects.
Depending on how you include jQuery, you may have to add one line of
code to prevent jQuery from overwriting functions from the other
libraries, see the documentation in jQuery ("Using jQuery with other
libraries") for details.
#### Flot doesn't work with [insert name of Javascript UI framework]! ####
Flot is using standard HTML to make charts. If this is not working,
it's probably because the framework you're using is doing something
weird with the DOM or with the CSS that is interfering with Flot.
A common problem is that there's display:none on a container until the
user does something. Many tab widgets work this way, and there's
nothing wrong with it - you just can't call Flot inside a display:none
container as explained in the README so you need to hold off the Flot
call until the container is actually displayed (or use
visibility:hidden instead of display:none or move the container
off-screen).
If you find there's a specific thing we can do to Flot to help, feel
free to submit a bug report. Otherwise, you're welcome to ask for help
on the forum/mailing list, but please don't submit a bug report to
Flot.

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