Merge pull request #10 from SundownDEV/docker

Docker
pull/16/head
Raphael Cerveaux 2018-06-05 17:11:45 +02:00 committed by GitHub
commit 923854fa31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1327 additions and 32 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ node_modules
###> symfony/web-server-bundle ###
/.web-server-pid
###< symfony/web-server-bundle ###
/logs/

19
.travis.yml Normal file
View File

@ -0,0 +1,19 @@
sudo: required
env:
DOCKER_COMPOSE_VERSION: 1.16.1
services:
- docker
before_install:
- 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 -v
- docker -v
- mkdir symfony
script:
- docker-compose -f docker-compose.travis.yml up -d
- docker-compose -f docker-compose.travis.yml ps

View File

View File

@ -6,8 +6,10 @@
"ext-iconv": "*",
"api-platform/api-pack": "^1.1",
"doctrine/doctrine-fixtures-bundle": "^3.0",
"sensio/framework-extra-bundle": "^5.1",
"symfony/console": "^4.0",
"symfony/flex": "^1.0",
"symfony/form": "^4.0",
"symfony/framework-bundle": "^4.0",
"symfony/lts": "^4@dev",
"symfony/maker-bundle": "^1.4",

339
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "6fb85b3fa57133c433a33fb80ed9c9c6",
"content-hash": "390029222132b498c5dda4068ec3b022",
"packages": [
{
"name": "api-platform/api-pack",
@ -1821,6 +1821,75 @@
],
"time": "2017-10-23T01:57:42+00:00"
},
{
"name": "sensio/framework-extra-bundle",
"version": "v5.1.6",
"source": {
"type": "git",
"url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git",
"reference": "bf4940572e43af679aaa13be98f3446a1c237bd8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/bf4940572e43af679aaa13be98f3446a1c237bd8",
"reference": "bf4940572e43af679aaa13be98f3446a1c237bd8",
"shasum": ""
},
"require": {
"doctrine/common": "^2.2",
"symfony/config": "^3.3|^4.0",
"symfony/dependency-injection": "^3.3|^4.0",
"symfony/framework-bundle": "^3.3|^4.0",
"symfony/http-kernel": "^3.3|^4.0"
},
"require-dev": {
"doctrine/doctrine-bundle": "^1.6",
"doctrine/orm": "^2.5",
"symfony/browser-kit": "^3.3|^4.0",
"symfony/dom-crawler": "^3.3|^4.0",
"symfony/expression-language": "^3.3|^4.0",
"symfony/finder": "^3.3|^4.0",
"symfony/phpunit-bridge": "^3.3|^4.0",
"symfony/psr-http-message-bridge": "^0.3",
"symfony/security-bundle": "^3.3|^4.0",
"symfony/twig-bundle": "^3.3|^4.0",
"symfony/yaml": "^3.3|^4.0",
"twig/twig": "~1.12|~2.0",
"zendframework/zend-diactoros": "^1.3"
},
"suggest": {
"symfony/expression-language": "",
"symfony/psr-http-message-bridge": "To use the PSR-7 converters",
"symfony/security-bundle": ""
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "5.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Sensio\\Bundle\\FrameworkExtraBundle\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "This bundle provides a way to configure your controllers with annotations",
"keywords": [
"annotations",
"controllers"
],
"time": "2018-02-14T08:40:54+00:00"
},
{
"name": "symfony/asset",
"version": "v4.1.0",
@ -2542,6 +2611,87 @@
],
"time": "2018-05-02T19:08:56+00:00"
},
{
"name": "symfony/form",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/form.git",
"reference": "95f8237303e1f7101fee0e72d6ba630a3e4c5178"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/form/zipball/95f8237303e1f7101fee0e72d6ba630a3e4c5178",
"reference": "95f8237303e1f7101fee0e72d6ba630a3e4c5178",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/intl": "~3.4|~4.0",
"symfony/options-resolver": "~3.4|~4.0",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/property-access": "~3.4|~4.0"
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/dependency-injection": "<3.4",
"symfony/doctrine-bridge": "<3.4",
"symfony/framework-bundle": "<3.4",
"symfony/http-kernel": "<3.4",
"symfony/twig-bridge": "<3.4.5|<4.0.5,>=4.0"
},
"require-dev": {
"doctrine/collections": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/validator": "~3.4|~4.0",
"symfony/var-dumper": "~3.4|~4.0"
},
"suggest": {
"symfony/framework-bundle": "For templating with PHP.",
"symfony/security-csrf": "For protecting forms against CSRF attacks.",
"symfony/twig-bridge": "For templating with Twig.",
"symfony/validator": "For form validation."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Form\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Form Component",
"homepage": "https://symfony.com",
"time": "2018-05-30T07:26:09+00:00"
},
{
"name": "symfony/framework-bundle",
"version": "v4.1.0",
@ -2856,6 +3006,81 @@
],
"time": "2018-05-01T23:02:13+00:00"
},
{
"name": "symfony/intl",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/intl.git",
"reference": "e2a48225f7d525b23a6e34caaa7320205abcf179"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/intl/zipball/e2a48225f7d525b23a6e34caaa7320205abcf179",
"reference": "e2a48225f7d525b23a6e34caaa7320205abcf179",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-intl-icu": "~1.0"
},
"require-dev": {
"symfony/filesystem": "~3.4|~4.0"
},
"suggest": {
"ext-intl": "to use the component with locales other than \"en\""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Intl\\": ""
},
"classmap": [
"Resources/stubs"
],
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
},
{
"name": "Eriksen Costa",
"email": "eriksen.costa@infranology.com.br"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
"homepage": "https://symfony.com",
"keywords": [
"i18n",
"icu",
"internationalization",
"intl",
"l10n",
"localization"
],
"time": "2018-05-30T07:26:09+00:00"
},
{
"name": "symfony/lts",
"version": "dev-master",
@ -3014,6 +3239,60 @@
],
"time": "2018-05-17T19:26:29+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "9b9ab6043c57c8c5571bc846e6ebfd27dff3b589"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/9b9ab6043c57c8c5571bc846e6ebfd27dff3b589",
"reference": "9b9ab6043c57c8c5571bc846e6ebfd27dff3b589",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony OptionsResolver Component",
"homepage": "https://symfony.com",
"keywords": [
"config",
"configuration",
"options"
],
"time": "2018-05-30T07:26:09+00:00"
},
{
"name": "symfony/orm-pack",
"version": "v1.0.5",
@ -3097,6 +3376,64 @@
],
"time": "2018-04-30T19:57:29+00:00"
},
{
"name": "symfony/polyfill-intl-icu",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-icu.git",
"reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/80ee17ae83c10cd513e5144f91a73607a21edb4e",
"reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"symfony/intl": "~2.3|~3.0|~4.0"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
}
},
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's ICU-related data and classes",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"icu",
"intl",
"polyfill",
"portable",
"shim"
],
"time": "2018-04-25T14:53:50+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.8.0",

View File

@ -13,4 +13,5 @@ return [
ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
];

38
docker-compose.travis.yml Normal file
View File

@ -0,0 +1,38 @@
version: '2'
services:
db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: symfony
MYSQL_USER: symfony
MYSQL_PASSWORD: symfony
php:
build: ./php-fpm
expose:
- "9000"
volumes:
- ./symfony:/var/www/symfony
- ./logs/symfony:/var/www/symfony/var/logs
links:
- db
nginx:
build: ./nginx
ports:
- "80:80"
links:
- php
volumes_from:
- php
volumes:
- ./logs/nginx/:/var/log/nginx
elk:
image: willdurand/elk
ports:
- "81:80"
volumes:
- ./elk/logstash:/etc/logstash
- ./elk/logstash/patterns:/opt/logstash/patterns
volumes_from:
- php
- nginx

53
docker-compose.yml Normal file
View File

@ -0,0 +1,53 @@
version: '2'
services:
db:
image: mysql
ports:
- "3311:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: symfony
MYSQL_USER: symfony
MYSQL_PASSWORD: symfony
php:
build: ./docker/php-fpm
ports:
- "9001:9000"
#volumes:
# - ./symfony:/var/www/symfony:cached
# - ./logs/symfony:/var/www/symfony/var/logs:cached
links:
- db
nginx:
build: ./docker/nginx
ports:
- "81:80"
links:
- php
volumes_from:
- php
volumes:
- ./logs/nginx/:/var/log/nginx:cached
elk:
image: willdurand/elk
ports:
- "82:80"
volumes:
- ./docker/elk/logstash:/etc/logstash:cached
- ./docker/elk/logstash/patterns:/opt/logstash/patterns:cached
volumes_from:
- php
- nginx
react-app:
container_name: react-app
build:
context: .
dockerfile: ./docker/react/Dockerfile
volumes:
- '.:/usr/src/app'
- '/usr/src/app/node_modules'
ports:
- '3000:3000'
environment:
- NODE_ENV=development

View File

@ -0,0 +1,39 @@
input {
file {
type => "nginx_access"
path => "/var/log/nginx/symfony_access.log"
start_position => beginning
}
file {
type => "symfony_dev"
path => "/var/www/symfony/var/log/dev.log"
start_position => beginning
}
file {
type => "symfony_prod"
path => "/var/www/symfony/var/log/prod.log"
start_position => beginning
}
}
filter {
if [type] == "nginx_access" {
grok {
patterns_dir => "./patterns"
match => { "message" => "%{NGINXACCESS}"}
}
}
else if [type] in ["symfony_dev", "symfony_prod"] {
grok {
patterns_dir => "./patterns"
match => { "message" => "%{SYMFONY}"}
}
}
}
output {
elasticsearch {
host => "localhost"
cluster => "logstash"
}
}

View File

@ -0,0 +1,85 @@
USERNAME [a-zA-Z0-9._-]+
USER %{USERNAME}
INT (?:[+-]?(?:[0-9]+))
BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+)))
NUMBER (?:%{BASE10NUM})
BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))
BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b
POSINT \b(?:[1-9][0-9]*)\b
NONNEGINT \b(?:[0-9]+)\b
WORD \b\w+\b
NOTSPACE \S+
SPACE \s*
DATA .*?
GREEDYDATA .*
QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))
UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}
# Networking
MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})
CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})
WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})
COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})
IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?
IPV4 (?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])
IP (?:%{IPV6}|%{IPV4})
HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b)
HOST %{HOSTNAME}
IPORHOST (?:%{HOSTNAME}|%{IP})
HOSTPORT %{IPORHOST}:%{POSINT}
# paths
PATH (?:%{UNIXPATH}|%{WINPATH})
UNIXPATH (?>/(?>[\w_%!$@:.,-]+|\\.)*)+
TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+))
WINPATH (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+
URIPROTO [A-Za-z]+(\+[A-Za-z+]+)?
URIHOST %{IPORHOST}(?::%{POSINT:port})?
# uripath comes loosely from RFC1738, but mostly from what Firefox
# doesn't turn into %XX
URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+
#URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)?
URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]*
URIPATHPARAM %{URIPATH}(?:%{URIPARAM})?
URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})?
# Months: January, Feb, 3, 03, 12, December
MONTH \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b
MONTHNUM (?:0?[1-9]|1[0-2])
MONTHNUM2 (?:0[1-9]|1[0-2])
MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])
# Days: Monday, Tue, Thu, etc...
DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)
# Years?
YEAR (?>\d\d){1,2}
HOUR (?:2[0123]|[01]?[0-9])
MINUTE (?:[0-5][0-9])
# '60' is a leap second in most time standards and thus is valid.
SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)
TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9])
# datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it)
DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR}
DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR}
ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE}))
ISO8601_SECOND (?:%{SECOND}|60)
TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
DATE %{DATE_US}|%{DATE_EU}
DATESTAMP %{DATE}[- ]%{TIME}
TZ (?:[PMCE][SD]T|UTC)
DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ}
DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE}
DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR}
DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND}
# Syslog Dates: Month Day HH:MM:SS
SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}
PROG (?:[\w._/%-]+)
SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])?
SYSLOGHOST %{IPORHOST}
SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}>
HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT}
# Shortcuts
QS %{QUOTEDSTRING}
# Log formats
SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}:
COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-)
COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent}
# Log Levels
LOGLEVEL ([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)

View File

@ -0,0 +1 @@
NGINXACCESS %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{URIPATHPARAM:request}(?: HTTP/%{NUMBER:httpversion})?|-)" %{NUMBER:response} (?:%{NUMBER:bytes}|-) "(?:%{URI:referrer}|-)" %{QS:agent} %{NUMBER:request_time} %{NUMBER:upstream_response_time} %{NUMBER:gzip_ratio} (?:%{WORD:cache_hit}|-)%{GREEDYDATA}

View File

@ -0,0 +1,34 @@
VERYGREEDYDATA (.|\n)*
SYMFONY_EXCEPTION [^:]*
SYMFONY_LOG_TYPE request|security|app|profiler|doctrine|event
SYMFONY_LOG_LEVEL DEBUG|INFO|WARNING|ERROR|CRITICAL|ALERT
SYMFONY_LOG %{SYMFONY_LOG_TYPE:log_type}\.%{SYMFONY_LOG_LEVEL:log_level}
SYMFONY_PARAMETER "[^"]*":( )?"[^"]*"
SYMFONY_PARAMETERS (%{SYMFONY_PARAMETER}(, )?)*
SYMFONY_CONTEXT {.*}
SYMFONY_REQUEST_METHOD GET|POST|PUT|DELETE|HEAD|OPTIONS|CONNECT
SYMFONY_REQUEST_PARAMETERS {"url":"%{GREEDYDATA:request_url}","ip":"%{IP:request_ip}","http_method":"%{SYMFONY_REQUEST_METHOD:request_method}"}
SYMFONY_REQUEST_INFO Matched route "%{GREEDYDATA:route}" \(parameters: %{SYMFONY_PARAMETERS:parameters}\)
SYMFONY_REQUEST_UNCAUGHT_EXCEPTION %{SYMFONY_EXCEPTION:exception}: %{VERYGREEDYDATA:exception_message} \(uncaught exception\) at %{VERYGREEDYDATA:exception_file} line %{NUMBER:exception_file_line}
SYMFONY_REQUEST_CRITICAL Exception thrown when handling an exception \(ErrorException: %{GREEDYDATA:exception_message} in %{GREEDYDATA:exception_file} line %{NUMBER:exception_file_line}\)
SYMFONY_SECURITY_WARNING_USER_MISSING Username "%{GREEDYDATA:user}" could not be found.
SYMFONY_SECURITY_INFO_USER_AUTHENTICATED User "%{GREEDYDATA:user}" has been authenticated successfully
SYMFONY_SECURITY_INFO_AUTHENTICATION_FAILED Authentication request failed: %{GREEDYDATA:authentication_fail_reason}
SYMFONY_SECURITY_DEBUG Username "%{GREEDYDATA:user}" was reloaded from user provider.
SYMFONY_EVENT_DEBUG_NOTIFICATION Notified event "%{GREEDYDATA:event}" to listener "%{GREEDYDATA:listener}".
SYMFONY_EVENT_DEBUG_PROPAGATION_STOP Listener "%{GREEDYDATA:listener}" stopped propagation of the event "%{GREEDYDATA:event}".
SYMFONY_DOCTRINE_DEBUG (?<=doctrine.DEBUG: ).*
SYMFONY_REQUEST %{SYMFONY_REQUEST_INFO}|%{SYMFONY_REQUEST_UNCAUGHT_EXCEPTION}|%{SYMFONY_REQUEST_CRITICAL}
SYMFONY_SECURITY %{SYMFONY_SECURITY_WARNING_USER_MISSING}|%{SYMFONY_SECURITY_INFO_USER_AUTHENTICATED}|%{SYMFONY_SECURITY_DEBUG}|%{SYMFONY_SECURITY_INFO_AUTHENTICATION_FAILED}
SYMFONY_EVENT %{SYMFONY_EVENT_DEBUG_NOTIFICATION}|%{SYMFONY_EVENT_DEBUG_PROPAGATION_STOP}
SYMFONY_DOCTRINE %{SYMFONY_DOCTRINE_DEBUG:doctrine_sql_query}
SYMFONY_VARIOUS_INFO Write SecurityContext in the session|Reloading user from user provider.|Read SecurityContext from the session|Populated SecurityContext with an anonymous Token|Access is denied (and user is neither anonymous, nor remember-me)|Unable to store the profiler information.|Remember-me cookie accepted.
SYMFONY_LOG_MESSAGE %{SYMFONY_REQUEST}|%{SYMFONY_SECURITY}|%{SYMFONY_EVENT}|%{SYMFONY_DOCTRINE}|%{SYMFONY_VARIOUS_INFO:log_various_info}|%{VERYGREEDYDATA:log_unparsed_message}
SYMFONY ^\[%{TIMESTAMP_ISO8601:date}\] %{SYMFONY_LOG}: %{SYMFONY_LOG_MESSAGE:log_message} (\[\]|%{SYMFONY_CONTEXT:log_context}) (\[\]|%{SYMFONY_REQUEST_PARAMETERS:log_request})

18
docker/nginx/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM alpine:3.6
MAINTAINER Vincent Composieux <vincent.composieux@gmail.com>
RUN apk add --update nginx
RUN rm -rf /var/cache/apk/* && rm -rf /tmp/*
ADD nginx.conf /etc/nginx/
ADD symfony.conf /etc/nginx/conf.d/
RUN echo "upstream php-upstream { server php:9001; }" > /etc/nginx/conf.d/upstream.conf
RUN adduser -D -g '' -G www-data www-data
CMD ["nginx"]
EXPOSE 80
EXPOSE 443

29
docker/nginx/nginx.conf Normal file
View File

@ -0,0 +1,29 @@
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 2048;
multi_accept on;
use epoll;
}
http {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 15;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log off;
error_log off;
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
open_file_cache max=100;
}
daemon off;

23
docker/nginx/symfony.conf Normal file
View File

@ -0,0 +1,23 @@
server {
server_name localhost;
root /var/www/symfony/public;
location / {
try_files $uri @rewriteapp;
}
location @rewriteapp {
rewrite ^(.*)$ /index.php/$1 last;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass php-upstream;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
error_log /var/log/nginx/symfony_error.log;
access_log /var/log/nginx/symfony_access.log;
}

44
docker/php-fpm/Dockerfile Normal file
View File

@ -0,0 +1,44 @@
FROM alpine:3.6
LABEL maintainer="Vincent Composieux <vincent.composieux@gmail.com>"
RUN apk add --update \
php7-fpm \
php7-apcu \
php7-ctype \
php7-curl \
php7-dom \
php7-gd \
php7-iconv \
php7-imagick \
php7-json \
php7-intl \
php7-mcrypt \
php7-mbstring \
php7-opcache \
php7-openssl \
php7-pdo \
php7-pdo_mysql \
php7-mysqli \
php7-xml \
php7-zlib \
php7-phar \
php7-tokenizer \
php7-session \
php7-simplexml \
make \
curl
RUN rm -rf /var/cache/apk/* && rm -rf /tmp/*
RUN curl --insecure https://getcomposer.org/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer
ADD symfony.ini /etc/php7/php-fpm.d/
ADD symfony.ini /etc/php7/cli/conf.d/
ADD symfony.pool.conf /etc/php7/php-fpm.d/
CMD ["php-fpm7", "-F"]
WORKDIR /var/www/symfony
EXPOSE 9000

View File

@ -0,0 +1 @@
date.timezone = UTC

View File

@ -0,0 +1,81 @@
; Start a new pool named 'symfony'.
; the variable $pool can be used in any directive and will be replaced by the
; pool name ('symfony' here)
[symfony]
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = nobody
group = nobody
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses on a
; specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = 0.0.0.0:9001
; Choose how the process manager will control the number of child processes.
; Possible Values:
; static - a fixed number (pm.max_children) of child processes;
; dynamic - the number of child processes are set dynamically based on the
; following directives. With this process management, there will be
; always at least 1 children.
; pm.max_children - the maximum number of children that can
; be alive at the same time.
; pm.start_servers - the number of children created on startup.
; pm.min_spare_servers - the minimum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is less than this
; number then some children will be created.
; pm.max_spare_servers - the maximum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is greater than this
; number then some children will be killed.
; ondemand - no children are created at startup. Children will be forked when
; new requests will connect. The following parameter are used:
; pm.max_children - the maximum number of children that
; can be alive at the same time.
; pm.process_idle_timeout - The number of seconds after which
; an idle process will be killed.
; Note: This value is mandatory.
pm = dynamic
; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 20
; The number of child processes created on startup.
; Note: Used only when pm is set to 'dynamic'
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
pm.start_servers = 2
; The desired minimum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.min_spare_servers = 1
; The desired maximum number of idle server processes.
; Note: Used only when pm is set to 'dynamic'
; Note: Mandatory when pm is set to 'dynamic'
pm.max_spare_servers = 3
;---------------------
; Make specific Docker environment variables available to PHP
env[DB_1_ENV_MYSQL_DATABASE] = $DB_1_ENV_MYSQL_DATABASE
env[DB_1_ENV_MYSQL_USER] = $DB_1_ENV_MYSQL_USER
env[DB_1_ENV_MYSQL_PASSWORD] = $DB_1_ENV_MYSQL_PASSWORD
catch_workers_output = yes

17
docker/react/Dockerfile Normal file
View File

@ -0,0 +1,17 @@
# base image
FROM node:9.6.1
# set working directory
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
# add `/usr/src/app/node_modules/.bin` to $PATH
ENV PATH /usr/src/app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY client/package.json /usr/src/app/package.json
RUN npm install --silent
#RUN npm install react-scripts@1.1.1 -g --silent
# start app
CMD ["make", "front-run"]

View File

@ -0,0 +1,90 @@
<?php
namespace App\Controller;
use App\Entity\Question;
use App\Form\QuestionType;
use App\Repository\QuestionRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/question")
*/
class QuestionController extends Controller
{
/**
* @Route("/", name="question_index", methods="GET")
*/
public function index(QuestionRepository $questionRepository): Response
{
return $this->render('question/index.html.twig', ['questions' => $questionRepository->findAll()]);
}
/**
* @Route("/new", name="question_new", methods="GET|POST")
*/
public function new(Request $request): Response
{
$question = new Question();
$form = $this->createForm(QuestionType::class, $question);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($question);
$em->flush();
return $this->redirectToRoute('question_index');
}
return $this->render('question/new.html.twig', [
'question' => $question,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="question_show", methods="GET")
*/
public function show(Question $question): Response
{
return $this->render('question/show.html.twig', ['question' => $question]);
}
/**
* @Route("/{id}/edit", name="question_edit", methods="GET|POST")
*/
public function edit(Request $request, Question $question): Response
{
$form = $this->createForm(QuestionType::class, $question);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('question_edit', ['id' => $question->getId()]);
}
return $this->render('question/edit.html.twig', [
'question' => $question,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="question_delete", methods="DELETE")
*/
public function delete(Request $request, Question $question): Response
{
if ($this->isCsrfTokenValid('delete'.$question->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$em->remove($question);
$em->flush();
}
return $this->redirectToRoute('question_index');
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Controller;
use App\Entity\Response;
use App\Form\ResponseType;
use App\Repository\ResponseRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response as HttpResponse;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/response")
*/
class ResponseController extends Controller
{
/**
* @Route("/", name="response_index", methods="GET")
*/
public function index(ResponseRepository $responseRepository): HttpResponse
{
return $this->render('response/index.html.twig', ['responses' => $responseRepository->findAll()]);
}
/**
* @Route("/new", name="response_new", methods="GET|POST")
*/
public function new(Request $request): HttpResponse
{
$response = new Response();
$form = $this->createForm(ResponseType::class, $response);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($response);
$em->flush();
return $this->redirectToRoute('response_index');
}
return $this->render('response/new.html.twig', [
'response' => $response,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="response_show", methods="GET")
*/
public function show(Response $response): HttpResponse
{
return $this->render('response/show.html.twig', ['response' => $response]);
}
/**
* @Route("/{id}/edit", name="response_edit", methods="GET|POST")
*/
public function edit(Request $request, Response $response): HttpResponse
{
$form = $this->createForm(ResponseType::class, $response);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('response_edit', ['id' => $response->getId()]);
}
return $this->render('response/edit.html.twig', [
'response' => $response,
'form' => $form->createView(),
]);
}
/**
* @Route("/{id}", name="response_delete", methods="DELETE")
*/
public function delete(Request $request, Response $response): HttpResponse
{
if ($this->isCsrfTokenValid('delete'.$response->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$em->remove($response);
$em->flush();
}
return $this->redirectToRoute('response_index');
}
}

View File

@ -12,21 +12,26 @@ namespace App\DataFixtures;
use App\Entity\Question;
use App\Entity\Response;
use App\Repository\ResponseRepository;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class AppFixtures extends Fixture
{
private $container;
public function __construct()
public function __construct(ContainerInterface $container = null)
{
//
$this->container = $container;
}
public function load(ObjectManager $manager)
{
$this->loadQuestions($manager);
//$this->loadResponses($manager);
$this->loadResponses($manager);
}
private function loadQuestions(ObjectManager $manager)
@ -34,18 +39,15 @@ class AppFixtures extends Fixture
foreach ($this->getData() as $data) {
$question = new Question();
$question->setText($data['text']);
$question->setToken($data['token']);
$manager->persist($question);
foreach ($data['responses'] as $response) {
$newResponse = new Response();
$newResponse->setText($response['text']);
$newResponse->setQuestion($question->getId());
$newResponse->setQuestion($question);
$manager->persist($newResponse);
$question->addResponse($newResponse);
}
$manager->persist($question);
//$this->addReference($username, $user);
}
$manager->flush();
@ -53,35 +55,57 @@ class AppFixtures extends Fixture
private function loadResponses(ObjectManager $manager)
{
//
$container = $this->container->get('doctrine');
$responseRepository = $container->getRepository('App:Response');
$questionRepository = $container->getRepository('App:Question');
foreach ($this->getData() as $data) {
foreach ($data['responses'] as $response) {
if (null !== $response['child']) {
$newResponse = $responseRepository->findOneBy(['text' => $response['text']]);
$question = $questionRepository->findByToken($response['child']);
if (null !== $newResponse && null !== $question) {
$newResponse->setChild($question);
$manager->flush();
}
}
}
}
}
private function getData()
{
return [
[
"token" => "aNs9skL",
"text" => "ma question 1",
"responses" => [
[
"text" => "option1",
"child" => 1,
"child" => "0ks6dkP",
],
[
"text" => "option2",
"child" => null,
],
]
],
[
"token" => "0ks6dkP",
"text" => "ma question 2",
"responses" => [
[
"text" => "option1",
"child" => null,
],
[
"text" => "option2",
"child" => null,
],
[
"text" => "option3",
"child" => null,
],
]
]

View File

@ -6,18 +6,13 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Query;
use Symfony\Component\Validator\Constraints as Assert;
use ApiPlatform\Core\Annotation\ApiSubresource;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
/**
* @ApiResource()
* @ApiResource(
* collectionOperations={"get"={"method"="GET"}},
* itemOperations={"get"={"method"="GET"}}
* )
* @ORM\Table(name="question")
* @ORM\Entity(repositoryClass="App\Repository\QuestionRepository")
*/
@ -60,6 +55,11 @@ class Question
return $question;
}*/
public function __toString()
{
return $this->getText();
}
public function getId()
{
return $this->id;

View File

@ -9,7 +9,10 @@ use Symfony\Component\Validator\Constraints as Assert;
use ApiPlatform\Core\Annotation\ApiSubresource;
/**
* @ApiResource()
* @ApiResource(
* collectionOperations={"get"={"method"="GET"}},
* itemOperations={"get"={"method"="GET"}}
* )
* @ORM\Table(name="response")
* @ORM\Entity(repositoryClass="App\Repository\ResponseRepository")
*/
@ -36,6 +39,7 @@ class Response
/**
* @ORM\OneToOne(targetEntity="App\Entity\Question", cascade={"persist", "remove"})
* @ORM\JoinTable(name="question")
* @ApiSubresource()
*/
private $child;

25
src/Form/QuestionType.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace App\Form;
use App\Entity\Question;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class QuestionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('text')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Question::class,
]);
}
}

27
src/Form/ResponseType.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace App\Form;
use App\Entity\Response;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ResponseType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('text')
->add('question')
->add('child')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Response::class,
]);
}
}

View File

@ -19,22 +19,19 @@ class QuestionRepository extends ServiceEntityRepository
parent::__construct($registry, Question::class);
}
// /**
// * @return Question[] Returns an array of Question objects
// */
/*
public function findByExampleField($value)
/**
* @return Question[] Returns an array of Question objects
*/
public function findByToken($token)
{
return $this->createQueryBuilder('q')
->andWhere('q.exampleField = :val')
->setParameter('val', $value)
->orderBy('q.id', 'ASC')
->setMaxResults(10)
->andWhere('q.token = :token')
->setParameter('token', $token)
->setMaxResults(1)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Question

View File

@ -122,6 +122,15 @@
"psr/simple-cache": {
"version": "1.0.1"
},
"sensio/framework-extra-bundle": {
"version": "4.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "4.0",
"ref": "aaddfdf43cdecd4cf91f992052d76c2cadc04543"
}
},
"symfony/asset": {
"version": "v4.0.9"
},
@ -173,6 +182,9 @@
"ref": "cc1afd81841db36fbef982fe56b48ade6716fac4"
}
},
"symfony/form": {
"version": "v4.1.0"
},
"symfony/framework-bundle": {
"version": "3.3",
"recipe": {
@ -191,6 +203,9 @@
"symfony/inflector": {
"version": "v4.0.9"
},
"symfony/intl": {
"version": "v4.1.0"
},
"symfony/lts": {
"version": "4-dev"
},
@ -203,12 +218,18 @@
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
}
},
"symfony/options-resolver": {
"version": "v4.1.0"
},
"symfony/orm-pack": {
"version": "v1.0.5"
},
"symfony/polyfill-ctype": {
"version": "v1.8.0"
},
"symfony/polyfill-intl-icu": {
"version": "v1.8.0"
},
"symfony/polyfill-mbstring": {
"version": "v1.8.0"
},

View File

@ -0,0 +1,5 @@
<form method="post" action="{{ path('question_delete', {'id': question.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ question.id) }}">
<button class="btn">Delete</button>
</form>

View File

@ -0,0 +1,4 @@
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

View File

@ -0,0 +1,13 @@
{% extends 'base.html.twig' %}
{% block title %}Edit Question{% endblock %}
{% block body %}
<h1>Edit Question</h1>
{{ include('question/_form.html.twig', {'button_label': 'Update'}) }}
<a href="{{ path('question_index') }}">back to list</a>
{{ include('question/_delete_form.html.twig') }}
{% endblock %}

View File

@ -0,0 +1,37 @@
{% extends 'base.html.twig' %}
{% block title %}Question index{% endblock %}
{% block body %}
<h1>Question index</h1>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Text</th>
<th>Date</th>
<th>actions</th>
</tr>
</thead>
<tbody>
{% for question in questions %}
<tr>
<td>{{ question.id }}</td>
<td>{{ question.text }}</td>
<td>{{ question.date ? question.date|date('Y-m-d H:i:s') : '' }}</td>
<td>
<a href="{{ path('question_show', {'id': question.id}) }}">show</a>
<a href="{{ path('question_edit', {'id': question.id}) }}">edit</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="5">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ path('question_new') }}">Create new</a>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'base.html.twig' %}
{% block title %}New Question{% endblock %}
{% block body %}
<h1>Create new Question</h1>
{{ include('question/_form.html.twig') }}
<a href="{{ path('question_index') }}">back to list</a>
{% endblock %}

View File

@ -0,0 +1,30 @@
{% extends 'base.html.twig' %}
{% block title %}Question{% endblock %}
{% block body %}
<h1>Question</h1>
<table class="table">
<tbody>
<tr>
<th>Id</th>
<td>{{ question.id }}</td>
</tr>
<tr>
<th>Text</th>
<td>{{ question.text }}</td>
</tr>
<tr>
<th>Date</th>
<td>{{ question.date ? question.date|date('Y-m-d H:i:s') : '' }}</td>
</tr>
</tbody>
</table>
<a href="{{ path('question_index') }}">back to list</a>
<a href="{{ path('question_edit', {'id': question.id}) }}">edit</a>
{{ include('question/_delete_form.html.twig') }}
{% endblock %}

View File

@ -0,0 +1,5 @@
<form method="post" action="{{ path('response_delete', {'id': response.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ response.id) }}">
<button class="btn">Delete</button>
</form>

View File

@ -0,0 +1,4 @@
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

View File

@ -0,0 +1,13 @@
{% extends 'base.html.twig' %}
{% block title %}Edit Response{% endblock %}
{% block body %}
<h1>Edit Response</h1>
{{ include('response/_form.html.twig', {'button_label': 'Update'}) }}
<a href="{{ path('response_index') }}">back to list</a>
{{ include('response/_delete_form.html.twig') }}
{% endblock %}

View File

@ -0,0 +1,35 @@
{% extends 'base.html.twig' %}
{% block title %}Response index{% endblock %}
{% block body %}
<h1>Response index</h1>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Text</th>
<th>actions</th>
</tr>
</thead>
<tbody>
{% for response in responses %}
<tr>
<td>{{ response.id }}</td>
<td>{{ response.text }}</td>
<td>
<a href="{{ path('response_show', {'id': response.id}) }}">show</a>
<a href="{{ path('response_edit', {'id': response.id}) }}">edit</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="3">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ path('response_new') }}">Create new</a>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'base.html.twig' %}
{% block title %}New Response{% endblock %}
{% block body %}
<h1>Create new Response</h1>
{{ include('response/_form.html.twig') }}
<a href="{{ path('response_index') }}">back to list</a>
{% endblock %}

View File

@ -0,0 +1,26 @@
{% extends 'base.html.twig' %}
{% block title %}Response{% endblock %}
{% block body %}
<h1>Response</h1>
<table class="table">
<tbody>
<tr>
<th>Id</th>
<td>{{ response.id }}</td>
</tr>
<tr>
<th>Text</th>
<td>{{ response.text }}</td>
</tr>
</tbody>
</table>
<a href="{{ path('response_index') }}">back to list</a>
<a href="{{ path('response_edit', {'id': response.id}) }}">edit</a>
{{ include('response/_delete_form.html.twig') }}
{% endblock %}