├── .editorconfig
├── .gitattributes
├── .gitignore
├── LICENSE
├── Makefile
├── admin
├── .dockerignore
├── .env
├── .gitignore
├── Dockerfile
├── docker
│ └── nginx
│ │ └── conf.d
│ │ └── default.conf
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.js
│ ├── App.test.js
│ ├── index.js
│ ├── serviceWorker.js
│ └── setupTests.js
└── yarn.lock
├── api
├── .dockerignore
├── .env
├── .gitignore
├── .php_cs.dist
├── Dockerfile
├── bin
│ └── console
├── composer.json
├── composer.lock
├── config
│ ├── bootstrap.php
│ ├── bundles.php
│ ├── packages
│ │ ├── api_platform.yaml
│ │ ├── cache.yaml
│ │ ├── dev
│ │ │ ├── routing.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── doctrine.yaml
│ │ ├── doctrine_migrations.yaml
│ │ ├── framework.yaml
│ │ ├── mercure.yaml
│ │ ├── nelmio_cors.yaml
│ │ ├── prod
│ │ │ ├── api_platform.yaml
│ │ │ ├── doctrine.yaml
│ │ │ └── routing.yaml
│ │ ├── routing.yaml
│ │ ├── security.yaml
│ │ ├── test
│ │ │ ├── framework.yaml
│ │ │ ├── routing.yaml
│ │ │ ├── twig.yaml
│ │ │ ├── validator.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── twig.yaml
│ │ └── validator.yaml
│ ├── routes.yaml
│ ├── routes
│ │ ├── annotations.yaml
│ │ ├── api_platform.yaml
│ │ └── dev
│ │ │ ├── framework.yaml
│ │ │ ├── twig.yaml
│ │ │ └── web_profiler.yaml
│ └── services.yaml
├── docker
│ ├── nginx
│ │ └── conf.d
│ │ │ └── default.conf
│ ├── php
│ │ ├── conf.d
│ │ │ ├── api-platform.dev.ini
│ │ │ └── api-platform.prod.ini
│ │ ├── docker-entrypoint.sh
│ │ └── docker-healthcheck.sh
│ └── varnish
│ │ └── conf
│ │ └── default.vcl
├── helm
│ └── api
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── configmap.yaml
│ │ ├── ingress.yaml
│ │ ├── nginx-deployment.yaml
│ │ ├── nginx-service.yaml
│ │ ├── php-deployment.yaml
│ │ ├── php-service.yaml
│ │ ├── secrets.yaml
│ │ ├── serviceaccount.yaml
│ │ ├── tests
│ │ │ └── test-connection.yaml
│ │ ├── varnish-deployment.yaml
│ │ └── varnish-service.yaml
│ │ └── values.yaml
├── public
│ ├── favicon.ico
│ └── index.php
├── src
│ ├── Controller
│ │ └── .gitignore
│ ├── DataFixtures
│ │ └── AppFixtures.php
│ ├── Entity
│ │ ├── .gitignore
│ │ ├── Greeting.php
│ │ └── ProjectAuthor.php
│ ├── Kernel.php
│ ├── Migrations
│ │ ├── .gitignore
│ │ └── Version20200830163015.php
│ └── Repository
│ │ ├── .gitignore
│ │ └── ProjectAuthorRepository.php
├── symfony.lock
└── templates
│ └── base.html.twig
├── client
├── .dockerignore
├── .env
├── .gitignore
├── Dockerfile
├── docker
│ └── nginx
│ │ └── conf.d
│ │ └── default.conf
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── Welcome.js
│ ├── Welcome.test.js
│ ├── config
│ │ └── entrypoint.js
│ ├── index.js
│ ├── serviceWorker.js
│ ├── setupTests.js
│ └── welcome.css
└── yarn.lock
├── docker-compose.yml
├── docker
└── dev-tls
│ └── Dockerfile
└── github
└── img
├── admin-page-1.png
├── admin-page-2.png
├── admin-page-3.png
├── api-page-1.png
├── api-page-2.png
├── client-page.png
├── make-dev.png
├── make-rebuild-2.png
└── make-rebuild.png
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | # Change these settings to your own preference
9 | indent_style = space
10 | indent_size = 4
11 |
12 | # We recommend you to keep these unchanged
13 | end_of_line = lf
14 | charset = utf-8
15 | trim_trailing_whitespace = true
16 | insert_final_newline = true
17 |
18 | [*.feature]
19 | indent_style = space
20 | indent_size = 2
21 |
22 | [*.js]
23 | indent_style = space
24 | indent_size = 2
25 |
26 | [*.json]
27 | indent_style = space
28 | indent_size = 2
29 |
30 | [*.md]
31 | trim_trailing_whitespace = false
32 |
33 | [*.php]
34 | indent_style = space
35 | indent_size = 4
36 |
37 | [*.sh]
38 | indent_style = tab
39 | indent_size = 4
40 |
41 | [*.vcl]
42 | indent_style = space
43 | indent_size = 2
44 |
45 | [*.xml]
46 | indent_style = space
47 | indent_size = 4
48 |
49 | [*.{yaml,yml}]
50 | indent_style = space
51 | indent_size = 4
52 | trim_trailing_whitespace = false
53 |
54 | [api/helm/api/**.yaml]
55 | indent_style = space
56 | indent_size = 2
57 |
58 | [.github/workflows/*.yml]
59 | indent_style = space
60 | indent_size = 2
61 |
62 | [.gitmodules]
63 | indent_style = tab
64 | indent_size = 4
65 |
66 | [.php_cs{,.dist}]
67 | indent_style = space
68 | indent_size = 4
69 |
70 | [.travis.yml]
71 | indent_style = space
72 | indent_size = 2
73 |
74 | [composer.json]
75 | indent_style = space
76 | indent_size = 4
77 |
78 | [docker-compose{,.*}.{yaml,yml}]
79 | indent_style = space
80 | indent_size = 2
81 |
82 | [Dockerfile]
83 | indent_style = tab
84 | indent_size = 4
85 |
86 | [package.json]
87 | indent_style = space
88 | indent_size = 2
89 |
90 | [phpunit.xml{,.dist}]
91 | indent_style = space
92 | indent_size = 4
93 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
3 | *.conf text eol=lf
4 | *.html text eol=lf
5 | *.ini text eol=lf
6 | *.js text eol=lf
7 | *.json text eol=lf
8 | *.md text eol=lf
9 | *.php text eol=lf
10 | *.sh text eol=lf
11 | *.yaml text eol=lf
12 | *.yml text eol=lf
13 | bin/console text eol=lf
14 | composer.lock text eol=lf merge=ours
15 |
16 | *.ico binary
17 | *.png binary
18 |
19 | .github export-ignore
20 | .travis.yml export-ignore
21 | README.md export-ignore
22 | update-deps.sh export-ignore
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.env
2 | /docker-compose.override.yaml
3 | /docker-compose.override.yml
4 | docker/mysql/
5 | .docker
6 | .idea/
7 | .vscode
8 | vendor/
9 | *.psd
10 | *.zip
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Andy Ng (andy@pcinvent.com) at www.pcinvent.com
4 | http://linkedin.com/in/pcinvent
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # pls sort alphabetically
2 |
3 | default: dev
4 |
5 | dev: dockers
6 | @echo "\033[34mCopying Dev configuration files\033[0m"
7 |
8 | rebuild:
9 | docker ps -a -q | xargs -n 1 -P 8 -I {} docker stop {}
10 | docker builder prune --all --force
11 | docker-compose build
12 |
13 | dockers:
14 | # prevent timeout
15 | export DOCKER_CLIENT_TIMEOUT=120
16 | export COMPOSE_HTTP_TIMEOUT=12
17 | docker-compose up --remove-orphans
18 | # fixed known api platform php-fpm issue
19 | docker-compose exec php php-fpm -D
20 |
21 |
--------------------------------------------------------------------------------
/admin/.dockerignore:
--------------------------------------------------------------------------------
1 | **/*.log
2 | **/*.md
3 | **/._*
4 | **/.dockerignore
5 | **/.DS_Store
6 | **/.git/
7 | **/.gitattributes
8 | **/.gitignore
9 | **/.gitmodules
10 | **/docker-compose.*.yaml
11 | **/docker-compose.*.yml
12 | **/docker-compose.yaml
13 | **/docker-compose.yml
14 | **/Dockerfile
15 | **/Thumbs.db
16 | .editorconfig
17 | .env.*.local
18 | .env.local
19 | build/
20 | node_modules/
21 |
--------------------------------------------------------------------------------
/admin/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_API_ENTRYPOINT=https://localhost:8443
2 |
--------------------------------------------------------------------------------
/admin/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/admin/Dockerfile:
--------------------------------------------------------------------------------
1 | # https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
2 | # https://docs.docker.com/compose/compose-file/#target
3 |
4 |
5 | # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
6 | ARG NODE_VERSION=13
7 | ARG NGINX_VERSION=1.17
8 |
9 |
10 | # "development" stage
11 | FROM node:${NODE_VERSION}-alpine AS api_platform_admin_development
12 |
13 | WORKDIR /usr/src/admin
14 |
15 | # prevent the reinstallation of node modules at every changes in the source code
16 | COPY package.json yarn.lock ./
17 | RUN set -eux; \
18 | apk add --no-cache --virtual .gyp \
19 | g++ \
20 | make \
21 | python \
22 | ; \
23 | yarn install; \
24 | apk del .gyp
25 |
26 | COPY . ./
27 |
28 | VOLUME /usr/src/admin/node_modules
29 |
30 | ENV HTTPS true
31 |
32 | CMD ["yarn", "start"]
33 |
34 |
35 | # "build" stage
36 | # depends on the "development" stage above
37 | FROM api_platform_admin_development AS api_platform_admin_build
38 |
39 | ARG REACT_APP_API_ENTRYPOINT
40 |
41 | RUN set -eux; \
42 | yarn build
43 |
44 |
45 | # "nginx" stage
46 | # depends on the "build" stage above
47 | FROM nginx:${NGINX_VERSION}-alpine AS api_platform_admin_nginx
48 |
49 | COPY docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
50 |
51 | WORKDIR /usr/src/admin/build
52 |
53 | COPY --from=api_platform_admin_build /usr/src/admin/build ./
54 |
--------------------------------------------------------------------------------
/admin/docker/nginx/conf.d/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | root /usr/src/admin/build;
3 |
4 | location / {
5 | try_files $uri /index.html;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "admin",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@api-platform/admin": "^2.0.0",
7 | "@babel/runtime": "^7.0.0",
8 | "@testing-library/jest-dom": "^4.2.4",
9 | "@testing-library/react": "^9.3.2",
10 | "@testing-library/user-event": "^7.1.2",
11 | "react": "^16.12.0",
12 | "react-dom": "^16.12.0",
13 | "react-scripts": "^3.4.0"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": "react-app"
23 | },
24 | "browserslist": {
25 | "production": [
26 | ">0.2%",
27 | "not dead",
28 | "not op_mini all"
29 | ],
30 | "development": [
31 | "last 1 chrome version",
32 | "last 1 firefox version",
33 | "last 1 safari version"
34 | ]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/admin/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/admin/public/favicon.ico
--------------------------------------------------------------------------------
/admin/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | API Platform Admin
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/admin/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/admin/public/logo192.png
--------------------------------------------------------------------------------
/admin/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/admin/public/logo512.png
--------------------------------------------------------------------------------
/admin/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Admin",
3 | "name": "API Platform Admin",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/admin/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/admin/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { HydraAdmin } from '@api-platform/admin';
3 |
4 | export default () => ;
5 |
--------------------------------------------------------------------------------
/admin/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders loader', () => {
6 | const { getByText } = render();
7 | const divElement = getByText(/The page is loading, just a moment please/i);
8 | expect(divElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/admin/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import * as serviceWorker from './serviceWorker';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
8 | // If you want your app to work offline and load faster, you can change
9 | // unregister() to register() below. Note this comes with some pitfalls.
10 | // Learn more about service workers: https://bit.ly/CRA-PWA
11 | serviceWorker.unregister();
12 |
--------------------------------------------------------------------------------
/admin/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' }
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/admin/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/api/.dockerignore:
--------------------------------------------------------------------------------
1 | **/*.log
2 | **/*.md
3 | **/*.php~
4 | **/._*
5 | **/.dockerignore
6 | **/.DS_Store
7 | **/.git/
8 | **/.gitattributes
9 | **/.gitignore
10 | **/.gitmodules
11 | **/docker-compose.*.yaml
12 | **/docker-compose.*.yml
13 | **/docker-compose.yaml
14 | **/docker-compose.yml
15 | **/Dockerfile
16 | **/Thumbs.db
17 | .editorconfig
18 | .env.*.local
19 | .env.local
20 | .env.local.php
21 | .php_cs.cache
22 | bin/*
23 | !bin/console
24 | build/
25 | docker/db/data/
26 | helm/
27 | public/bundles/
28 | var/
29 | vendor/
30 |
--------------------------------------------------------------------------------
/api/.env:
--------------------------------------------------------------------------------
1 | # In all environments, the following files are loaded if they exist,
2 | # the latter taking precedence over the former:
3 | #
4 | # * .env contains default values for the environment variables needed by the app
5 | # * .env.local uncommitted file with local overrides
6 | # * .env.$APP_ENV committed environment-specific defaults
7 | # * .env.$APP_ENV.local uncommitted environment-specific overrides
8 | #
9 | # Real environment variables win over .env files.
10 | #
11 | # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
12 | #
13 | # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
14 | # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
15 |
16 | # API Platform distribution
17 | MERCURE_SUBSCRIBE_URL=https://localhost:1337/.well-known/mercure
18 | VARNISH_URL=http://cache-proxy
19 |
20 | ###> symfony/framework-bundle ###
21 | APP_ENV=dev
22 | APP_SECRET=!ChangeMe!
23 | TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
24 | TRUSTED_HOSTS='^api.dev.provetrade.com|api.staging.provetrade.com|api.provetrade.com|localhost|api$'
25 | ###< symfony/framework-bundle ###
26 |
27 | ###> doctrine/doctrine-bundle ###
28 | # Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
29 | # For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
30 | # For a MySQL database, use: "mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
31 | # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
32 | DATABASE_URL=mysql://api-platform:!ChangeMe!@db:3306/api?server_version=8
33 | ###< doctrine/doctrine-bundle ###
34 |
35 | ###> nelmio/cors-bundle ###
36 | CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$
37 | ###< nelmio/cors-bundle ###
38 |
39 | ###> symfony/mercure-bundle ###
40 | # See https://symfony.com/doc/current/mercure.html#configuration
41 | MERCURE_PUBLISH_URL=https://mercure/.well-known/mercure
42 | # The default token is signed with the secret key: !ChangeMe!
43 | MERCURE_JWT_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOltdfX0.Oo0yg7y4yMa1vr_bziltxuTCqb8JVHKxp-f_FwwOim0
44 | ###< symfony/mercure-bundle ###
45 |
--------------------------------------------------------------------------------
/api/.gitignore:
--------------------------------------------------------------------------------
1 | /docker/db/data
2 | /helm/api/charts
3 | /helm/api/Chart.lock
4 |
5 | ###> symfony/framework-bundle ###
6 | /.env.local
7 | /.env.local.php
8 | /.env.*.local
9 | /config/secrets/prod/prod.decrypt.private.php
10 | /public/bundles/
11 | /var/
12 | /vendor/
13 | ###< symfony/framework-bundle ###
14 |
15 | ###> friendsofphp/php-cs-fixer ###
16 | /.php_cs
17 | /.php_cs.cache
18 | ###< friendsofphp/php-cs-fixer ###
19 |
--------------------------------------------------------------------------------
/api/.php_cs.dist:
--------------------------------------------------------------------------------
1 | in(__DIR__)
5 | ->exclude('var')
6 | ;
7 |
8 | return PhpCsFixer\Config::create()
9 | ->setRules([
10 | '@Symfony' => true,
11 | 'array_syntax' => ['syntax' => 'short'],
12 | ])
13 | ->setFinder($finder)
14 | ;
15 |
--------------------------------------------------------------------------------
/api/Dockerfile:
--------------------------------------------------------------------------------
1 | # the different stages of this Dockerfile are meant to be built into separate images
2 | # https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
3 | # https://docs.docker.com/compose/compose-file/#target
4 |
5 |
6 | # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
7 | ARG PHP_VERSION=7.4
8 | ARG OPENRESTY_VERSION=1.15.8.3
9 | ARG VARNISH_VERSION=6.4
10 |
11 |
12 | # "php" stage
13 | FROM php:${PHP_VERSION}-fpm-alpine AS api_platform_php
14 |
15 | # persistent / runtime deps
16 | RUN apk add --no-cache \
17 | acl \
18 | fcgi \
19 | file \
20 | gettext \
21 | git \
22 | ;
23 |
24 | ARG APCU_VERSION=5.1.18
25 | RUN set -eux; \
26 | apk add --no-cache --virtual .\build-deps \
27 | $PHPIZE_DEPS \
28 | icu-dev \
29 | libzip-dev \
30 | zip \
31 | ; \
32 | docker-php-ext-configure zip; \
33 | docker-php-ext-install -j$(nproc) \
34 | intl \
35 | pdo_mysql \
36 | zip \
37 | ; \
38 | runDeps="$( \
39 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
40 | | tr ',' '\n' \
41 | | sort -u \
42 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
43 | )"; \
44 | apk add --no-cache --virtual .api-phpexts-rundeps $runDeps; \
45 | \
46 | apk del .build-deps
47 |
48 | COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
49 |
50 | RUN ln -s $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
51 | COPY docker/php/conf.d/api-platform.prod.ini $PHP_INI_DIR/conf.d/api-platform.ini
52 |
53 | RUN set -eux; \
54 | { \
55 | echo '[www]'; \
56 | echo 'ping.path = /ping'; \
57 | } | tee /usr/local/etc/php-fpm.d/docker-healthcheck.conf
58 |
59 | # https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
60 | ENV COMPOSER_ALLOW_SUPERUSER=1
61 | # install Symfony Flex globally to speed up download of Composer packages (parallelized prefetching)
62 | RUN set -eux; \
63 | composer global require "symfony/flex" --prefer-dist --no-progress --no-suggest --classmap-authoritative; \
64 | composer clear-cache
65 | ENV PATH="${PATH}:/root/.composer/vendor/bin"
66 |
67 | WORKDIR /srv/api
68 |
69 | # build for production
70 | ARG APP_ENV=prod
71 |
72 | # prevent the reinstallation of vendors at every changes in the source code
73 | COPY composer.json composer.lock symfony.lock ./
74 | RUN set -eux; \
75 | composer install --prefer-dist --no-dev --no-scripts --no-progress --no-suggest; \
76 | composer clear-cache
77 |
78 | # do not use .env files in production
79 | COPY .env ./
80 | RUN composer dump-env prod; \
81 | rm .env
82 |
83 | # copy only specifically what we need
84 | COPY bin bin/
85 | COPY config config/
86 | COPY public public/
87 | COPY src src/
88 |
89 | RUN set -eux; \
90 | mkdir -p var/cache var/log; \
91 | composer dump-autoload --classmap-authoritative --no-dev; \
92 | composer run-script --no-dev post-install-cmd; \
93 | chmod +x bin/console; sync
94 | VOLUME /srv/api/var
95 |
96 | COPY docker/php/docker-healthcheck.sh /usr/local/bin/docker-healthcheck
97 | RUN chmod +x /usr/local/bin/docker-healthcheck
98 |
99 | HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD ["docker-healthcheck"]
100 |
101 | COPY docker/php/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
102 | RUN chmod +x /usr/local/bin/docker-entrypoint
103 |
104 | ENTRYPOINT ["docker-entrypoint"]
105 | CMD ["php-fpm"]
106 |
107 |
108 | # "nginx" stage
109 | # depends on the "php" stage above
110 | # The OpenResty distribution of NGINX is only needed for Kubernetes compatiblity (dynamic upstream resolution)
111 | FROM openresty/openresty:${OPENRESTY_VERSION}-alpine AS api_platform_nginx
112 |
113 | RUN echo -e "env UPSTREAM;\n$(cat /usr/local/openresty/nginx/conf/nginx.conf)" > /usr/local/openresty/nginx/conf/nginx.conf
114 | COPY docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
115 |
116 | WORKDIR /srv/api/public
117 |
118 | COPY --from=api_platform_php /srv/api/public ./
119 |
120 |
121 | # "varnish" stage
122 | # does not depend on any of the above stages, but placed here to keep everything in one Dockerfile
123 | FROM varnish:${VARNISH_VERSION} AS api_platform_varnish
124 |
125 | COPY docker/varnish/conf/default.vcl /etc/varnish/default.vcl
126 |
127 | CMD ["varnishd", "-F", "-f", "/etc/varnish/default.vcl", "-p", "http_resp_hdr_len=65536", "-p", "http_resp_size=98304"]
128 |
--------------------------------------------------------------------------------
/api/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(['--env', '-e'], null, true)) {
23 | putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
24 | }
25 |
26 | if ($input->hasParameterOption('--no-debug', true)) {
27 | putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
28 | }
29 |
30 | require dirname(__DIR__).'/config/bootstrap.php';
31 |
32 | if ($_SERVER['APP_DEBUG']) {
33 | umask(0000);
34 |
35 | if (class_exists(Debug::class)) {
36 | Debug::enable();
37 | }
38 | }
39 |
40 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
41 | $application = new Application($kernel);
42 | $application->run($input);
43 |
--------------------------------------------------------------------------------
/api/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "license": "MIT",
3 | "require": {
4 | "php": "^7.2.5",
5 | "ext-ctype": "*",
6 | "ext-iconv": "*",
7 | "api-platform/api-pack": "^1.1",
8 | "doctrine/doctrine-migrations-bundle": "^2.0",
9 | "guzzlehttp/guzzle": "^6.3",
10 | "symfony/console": "5.0.*",
11 | "symfony/dotenv": "5.0.*",
12 | "symfony/flex": "^1.1",
13 | "symfony/framework-bundle": "5.0.*",
14 | "symfony/mercure-bundle": "^0.2",
15 | "symfony/yaml": "5.0.*"
16 | },
17 | "require-dev": {
18 | "api-platform/schema-generator": "^2.1",
19 | "doctrine/doctrine-fixtures-bundle": "^3.3",
20 | "symfony/maker-bundle": "^1.11",
21 | "symfony/profiler-pack": "^1.0"
22 | },
23 | "conflict": {
24 | "symfony/symfony": "*"
25 | },
26 | "replace": {
27 | "paragonie/random_compat": "2.*",
28 | "symfony/polyfill-ctype": "*",
29 | "symfony/polyfill-iconv": "*",
30 | "symfony/polyfill-php56": "*",
31 | "symfony/polyfill-php70": "*",
32 | "symfony/polyfill-php71": "*"
33 | },
34 | "autoload": {
35 | "psr-4": {
36 | "App\\": "src/"
37 | }
38 | },
39 | "autoload-dev": {
40 | "psr-4": {
41 | "App\\Tests\\": "tests/"
42 | }
43 | },
44 | "config": {
45 | "preferred-install": {
46 | "*": "dist"
47 | },
48 | "sort-packages": true
49 | },
50 | "scripts": {
51 | "auto-scripts": {
52 | "cache:clear": "symfony-cmd",
53 | "assets:install %PUBLIC_DIR%": "symfony-cmd"
54 | },
55 | "post-install-cmd": [
56 | "@auto-scripts"
57 | ],
58 | "post-update-cmd": [
59 | "@auto-scripts"
60 | ]
61 | },
62 | "extra": {
63 | "symfony": {
64 | "allow-contrib": false,
65 | "require": "5.0.*"
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/api/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | =1.2)
13 | if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) {
14 | (new Dotenv(false))->populate($env);
15 | } else {
16 | // load all the .env files
17 | (new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
18 | }
19 |
20 | $_SERVER += $_ENV;
21 | $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
22 | $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
23 | $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
24 |
--------------------------------------------------------------------------------
/api/config/bundles.php:
--------------------------------------------------------------------------------
1 | ['all' => true],
5 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
6 | Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
7 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
8 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
9 | ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
10 | Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
11 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
12 | Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
13 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
14 | Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
15 | ];
16 |
--------------------------------------------------------------------------------
/api/config/packages/api_platform.yaml:
--------------------------------------------------------------------------------
1 | api_platform:
2 | title: Hello API Platform
3 | version: 1.0.0
4 | mapping:
5 | paths: ['%kernel.project_dir%/src/Entity']
6 | patch_formats:
7 | json: ['application/merge-patch+json']
8 | swagger:
9 | versions: [3]
10 | # Mercure integration, remove if unwanted
11 | mercure:
12 | hub_url: '%env(MERCURE_SUBSCRIBE_URL)%'
13 |
--------------------------------------------------------------------------------
/api/config/packages/cache.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | cache:
3 | # Unique name of your app: used to compute stable namespaces for cache keys.
4 | #prefix_seed: your_vendor_name/app_name
5 |
6 | # The "app" cache stores to the filesystem by default.
7 | # The data in this cache should persist between deploys.
8 | # Other options include:
9 |
10 | # Redis
11 | #app: cache.adapter.redis
12 | #default_redis_provider: redis://localhost
13 |
14 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
15 | #app: cache.adapter.apcu
16 |
17 | # Namespaced pools use the above "app" backend by default
18 | #pools:
19 | #my.dedicated.cache: null
20 |
--------------------------------------------------------------------------------
/api/config/packages/dev/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: true
4 |
--------------------------------------------------------------------------------
/api/config/packages/dev/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: true
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler: { only_exceptions: false }
7 |
--------------------------------------------------------------------------------
/api/config/packages/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | dbal:
3 | url: '%env(resolve:DATABASE_URL)%'
4 |
5 | # IMPORTANT: You MUST configure your server version,
6 | # either here or in the DATABASE_URL env var (see .env file)
7 | server_version: '8'
8 | orm:
9 | auto_generate_proxy_classes: true
10 | naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
11 | auto_mapping: true
12 | mappings:
13 | App:
14 | is_bundle: false
15 | type: annotation
16 | dir: '%kernel.project_dir%/src/Entity'
17 | prefix: 'App\Entity'
18 | alias: App
19 |
--------------------------------------------------------------------------------
/api/config/packages/doctrine_migrations.yaml:
--------------------------------------------------------------------------------
1 | doctrine_migrations:
2 | dir_name: '%kernel.project_dir%/src/Migrations'
3 | # namespace is arbitrary but should be different from App\Migrations
4 | # as migrations classes should NOT be autoloaded
5 | namespace: DoctrineMigrations
6 |
--------------------------------------------------------------------------------
/api/config/packages/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | secret: '%env(APP_SECRET)%'
3 | #csrf_protection: true
4 | #http_method_override: true
5 |
6 | # Enables session support. Note that the session will ONLY be started if you read or write from it.
7 | # Remove or comment this section to explicitly disable session support.
8 | session:
9 | handler_id: null
10 | cookie_secure: auto
11 | cookie_samesite: lax
12 |
13 | #esi: true
14 | #fragments: true
15 | php_errors:
16 | log: true
17 |
--------------------------------------------------------------------------------
/api/config/packages/mercure.yaml:
--------------------------------------------------------------------------------
1 | mercure:
2 | enable_profiler: '%kernel.debug%'
3 | hubs:
4 | default:
5 | url: '%env(MERCURE_PUBLISH_URL)%'
6 | jwt: '%env(MERCURE_JWT_TOKEN)%'
7 |
--------------------------------------------------------------------------------
/api/config/packages/nelmio_cors.yaml:
--------------------------------------------------------------------------------
1 | nelmio_cors:
2 | defaults:
3 | origin_regex: true
4 | allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
5 | allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
6 | allow_headers: ['Content-Type', 'Authorization', 'Preload', 'Fields']
7 | expose_headers: ['Link']
8 | max_age: 3600
9 | paths:
10 | '^/': null
11 |
--------------------------------------------------------------------------------
/api/config/packages/prod/api_platform.yaml:
--------------------------------------------------------------------------------
1 | api_platform:
2 | # Varnish integration, remove if unwanted
3 | http_cache:
4 | invalidation:
5 | enabled: true
6 | varnish_urls: ['%env(VARNISH_URL)%']
7 | max_age: 0
8 | shared_max_age: 3600
9 | vary: ['Content-Type', 'Authorization', 'Origin']
10 | public: true
11 |
--------------------------------------------------------------------------------
/api/config/packages/prod/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | orm:
3 | auto_generate_proxy_classes: false
4 | metadata_cache_driver:
5 | type: pool
6 | pool: doctrine.system_cache_pool
7 | query_cache_driver:
8 | type: pool
9 | pool: doctrine.system_cache_pool
10 | result_cache_driver:
11 | type: pool
12 | pool: doctrine.result_cache_pool
13 |
14 | framework:
15 | cache:
16 | pools:
17 | doctrine.result_cache_pool:
18 | adapter: cache.app
19 | doctrine.system_cache_pool:
20 | adapter: cache.system
21 |
--------------------------------------------------------------------------------
/api/config/packages/prod/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: null
4 |
--------------------------------------------------------------------------------
/api/config/packages/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | utf8: true
4 |
--------------------------------------------------------------------------------
/api/config/packages/security.yaml:
--------------------------------------------------------------------------------
1 | security:
2 | # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
3 | providers:
4 | users_in_memory: { memory: null }
5 | firewalls:
6 | dev:
7 | pattern: ^/(_(profiler|wdt)|css|images|js)/
8 | security: false
9 | main:
10 | anonymous: lazy
11 | provider: users_in_memory
12 |
13 | # activate different ways to authenticate
14 | # https://symfony.com/doc/current/security.html#firewalls-authentication
15 |
16 | # https://symfony.com/doc/current/security/impersonating_user.html
17 | # switch_user: true
18 |
19 | # Easy way to control access for large sections of your site
20 | # Note: Only the *first* access control that matches will be used
21 | access_control:
22 | # - { path: ^/admin, roles: ROLE_ADMIN }
23 | # - { path: ^/profile, roles: ROLE_USER }
24 |
--------------------------------------------------------------------------------
/api/config/packages/test/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | test: true
3 | session:
4 | storage_id: session.storage.mock_file
5 |
--------------------------------------------------------------------------------
/api/config/packages/test/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: true
4 |
--------------------------------------------------------------------------------
/api/config/packages/test/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | strict_variables: true
3 |
--------------------------------------------------------------------------------
/api/config/packages/test/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | not_compromised_password: false
4 |
--------------------------------------------------------------------------------
/api/config/packages/test/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: false
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler: { collect: false }
7 |
--------------------------------------------------------------------------------
/api/config/packages/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | default_path: '%kernel.project_dir%/templates'
3 |
--------------------------------------------------------------------------------
/api/config/packages/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | email_validation_mode: html5
4 |
5 | # Enables validator auto-mapping support.
6 | # For instance, basic validation constraints will be inferred from Doctrine's metadata.
7 | #auto_mapping:
8 | # App\Entity\: []
9 |
--------------------------------------------------------------------------------
/api/config/routes.yaml:
--------------------------------------------------------------------------------
1 | #index:
2 | # path: /
3 | # controller: App\Controller\DefaultController::index
4 |
--------------------------------------------------------------------------------
/api/config/routes/annotations.yaml:
--------------------------------------------------------------------------------
1 | controllers:
2 | resource: ../../src/Controller/
3 | type: annotation
4 |
5 | kernel:
6 | resource: ../../src/Kernel.php
7 | type: annotation
8 |
--------------------------------------------------------------------------------
/api/config/routes/api_platform.yaml:
--------------------------------------------------------------------------------
1 | api_platform:
2 | resource: .
3 | type: api_platform
4 |
--------------------------------------------------------------------------------
/api/config/routes/dev/framework.yaml:
--------------------------------------------------------------------------------
1 | _errors:
2 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
3 | prefix: /_error
4 |
--------------------------------------------------------------------------------
/api/config/routes/dev/twig.yaml:
--------------------------------------------------------------------------------
1 | _errors:
2 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
3 | prefix: /_error
4 |
--------------------------------------------------------------------------------
/api/config/routes/dev/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler_wdt:
2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
3 | prefix: /_wdt
4 |
5 | web_profiler_profiler:
6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
7 | prefix: /_profiler
8 |
--------------------------------------------------------------------------------
/api/config/services.yaml:
--------------------------------------------------------------------------------
1 | # This file is the entry point to configure your own services.
2 | # Files in the packages/ subdirectory configure your dependencies.
3 |
4 | # Put parameters here that don't need to change on each machine where the app is deployed
5 | # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
6 | parameters:
7 |
8 | services:
9 | # default configuration for services in *this* file
10 | _defaults:
11 | autowire: true # Automatically injects dependencies in your services.
12 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
13 |
14 | # makes classes in src/ available to be used as services
15 | # this creates a service per class whose id is the fully-qualified class name
16 | App\:
17 | resource: '../src/*'
18 | exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
19 |
20 | # controllers are imported separately to make sure services can be injected
21 | # as action arguments even if you don't extend any base controller class
22 | App\Controller\:
23 | resource: '../src/Controller'
24 | tags: ['controller.service_arguments']
25 |
26 | # add more service definitions when explicit configuration is needed
27 | # please note that last definitions always *replace* previous ones
28 |
--------------------------------------------------------------------------------
/api/docker/nginx/conf.d/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | root /srv/api/public;
3 |
4 | location / {
5 | # try to serve file directly, fallback to index.php
6 | try_files $uri /index.php$is_args$args;
7 | }
8 |
9 | location ~ ^/index\.php(/|$) {
10 | set_by_lua $upstream_host 'return os.getenv("UPSTREAM") or "php:9000"';
11 | fastcgi_pass $upstream_host;
12 | resolver local=on;
13 |
14 | # Increase the buffer size to handle large cache invalidation headers
15 | fastcgi_buffer_size 32k;
16 | fastcgi_buffers 32 4k;
17 |
18 | fastcgi_split_path_info ^(.+\.php)(/.*)$;
19 | include fastcgi_params;
20 |
21 | # When you are using symlinks to link the document root to the
22 | # current version of your application, you should pass the real
23 | # application path instead of the path to the symlink to PHP
24 | # FPM.
25 | # Otherwise, PHP's OPcache may not properly detect changes to
26 | # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
27 | # for more information).
28 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
29 | fastcgi_param DOCUMENT_ROOT $realpath_root;
30 | # Prevents URIs that include the front controller. This will 404:
31 | # http://domain.tld/index.php/some-path
32 | # Remove the internal directive to allow URIs like this
33 | internal;
34 | }
35 |
36 | # return 404 for all other php files not matching the front controller
37 | # this prevents access to other php files you don't want to be accessible.
38 | location ~ \.php$ {
39 | return 404;
40 | }
41 |
42 | # URL for health checks
43 | location /nginx-health {
44 | access_log off;
45 | default_type text/plain;
46 | return 200 "healthy\n";
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/api/docker/php/conf.d/api-platform.dev.ini:
--------------------------------------------------------------------------------
1 | apc.enable_cli = 1
2 | date.timezone = UTC
3 | session.auto_start = Off
4 | short_open_tag = Off
5 |
6 | # https://symfony.com/doc/current/performance.html
7 | opcache.interned_strings_buffer = 16
8 | opcache.max_accelerated_files = 20000
9 | opcache.memory_consumption = 256
10 | realpath_cache_size = 4096K
11 | realpath_cache_ttl = 600
12 |
--------------------------------------------------------------------------------
/api/docker/php/conf.d/api-platform.prod.ini:
--------------------------------------------------------------------------------
1 | apc.enable_cli = 1
2 | date.timezone = UTC
3 | session.auto_start = Off
4 | short_open_tag = Off
5 |
6 | # https://symfony.com/doc/current/performance.html
7 | opcache.interned_strings_buffer = 16
8 | opcache.max_accelerated_files = 20000
9 | opcache.memory_consumption = 256
10 | opcache.validate_timestamps = 0
11 | realpath_cache_size = 4096K
12 | realpath_cache_ttl = 600
13 |
--------------------------------------------------------------------------------
/api/docker/php/docker-entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | # first arg is `-f` or `--some-option`
5 | if [ "${1#-}" != "$1" ]; then
6 | set -- php-fpm "$@"
7 | fi
8 |
9 | if [ "$1" = 'php-fpm' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then
10 | PHP_INI_RECOMMENDED="$PHP_INI_DIR/php.ini-production"
11 | if [ "$APP_ENV" != 'prod' ]; then
12 | PHP_INI_RECOMMENDED="$PHP_INI_DIR/php.ini-development"
13 | fi
14 | ln -sf "$PHP_INI_RECOMMENDED" "$PHP_INI_DIR/php.ini"
15 |
16 | mkdir -p var/cache var/log
17 | setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var
18 | setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var
19 |
20 | if [ "$APP_ENV" != 'prod' ] && [ -f /certs/localCA.crt ]; then
21 | ln -sf /certs/localCA.crt /usr/local/share/ca-certificates/localCA.crt
22 | update-ca-certificates
23 | fi
24 |
25 | if [ "$APP_ENV" != 'prod' ]; then
26 | composer install --prefer-dist --no-progress --no-suggest --no-interaction
27 | fi
28 |
29 | echo "Waiting for db to be ready..."
30 | until bin/console doctrine:query:sql "SELECT 1" > /dev/null 2>&1; do
31 | sleep 1
32 | done
33 |
34 | if ls -A src/Migrations/*.php > /dev/null 2>&1; then
35 | bin/console doctrine:migrations:migrate --no-interaction
36 | fi
37 | fi
38 |
39 | exec docker-php-entrypoint "$@"
40 |
--------------------------------------------------------------------------------
/api/docker/php/docker-healthcheck.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | export SCRIPT_NAME=/ping
5 | export SCRIPT_FILENAME=/ping
6 | export REQUEST_METHOD=GET
7 |
8 | if cgi-fcgi -bind -connect 127.0.0.1:9000; then
9 | exit 0
10 | fi
11 |
12 | exit 1
13 |
--------------------------------------------------------------------------------
/api/docker/varnish/conf/default.vcl:
--------------------------------------------------------------------------------
1 | vcl 4.0;
2 |
3 | import std;
4 |
5 | backend default {
6 | .host = "api";
7 | .port = "80";
8 | # Health check
9 | #.probe = {
10 | # .url = "/";
11 | # .timeout = 5s;
12 | # .interval = 10s;
13 | # .window = 5;
14 | # .threshold = 3;
15 | #}
16 | }
17 |
18 | # Hosts allowed to send BAN requests
19 | acl invalidators {
20 | "localhost";
21 | "php";
22 | # local Kubernetes network
23 | "10.0.0.0"/8;
24 | "172.16.0.0"/12;
25 | "192.168.0.0"/16;
26 | }
27 |
28 | sub vcl_recv {
29 | if (req.restarts > 0) {
30 | set req.hash_always_miss = true;
31 | }
32 |
33 | # Remove the "Forwarded" HTTP header if exists (security)
34 | unset req.http.forwarded;
35 |
36 | # To allow API Platform to ban by cache tags
37 | if (req.method == "BAN") {
38 | if (client.ip !~ invalidators) {
39 | return (synth(405, "Not allowed"));
40 | }
41 |
42 | if (req.http.ApiPlatform-Ban-Regex) {
43 | ban("obj.http.Cache-Tags ~ " + req.http.ApiPlatform-Ban-Regex);
44 |
45 | return (synth(200, "Ban added"));
46 | }
47 |
48 | return (synth(400, "ApiPlatform-Ban-Regex HTTP header must be set."));
49 | }
50 |
51 | # For health checks
52 | if (req.method == "GET" && req.url == "/healthz") {
53 | return (synth(200, "OK"));
54 | }
55 | }
56 |
57 | sub vcl_hit {
58 | if (obj.ttl >= 0s) {
59 | # A pure unadulterated hit, deliver it
60 | return (deliver);
61 | }
62 |
63 | if (std.healthy(req.backend_hint)) {
64 | # The backend is healthy
65 | # Fetch the object from the backend
66 | return (restart);
67 | }
68 |
69 | # No fresh object and the backend is not healthy
70 | if (obj.ttl + obj.grace > 0s) {
71 | # Deliver graced object
72 | # Automatically triggers a background fetch
73 | return (deliver);
74 | }
75 |
76 | # No valid object to deliver
77 | # No healthy backend to handle request
78 | # Return error
79 | return (synth(503, "API is down"));
80 | }
81 |
82 | sub vcl_deliver {
83 | # Don't send cache tags related headers to the client
84 | unset resp.http.url;
85 | # Comment the following line to send the "Cache-Tags" header to the client (e.g. to use CloudFlare cache tags)
86 | unset resp.http.Cache-Tags;
87 | }
88 |
89 | sub vcl_backend_response {
90 | # Ban lurker friendly header
91 | set beresp.http.url = bereq.url;
92 |
93 | # Add a grace in case the backend is down
94 | set beresp.grace = 1h;
95 | }
96 |
--------------------------------------------------------------------------------
/api/helm/api/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/api/helm/api/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | appVersion: 0.1.0
3 | description: A Helm chart for an API Platform API
4 | name: api
5 | version: 0.1.0
6 | home: https://api-platform.com
7 | icon: https://api-platform.com/logo-250x250.png
8 | dependencies:
9 | - name: postgresql
10 | version: ~8.6.0
11 | repository: https://charts.bitnami.com/bitnami
12 | condition: postgresql.enabled
13 | - name: mercure
14 | version: ~3.0.0
15 | repository: https://kubernetes-charts.storage.googleapis.com/
16 | condition: mercure.enabled
17 |
--------------------------------------------------------------------------------
/api/helm/api/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | {{- $serviceName := "varnish" -}}
2 | {{- $service := .Values.varnish.service -}}
3 | {{- if not .Values.varnish.enabled -}}
4 | {{- $serviceName = print (include "api.fullname" .) "-" "nginx" -}}
5 | {{- $service = .Values.nginx.service -}}
6 | {{- end -}}
7 | 1. Get the application URL by running these commands:
8 | {{- if .Values.ingress.enabled }}
9 | {{- range $host := .Values.ingress.hosts }}
10 | {{- range .paths }}
11 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
12 | {{- end }}
13 | {{- end }}
14 | {{- else if contains "NodePort" $service.type }}
15 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ $serviceName }})
16 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
17 | echo http://$NODE_IP:$NODE_PORT
18 | {{- else if contains "LoadBalancer" $service.type }}
19 | NOTE: It may take a few minutes for the LoadBalancer IP to be available.
20 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "api.fullname" . }}'
21 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "api.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
22 | echo http://$SERVICE_IP:{{ $service.port }}
23 | {{- else if contains "ClusterIP" $service.type }}
24 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "api.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
25 | echo "Visit http://127.0.0.1:8080 to use your application"
26 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
27 | {{- end }}
28 |
--------------------------------------------------------------------------------
/api/helm/api/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/*
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "api.name" -}}
6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7 | {{- end -}}
8 |
9 | {{/*
10 | Create a default fully qualified app name.
11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12 | If release name contains chart name it will be used as a full name.
13 | */}}
14 | {{- define "api.fullname" -}}
15 | {{- if .Values.fullnameOverride -}}
16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
17 | {{- else -}}
18 | {{- $name := default .Chart.Name .Values.nameOverride -}}
19 | {{- if contains $name .Release.Name -}}
20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}}
21 | {{- else -}}
22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
23 | {{- end -}}
24 | {{- end -}}
25 | {{- end -}}
26 |
27 | {{/*
28 | Create chart name and version as used by the chart label.
29 | */}}
30 | {{- define "api.chart" -}}
31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
32 | {{- end -}}
33 |
34 | {{/*
35 | Common labels
36 | */}}
37 | {{- define "api.labels" -}}
38 | helm.sh/chart: {{ include "api.chart" . }}
39 | {{ include "api.selectorLabels" . }}
40 | {{- if .Chart.AppVersion }}
41 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
42 | {{- end }}
43 | app.kubernetes.io/managed-by: {{ .Release.Service }}
44 | app.kubernetes.io/part-of: {{ include "api.name" . }}
45 | {{- end -}}
46 |
47 | {{/*
48 | Selector labels
49 | */}}
50 | {{- define "api.selectorLabels" -}}
51 | app.kubernetes.io/name: {{ include "api.name" . }}{{- if .name -}}-{{- .name -}}{{- end }}
52 | app.kubernetes.io/instance: {{ .Release.Name }}
53 | {{- end -}}
54 |
55 | {{/*
56 | Create the name of the service account to use
57 | */}}
58 | {{- define "api.serviceAccountName" -}}
59 | {{- if .Values.serviceAccount.create -}}
60 | {{ default (include "api.fullname" .) .Values.serviceAccount.name }}
61 | {{- else -}}
62 | {{ default "default" .Values.serviceAccount.name }}
63 | {{- end -}}
64 | {{- end -}}
65 |
--------------------------------------------------------------------------------
/api/helm/api/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: {{ include "api.fullname" . }}
5 | labels:
6 | {{- include "api.labels" . | nindent 4 }}
7 | data:
8 | env: {{ .Values.php.env | quote }}
9 | debug: {{ .Values.php.debug | quote }}
10 | cors-allow-origin: {{ .Values.php.corsAllowOrigin | quote }}
11 | varnish-url: {{ if .Values.varnish.url }}{{ .Values.varnish.url | quote }}{{ else }}http://varnish{{ end }}
12 | trusted-hosts: {{ .Values.php.trustedHosts | quote }}
13 | trusted-proxies: {{ join "," .Values.php.trustedProxies }}
14 | mercure-publish-url: {{ .Values.mercure.publishUrl | quote }}
15 | mercure-subscribe-url: {{ .Values.mercure.subscribeUrl | quote }}
16 |
--------------------------------------------------------------------------------
/api/helm/api/templates/ingress.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.ingress.enabled -}}
2 | {{- $fullName := include "api.fullname" . -}}
3 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
4 | apiVersion: networking.k8s.io/v1beta1
5 | {{- else -}}
6 | apiVersion: extensions/v1beta1
7 | {{- end }}
8 | kind: Ingress
9 | metadata:
10 | name: {{ $fullName }}
11 | labels:
12 | {{- include "api.labels" . | nindent 4 }}
13 | {{- with .Values.ingress.annotations }}
14 | annotations:
15 | {{- toYaml . | nindent 4 }}
16 | {{- end }}
17 | spec:
18 | {{- if .Values.ingress.tls }}
19 | tls:
20 | {{- range .Values.ingress.tls }}
21 | - hosts:
22 | {{- range .hosts }}
23 | - {{ . | quote }}
24 | {{- end }}
25 | secretName: {{ .secretName }}
26 | {{- end }}
27 | {{- end }}
28 | rules:
29 | {{- range .Values.ingress.hosts }}
30 | - host: {{ .host | quote }}
31 | http:
32 | paths:
33 | {{- range .paths }}
34 | - path: {{ . }}
35 | backend:
36 | {{- if $.Values.varnish.enabled }}
37 | serviceName: {{ $fullName }}-varnish
38 | servicePort: {{ $.Values.varnish.service.port }}
39 | {{- else }}
40 | serviceName: {{ $fullName }}-nginx
41 | servicePort: {{ $.Values.nginx.service.port }}
42 | {{- end }}
43 | {{- end }}
44 | {{- end }}
45 | {{- end }}
46 |
--------------------------------------------------------------------------------
/api/helm/api/templates/nginx-deployment.yaml:
--------------------------------------------------------------------------------
1 | {{- $name := "nginx" -}}
2 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
3 | {{- $fullName := include "api.fullname" . -}}
4 | apiVersion: apps/v1
5 | kind: Deployment
6 | metadata:
7 | name: {{ $fullName }}-{{ $name }}
8 | labels:
9 | {{- include "api.labels" $data | nindent 4 }}
10 | spec:
11 | replicas: {{ .Values.nginx.replicaCount }}
12 | selector:
13 | matchLabels:
14 | {{- include "api.selectorLabels" $data | nindent 6 }}
15 | template:
16 | metadata:
17 | labels:
18 | {{- include "api.selectorLabels" $data | nindent 8 }}
19 | spec:
20 | {{- with .Values.imagePullSecrets }}
21 | imagePullSecrets:
22 | {{- toYaml . | nindent 8 }}
23 | {{- end }}
24 | serviceAccountName: {{ include "api.serviceAccountName" . }}
25 | securityContext:
26 | {{- toYaml .Values.podSecurityContext | nindent 8 }}
27 | containers:
28 | - name: {{ .Chart.Name }}-{{ $name }}
29 | securityContext:
30 | {{- toYaml .Values.securityContext | nindent 12 }}
31 | image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag | default .Chart.AppVersion }}"
32 | imagePullPolicy: {{ .Values.nginx.image.pullPolicy }}
33 | env:
34 | - name: UPSTREAM
35 | value: "{{ $fullName }}-php.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.php.service.port }}"
36 | ports:
37 | - name: http
38 | containerPort: 80
39 | protocol: TCP
40 | livenessProbe:
41 | httpGet:
42 | path: /nginx-health
43 | port: http
44 | readinessProbe:
45 | httpGet:
46 | path: /nginx-health
47 | port: http
48 | resources:
49 | {{- toYaml .Values.resources | nindent 12 }}
50 | {{- with .Values.nodeSelector }}
51 | nodeSelector:
52 | {{- toYaml . | nindent 8 }}
53 | {{- end }}
54 | {{- with .Values.affinity }}
55 | affinity:
56 | {{- toYaml . | nindent 8 }}
57 | {{- end }}
58 | {{- with .Values.tolerations }}
59 | tolerations:
60 | {{- toYaml . | nindent 8 }}
61 | {{- end }}
62 |
--------------------------------------------------------------------------------
/api/helm/api/templates/nginx-service.yaml:
--------------------------------------------------------------------------------
1 | {{- $name := "nginx" -}}
2 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | # /!\ To be reachable by Varnish, the service name MUST be hardcoded.
7 | # /!\ To deploy several instances in the same namespace you MUST rename the service here and in api/docker/varnish/conf/default.vcl
8 | name: {{ if .Values.varnish.enabled }}api{{ else }}{{ include "api.fullname" . }}-{{ $name }}{{ end }}
9 | labels:
10 | {{- include "api.labels" $data | nindent 4 }}
11 | spec:
12 | type: {{ .Values.nginx.service.type }}
13 | ports:
14 | - port: {{ .Values.nginx.service.port }}
15 | targetPort: http
16 | protocol: TCP
17 | name: http
18 | selector:
19 | {{- include "api.selectorLabels" $data | nindent 4 }}
20 |
--------------------------------------------------------------------------------
/api/helm/api/templates/php-deployment.yaml:
--------------------------------------------------------------------------------
1 | {{- $fullName := include "api.fullname" . -}}
2 | {{- $name := "php" -}}
3 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
4 | apiVersion: apps/v1
5 | kind: Deployment
6 | metadata:
7 | name: {{ $fullName }}-{{ $name }}
8 | labels:
9 | {{- include "api.labels" $data | nindent 4 }}
10 | spec:
11 | replicas: {{ .Values.php.replicaCount }}
12 | selector:
13 | matchLabels:
14 | {{- include "api.selectorLabels" $data | nindent 6 }}
15 | template:
16 | metadata:
17 | labels:
18 | {{- include "api.selectorLabels" $data | nindent 8 }}
19 | spec:
20 | {{- with .Values.imagePullSecrets }}
21 | imagePullSecrets:
22 | {{- toYaml . | nindent 8 }}
23 | {{- end }}
24 | serviceAccountName: {{ include "api.serviceAccountName" . }}
25 | securityContext:
26 | {{- toYaml .Values.podSecurityContext | nindent 8 }}
27 | initContainers:
28 | - name: init-php
29 | image: "{{ .Values.php.image.repository }}:{{ .Values.php.image.tag | default .Chart.AppVersion }}"
30 | command: ['/bin/bash', '-c']
31 | args: ['bin/console doctrine:migrations:migrate --no-interaction']
32 | env:
33 | - name: APP_DEBUG
34 | valueFrom:
35 | configMapKeyRef:
36 | name: {{ $fullName }}
37 | key: debug
38 | - name: APP_ENV
39 | valueFrom:
40 | configMapKeyRef:
41 | name: {{ $fullName }}
42 | key: env
43 | - name: DATABASE_URL
44 | valueFrom:
45 | secretKeyRef:
46 | name: {{ $fullName }}
47 | key: database-url
48 | containers:
49 | - name: {{ .Chart.Name }}-{{ $name }}
50 | image: "{{ .Values.php.image.repository }}:{{ .Values.php.image.tag | default .Chart.AppVersion }}"
51 | imagePullPolicy: {{ .Values.php.image.pullPolicy }}
52 | env:
53 | - name: TRUSTED_HOSTS
54 | valueFrom:
55 | configMapKeyRef:
56 | name: {{ $fullName }}
57 | key: trusted-hosts
58 | - name: TRUSTED_PROXIES
59 | valueFrom:
60 | configMapKeyRef:
61 | name: {{ $fullName }}
62 | key: trusted-proxies
63 | - name: APP_ENV
64 | valueFrom:
65 | configMapKeyRef:
66 | name: {{ $fullName }}
67 | key: env
68 | - name: APP_DEBUG
69 | valueFrom:
70 | configMapKeyRef:
71 | name: {{ $fullName }}
72 | key: debug
73 | - name: CORS_ALLOW_ORIGIN
74 | valueFrom:
75 | configMapKeyRef:
76 | name: {{ $fullName }}
77 | key: cors-allow-origin
78 | - name: VARNISH_URL
79 | valueFrom:
80 | configMapKeyRef:
81 | name: {{ $fullName }}
82 | key: varnish-url
83 | - name: APP_SECRET
84 | valueFrom:
85 | secretKeyRef:
86 | name: {{ $fullName }}
87 | key: secret
88 | - name: DATABASE_URL
89 | valueFrom:
90 | secretKeyRef:
91 | name: {{ $fullName }}
92 | key: database-url
93 | - name: MERCURE_PUBLISH_URL
94 | valueFrom:
95 | configMapKeyRef:
96 | name: {{ $fullName }}
97 | key: mercure-publish-url
98 | - name: MERCURE_SUBSCRIBE_URL
99 | valueFrom:
100 | configMapKeyRef:
101 | name: {{ $fullName }}
102 | key: mercure-subscribe-url
103 | - name: MERCURE_JWT_TOKEN
104 | valueFrom:
105 | secretKeyRef:
106 | name: {{ $fullName }}
107 | key: mercure-jwt-token
108 | ports:
109 | - containerPort: 9000
110 | readinessProbe:
111 | tcpSocket:
112 | port: 9000
113 | initialDelaySeconds: 120
114 | periodSeconds: 3
115 | livenessProbe:
116 | tcpSocket:
117 | port: 9000
118 | initialDelaySeconds: 120
119 | periodSeconds: 3
120 | resources:
121 | {{- toYaml .Values.resources | nindent 12 }}
122 | {{- with .Values.nodeSelector }}
123 | nodeSelector:
124 | {{- toYaml . | nindent 8 }}
125 | {{- end }}
126 | {{- with .Values.affinity }}
127 | affinity:
128 | {{- toYaml . | nindent 8 }}
129 | {{- end }}
130 | {{- with .Values.tolerations }}
131 | tolerations:
132 | {{- toYaml . | nindent 8 }}
133 | {{- end }}
134 |
--------------------------------------------------------------------------------
/api/helm/api/templates/php-service.yaml:
--------------------------------------------------------------------------------
1 | {{- $name := "php" -}}
2 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | name: {{ include "api.fullname" . }}-{{ $name }}
7 | labels:
8 | {{- include "api.labels" $data | nindent 4 }}
9 | spec:
10 | type: {{ .Values.php.service.type }}
11 | ports:
12 | - port: {{ .Values.php.service.port }}
13 | selector:
14 | {{- include "api.selectorLabels" $data | nindent 4 }}
15 |
--------------------------------------------------------------------------------
/api/helm/api/templates/secrets.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: {{ include "api.fullname" . }}
5 | labels:
6 | {{- include "api.labels" . | nindent 4 }}
7 | type: Opaque
8 | data:
9 | {{- if .Values.postgresql.enabled }}
10 | {{- $postgresqlFullName := include "postgresql.fullname" . }}
11 | database-url: {{ printf "pgsql://%s:%s@%s-postgresql/%s?serverVersion=12" .Values.postgresql.postgresqlUsername .Values.postgresql.postgresqlPassword $postgresqlFullName .Values.postgresql.postgresqlDatabase | b64enc | quote }}
12 | {{- else }}
13 | database-url: {{ .Values.postgresql.url | b64enc | quote }}
14 | {{- end }}
15 | secret: {{ .Values.php.secret | default (randAlphaNum 40) | b64enc | quote }}
16 | mercure-jwt-token: {{ .Values.php.mercure.jwtToken | b64enc | quote }}
17 |
--------------------------------------------------------------------------------
/api/helm/api/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.serviceAccount.create -}}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "api.serviceAccountName" . }}
6 | labels:
7 | {{- include "api.labels" . | nindent 4 }}
8 | {{- with .Values.serviceAccount.annotations }}
9 | annotations:
10 | {{- toYaml . | nindent 4 }}
11 | {{- end }}
12 | {{- end -}}
13 |
--------------------------------------------------------------------------------
/api/helm/api/templates/tests/test-connection.yaml:
--------------------------------------------------------------------------------
1 | {{- $fullName := include "api.fullname" . -}}
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: $fullName-test-connection
6 | labels:
7 | {{- include "api.labels" . | nindent 4 }}
8 | annotations:
9 | "helm.sh/hook": test-success
10 | spec:
11 | containers:
12 | - name: wget
13 | image: busybox
14 | command: ['wget']
15 | args: ['{{ if .Values.varnish.enabled }}{{ $fullName }}-varnish:{{ .Values.varnish.service.port }}{{ else }}{{ $fullName }}-nginx:{{ .Values.nginx.service.port }}{{ end }}']
16 | restartPolicy: Never
17 |
--------------------------------------------------------------------------------
/api/helm/api/templates/varnish-deployment.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.varnish.enabled -}}
2 | {{- $name := "varnish" -}}
3 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
4 | apiVersion: apps/v1
5 | kind: Deployment
6 | metadata:
7 | name: {{ include "api.fullname" . }}-{{ $name }}
8 | labels:
9 | {{- include "api.labels" $data | nindent 4 }}
10 | spec:
11 | replicas: {{ .Values.varnish.replicaCount }}
12 | selector:
13 | matchLabels:
14 | {{- include "api.selectorLabels" $data | nindent 6 }}
15 | template:
16 | metadata:
17 | labels:
18 | {{- include "api.selectorLabels" $data | nindent 8 }}
19 | spec:
20 | {{- with .Values.imagePullSecrets }}
21 | imagePullSecrets:
22 | {{- toYaml . | nindent 8 }}
23 | {{- end }}
24 | serviceAccountName: {{ include "api.serviceAccountName" . }}
25 | securityContext:
26 | {{- toYaml .Values.podSecurityContext | nindent 8 }}
27 | containers:
28 | - name: {{ .Chart.Name }}-{{ $name }}
29 | image: "{{ .Values.varnish.image.repository }}:{{ .Values.varnish.image.tag }}"
30 | imagePullPolicy: {{ .Values.varnish.image.pullPolicy }}
31 | command: ["varnishd"]
32 | args: ["-F", "-f", "/etc/varnish/default.vcl", "-p", "http_resp_hdr_len=65536", "-p", "http_resp_size=98304"]
33 | ports:
34 | - containerPort: 80
35 | livenessProbe:
36 | httpGet:
37 | path: /healthz
38 | port: 80
39 | readinessProbe:
40 | httpGet:
41 | path: /healthz
42 | port: 80
43 | resources:
44 | {{ toYaml .Values.resources | indent 12 }}
45 | {{- if .Values.nodeSelector }}
46 | nodeSelector:
47 | {{ toYaml .Values.nodeSelector | indent 8 }}
48 | {{- end }}
49 | {{- end -}}
50 |
--------------------------------------------------------------------------------
/api/helm/api/templates/varnish-service.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.varnish.enabled -}}
2 | {{- $name := "varnish" -}}
3 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
4 | apiVersion: v1
5 | kind: Service
6 | metadata:
7 | name: {{ include "api.fullname" . }}-{{ $name }}
8 | labels:
9 | {{- include "api.labels" $data | nindent 4 }}
10 | spec:
11 | type: {{ .Values.varnish.service.type }}
12 | ports:
13 | - port: {{ .Values.varnish.service.port }}
14 | targetPort: http
15 | protocol: TCP
16 | name: http
17 | selector:
18 | {{- include "api.selectorLabels" $data | nindent 4 }}
19 | {{- end -}}
20 |
--------------------------------------------------------------------------------
/api/helm/api/values.yaml:
--------------------------------------------------------------------------------
1 | # Default values for api.
2 | # This is a YAML-formatted file.
3 | # Declare variables to be passed into your templates.
4 |
5 | php:
6 | image:
7 | repository: quay.io/api-platform/php
8 | tag: latest
9 | pullPolicy: Always
10 | replicaCount: 1
11 | mercure:
12 | jwtToken: ""
13 | env: prod
14 | debug: '0'
15 | secret: ""
16 | corsAllowOrigin: "^https?://.*?\\.example\\.com$"
17 | trustedHosts: "^.*\\.example\\.com$"
18 | trustedProxies:
19 | - 10.0.0.0/8
20 | - 172.16.0.0/12
21 | - 192.168.0.0/16
22 | service:
23 | type: ClusterIP
24 | port: 9000
25 |
26 | nginx:
27 | image:
28 | repository: quay.io/api-platform/nginx
29 | tag: latest
30 | pullPolicy: Always
31 | replicaCount: 1
32 | service:
33 | type: ClusterIP
34 | port: 80
35 |
36 | varnish:
37 | enabled: false
38 | #url: https://example.com
39 | image:
40 | repository: quay.io/api-platform/varnish
41 | tag: latest
42 | pullPolicy: Always
43 | replicaCount: 1
44 | service:
45 | type: ClusterIP
46 | port: 80
47 |
48 | # Full configuration: https://github.com/bitnami/charts/tree/master/bitnami/postgresql
49 | postgresql:
50 | enabled: true
51 | imageTag: 12-alpine
52 | # If bringing your own PostgreSQL, the full uri to use
53 | url: pgsql://api-platform:!ChangeMe!@example.com/api?serverVersion=10.1
54 | postgresqlUsername: "example"
55 | postgresqlPassword: "!ChangeMe!"
56 | postgresqlDatabase: "api"
57 | # Persistent Volume Storage configuration.
58 | # ref: https://kubernetes.io/docs/user-guide/persistent-volumes
59 | persistence:
60 | enabled: false
61 | pullPolicy: Always
62 |
63 | # Full configuration: https://github.com/helm/charts/tree/master/stable/mercure
64 | mercure:
65 | enabled: true
66 | publishUrl: http://mercure/.well-known/mercure
67 | subscribeUrl: https://mercure.example.com/.well-known/mercure
68 | allowAnonymous: "1"
69 | corsAllowedOrigins: "^https?://.*?\\.example\\.com$"
70 | jwtKey: ""
71 | ingress:
72 | enabled: false
73 | hosts:
74 | - host: mercure.example.com
75 | paths: []
76 | tls: []
77 | # - secretName: mercure-example-tls
78 | # hosts:
79 | # - chart-example.local
80 |
81 | imagePullSecrets: []
82 | nameOverride: ""
83 | fullnameOverride: ""
84 |
85 | serviceAccount:
86 | # Specifies whether a service account should be created
87 | create: true
88 | # Annotations to add to the service account
89 | annotations: {}
90 | # The name of the service account to use.
91 | # If not set and create is true, a name is generated using the fullname template
92 | name:
93 |
94 | podSecurityContext: {}
95 | # fsGroup: 2000
96 |
97 | securityContext: {}
98 | # capabilities:
99 | # drop:
100 | # - ALL
101 | # readOnlyRootFilesystem: true
102 | # runAsNonRoot: true
103 | # runAsUser: 1000
104 |
105 | ingress:
106 | enabled: false
107 | annotations: {}
108 | # kubernetes.io/ingress.class: nginx
109 | # kubernetes.io/tls-acme: "true"
110 | hosts:
111 | - host: api.example.com
112 | paths: []
113 | tls: []
114 | # - secretName: api-example-tls
115 | # hosts:
116 | # - api.example.com
117 |
118 | resources: {}
119 | # We usually recommend not to specify default resources and to leave this as a conscious
120 | # choice for the user. This also increases chances charts run on environments with little
121 | # resources, such as Minikube. If you do want to specify resources, uncomment the following
122 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
123 | # limits:
124 | # cpu: 100m
125 | # memory: 128Mi
126 | # requests:
127 | # cpu: 100m
128 | # memory: 128Mi
129 |
130 | nodeSelector: {}
131 |
132 | tolerations: []
133 |
134 | affinity: {}
135 |
--------------------------------------------------------------------------------
/api/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/api/public/favicon.ico
--------------------------------------------------------------------------------
/api/public/index.php:
--------------------------------------------------------------------------------
1 | handle($request);
26 | $response->send();
27 | $kernel->terminate($request, $response);
28 |
--------------------------------------------------------------------------------
/api/src/Controller/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/api/src/Controller/.gitignore
--------------------------------------------------------------------------------
/api/src/DataFixtures/AppFixtures.php:
--------------------------------------------------------------------------------
1 | persist($product);
14 |
15 | $manager->flush();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/api/src/Entity/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/api/src/Entity/.gitignore
--------------------------------------------------------------------------------
/api/src/Entity/Greeting.php:
--------------------------------------------------------------------------------
1 | id;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/api/src/Entity/ProjectAuthor.php:
--------------------------------------------------------------------------------
1 | id;
35 | }
36 |
37 | public function getName(): ?string
38 | {
39 | return $this->name;
40 | }
41 |
42 | public function setName(string $name): self
43 | {
44 | $this->name = $name;
45 |
46 | return $this;
47 | }
48 |
49 | public function getEmail(): ?string
50 | {
51 | return $this->email;
52 | }
53 |
54 | public function setEmail(string $email): self
55 | {
56 | $this->email = $email;
57 |
58 | return $this;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/api/src/Kernel.php:
--------------------------------------------------------------------------------
1 | getProjectDir().'/config/bundles.php';
21 | foreach ($contents as $class => $envs) {
22 | if ($envs[$this->environment] ?? $envs['all'] ?? false) {
23 | yield new $class();
24 | }
25 | }
26 | }
27 |
28 | public function getProjectDir(): string
29 | {
30 | return \dirname(__DIR__);
31 | }
32 |
33 | protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
34 | {
35 | $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
36 | $container->setParameter('container.dumper.inline_class_loader', \PHP_VERSION_ID < 70400 || $this->debug);
37 | $container->setParameter('container.dumper.inline_factories', true);
38 | $confDir = $this->getProjectDir().'/config';
39 |
40 | $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
41 | $loader->load($confDir.'/{packages}/'.$this->environment.'/*'.self::CONFIG_EXTS, 'glob');
42 | $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
43 | $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
44 | }
45 |
46 | protected function configureRoutes(RouteCollectionBuilder $routes): void
47 | {
48 | $confDir = $this->getProjectDir().'/config';
49 |
50 | $routes->import($confDir.'/{routes}/'.$this->environment.'/*'.self::CONFIG_EXTS, '/', 'glob');
51 | $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob');
52 | $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob');
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/api/src/Migrations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/api/src/Migrations/.gitignore
--------------------------------------------------------------------------------
/api/src/Migrations/Version20200830163015.php:
--------------------------------------------------------------------------------
1 | abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
24 |
25 | $this->addSql('CREATE TABLE project_author (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
26 | $this->addSql('CREATE TABLE greeting (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
27 | }
28 |
29 | public function down(Schema $schema) : void
30 | {
31 | // this down() migration is auto-generated, please modify it to your needs
32 | $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
33 |
34 | $this->addSql('DROP TABLE project_author');
35 | $this->addSql('DROP TABLE greeting');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/api/src/Repository/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/api/src/Repository/.gitignore
--------------------------------------------------------------------------------
/api/src/Repository/ProjectAuthorRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('p')
29 | ->andWhere('p.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('p.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?ProjectAuthor
41 | {
42 | return $this->createQueryBuilder('p')
43 | ->andWhere('p.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/symfony.lock:
--------------------------------------------------------------------------------
1 | {
2 | "api-platform/api-pack": {
3 | "version": "v1.2.2"
4 | },
5 | "api-platform/core": {
6 | "version": "2.5",
7 | "recipe": {
8 | "repo": "github.com/symfony/recipes",
9 | "branch": "master",
10 | "version": "2.5",
11 | "ref": "a93061567140e386f107be75340ac2aee3f86cbf"
12 | },
13 | "files": [
14 | "config/packages/api_platform.yaml",
15 | "config/routes/api_platform.yaml",
16 | "src/Entity/.gitignore"
17 | ]
18 | },
19 | "api-platform/schema-generator": {
20 | "version": "v2.2.2"
21 | },
22 | "composer/semver": {
23 | "version": "1.5.1"
24 | },
25 | "composer/xdebug-handler": {
26 | "version": "1.4.1"
27 | },
28 | "doctrine/annotations": {
29 | "version": "1.0",
30 | "recipe": {
31 | "repo": "github.com/symfony/recipes",
32 | "branch": "master",
33 | "version": "1.0",
34 | "ref": "a2759dd6123694c8d901d0ec80006e044c2e6457"
35 | },
36 | "files": [
37 | "config/routes/annotations.yaml"
38 | ]
39 | },
40 | "doctrine/cache": {
41 | "version": "1.10.1"
42 | },
43 | "doctrine/collections": {
44 | "version": "1.6.5"
45 | },
46 | "doctrine/common": {
47 | "version": "2.13.1"
48 | },
49 | "doctrine/data-fixtures": {
50 | "version": "1.4.3"
51 | },
52 | "doctrine/dbal": {
53 | "version": "2.10.2"
54 | },
55 | "doctrine/doctrine-bundle": {
56 | "version": "2.0",
57 | "recipe": {
58 | "repo": "github.com/symfony/recipes",
59 | "branch": "master",
60 | "version": "2.0",
61 | "ref": "a9f2463b9f73efe74482f831f03a204a41328555"
62 | },
63 | "files": [
64 | "config/packages/doctrine.yaml",
65 | "config/packages/prod/doctrine.yaml",
66 | "src/Entity/.gitignore",
67 | "src/Repository/.gitignore"
68 | ]
69 | },
70 | "doctrine/doctrine-cache-bundle": {
71 | "version": "1.3.5"
72 | },
73 | "doctrine/doctrine-fixtures-bundle": {
74 | "version": "3.0",
75 | "recipe": {
76 | "repo": "github.com/symfony/recipes",
77 | "branch": "master",
78 | "version": "3.0",
79 | "ref": "e5b542d4ef47d8a003c91beb35650c76907f7e53"
80 | },
81 | "files": [
82 | "src/DataFixtures/AppFixtures.php"
83 | ]
84 | },
85 | "doctrine/doctrine-migrations-bundle": {
86 | "version": "1.2",
87 | "recipe": {
88 | "repo": "github.com/symfony/recipes",
89 | "branch": "master",
90 | "version": "1.2",
91 | "ref": "c1431086fec31f17fbcfe6d6d7e92059458facc1"
92 | },
93 | "files": [
94 | "config/packages/doctrine_migrations.yaml",
95 | "src/Migrations/.gitignore"
96 | ]
97 | },
98 | "doctrine/event-manager": {
99 | "version": "1.1.0"
100 | },
101 | "doctrine/inflector": {
102 | "version": "1.4.2"
103 | },
104 | "doctrine/instantiator": {
105 | "version": "1.3.0"
106 | },
107 | "doctrine/lexer": {
108 | "version": "1.2.1"
109 | },
110 | "doctrine/migrations": {
111 | "version": "2.2.1"
112 | },
113 | "doctrine/orm": {
114 | "version": "v2.7.3"
115 | },
116 | "doctrine/persistence": {
117 | "version": "1.3.7"
118 | },
119 | "doctrine/reflection": {
120 | "version": "1.2.1"
121 | },
122 | "doctrine/sql-formatter": {
123 | "version": "1.0.1"
124 | },
125 | "easyrdf/easyrdf": {
126 | "version": "0.9.1"
127 | },
128 | "fig/link-util": {
129 | "version": "1.1.1"
130 | },
131 | "friendsofphp/php-cs-fixer": {
132 | "version": "2.2",
133 | "recipe": {
134 | "repo": "github.com/symfony/recipes",
135 | "branch": "master",
136 | "version": "2.2",
137 | "ref": "cc05ab6abf6894bddb9bbd6a252459010ebe040b"
138 | },
139 | "files": [
140 | ".php_cs.dist"
141 | ]
142 | },
143 | "guzzlehttp/guzzle": {
144 | "version": "6.5.4"
145 | },
146 | "guzzlehttp/promises": {
147 | "version": "v1.3.1"
148 | },
149 | "guzzlehttp/psr7": {
150 | "version": "1.6.1"
151 | },
152 | "laminas/laminas-code": {
153 | "version": "3.4.1"
154 | },
155 | "laminas/laminas-eventmanager": {
156 | "version": "3.2.1"
157 | },
158 | "laminas/laminas-zendframework-bridge": {
159 | "version": "1.0.4"
160 | },
161 | "league/html-to-markdown": {
162 | "version": "4.9.1"
163 | },
164 | "nelmio/cors-bundle": {
165 | "version": "1.5",
166 | "recipe": {
167 | "repo": "github.com/symfony/recipes",
168 | "branch": "master",
169 | "version": "1.5",
170 | "ref": "6388de23860284db9acce0a7a5d9d13153bcb571"
171 | },
172 | "files": [
173 | "config/packages/nelmio_cors.yaml"
174 | ]
175 | },
176 | "nikic/php-parser": {
177 | "version": "v4.4.0"
178 | },
179 | "ocramius/package-versions": {
180 | "version": "1.8.0"
181 | },
182 | "ocramius/proxy-manager": {
183 | "version": "2.8.0"
184 | },
185 | "php": {
186 | "version": "7.4"
187 | },
188 | "php-cs-fixer/diff": {
189 | "version": "v1.3.0"
190 | },
191 | "phpdocumentor/reflection-common": {
192 | "version": "2.1.0"
193 | },
194 | "phpdocumentor/reflection-docblock": {
195 | "version": "5.1.0"
196 | },
197 | "phpdocumentor/type-resolver": {
198 | "version": "1.1.0"
199 | },
200 | "psr/cache": {
201 | "version": "1.0.1"
202 | },
203 | "psr/container": {
204 | "version": "1.0.0"
205 | },
206 | "psr/event-dispatcher": {
207 | "version": "1.0.0"
208 | },
209 | "psr/http-message": {
210 | "version": "1.0.1"
211 | },
212 | "psr/link": {
213 | "version": "1.0.0"
214 | },
215 | "psr/log": {
216 | "version": "1.1.3"
217 | },
218 | "ralouphie/getallheaders": {
219 | "version": "3.0.3"
220 | },
221 | "symfony/asset": {
222 | "version": "v5.0.8"
223 | },
224 | "symfony/cache": {
225 | "version": "v5.0.8"
226 | },
227 | "symfony/cache-contracts": {
228 | "version": "v2.1.2"
229 | },
230 | "symfony/config": {
231 | "version": "v5.0.8"
232 | },
233 | "symfony/console": {
234 | "version": "4.4",
235 | "recipe": {
236 | "repo": "github.com/symfony/recipes",
237 | "branch": "master",
238 | "version": "4.4",
239 | "ref": "ea8c0eda34fda57e7d5cd8cbd889e2a387e3472c"
240 | },
241 | "files": [
242 | "bin/console",
243 | "config/bootstrap.php"
244 | ]
245 | },
246 | "symfony/dependency-injection": {
247 | "version": "v5.0.8"
248 | },
249 | "symfony/doctrine-bridge": {
250 | "version": "v5.0.8"
251 | },
252 | "symfony/dotenv": {
253 | "version": "v5.0.8"
254 | },
255 | "symfony/error-handler": {
256 | "version": "v5.0.8"
257 | },
258 | "symfony/event-dispatcher": {
259 | "version": "v5.0.8"
260 | },
261 | "symfony/event-dispatcher-contracts": {
262 | "version": "v2.1.2"
263 | },
264 | "symfony/expression-language": {
265 | "version": "v5.0.8"
266 | },
267 | "symfony/filesystem": {
268 | "version": "v5.0.8"
269 | },
270 | "symfony/finder": {
271 | "version": "v5.0.8"
272 | },
273 | "symfony/flex": {
274 | "version": "1.0",
275 | "recipe": {
276 | "repo": "github.com/symfony/recipes",
277 | "branch": "master",
278 | "version": "1.0",
279 | "ref": "c0eeb50665f0f77226616b6038a9b06c03752d8e"
280 | },
281 | "files": [
282 | ".env"
283 | ]
284 | },
285 | "symfony/framework-bundle": {
286 | "version": "4.4",
287 | "recipe": {
288 | "repo": "github.com/symfony/recipes",
289 | "branch": "master",
290 | "version": "4.4",
291 | "ref": "36d3075b2b8e0c4de0e82356a86e4c4a4eb6681b"
292 | },
293 | "files": [
294 | "config/bootstrap.php",
295 | "config/packages/cache.yaml",
296 | "config/packages/framework.yaml",
297 | "config/packages/test/framework.yaml",
298 | "config/routes/dev/framework.yaml",
299 | "config/services.yaml",
300 | "public/index.php",
301 | "src/Controller/.gitignore",
302 | "src/Kernel.php"
303 | ]
304 | },
305 | "symfony/http-client": {
306 | "version": "v5.0.8"
307 | },
308 | "symfony/http-client-contracts": {
309 | "version": "v2.1.2"
310 | },
311 | "symfony/http-foundation": {
312 | "version": "v5.0.8"
313 | },
314 | "symfony/http-kernel": {
315 | "version": "v5.0.8"
316 | },
317 | "symfony/inflector": {
318 | "version": "v5.0.8"
319 | },
320 | "symfony/maker-bundle": {
321 | "version": "1.0",
322 | "recipe": {
323 | "repo": "github.com/symfony/recipes",
324 | "branch": "master",
325 | "version": "1.0",
326 | "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
327 | }
328 | },
329 | "symfony/mercure": {
330 | "version": "v0.4.0"
331 | },
332 | "symfony/mercure-bundle": {
333 | "version": "0.2",
334 | "recipe": {
335 | "repo": "github.com/symfony/recipes",
336 | "branch": "master",
337 | "version": "0.2",
338 | "ref": "a37d3438e4bd4f9f924c516996bc29e25f66b07e"
339 | },
340 | "files": [
341 | "config/packages/mercure.yaml"
342 | ]
343 | },
344 | "symfony/mime": {
345 | "version": "v5.0.8"
346 | },
347 | "symfony/options-resolver": {
348 | "version": "v5.0.8"
349 | },
350 | "symfony/polyfill-intl-idn": {
351 | "version": "v1.17.0"
352 | },
353 | "symfony/polyfill-mbstring": {
354 | "version": "v1.17.0"
355 | },
356 | "symfony/polyfill-php72": {
357 | "version": "v1.17.0"
358 | },
359 | "symfony/polyfill-php73": {
360 | "version": "v1.17.0"
361 | },
362 | "symfony/process": {
363 | "version": "v5.0.8"
364 | },
365 | "symfony/profiler-pack": {
366 | "version": "v1.0.4"
367 | },
368 | "symfony/property-access": {
369 | "version": "v5.0.8"
370 | },
371 | "symfony/property-info": {
372 | "version": "v5.0.8"
373 | },
374 | "symfony/routing": {
375 | "version": "4.2",
376 | "recipe": {
377 | "repo": "github.com/symfony/recipes",
378 | "branch": "master",
379 | "version": "4.2",
380 | "ref": "683dcb08707ba8d41b7e34adb0344bfd68d248a7"
381 | },
382 | "files": [
383 | "config/packages/prod/routing.yaml",
384 | "config/packages/routing.yaml",
385 | "config/routes.yaml"
386 | ]
387 | },
388 | "symfony/security-bundle": {
389 | "version": "4.4",
390 | "recipe": {
391 | "repo": "github.com/symfony/recipes",
392 | "branch": "master",
393 | "version": "4.4",
394 | "ref": "7b4408dc203049666fe23fabed23cbadc6d8440f"
395 | },
396 | "files": [
397 | "config/packages/security.yaml"
398 | ]
399 | },
400 | "symfony/security-core": {
401 | "version": "v5.0.8"
402 | },
403 | "symfony/security-csrf": {
404 | "version": "v5.0.8"
405 | },
406 | "symfony/security-guard": {
407 | "version": "v5.0.8"
408 | },
409 | "symfony/security-http": {
410 | "version": "v5.0.8"
411 | },
412 | "symfony/serializer": {
413 | "version": "v5.0.8"
414 | },
415 | "symfony/service-contracts": {
416 | "version": "v2.1.2"
417 | },
418 | "symfony/stopwatch": {
419 | "version": "v5.0.8"
420 | },
421 | "symfony/translation-contracts": {
422 | "version": "v2.1.2"
423 | },
424 | "symfony/twig-bridge": {
425 | "version": "v5.0.8"
426 | },
427 | "symfony/twig-bundle": {
428 | "version": "5.0",
429 | "recipe": {
430 | "repo": "github.com/symfony/recipes",
431 | "branch": "master",
432 | "version": "5.0",
433 | "ref": "fab9149bbaa4d5eca054ed93f9e1b66cc500895d"
434 | },
435 | "files": [
436 | "config/packages/test/twig.yaml",
437 | "config/packages/twig.yaml",
438 | "templates/base.html.twig"
439 | ]
440 | },
441 | "symfony/validator": {
442 | "version": "4.3",
443 | "recipe": {
444 | "repo": "github.com/symfony/recipes",
445 | "branch": "master",
446 | "version": "4.3",
447 | "ref": "d902da3e4952f18d3bf05aab29512eb61cabd869"
448 | },
449 | "files": [
450 | "config/packages/test/validator.yaml",
451 | "config/packages/validator.yaml"
452 | ]
453 | },
454 | "symfony/var-dumper": {
455 | "version": "v5.0.8"
456 | },
457 | "symfony/var-exporter": {
458 | "version": "v5.0.8"
459 | },
460 | "symfony/web-link": {
461 | "version": "v5.0.8"
462 | },
463 | "symfony/web-profiler-bundle": {
464 | "version": "3.3",
465 | "recipe": {
466 | "repo": "github.com/symfony/recipes",
467 | "branch": "master",
468 | "version": "3.3",
469 | "ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6"
470 | },
471 | "files": [
472 | "config/packages/dev/web_profiler.yaml",
473 | "config/packages/test/web_profiler.yaml",
474 | "config/routes/dev/web_profiler.yaml"
475 | ]
476 | },
477 | "symfony/yaml": {
478 | "version": "v5.0.8"
479 | },
480 | "twig/twig": {
481 | "version": "v3.0.3"
482 | },
483 | "webimpress/safe-writer": {
484 | "version": "2.0.1"
485 | },
486 | "webmozart/assert": {
487 | "version": "1.8.0"
488 | },
489 | "willdurand/negotiation": {
490 | "version": "v2.3.1"
491 | },
492 | "zendframework/zend-code": {
493 | "version": "3.4.1"
494 | },
495 | "zendframework/zend-eventmanager": {
496 | "version": "3.2.1"
497 | }
498 | }
499 |
--------------------------------------------------------------------------------
/api/templates/base.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% block title %}Welcome!{% endblock %}
6 | {% block stylesheets %}{% endblock %}
7 |
8 |
9 | {% block body %}{% endblock %}
10 | {% block javascripts %}{% endblock %}
11 |
12 |
13 |
--------------------------------------------------------------------------------
/client/.dockerignore:
--------------------------------------------------------------------------------
1 | **/*.log
2 | **/*.md
3 | **/._*
4 | **/.dockerignore
5 | **/.DS_Store
6 | **/.git/
7 | **/.gitattributes
8 | **/.gitignore
9 | **/.gitmodules
10 | **/docker-compose.*.yaml
11 | **/docker-compose.*.yml
12 | **/docker-compose.yaml
13 | **/docker-compose.yml
14 | **/Dockerfile
15 | **/Thumbs.db
16 | .editorconfig
17 | .env.*.local
18 | .env.local
19 | build/
20 | node_modules/
21 |
--------------------------------------------------------------------------------
/client/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_API_ENTRYPOINT=https://localhost:8443
2 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/client/Dockerfile:
--------------------------------------------------------------------------------
1 | # https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
2 | # https://docs.docker.com/compose/compose-file/#target
3 |
4 |
5 | # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
6 | ARG NODE_VERSION=13
7 | ARG NGINX_VERSION=1.17
8 |
9 |
10 | # "development" stage
11 | FROM node:${NODE_VERSION}-alpine AS api_platform_client_development
12 |
13 | WORKDIR /usr/src/client
14 |
15 | RUN yarn global add @api-platform/client-generator
16 |
17 | # prevent the reinstallation of node modules at every changes in the source code
18 | COPY package.json yarn.lock ./
19 | RUN set -eux; \
20 | yarn install
21 |
22 | COPY . ./
23 |
24 | VOLUME /usr/src/client/node_modules
25 |
26 | ENV HTTPS true
27 |
28 | CMD ["yarn", "start"]
29 |
30 |
31 | # "build" stage
32 | # depends on the "development" stage above
33 | FROM api_platform_client_development AS api_platform_client_build
34 |
35 | ARG REACT_APP_API_ENTRYPOINT
36 |
37 | RUN set -eux; \
38 | yarn build
39 |
40 |
41 | # "nginx" stage
42 | # depends on the "build" stage above
43 | FROM nginx:${NGINX_VERSION}-alpine AS api_platform_client_nginx
44 |
45 | COPY docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
46 |
47 | WORKDIR /usr/src/client/build
48 |
49 | COPY --from=api_platform_client_build /usr/src/client/build ./
50 |
--------------------------------------------------------------------------------
/client/docker/nginx/conf.d/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | root /usr/src/client/build;
3 |
4 | location / {
5 | try_files $uri /index.html;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@fortawesome/fontawesome-free": "^5.12.0",
7 | "@testing-library/jest-dom": "^4.2.4",
8 | "@testing-library/react": "^9.3.2",
9 | "@testing-library/user-event": "^7.1.2",
10 | "bootstrap": "^4.4.0",
11 | "connected-react-router": "^6.7.0",
12 | "lodash.get": "^4.4.2",
13 | "lodash.has": "^4.5.2",
14 | "lodash.mapvalues": "^4.6.0",
15 | "prop-types": "^15.6.2",
16 | "react": "^16.12.0",
17 | "react-dom": "^16.12.0",
18 | "react-redux": "^7.2.0",
19 | "react-router-dom": "^5.1.2",
20 | "react-scripts": "^3.4.0",
21 | "redux": "^4.0.1",
22 | "redux-form": "^8.3.0",
23 | "redux-thunk": "^2.3.0"
24 | },
25 | "scripts": {
26 | "start": "react-scripts start",
27 | "build": "react-scripts build",
28 | "test": "react-scripts test",
29 | "eject": "react-scripts eject"
30 | },
31 | "eslintConfig": {
32 | "extends": "react-app"
33 | },
34 | "browserslist": {
35 | "production": [
36 | ">0.2%",
37 | "not dead",
38 | "not op_mini all"
39 | ],
40 | "development": [
41 | "last 1 chrome version",
42 | "last 1 firefox version",
43 | "last 1 safari version"
44 | ]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | API Platform
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/client/public/logo192.png
--------------------------------------------------------------------------------
/client/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/client/public/logo512.png
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "API Platform App",
3 | "name": "API Platform App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client/src/Welcome.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './Welcome';
4 |
5 | test('renders API Platform title', () => {
6 | const { getByText } = render();
7 | const strongElement = getByText(/API Platform/i);
8 | expect(strongElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/client/src/config/entrypoint.js:
--------------------------------------------------------------------------------
1 | export const ENTRYPOINT = process.env.REACT_APP_API_ENTRYPOINT;
2 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { createStore, combineReducers, applyMiddleware } from 'redux';
4 | import { Provider } from 'react-redux';
5 | import thunk from 'redux-thunk';
6 | import { reducer as form } from 'redux-form';
7 | import { Route, Switch } from 'react-router-dom';
8 | import { createBrowserHistory } from 'history';
9 | import {
10 | ConnectedRouter,
11 | connectRouter,
12 | routerMiddleware
13 | } from 'connected-react-router';
14 | import 'bootstrap/dist/css/bootstrap.css';
15 | import '@fortawesome/fontawesome-free/css/all.css';
16 | import * as serviceWorker from './serviceWorker';
17 | // Import your reducers and routes here
18 | import Welcome from './Welcome';
19 |
20 | const history = createBrowserHistory();
21 | const store = createStore(
22 | combineReducers({
23 | router: connectRouter(history),
24 | form,
25 | /* Add your reducers here */
26 | }),
27 | applyMiddleware(routerMiddleware(history), thunk)
28 | );
29 |
30 | ReactDOM.render(
31 |
32 |
33 |
34 |
35 | {/* Add your routes here */}
36 | Not Found
} />
37 |
38 |
39 | ,
40 | document.getElementById('root')
41 | );
42 |
43 | // If you want your app to work offline and load faster, you can change
44 | // unregister() to register() below. Note this comes with some pitfalls.
45 | // Learn more about service workers: https://bit.ly/CRA-PWA
46 | serviceWorker.unregister();
47 |
--------------------------------------------------------------------------------
/client/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' }
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/client/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/client/src/welcome.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700|Roboto+Slab:300,700');
2 |
3 | body {
4 | margin: 0;
5 | }
6 |
7 | /***** GLOBAL *****/
8 |
9 | .welcome {
10 | height: 100vh;
11 | width: 100vw;
12 | text-align: center;
13 | color: #1d1e1c;
14 | font-family: 'Open Sans', sans-serif;
15 | font-size: 14px;
16 | overflow: auto;
17 | background-color: #ececec;
18 | }
19 |
20 | .welcome a {
21 | text-decoration: none;
22 | color: #38a9b4;
23 | font-weight: bold;
24 | }
25 |
26 | .welcome h1 {
27 | font-family: 'Roboto Slab', serif;
28 | font-weight: 300;
29 | font-size: 36px;
30 | margin: 0 0 10px;
31 | line-height: 30px;
32 | }
33 |
34 | .welcome h1 strong {
35 | font-weight: 700;
36 | color: #38a9b4;
37 | }
38 |
39 | .welcome h2 {
40 | text-transform: uppercase;
41 | font-size: 18px;
42 | font-weight: bold;
43 | margin: 25px 0 5px;
44 | }
45 |
46 | .welcome h3 {
47 | text-transform: uppercase;
48 | font-weight: 500;
49 | color: #38a9b4;
50 | font-size: 16px;
51 | margin: 0 0 5px;
52 | display: block;
53 | }
54 |
55 | /***** TOP *****/
56 |
57 | .welcome__top {
58 | background-color: #67cece;
59 | padding-bottom: 40px;
60 | }
61 |
62 | .welcome__flag {
63 | transform: rotate(30deg);
64 | position: fixed;
65 | right: -190px;
66 | top: 65px;
67 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.2);
68 | z-index: 5;
69 | }
70 |
71 | /***** MAIN *****/
72 |
73 | .welcome__main {
74 | box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
75 | 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.3);
76 | width: 80%;
77 | max-width: 1100px;
78 | margin-left: auto;
79 | margin-right: auto;
80 | transform: translateY(-50px);
81 | background-color: white;
82 | display: flex;
83 | }
84 |
85 | .main__aside {
86 | background-color: #afe5e5;
87 | width: 30%;
88 | position: relative;
89 | overflow: hidden;
90 | }
91 |
92 | .aside__circle,
93 | .main__aside svg {
94 | position: absolute;
95 | left: 50%;
96 | top: 50%;
97 | transform: translate(-50%, -50%);
98 | }
99 |
100 | .aside__circle {
101 | background-color: white;
102 | border-radius: 50%;
103 | width: 90%;
104 | height: 0;
105 | padding-bottom: 90%;
106 | }
107 |
108 | .aside__circle:after {
109 | content: '';
110 | width: 4px;
111 | left: calc(50% - 5px);
112 | top: -50%;
113 | position: absolute;
114 | height: 100%;
115 | background-color: #1d1e1c;
116 | }
117 |
118 | .main__aside svg {
119 | width: 100%;
120 | }
121 |
122 | .main__content {
123 | padding: 30px;
124 | text-align: left;
125 | flex: auto;
126 | }
127 | .other__bloc {
128 | display: inline-flex;
129 | align-items: center;
130 | border: 4px solid #afe5e5;
131 | padding: 10px 20px;
132 | margin: 10px 0;
133 | height: 170px;
134 | box-sizing: border-box;
135 | text-align: left;
136 | width: 40%;
137 | }
138 |
139 | .other__bloc:not(:last-of-type) {
140 | margin-right: 10px;
141 | }
142 |
143 | .other__bloc h3:not(:first-child) {
144 | margin-top: 15px;
145 | padding-top: 5px;
146 | }
147 |
148 | .other__circle {
149 | width: 110px;
150 | height: 110px;
151 | background-color: #afe5e5;
152 | border-radius: 50%;
153 | margin-right:20px;
154 | }
155 |
156 | .other__circle svg{
157 | width: 110px;
158 | }
159 |
160 | .buttons__group {
161 | display: inline-flex;
162 | vertical-align: center;
163 | }
164 |
165 | .buttons__group .buttons__or {
166 | width: 4px;
167 | position: relative;
168 | text-align:center;
169 | }
170 |
171 | .buttons__group .buttons__or:before {
172 | content: 'or';
173 | font-size: 12px;
174 | color: #aaa;
175 | line-height: 18px;
176 | position: absolute;
177 | border-radius: 50%;
178 | top: 50%;
179 | left: 50%;
180 | transform: translate(-50%, -50%);
181 | background-color: white;
182 | width: 18px;
183 | height: 18px;
184 | }
185 |
186 | .buttons__group .other__button:first-child {
187 | border-radius: 5px 0 0 5px;
188 | padding-right: 15px;
189 | }
190 |
191 | .buttons__group .other__button:last-child {
192 | border-radius: 0 5px 5px 0;
193 | padding-left: 15px;
194 | }
195 |
196 | a.other__button {
197 | background-color: #e0e1e2;
198 | font-size: 11px;
199 | color: #686e63;
200 | cursor: pointer;
201 | padding: 5px 10px;
202 | display: inline-block;
203 | transition: all ease 0.2s;
204 | text-transform: uppercase;
205 | }
206 |
207 | .other__button:hover {
208 | background-color: #afe5e5;
209 | color: #339ba5;
210 | }
211 |
212 | .main__button {
213 | display: inline-block;
214 | padding: 10px 50px 10px 10px;
215 | border: 3px solid #339ba5;
216 | font-size: 22px;
217 | color: #339ba5;
218 | text-transform: uppercase;
219 | margin: 15px 0;
220 | overflow: hidden;
221 | transition: all ease 0.3s;
222 | cursor: pointer;
223 | position: relative;
224 | }
225 |
226 | .main__button svg {
227 | position: absolute;
228 | right: 10px;
229 | top: 50%;
230 | transform: translateY(-50%);
231 | transition: transform ease 0.2s;
232 | }
233 |
234 | .main__button:hover {
235 | background-color: #afe5e5;
236 | }
237 |
238 | .main__button:hover svg {
239 | transform: translateY(-50%) rotate(35deg);
240 | }
241 |
242 | /***** HELP *****/
243 |
244 | .welcome__help {
245 | background-color: white;
246 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.2);
247 | padding: 10px;
248 | position: fixed;
249 | right: -5px;
250 | top: 50%;
251 | transform: translateY(-50%);
252 | border-radius: 5px;
253 | text-align: center;
254 | }
255 |
256 | .welcome__help h2 {
257 | color: #aaa;
258 | font-size: 12px;
259 | margin: 10px 0;
260 | }
261 |
262 | .help__circle {
263 | width: 36px;
264 | height: 36px;
265 | border-radius: 50%;
266 | border: 2px solid #ccc;
267 | display: block;
268 | margin: 10px auto;
269 | transition: all ease 0.2s;
270 | position:relative;
271 | }
272 |
273 | .help__circle svg {
274 | position:absolute;
275 | left: 50%;
276 | top: 50%;
277 | transform:translate(-50%, -50%);
278 | }
279 |
280 | .help__circle:hover {
281 | border-color: #67cece;
282 | background-color: #afe5e5;
283 | }
284 |
285 | /***** MEDIAS *****/
286 |
287 | @media (max-width: 1200px) {
288 | .main__aside,
289 | .welcome__help {
290 | display: none;
291 | }
292 | .main__content {
293 | width: 100%;
294 | text-align: center;
295 | padding: 20px;
296 | }
297 | }
298 |
299 | @media (max-width: 600px) {
300 | .welcome__main {
301 | width: calc(100% - 40px);
302 | }
303 | .welcome h1 {
304 | display: none;
305 | }
306 | .welcome__flag,
307 | .main__other {
308 | display: none;
309 | }
310 | .main__content {
311 | padding: 10px;
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.4'
2 |
3 | x-cache-from:
4 | - &api-cache-from
5 | cache_from:
6 | - ${NGINX_IMAGE:-quay.io/api-platform/nginx}
7 | - ${PHP_IMAGE:-quay.io/api-platform/php}
8 |
9 | services:
10 | php:
11 | build:
12 | context: ./api
13 | target: api_platform_php
14 | <<: *api-cache-from
15 | image: ${PHP_IMAGE:-quay.io/api-platform/php}
16 | healthcheck:
17 | interval: 10s
18 | timeout: 3s
19 | retries: 3
20 | start_period: 30s
21 | depends_on:
22 | - db
23 | - dev-tls
24 | volumes:
25 | - ./api:/srv/api:rw,cached
26 | - ./api/docker/php/conf.d/api-platform.dev.ini:/usr/local/etc/php/conf.d/api-platform.ini
27 | # if you develop on Linux, you may use a bind-mounted host directory instead
28 | # - ./api/var:/srv/api/var:rw
29 | - dev-certs:/certs:ro,nocopy
30 |
31 | api:
32 | build:
33 | context: ./api
34 | target: api_platform_nginx
35 | <<: *api-cache-from
36 | image: ${NGINX_IMAGE:-quay.io/api-platform/nginx}
37 | depends_on:
38 | - php
39 | volumes:
40 | - ./api/public:/srv/api/public:ro
41 |
42 | vulcain:
43 | image: dunglas/vulcain
44 | environment:
45 | - CERT_FILE=/certs/localhost.crt
46 | - KEY_FILE=/certs/localhost.key
47 | - UPSTREAM=http://api
48 | depends_on:
49 | - api
50 | - dev-tls
51 | volumes:
52 | - dev-certs:/certs:ro,nocopy
53 | ports:
54 | - target: 443
55 | published: 8443
56 | protocol: tcp
57 |
58 | db:
59 | image: mysql:8.0.19
60 | restart: always
61 | environment:
62 | - MYSQL_ROOT_PASSWORD=root
63 | - MYSQL_USER=api-platform
64 | - MYSQL_PASSWORD=!ChangeMe!
65 | - MYSQL_DATABASE=api
66 | volumes:
67 | - ./docker/mysql/data:/var/lib/mysql
68 | ports:
69 | - target: 3306
70 | published: 3306
71 | protocol: tcp
72 |
73 | mercure:
74 | image: dunglas/mercure
75 | environment:
76 | - ALLOW_ANONYMOUS=1
77 | - CERT_FILE=/certs/localhost.crt
78 | - CORS_ALLOWED_ORIGINS=*
79 | - DEMO=1
80 | - JWT_KEY=!ChangeMe!
81 | - KEY_FILE=/certs/localhost.key
82 | - PUBLISH_ALLOWED_ORIGINS=https://localhost:1337 # required for publishing from the demo page
83 | depends_on:
84 | - dev-tls
85 | volumes:
86 | - dev-certs:/certs:ro,nocopy
87 | ports:
88 | - target: 443
89 | published: 1337
90 | protocol: tcp
91 |
92 | client:
93 | build:
94 | context: ./client
95 | target: api_platform_client_development
96 | cache_from:
97 | - ${CLIENT_IMAGE:-quay.io/api-platform/client}
98 | image: ${CLIENT_IMAGE:-quay.io/api-platform/client}
99 | tty: true # https://github.com/facebook/create-react-app/issues/8688
100 | environment:
101 | - API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT=http://api
102 | - API_PLATFORM_CLIENT_GENERATOR_OUTPUT=src
103 | depends_on:
104 | - dev-tls
105 | volumes:
106 | - ./client:/usr/src/client:rw,cached
107 | - dev-certs:/usr/src/client/node_modules/webpack-dev-server/ssl:rw,nocopy
108 | ports:
109 | - target: 3000
110 | published: 443
111 | protocol: tcp
112 |
113 | admin:
114 | build:
115 | context: ./admin
116 | target: api_platform_admin_development
117 | cache_from:
118 | - ${ADMIN_IMAGE:-quay.io/api-platform/admin}
119 | image: ${ADMIN_IMAGE:-quay.io/api-platform/admin}
120 | tty: true # https://github.com/facebook/create-react-app/issues/8688
121 | depends_on:
122 | - dev-tls
123 | volumes:
124 | - ./admin:/usr/src/admin:rw,cached
125 | - dev-certs:/usr/src/admin/node_modules/webpack-dev-server/ssl:rw,nocopy
126 | ports:
127 | - target: 3000
128 | published: 444
129 | protocol: tcp
130 |
131 | dev-tls:
132 | build:
133 | context: ./docker/dev-tls
134 | volumes:
135 | - dev-certs:/certs:rw
136 | ports:
137 | - target: 80
138 | published: 80
139 | protocol: tcp
140 |
141 | volumes:
142 | db-data: {}
143 | dev-certs: {}
144 |
--------------------------------------------------------------------------------
/docker/dev-tls/Dockerfile:
--------------------------------------------------------------------------------
1 | # use this self-generated certificate only in dev, IT IS NOT SECURE!
2 |
3 |
4 | # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
5 | ARG NGINX_VERSION=1.17
6 |
7 |
8 | FROM nginx:${NGINX_VERSION}-alpine
9 |
10 | # persistent / runtime deps
11 | RUN apk add --no-cache \
12 | nss-tools \
13 | ;
14 |
15 | WORKDIR /certs
16 |
17 | ARG MKCERT_VERSION=1.4.1
18 | RUN set -eux; \
19 | wget -O /usr/local/bin/mkcert https://github.com/FiloSottile/mkcert/releases/download/v$MKCERT_VERSION/mkcert-v$MKCERT_VERSION-linux-amd64; \
20 | chmod +x /usr/local/bin/mkcert; \
21 | mkcert --cert-file localhost.crt --key-file localhost.key localhost 127.0.0.1 ::1 mercure; \
22 | # the file must be named server.pem - the default certificate path in webpack-dev-server
23 | cat localhost.key localhost.crt > server.pem; \
24 | # export the root CA cert, but not the root CA key
25 | cp "$(mkcert -CAROOT)/rootCA.pem" /certs/localCA.crt
26 |
27 | VOLUME /certs
28 |
29 | # add redirect from http://localhost to https://localhost
30 | RUN set -eux; \
31 | { \
32 | echo 'server {'; \
33 | echo ' return 301 https://$host$request_uri;'; \
34 | echo '}'; \
35 | } | tee /etc/nginx/conf.d/default.conf
36 |
--------------------------------------------------------------------------------
/github/img/admin-page-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/admin-page-1.png
--------------------------------------------------------------------------------
/github/img/admin-page-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/admin-page-2.png
--------------------------------------------------------------------------------
/github/img/admin-page-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/admin-page-3.png
--------------------------------------------------------------------------------
/github/img/api-page-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/api-page-1.png
--------------------------------------------------------------------------------
/github/img/api-page-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/api-page-2.png
--------------------------------------------------------------------------------
/github/img/client-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/client-page.png
--------------------------------------------------------------------------------
/github/img/make-dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/make-dev.png
--------------------------------------------------------------------------------
/github/img/make-rebuild-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/make-rebuild-2.png
--------------------------------------------------------------------------------
/github/img/make-rebuild.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webcoderio/webdcoder-api-platform-mysql/843f3946913fc41c2d63ab654a9a9fd25e445d79/github/img/make-rebuild.png
--------------------------------------------------------------------------------