diff --git a/docker/.env b/docker/.env
new file mode 100755
index 0000000000000000000000000000000000000000..760f38cbcf909ae699347d806659af16602f53b4
--- /dev/null
+++ b/docker/.env
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# See https://docs.docker.com/compose/environment-variables/#the-env-file
+
+# Nginx
+NGINX_HOST=localhost
+
+# PHP
+
+# See https://hub.docker.com/r/nanoninja/php-fpm/tags/
+PHP_VERSION=latest
+
+# MySQL
+MYSQL_VERSION=5.7.22
+MYSQL_HOST=mysql
+MYSQL_DATABASE=test
+MYSQL_ROOT_USER=root
+MYSQL_ROOT_PASSWORD=root
+MYSQL_USER=dev
+MYSQL_PASSWORD=dev
diff --git a/docker/.gitignore b/docker/.gitignore
new file mode 100755
index 0000000000000000000000000000000000000000..7fbb7857b2e71d150689f95fc49dfb96daa64af3
--- /dev/null
+++ b/docker/.gitignore
@@ -0,0 +1,25 @@
+# Global
+.*.swp
+.DS_Store
+
+# Application
+web/app/composer.json
+web/app/composer.lock
+web/app/vendor/
+web/app/doc/
+web/app/report/
+data/
+
+# PHPStorm
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Netbeans
+nbproject/
+/nbproject/
+/nbproject/private/
+/nbproject/private/private.properties
+
+# SSL Certs
+etc/ssl/
\ No newline at end of file
diff --git a/docker/.travis.yml b/docker/.travis.yml
new file mode 100755
index 0000000000000000000000000000000000000000..8ec19785543cdaf683230d48c504434cc3df7264
--- /dev/null
+++ b/docker/.travis.yml
@@ -0,0 +1,30 @@
+sudo: required
+
+env:
+ DOCKER_COMPOSE_VERSION: 1.18.0
+
+services:
+ - docker
+
+before_install:
+ - sudo apt update
+ - sudo rm /usr/local/bin/docker-compose
+ - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
+ - chmod +x docker-compose
+ - sudo mv docker-compose /usr/local/bin
+ - docker-compose --version
+
+before_script:
+ - sudo make docker-start
+ - sleep 2m
+
+script:
+ - sudo make apidoc
+ - sudo make gen-certs
+ - sudo make mysql-dump
+ - sudo make mysql-restore
+ - sudo make phpmd
+ - sudo make test
+
+after_script:
+ - sudo make docker-stop
\ No newline at end of file
diff --git a/docker/Makefile b/docker/Makefile
new file mode 100755
index 0000000000000000000000000000000000000000..86b5d3c4360618c253a0e844c29ffe59c8dd2f1d
--- /dev/null
+++ b/docker/Makefile
@@ -0,0 +1,83 @@
+# Makefile for Docker Nginx PHP Composer MySQL
+
+include .env
+
+# MySQL
+MYSQL_DUMPS_DIR=data/db/dumps
+
+help:
+ @echo ""
+ @echo "usage: make COMMAND"
+ @echo ""
+ @echo "Commands:"
+ @echo " apidoc Generate documentation of API"
+ @echo " code-sniff Check the API with PHP Code Sniffer (PSR2)"
+ @echo " clean Clean directories for reset"
+ @echo " composer-up Update PHP dependencies with composer"
+ @echo " docker-start Create and start containers"
+ @echo " docker-stop Stop and clear all services"
+ @echo " gen-certs Generate SSL certificates"
+ @echo " logs Follow log output"
+ @echo " mysql-dump Create backup of all databases"
+ @echo " mysql-restore Restore backup of all databases"
+ @echo " phpmd Analyse the API with PHP Mess Detector"
+ @echo " test Test application"
+
+init:
+ @$(shell cp -n $(shell pwd)/web/app/composer.json.dist $(shell pwd)/web/app/composer.json 2> /dev/null)
+
+apidoc:
+ @docker-compose exec -T php php -d memory_limit=256M -d xdebug.profiler_enable=0 ./app/vendor/bin/apigen generate app/src --destination app/doc
+ @make resetOwner
+
+clean:
+ @rm -Rf data/db/mysql/*
+ @rm -Rf $(MYSQL_DUMPS_DIR)/*
+ @rm -Rf web/app/vendor
+ @rm -Rf web/app/composer.lock
+ @rm -Rf web/app/doc
+ @rm -Rf web/app/report
+ @rm -Rf etc/ssl/*
+
+code-sniff:
+ @echo "Checking the standard code..."
+ @docker-compose exec -T php ./app/vendor/bin/phpcs -v --standard=PSR2 app/src
+
+composer-up:
+ @docker run --rm -v $(shell pwd)/web/app:/app composer update
+
+docker-start: init
+ docker-compose up -d
+
+docker-stop:
+ @docker-compose down -v
+ @make clean
+
+gen-certs:
+ @docker run --rm -v $(shell pwd)/etc/ssl:/certificates -e "SERVER=$(NGINX_HOST)" jacoelho/generate-certificate
+
+logs:
+ @docker-compose logs -f
+
+mysql-dump:
+ @mkdir -p $(MYSQL_DUMPS_DIR)
+ @docker exec $(shell docker-compose ps -q mysqldb) mysqldump --all-databases -u"$(MYSQL_ROOT_USER)" -p"$(MYSQL_ROOT_PASSWORD)" > $(MYSQL_DUMPS_DIR)/db.sql 2>/dev/null
+ @make resetOwner
+
+mysql-restore:
+ @docker exec -i $(shell docker-compose ps -q mysqldb) mysql -u"$(MYSQL_ROOT_USER)" -p"$(MYSQL_ROOT_PASSWORD)" < $(MYSQL_DUMPS_DIR)/db.sql 2>/dev/null
+
+phpmd:
+ @docker-compose exec -T php \
+ ./app/vendor/bin/phpmd \
+ ./app/src \
+ text cleancode,codesize,controversial,design,naming,unusedcode
+
+test: code-sniff
+ @docker-compose exec -T php ./app/vendor/bin/phpunit --colors=always --configuration ./app/
+ @make resetOwner
+
+resetOwner:
+ @$(shell chown -Rf $(SUDO_USER):$(shell id -g -n $(SUDO_USER)) $(MYSQL_DUMPS_DIR) "$(shell pwd)/etc/ssl" "$(shell pwd)/web/app" 2> /dev/null)
+
+.PHONY: clean test code-sniff init
\ No newline at end of file
diff --git a/docker/README.md b/docker/README.md
new file mode 100755
index 0000000000000000000000000000000000000000..3595746ed04e6663b81ee58823628dc3a3def1e0
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,22 @@
+# 用docker-compose 部署shopxo
+
+## Nginx PHP MySQL
+
+方案来源于 [nanoninja/docker-nginx-php-mysql](https://github.com/nanoninja/docker-nginx-php-mysql)涉及到php相关的内容,请参考该仓库
+
+## 部署步骤
+
+1. [安装docker](https://www.docker.com/)
+ [国内用户安装docker](https://www.runoob.com/docker/ubuntu-docker-install.html)
+ [docker从入门到实践](https://legacy.gitbook.com/book/yeasy/docker_practice/details)
+2. [安装docker-compose](https://docs.docker.com/compose/reference/overview/)
+
+3. 克隆代码并且修改shopxo文件夹权限
+ - git clone git@github.com:gongfuxiang/shopxo.git
+ - sudo chmod -R 777 shopxo
+
+4. 用docker-compose 运行项目包括数据库,如果不想用容器里面的数据库可以单独配置数据库
+ - cd shopxo
+ - docker-compose up
+
+5.
\ No newline at end of file
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
new file mode 100755
index 0000000000000000000000000000000000000000..e2047561f11233b478a3ca7e4ef20e6de12f4e99
--- /dev/null
+++ b/docker/docker-compose.yml
@@ -0,0 +1,41 @@
+version: '3'
+services:
+ web:
+ image: nginx
+ volumes:
+ - "./etc/nginx/default.conf:/etc/nginx/conf.d/default.conf"
+ - "../:/var/www/html" # shopxo代码挂载在nginx里面
+ - "./etc/nginx/default.template.conf:/etc/nginx/conf.d/default.template"
+ ports:
+ - "10000:80"
+ - "3000:443"
+ environment:
+ - NGINX_HOST=${NGINX_HOST} # 可以设置nginx的域名
+ command: /bin/sh -c "envsubst '$$NGINX_HOST' < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
+ restart: always
+ depends_on:
+ - php
+ - mysqldb
+ php:
+ image: nanoninja/php-fpm:7.4.4
+ restart: always
+ volumes:
+ - "./etc/php/php.ini:/usr/local/etc/php/conf.d/php.ini"
+ - "../:/var/www/html"
+
+ mysqldb:
+ image: mysql:5.7
+ container_name: mysql
+ restart: always
+ env_file:
+ - ".env"
+ environment:
+ - MYSQL_DATABASE=yourdb
+ - MYSQL_ROOT_PASSWORD=yourpasswd
+ - MYSQL_USER=youruser
+ - MYSQL_PASSWORD=yourpasswd
+ ports:
+ - "10001:3306"
+ volumes:
+ - "/data/shopxo_db:/var/lib/mysql" # mysql数据库持久化配置
+ - "./etc/db/my.cnf:/etc/mysql/my.cnf" # 修改mysql配置,首页统计
diff --git a/docker/etc/db/my.cnf b/docker/etc/db/my.cnf
new file mode 100755
index 0000000000000000000000000000000000000000..3b54eec10b24f2e3a7c8b45288fc0d01c102b54a
--- /dev/null
+++ b/docker/etc/db/my.cnf
@@ -0,0 +1,25 @@
+#
+# The MySQL database server configuration file.
+#
+# You can copy this to one of:
+# - "/etc/mysql/my.cnf" to set global options,
+# - "~/.my.cnf" to set user-specific options.
+#
+# One can use all long options that the program supports.
+# Run program with --help to get a list of available options and with
+# --print-defaults to see which it would actually understand and use.
+#
+# For explanations see
+# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
+
+# This will be passed to all mysql clients
+# It has been reported that passwords should be enclosed with ticks/quotes
+# escpecially if they contain "#" chars...
+# Remember to edit /etc/mysql/debian.cnf when changing the socket location.
+
+# Here is entries for some specific programs
+# The following values assume you have at least 32M ram
+[mysqld]
+sql_mode=STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+
+!includedir /etc/mysql/conf.d/
diff --git a/docker/etc/nginx/default.conf b/docker/etc/nginx/default.conf
new file mode 100755
index 0000000000000000000000000000000000000000..1088f8f2a69ac458304c200cba3534f19396eceb
--- /dev/null
+++ b/docker/etc/nginx/default.conf
@@ -0,0 +1,48 @@
+# Nginx configuration
+
+server {
+ listen 80 default_server;
+ listen [::]:80 default_server;
+ server_name localhost;
+
+ index index.php index.html;
+ error_log /var/log/nginx/error.log;
+ access_log /var/log/nginx/access.log;
+ root /var/www/html/public;
+
+ location ~ \.php$ {
+ try_files $uri =404;
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_pass php:9000;
+ fastcgi_index index.php;
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ }
+}
+
+# server {
+# server_name localhost;
+
+# listen 443 ssl;
+# fastcgi_param HTTPS on;
+
+# ssl_certificate /etc/ssl/server.pem;
+# ssl_certificate_key /etc/ssl/server.key;
+# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
+
+# index index.php index.html;
+# error_log /var/log/nginx/error.log;
+# access_log /var/log/nginx/access.log;
+# root /var/www/html/public;
+
+# location ~ \.php$ {
+# try_files $uri =404;
+# fastcgi_split_path_info ^(.+\.php)(/.+)$;
+# fastcgi_pass php:9000;
+# fastcgi_index index.php;
+# include fastcgi_params;
+# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+# fastcgi_param PATH_INFO $fastcgi_path_info;
+# }
+# }
\ No newline at end of file
diff --git a/docker/etc/nginx/default.template.conf b/docker/etc/nginx/default.template.conf
new file mode 100755
index 0000000000000000000000000000000000000000..2a485890f793420e64c96ef87f8e40bec039a778
--- /dev/null
+++ b/docker/etc/nginx/default.template.conf
@@ -0,0 +1,48 @@
+# Nginx configuration
+
+server {
+ listen 80 default_server;
+ listen [::]:80 default_server;
+ server_name ${NGINX_HOST};
+
+ index index.php index.html;
+ error_log /var/log/nginx/error.log;
+ access_log /var/log/nginx/access.log;
+ root /var/www/html/public;
+
+ location ~ \.php$ {
+ try_files $uri =404;
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_pass php:9000;
+ fastcgi_index index.php;
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ }
+}
+
+# server {
+# server_name ${NGINX_HOST};
+
+# listen 443 ssl;
+# fastcgi_param HTTPS on;
+
+# ssl_certificate /etc/ssl/server.pem;
+# ssl_certificate_key /etc/ssl/server.key;
+# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
+
+# index index.php index.html;
+# error_log /var/log/nginx/error.log;
+# access_log /var/log/nginx/access.log;
+# root /var/www/html/public;
+
+# location ~ \.php$ {
+# try_files $uri =404;
+# fastcgi_split_path_info ^(.+\.php)(/.+)$;
+# fastcgi_pass php:9000;
+# fastcgi_index index.php;
+# include fastcgi_params;
+# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+# fastcgi_param PATH_INFO $fastcgi_path_info;
+# }
+# }
\ No newline at end of file
diff --git a/docker/etc/php/php.ini b/docker/etc/php/php.ini
new file mode 100755
index 0000000000000000000000000000000000000000..4f47c01f776b5b8260f81dc1182aadde2cb742d9
--- /dev/null
+++ b/docker/etc/php/php.ini
@@ -0,0 +1,29 @@
+; PHP Configuration
+
+;[Date]
+; Defines the default timezone used by the date functions
+; http://php.net/date.timezone
+;date.timezone =
+
+; Error handling
+;display_errors = Off
+
+; Xdebug
+; See https://xdebug.org/docs/all_settings
+
+;PHPStorm
+[Xdebug]
+xdebug.remote_enable=1
+xdebug.idekey=PHPSTORM
+xdebug.profiler_enable=0
+xdebug.max_nesting_level=700
+xdebug.remote_host=192.168.0.1 # your ip
+xdebug.remote_port=9000
+
+;Netbeans
+;[Xdebug]
+;xdebug.remote_enable=1
+;xdebug.remote_handler=dbgp
+;xdebug.remote_mode=req
+;xdebug.remote_host=192.168.0.1 # your ip
+;xdebug.remote_port=9000
\ No newline at end of file
diff --git a/docker/web/app/composer.json.dist b/docker/web/app/composer.json.dist
new file mode 100755
index 0000000000000000000000000000000000000000..1db4dfaa3462b234adc857e50981147d33ad38f1
--- /dev/null
+++ b/docker/web/app/composer.json.dist
@@ -0,0 +1,24 @@
+{
+ "require": {
+
+ },
+ "require-dev": {
+ "apigen/apigen": "dev-master",
+ "phpmd/phpmd": "@stable",
+ "phpunit/phpunit": "^7.0",
+ "roave/better-reflection": "dev-master",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\Acme\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "AppTest\\Acme\\": "test/"
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true
+}
\ No newline at end of file
diff --git a/docker/web/app/phpunit.xml.dist b/docker/web/app/phpunit.xml.dist
new file mode 100755
index 0000000000000000000000000000000000000000..7cd9c11cf829236d14f6a9aa55ca1d64394dc7ca
--- /dev/null
+++ b/docker/web/app/phpunit.xml.dist
@@ -0,0 +1,27 @@
+
+