Compare commits
116 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
139c313a84 | ||
|
64f1621e04 | ||
|
f9ee00b29b | ||
|
562599b00f | ||
|
f394bf42eb | ||
|
59118cd6a4 | ||
|
961711b34b | ||
|
d7ec6aee4d | ||
|
af801110aa | ||
|
d86c1fa0f8 | ||
|
53c72f729e | ||
|
188494a996 | ||
|
2f14e147b5 | ||
|
0bdc9cafc0 | ||
|
8ea48bcaf3 | ||
|
c4150dc362 | ||
|
4ed6c45441 | ||
|
eaf58bd477 | ||
|
69d51636f2 | ||
|
a865c5ec8d | ||
|
106aa2149e | ||
|
fb6cc37dd8 | ||
|
17dd5ed296 | ||
|
535f899aaf | ||
|
edba09be4c | ||
|
b71ca34dd3 | ||
|
65a9819b1b | ||
|
53d49d3894 | ||
|
ab56fe9917 | ||
|
75c0c98c8d | ||
|
c2b959a9da | ||
|
4647bb2cc1 | ||
|
2a96c5a863 | ||
|
3bc176936c | ||
|
e0574615a7 | ||
|
452a5c4993 | ||
|
85a2a2a4a7 | ||
|
ed8c62f4bd | ||
|
63c5f7572b | ||
|
531228dfca | ||
|
b8734d4dc6 | ||
|
7db9517840 | ||
|
ab9e1b5b99 | ||
|
c72bf86a96 | ||
|
a893929cf9 | ||
|
ec23a41e37 | ||
|
7279f2096e | ||
|
cde6507197 | ||
|
10756226f1 | ||
|
5c8a0238f1 | ||
|
87e4121444 | ||
|
ea283a86e7 | ||
|
ae05646888 | ||
|
3e695bfef7 | ||
|
1a0515742e | ||
|
50a79470e7 | ||
|
7ffd3c02cd | ||
|
e6c5047408 | ||
|
87255eaf13 | ||
|
ee0cde0400 | ||
|
45004444e6 | ||
|
a9a0f2f413 | ||
|
9f3f6bf22b | ||
|
a3de2b244f | ||
|
950e310096 | ||
|
847e3a078f | ||
|
67f7ba2a88 | ||
|
6bd71f0ec5 | ||
|
c1a58f4bd6 | ||
|
934561ca0e | ||
|
c602737ba1 | ||
|
ee3dc50914 | ||
|
4d98a8607b | ||
|
92c12d1c9a | ||
|
dd5fbc1ed8 | ||
|
a7bd34677b | ||
|
66e45c8112 | ||
|
9ecadfd4d1 | ||
|
5e4208067c | ||
|
7da2038e02 | ||
|
4545899d20 | ||
|
2b0792775f | ||
|
38e6ae52e1 | ||
|
f3fc6cb071 | ||
|
cb6c3a3950 | ||
|
9b13612c43 | ||
|
53c43cd431 | ||
|
4bbae18d54 | ||
|
4761d7a44c | ||
|
759096b8c4 | ||
|
519dc8de22 | ||
|
f9c289aacd | ||
|
ce8c8f97ec | ||
|
4bd5ee14ca | ||
|
b06a89350f | ||
|
253b206a39 | ||
|
6df7bdbea0 | ||
|
89b4f5911a | ||
|
b23bf3ad84 | ||
|
0fc075663a | ||
|
9e4a7c2d57 | ||
|
306c034de5 | ||
|
e49a70c71a | ||
|
c00e038fba | ||
|
1bdea1926d | ||
|
2c9a795756 | ||
|
02776c4c90 | ||
|
f33b3c21fe | ||
|
17d281fffe | ||
|
9802473d7c | ||
|
4b389582ad | ||
|
78263302c8 | ||
|
d07936d314 | ||
|
3b7932b976 | ||
|
ecd02d21bb | ||
|
cdffda56aa |
1
.docker-compose/api/.env
Normal file
1
.docker-compose/api/.env
Normal file
@ -0,0 +1 @@
|
||||
PHP_IDE_CONFIG=serverName=cojedzie
|
31
.docker-compose/nginx/cojedzie-rr.conf
Normal file
31
.docker-compose/nginx/cojedzie-rr.conf
Normal file
@ -0,0 +1,31 @@
|
||||
server {
|
||||
root /var/www/front/public/;
|
||||
|
||||
server_name cojedzie.localhost;
|
||||
|
||||
location /_profiler/ {
|
||||
try_files $uri $uri/ @api;
|
||||
}
|
||||
|
||||
location /bundles/ {
|
||||
try_files $uri $uri/ @api;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
try_files $uri $uri/ @api;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ @frontend;
|
||||
}
|
||||
|
||||
location @frontend {
|
||||
proxy_pass http://frontend:3000;
|
||||
proxy_intercept_errors on;
|
||||
}
|
||||
|
||||
location @api {
|
||||
proxy_pass http://api:8080;
|
||||
proxy_intercept_errors on;
|
||||
}
|
||||
}
|
44
.docker-compose/nginx/cojedzie.conf
Normal file
44
.docker-compose/nginx/cojedzie.conf
Normal file
@ -0,0 +1,44 @@
|
||||
server {
|
||||
root /var/www/front/public/;
|
||||
server_name cojedzie.localhost;
|
||||
|
||||
location /api/ {
|
||||
root /var/www/api/public/;
|
||||
try_files $uri $uri/ index.php$is_args$args;
|
||||
}
|
||||
|
||||
location /_profiler/ {
|
||||
root /var/www/api/public/;
|
||||
try_files $uri $uri/ index.php$is_args$args;
|
||||
}
|
||||
|
||||
location /bundles/ {
|
||||
root /var/www/api/public/;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ @frontend;
|
||||
}
|
||||
|
||||
location @frontend {
|
||||
proxy_pass http://frontend:3000;
|
||||
proxy_intercept_errors on;
|
||||
}
|
||||
|
||||
location ~ (.+).php(/|$) {
|
||||
root /var/www/api/public/;
|
||||
|
||||
fastcgi_pass api:9000;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME /var/www/public/$fastcgi_script_name;
|
||||
fastcgi_param DOCUMENT_ROOT /var/www/public/;
|
||||
|
||||
fastcgi_param APP_ENV "dev";
|
||||
fastcgi_param DATABASE_URL "sqlite:///%kernel.project_dir%/var/app.db";
|
||||
|
||||
internal;
|
||||
}
|
||||
}
|
17
.env.dist
17
.env.dist
@ -1,17 +0,0 @@
|
||||
# This file is a "template" of which env vars need to be defined for your application
|
||||
# Copy this file to .env file for development, create environment variables when deploying to production
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
|
||||
|
||||
GOOGLE_ANALYTICS=
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=1bdf86cdc78fba654e4f2c309c6bbdbd
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> doctrine/doctrine-bundle ###
|
||||
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
|
||||
# Configure your db driver and server_version in config/packages/doctrine.yaml
|
||||
DATABASE_URL=sqlite:///%kernel.project_dir%/var/app.db
|
||||
###< doctrine/doctrine-bundle ###
|
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,17 +1 @@
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
/.env
|
||||
/public/bundles/
|
||||
/var/
|
||||
/vendor/
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/web-server-bundle ###
|
||||
/.web-server-pid
|
||||
###< symfony/web-server-bundle ###
|
||||
|
||||
/node_modules/
|
||||
/.idea/
|
||||
/public/*
|
||||
!/public/index.php
|
||||
!/public/manifest.json
|
71
CLA.md
Normal file
71
CLA.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Co Jedzie Individual Contributor License Agreement
|
||||
|
||||
Adapted from http://www.apache.org/licenses/icla.txt © The Apache Software Foundation
|
||||
|
||||
Thank you for your interest in Co Jedzie (the **"Project"**) by Kacper Donat (the **"Author"**). In order to clarify the
|
||||
intellectual property license granted with Contributions from any person or entity, the Author must have a Contributor
|
||||
License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms
|
||||
below. This license is for your protection as a Contributor as well as the protection of the Author and its users; it
|
||||
does not change your rights to use your own Contributions for any other purpose.
|
||||
|
||||
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the
|
||||
Author. In return, the Author shall not use Your Contributions in a way that is contrary to the public benefit or
|
||||
inconsistent with its bylaws in effect at the time of the Contribution. Except for the license granted herein to the
|
||||
Author and recipients of software distributed by the Author, You reserve all right, title, and interest in and to Your
|
||||
Contributions.
|
||||
|
||||
1. Definitions.
|
||||
- **"You"** (or **"Your"**) shall mean the copyright owner or legal entity authorized by the copyright owner that is
|
||||
making this Agreement with the Author. For legal entities, the entity making a Contribution and all other entities
|
||||
that control, are controlled by, or are under common control with that entity are considered to be a single
|
||||
Contributor. For the purposes of this definition, **"control"** means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or
|
||||
more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
- **"Contribution"** shall mean any original work of authorship, including any modifications or additions to an existing
|
||||
work, that is intentionally submitted by You to the Author for inclusion in, or documentation of, any of the products
|
||||
owned or managed by the Author (the **"Work"**). For the purposes of this definition, **"submitted"** means any form
|
||||
of electronic, verbal, or written communication sent to the Author or its representatives, including but not limited
|
||||
to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed
|
||||
by, or on behalf of, the Author for the purpose of discussing and improving the Work, but excluding communication that
|
||||
is conspicuously marked or otherwise designated in writing by You as **"Not a Contribution."**
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to the Author and
|
||||
to recipients of software distributed by the Author a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform,
|
||||
sublicense, re-license, and distribute Your Contributions and such derivative works.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to the Author and to
|
||||
recipients of software distributed by the Author a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import,
|
||||
and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are
|
||||
necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which
|
||||
such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (
|
||||
including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have
|
||||
contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity
|
||||
under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to
|
||||
intellectual property that you create that includes your Contributions, you represent that you have received
|
||||
permission to make Contributions on behalf of that employer, that your employer has waived such rights for your
|
||||
Contributions to the Author, or that your employer has executed a separate Corporate CLA with the Author.
|
||||
|
||||
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of
|
||||
others). You represent that Your Contribution submissions include complete details of any third-party license or
|
||||
other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware
|
||||
and which are associated with any part of Your Contributions.
|
||||
|
||||
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support.
|
||||
You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in
|
||||
writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT,
|
||||
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
7. Should You wish to submit work that is not Your original creation, You may submit it to the Author separately from
|
||||
any Contribution, identifying the complete details of its source and of any license or other restriction (including,
|
||||
but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and
|
||||
conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
|
||||
|
||||
8. You agree to notify the Author of any facts or circumstances of which you become aware that would make these
|
||||
representations inaccurate in any respect.
|
||||
|
38
CONTRIBUTING.md
Normal file
38
CONTRIBUTING.md
Normal file
@ -0,0 +1,38 @@
|
||||
# How to contribute?
|
||||
|
||||
Thanks for your interest in the project!
|
||||
|
||||
## I'd like to propose some feature / change...
|
||||
|
||||
Cool! Go ahead, [create an issue] and describe your proposal so anyone can see it. You can also vote on features that
|
||||
you want the most.
|
||||
|
||||
## I've found a bug!
|
||||
|
||||
Well, less cool! Before creating an issue, please check if the bug remains after hard refreshing (usually `ctrl+F5`) the
|
||||
application. If the answer is yes, or this is not the first encounter of it please [create an issue] and describe the
|
||||
problem. If you can, please attach screenshots (especially if this is visual bug), and console logs (especially for
|
||||
connection problems) - this will help to reproduce the problem.
|
||||
|
||||
## I've got some spare resources on my server...
|
||||
Soon you will be able to help the project by hosting your own API node that will be available for clients to use.
|
||||
More details to come soon.
|
||||
|
||||
## I want to contribute some code...
|
||||
|
||||
That's great! If you want to make changes to API (which is responsible for collecting and supplying applicaiton with
|
||||
data) please check the [API contribution guidelines], if you are interested in UI side of the app please read the
|
||||
[frontend contribution guidelines].
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
Unfortunately due to this project nature and license I need you to sign [Contributor License Agreement] - the nice thing
|
||||
is that it can be done with simple push of a button! **You still will have full copyright to your contribution** but
|
||||
basically you consent that you are entitled to code you are submitting and also to allow me to license this project on
|
||||
other terms if needed to, for example, local governments. If you don't want to sign - I understand - but I won't be able
|
||||
to accept your contribution :(
|
||||
|
||||
[Contributor License Agreement]: ./CLA.md
|
||||
[create an issue]: https://github.com/cojedzie/cojedzie/issues/new
|
||||
[API contribution guidelines]: ./api/CONTRIBUTING.md
|
||||
[frontend contribution guidelines]: ./front/CONTRIBUTING.md
|
41
LICENSE.md
Normal file
41
LICENSE.md
Normal file
@ -0,0 +1,41 @@
|
||||
“Commons Clause” License Condition v1.0
|
||||
|
||||
The Software is provided to you by the Licensor under the License, as defined
|
||||
below, subject to the following condition.
|
||||
|
||||
Without limiting other conditions in the License, the grant of rights under the
|
||||
License will not include, and the License does not grant to you, the right to
|
||||
Sell the Software.
|
||||
|
||||
For purposes of the foregoing, “Sell” means practicing any or all of the rights
|
||||
granted to you under the License to provide to third parties, for a fee or other
|
||||
consideration (including without limitation fees for hosting or consulting/
|
||||
support services related to the Software), a product or service whose value
|
||||
derives, entirely or substantially, from the functionality of the Software. Any
|
||||
license notice or attribution required by the License must also include this
|
||||
Commons Clause License Condition notice.
|
||||
|
||||
Software: Co Jedzie
|
||||
|
||||
License: MIT
|
||||
|
||||
Licensor: Kacper Donat
|
||||
|
||||
Copyright 2020 Kacper Donat
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
32
README.md
Normal file
32
README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# [Co Jedzie](https://cojedzie.pl)
|
||||

|
||||

|
||||
|
||||
Co Jedzie is an app that allows you to quickly and easily check realtime departure times on public transport stops. It
|
||||
aims to be the central hub for all public transport information you will need.
|
||||
|
||||
You can use the app at [cojedzie.pl](https://cojedzie.pl).
|
||||
|
||||
## Roadmap
|
||||
Co Jedzie is in active development, roadmap of the project can be found on [trello]. This roadmap is regularly updated
|
||||
and represents current state of the project. Feel free to take a look.
|
||||
|
||||
### Contributing to roadmap
|
||||
If you have found a bug or want to propose some changes feel free to create an [issue] explaining your proposal or
|
||||
problem. Issue management and discussion would be done on the github, but planning will be carried away to the [trello]
|
||||
trello with linked issue.
|
||||
|
||||
## Contributing
|
||||
Wan't to contribute? Nice! Please see [CONTRIBUTING.md]
|
||||
|
||||
## License
|
||||
This project is [fair-code](https://faircode.io/) licensed under [MIT with Commons Clause](./LICENSE.md). Basically, Co
|
||||
Jedzie is free and code is available to everyone, but it's not allowed to make money directly with it without
|
||||
authors permission.
|
||||
|
||||
Note that data collected from available data sources is licensed by their respective owners, thus it may be
|
||||
available under different terms than the project itself and may require additional permissions to use.
|
||||
|
||||
[trello]: https://trello.com/b/QXqDvmoG/co-jedzie
|
||||
[issue]: https://github.com/cojedzie/cojedzie/issues/new
|
||||
[CONTRIBUTING.md]: ./CONTRIBUTING.md
|
2
api/.dockerignore
Normal file
2
api/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
/vendor/
|
||||
/var/
|
22
api/.env
Normal file
22
api/.env
Normal file
@ -0,0 +1,22 @@
|
||||
# This file is a "template" of which env vars need to be defined for your application
|
||||
# Copy this file to .env file for development, create environment variables when deploying to production
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=494a9d1f8cc383f16075f4d5e54ae1a2
|
||||
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||
#TRUSTED_HOSTS='^(localhost|example\.com)$'
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> doctrine/doctrine-bundle ###
|
||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||
#
|
||||
DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db"
|
||||
# DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
###> symfony/messenger ###
|
||||
APP_EVENT_QUEUE_DSN="doctrine://default"
|
||||
###< symfony/messenger ###
|
16
api/.gitignore
vendored
Normal file
16
api/.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
###> symfony/framework-bundle ###
|
||||
/.env.local
|
||||
/.env.local.php
|
||||
/.env.*.local
|
||||
/config/secrets/prod/prod.decrypt.private.php
|
||||
/public/bundles/
|
||||
/var/
|
||||
/vendor/
|
||||
###< symfony/framework-bundle ###
|
||||
/node_modules/
|
||||
/public/*
|
||||
!/public/index.php
|
||||
|
||||
###> baldinof/roadrunner-bundle ###
|
||||
/bin/rr
|
||||
###< baldinof/roadrunner-bundle ###
|
11
api/.rr.dev.yaml
Normal file
11
api/.rr.dev.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
include:
|
||||
- .rr.yaml
|
||||
|
||||
reload:
|
||||
enabled: true
|
||||
interval: 1s
|
||||
patterns: [".php"]
|
||||
services:
|
||||
http:
|
||||
dirs: ["."]
|
||||
recursive: true
|
13
api/.rr.yaml
Normal file
13
api/.rr.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
http:
|
||||
address: "0.0.0.0:8080"
|
||||
|
||||
uploads:
|
||||
forbid: [".php", ".exe", ".bat"]
|
||||
|
||||
workers:
|
||||
command: "php bin/console baldinof:roadrunner:worker"
|
||||
relay: "unix://var/roadrunner.sock"
|
||||
|
||||
static:
|
||||
dir: "public"
|
||||
forbid: [".php", ".htaccess"]
|
3
api/CONTRIBUTING.md
Normal file
3
api/CONTRIBUTING.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Contributing guidelines
|
||||
|
||||
TBD
|
28
api/Dockerfile
Normal file
28
api/Dockerfile
Normal file
@ -0,0 +1,28 @@
|
||||
FROM php:7.4-fpm-alpine
|
||||
|
||||
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
|
||||
RUN install-php-extensions bcmath intl opcache zip sockets xdebug-^3.0;
|
||||
RUN apk add git;
|
||||
|
||||
# XDebug
|
||||
RUN echo "xdebug.mode=debug" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \
|
||||
echo "xdebug.discover_client_host=On" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini;
|
||||
|
||||
# Blackfire
|
||||
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
|
||||
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \
|
||||
&& mkdir -p /tmp/blackfire \
|
||||
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
|
||||
&& mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
|
||||
&& printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
|
||||
&& rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz
|
||||
|
||||
# Timezone
|
||||
RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && \
|
||||
echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini;
|
||||
|
||||
WORKDIR /var/www
|
||||
|
||||
EXPOSE 9001
|
3
api/bin/docker-entrypoint.sh
Normal file
3
api/bin/docker-entrypoint.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec "$@"
|
5
api/bin/docker-init.sh
Executable file
5
api/bin/docker-init.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
./bin/console doctrine:migrations:migrate --no-interaction
|
||||
|
||||
exec "$@"
|
@ -1,34 +1,37 @@
|
||||
{
|
||||
"name": "kadet/czydojade",
|
||||
"name": "kadet/cojedzie",
|
||||
"description": "Co Jedzie",
|
||||
"type": "project",
|
||||
"license": "MIT",
|
||||
"license": "MIT with Commons Clause",
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"php": "^7.4",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"baldinof/roadrunner-bundle": "^1.3",
|
||||
"cerbero/json-objects": "^1.1",
|
||||
"doctrine/doctrine-cache-bundle": "^1.4",
|
||||
"illuminate/collections": "^8.35",
|
||||
"jms/serializer-bundle": "^3.5",
|
||||
"kadet/functional": "dev-master",
|
||||
"nelmio/api-doc-bundle": "^3.5",
|
||||
"nesbot/carbon": "^1.33",
|
||||
"nesbot/carbon": "^2.46.0",
|
||||
"ocramius/proxy-manager": "^2.0",
|
||||
"sensio/framework-extra-bundle": "^5.2",
|
||||
"symfony/asset": "^4.4",
|
||||
"symfony/console": "^4.4",
|
||||
"spiral/roadrunner": "^1.8",
|
||||
"symfony/asset": "^5.2",
|
||||
"symfony/console": "^5.2",
|
||||
"symfony/doctrine-messenger": "5.2.*",
|
||||
"symfony/flex": "^1.1",
|
||||
"symfony/framework-bundle": "^4.4",
|
||||
"symfony/framework-bundle": "^5.2",
|
||||
"symfony/messenger": "5.2.*",
|
||||
"symfony/monolog-bundle": "^3.3",
|
||||
"symfony/orm-pack": "^1.0",
|
||||
"symfony/profiler-pack": "^1.0",
|
||||
"symfony/twig-bundle": "^4.4",
|
||||
"symfony/yaml": "^4.4",
|
||||
"tightenco/collect": "^5.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/dotenv": "^4.4",
|
||||
"symfony/web-server-bundle": "^4.4",
|
||||
"kadet/functional": "dev-master"
|
||||
"symfony/twig-bundle": "^5.2",
|
||||
"symfony/yaml": "^5.2",
|
||||
"symfony/dotenv": "5.2.*",
|
||||
"symfony/amqp-messenger": "5.2.*",
|
||||
"symfony/redis-messenger": "5.2.*"
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": {
|
||||
@ -37,14 +40,17 @@
|
||||
"sort-packages": true,
|
||||
"secure-http": false,
|
||||
"platform": {
|
||||
"php": "7.3.12"
|
||||
"php": "7.4.15"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
},
|
||||
"files": ["./src/Functions/index.php"]
|
||||
"files": [
|
||||
"vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php",
|
||||
"./src/Functions/index.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
@ -75,7 +81,8 @@
|
||||
},
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": true
|
||||
"allow-contrib": true,
|
||||
"require": "5.2.*"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
@ -83,5 +90,8 @@
|
||||
"type": "vcs",
|
||||
"url": "https://git.kadet.net/kadet/functional-php.git"
|
||||
}
|
||||
]
|
||||
],
|
||||
"require-dev": {
|
||||
"symfony/maker-bundle": "^1.30"
|
||||
}
|
||||
}
|
6497
composer.lock → api/composer.lock
generated
6497
composer.lock → api/composer.lock
generated
File diff suppressed because it is too large
Load Diff
23
api/config/bootstrap.php
Normal file
23
api/config/bootstrap.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
|
||||
require dirname(__DIR__).'/vendor/autoload.php';
|
||||
|
||||
if (!class_exists(Dotenv::class)) {
|
||||
throw new LogicException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
|
||||
}
|
||||
|
||||
// Load cached env vars if the .env.local.php file exists
|
||||
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
|
||||
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'])) {
|
||||
(new Dotenv(false))->populate($env);
|
||||
} else {
|
||||
// load all the .env files
|
||||
(new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
|
||||
}
|
||||
|
||||
$_SERVER += $_ENV;
|
||||
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
|
||||
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
|
||||
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
|
@ -2,14 +2,14 @@
|
||||
|
||||
return [
|
||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true],
|
||||
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
|
||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
|
||||
JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Baldinof\RoadRunnerBundle\BaldinofRoadRunnerBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
];
|
18
api/config/packages/baldinof_road_runner.yaml
Normal file
18
api/config/packages/baldinof_road_runner.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
baldinof_road_runner:
|
||||
# The kernel is preserved between requests. Change this to `true`
|
||||
# if you want to reboot it, and use a fresh container on each request.
|
||||
should_reboot_kernel: false
|
||||
|
||||
# Integrations are automatically detected, depending on installed bundle & current configuration
|
||||
# See https://github.com/baldinof/roadrunner-bundle#integrations
|
||||
default_integrations: true
|
||||
|
||||
# Allow to send prometheus metrics to the master RoadRunner process,
|
||||
# via a `Spiral\RoadRunner\MetricsInterface` service.
|
||||
# See https://github.com/baldinof/roadrunner-bundle#metrics
|
||||
metrics_enabled: false
|
||||
|
||||
# You can use middlewares to manipulate PSR requests & responses.
|
||||
# See https://github.com/baldinof/roadrunner-bundle#middlewares
|
||||
# middlewares:
|
||||
# - App\Middleware\YourMiddleware
|
19
api/config/packages/cache.yaml
Normal file
19
api/config/packages/cache.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
framework:
|
||||
cache:
|
||||
# Unique name of your app: used to compute stable namespaces for cache keys.
|
||||
#prefix_seed: your_vendor_name/app_name
|
||||
|
||||
# The "app" cache stores to the filesystem by default.
|
||||
# The data in this cache should persist between deploys.
|
||||
# Other options include:
|
||||
|
||||
# Redis
|
||||
#app: cache.adapter.redis
|
||||
#default_redis_provider: redis://localhost
|
||||
|
||||
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
||||
#app: cache.adapter.apcu
|
||||
|
||||
# Namespaced pools use the above "app" backend by default
|
||||
#pools:
|
||||
#my.dedicated.cache: null
|
@ -1,5 +1,5 @@
|
||||
web_profiler:
|
||||
toolbar: true
|
||||
toolbar: false
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
@ -5,14 +5,13 @@ doctrine:
|
||||
dbal:
|
||||
driver: 'pdo_sqlite'
|
||||
url: '%env(resolve:DATABASE_URL)%'
|
||||
logging: true
|
||||
profiling: true
|
||||
logging: '%kernel.debug%'
|
||||
profiling: '%kernel.debug%'
|
||||
types:
|
||||
datetime: App\Doctrine\CarbonDateTimeType
|
||||
|
||||
orm:
|
||||
auto_generate_proxy_classes: '%kernel.debug%'
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore
|
||||
auto_generate_proxy_classes: true
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
auto_mapping: true
|
||||
mappings:
|
||||
App:
|
||||
@ -20,4 +19,4 @@ doctrine:
|
||||
type: annotation
|
||||
dir: '%kernel.project_dir%/src/Entity'
|
||||
prefix: 'App\Entity'
|
||||
alias: Entity
|
||||
alias: App
|
3
api/config/packages/doctrine_migrations.yaml
Normal file
3
api/config/packages/doctrine_migrations.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
doctrine_migrations:
|
||||
migrations_paths:
|
||||
'DoctrineMigrations': '%kernel.project_dir%/migrations'
|
6
api/config/packages/framework.yaml
Normal file
6
api/config/packages/framework.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
csrf_protection: false
|
||||
|
||||
php_errors:
|
||||
log: true
|
@ -1,4 +1,8 @@
|
||||
jms_serializer:
|
||||
default_context:
|
||||
serialization:
|
||||
serialize_null: true
|
||||
|
||||
visitors:
|
||||
xml_serialization:
|
||||
format_output: '%kernel.debug%'
|
11
api/config/packages/messenger.yaml
Normal file
11
api/config/packages/messenger.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
parameters:
|
||||
env(APP_EVENT_QUEUE): "doctrine://default"
|
||||
|
||||
framework:
|
||||
messenger:
|
||||
transports:
|
||||
main: '%env(resolve:APP_EVENT_QUEUE)%'
|
||||
sync: 'sync://'
|
||||
|
||||
routing:
|
||||
'App\Message\UpdateDataMessage': main
|
@ -1,7 +1,7 @@
|
||||
nelmio_api_doc:
|
||||
documentation:
|
||||
info:
|
||||
title: Czy Dojadę?
|
||||
title: Co Jedzie?
|
||||
version: 0.1.0
|
||||
parameters:
|
||||
provider:
|
||||
@ -13,7 +13,7 @@ nelmio_api_doc:
|
||||
|
||||
areas:
|
||||
path_patterns:
|
||||
- ^/[^\/]+/api(?!/doc$) # Accepts routes under /api except /api/doc
|
||||
- /api(?!/doc$) # Accepts routes under /api except /api/doc
|
||||
|
||||
|
||||
|
20
api/config/packages/prod/doctrine.yaml
Normal file
20
api/config/packages/prod/doctrine.yaml
Normal file
@ -0,0 +1,20 @@
|
||||
doctrine:
|
||||
orm:
|
||||
auto_generate_proxy_classes: false
|
||||
metadata_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.system_cache_pool
|
||||
query_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.system_cache_pool
|
||||
result_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.result_cache_pool
|
||||
|
||||
framework:
|
||||
cache:
|
||||
pools:
|
||||
doctrine.result_cache_pool:
|
||||
adapter: cache.app
|
||||
doctrine.system_cache_pool:
|
||||
adapter: cache.system
|
@ -1,3 +1,4 @@
|
||||
framework:
|
||||
router:
|
||||
strict_requirements: ~
|
||||
|
2
api/config/packages/test/twig.yaml
Normal file
2
api/config/packages/test/twig.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
twig:
|
||||
strict_variables: true
|
5
api/config/packages/twig.yaml
Normal file
5
api/config/packages/twig.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
twig:
|
||||
default_path: '%kernel.project_dir%/templates'
|
||||
debug: '%kernel.debug%'
|
||||
strict_variables: '%kernel.debug%'
|
||||
exception_controller: null
|
9
api/config/preload.php
Normal file
9
api/config/preload.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
if (file_exists(dirname(__DIR__).'/var/cache/prod/srcApp_KernelProdContainer.preload.php')) {
|
||||
require dirname(__DIR__).'/var/cache/prod/srcApp_KernelProdContainer.preload.php';
|
||||
}
|
||||
|
||||
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
|
||||
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
|
||||
}
|
16
api/config/routes.yaml
Normal file
16
api/config/routes.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
api_v1:
|
||||
resource: ../src/Controller/Api/v1
|
||||
type: annotation
|
||||
prefix: /api/v1/{provider}
|
||||
|
||||
api_v1_providers:
|
||||
path: /api/v1/providers
|
||||
methods: ["GET"]
|
||||
defaults:
|
||||
_controller: '\App\Controller\Api\v1\ProviderController::index'
|
||||
|
||||
api_v1_providers_one:
|
||||
path: /api/v1/providers/{id}
|
||||
methods: ["GET"]
|
||||
defaults:
|
||||
_controller: '\App\Controller\Api\v1\ProviderController::one'
|
3
api/config/routes/dev/framework.yaml
Normal file
3
api/config/routes/dev/framework.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
|
||||
prefix: /_error
|
@ -19,11 +19,14 @@ services:
|
||||
App\Provider\Provider:
|
||||
tags: [ app.provider ]
|
||||
|
||||
App\Service\Converter:
|
||||
tags: [ app.converter ]
|
||||
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: '../src/*'
|
||||
exclude: '../src/{DependencyInjection,Entity,Model,Migrations,Tests,Functions,Kernel.php}'
|
||||
exclude: '../src/{DependencyInjection,Exception,Modifier,Entity,Model,Migrations,Tests,Functions,Handler,Kernel.php}'
|
||||
|
||||
# controllers are imported separately to make sure services can be injected
|
||||
# as action arguments even if you don't extend any base controller class
|
||||
@ -35,12 +38,9 @@ services:
|
||||
resource: '../src/Provider'
|
||||
public: true
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
|
||||
#assets
|
||||
assets.modified_time_version_strategy:
|
||||
class: App\Asset\ModifiedTimeVersionStrategy
|
||||
App\Handler\:
|
||||
resource: '../src/Handler'
|
||||
tags: [ app.handler ]
|
||||
|
||||
#eerialziser
|
||||
jms_serializer.serialized_name_annotation_strategy:
|
||||
@ -53,7 +53,7 @@ services:
|
||||
|
||||
#proxy configuration
|
||||
proxy.locator:
|
||||
class: 'ProxyManager\FileLocator\FileLocator'
|
||||
class: 'App\Service\Proxy\FileLocator'
|
||||
arguments: ['%kernel.cache_dir%/proxy']
|
||||
|
||||
proxy.strategy:
|
||||
@ -68,16 +68,23 @@ services:
|
||||
|
||||
ProxyManager\Configuration: '@proxy.config'
|
||||
|
||||
# serializer configuration
|
||||
serializer.datetime_normalizer:
|
||||
class: Symfony\Component\Serializer\Normalizer\DateTimeNormalizer
|
||||
arguments: [!php/const DateTime::ATOM]
|
||||
tags: [serializer.normalizer]
|
||||
# converter
|
||||
App\Service\AggregateConverter:
|
||||
arguments:
|
||||
- !tagged_iterator app.converter
|
||||
|
||||
App\Service\Converter: '@App\Service\AggregateConverter'
|
||||
|
||||
# serializer configuration
|
||||
App\Service\SerializerContextFactory:
|
||||
arguments:
|
||||
$factory: '@jms_serializer.metadata_factory'
|
||||
|
||||
App\Service\Normalizer\:
|
||||
resource: '../src/Service/Normalizer'
|
||||
tags: [serializer.normalizer]
|
||||
|
||||
# other servces
|
||||
App\Service\ProviderResolver:
|
||||
arguments: [!tagged app.provider, '%kernel.debug%']
|
||||
|
||||
App\Service\HandlerProvider:
|
||||
arguments: [!tagged_locator app.handler]
|
||||
shared: false
|
45
api/migrations/Version20200131151757.php
Normal file
45
api/migrations/Version20200131151757.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20200131151757 extends AbstractMigration
|
||||
{
|
||||
public function getDescription() : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.');
|
||||
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__stop AS SELECT id, provider_id, name, description, variant, latitude, longitude, on_demand FROM stop');
|
||||
$this->addSql('DROP TABLE stop');
|
||||
$this->addSql('CREATE TABLE stop (id VARCHAR(255) NOT NULL COLLATE BINARY, provider_id VARCHAR(255) DEFAULT NULL COLLATE BINARY, name VARCHAR(255) NOT NULL COLLATE BINARY, description VARCHAR(255) DEFAULT NULL COLLATE BINARY, variant VARCHAR(255) DEFAULT NULL COLLATE BINARY, latitude DOUBLE PRECISION DEFAULT NULL, longitude DOUBLE PRECISION DEFAULT NULL, on_demand BOOLEAN NOT NULL, group_name VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('INSERT INTO stop (id, provider_id, name, description, variant, latitude, longitude, on_demand) SELECT id, provider_id, name, description, variant, latitude, longitude, on_demand FROM __temp__stop');
|
||||
$this->addSql('DROP TABLE __temp__stop');
|
||||
$this->addSql('CREATE INDEX group_idx ON stop (group_name)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.');
|
||||
|
||||
$this->addSql('DROP INDEX group_idx');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__stop AS SELECT id, name, description, variant, latitude, longitude, on_demand, provider_id FROM stop');
|
||||
$this->addSql('DROP TABLE stop');
|
||||
$this->addSql('CREATE TABLE stop (id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, variant VARCHAR(255) DEFAULT NULL, latitude DOUBLE PRECISION DEFAULT NULL, longitude DOUBLE PRECISION DEFAULT NULL, on_demand BOOLEAN NOT NULL, provider_id VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('INSERT INTO stop (id, name, description, variant, latitude, longitude, on_demand, provider_id) SELECT id, name, description, variant, latitude, longitude, on_demand, provider_id FROM __temp__stop');
|
||||
$this->addSql('DROP TABLE __temp__stop');
|
||||
}
|
||||
}
|
57
api/migrations/Version20200206183956.php
Normal file
57
api/migrations/Version20200206183956.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20200206183956 extends AbstractMigration
|
||||
{
|
||||
public function getDescription() : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.');
|
||||
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__track AS SELECT id, line_id, provider_id, variant, description FROM track');
|
||||
$this->addSql('DROP TABLE track');
|
||||
$this->addSql('CREATE TABLE track (id VARCHAR(255) NOT NULL COLLATE BINARY, line_id VARCHAR(255) DEFAULT NULL COLLATE BINARY, provider_id VARCHAR(255) DEFAULT NULL COLLATE BINARY, variant VARCHAR(16) DEFAULT NULL COLLATE BINARY, description VARCHAR(256) DEFAULT NULL COLLATE BINARY, final_id INTEGER DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('INSERT INTO track (id, line_id, provider_id, variant, description) SELECT id, line_id, provider_id, variant, description FROM __temp__track');
|
||||
$this->addSql('DROP TABLE __temp__track');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_D6E3F8A613D41B2D ON track (final_id)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__track_stop AS SELECT stop_id, track_id, sequence FROM track_stop');
|
||||
$this->addSql('DROP TABLE track_stop');
|
||||
$this->addSql('CREATE TABLE track_stop (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, sequence INTEGER NOT NULL, stop_id VARCHAR(255) DEFAULT NULL, track_id VARCHAR(255) DEFAULT NULL)');
|
||||
$this->addSql('INSERT INTO track_stop (stop_id, track_id, sequence) SELECT stop_id, track_id, sequence FROM __temp__track_stop');
|
||||
$this->addSql('DROP TABLE __temp__track_stop');
|
||||
$this->addSql('CREATE UNIQUE INDEX stop_in_track_idx ON track_stop (stop_id, track_id, sequence)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.');
|
||||
|
||||
$this->addSql('DROP INDEX UNIQ_D6E3F8A613D41B2D');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__track AS SELECT id, variant, description, line_id, provider_id FROM track');
|
||||
$this->addSql('DROP TABLE track');
|
||||
$this->addSql('CREATE TABLE track (id VARCHAR(255) NOT NULL, variant VARCHAR(16) DEFAULT NULL, description VARCHAR(256) DEFAULT NULL, line_id VARCHAR(255) DEFAULT NULL, provider_id VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('INSERT INTO track (id, variant, description, line_id, provider_id) SELECT id, variant, description, line_id, provider_id FROM __temp__track');
|
||||
$this->addSql('DROP TABLE __temp__track');
|
||||
$this->addSql('DROP INDEX stop_in_track_idx');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__track_stop AS SELECT sequence, stop_id, track_id FROM track_stop');
|
||||
$this->addSql('DROP TABLE track_stop');
|
||||
$this->addSql('CREATE TABLE track_stop (sequence INTEGER NOT NULL, stop_id VARCHAR(255) NOT NULL COLLATE BINARY, track_id VARCHAR(255) NOT NULL COLLATE BINARY, PRIMARY KEY(stop_id, track_id, sequence))');
|
||||
$this->addSql('INSERT INTO track_stop (sequence, stop_id, track_id) SELECT sequence, stop_id, track_id FROM __temp__track_stop');
|
||||
$this->addSql('DROP TABLE __temp__track_stop');
|
||||
}
|
||||
}
|
43
api/migrations/Version20200314112552.php
Normal file
43
api/migrations/Version20200314112552.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20200314112552 extends AbstractMigration
|
||||
{
|
||||
public function getDescription() : string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.');
|
||||
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__trip_stop AS SELECT stop_id, trip_id, sequence, arrival, departure FROM trip_stop');
|
||||
$this->addSql('DROP TABLE trip_stop');
|
||||
$this->addSql('CREATE TABLE trip_stop (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, sequence INTEGER NOT NULL, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, stop_id VARCHAR(255) DEFAULT NULL, trip_id VARCHAR(255) DEFAULT NULL)');
|
||||
$this->addSql('INSERT INTO trip_stop (stop_id, trip_id, sequence, arrival, departure) SELECT stop_id, trip_id, sequence, arrival, departure FROM __temp__trip_stop');
|
||||
$this->addSql('DROP TABLE __temp__trip_stop');
|
||||
}
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.');
|
||||
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__trip_stop AS SELECT sequence, arrival, departure, stop_id, trip_id FROM trip_stop');
|
||||
$this->addSql('DROP TABLE trip_stop');
|
||||
$this->addSql('CREATE TABLE trip_stop (sequence INTEGER NOT NULL, stop_id VARCHAR(255) NOT NULL COLLATE BINARY, trip_id VARCHAR(255) NOT NULL COLLATE BINARY, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, PRIMARY KEY(stop_id, trip_id, sequence))');
|
||||
$this->addSql('INSERT INTO trip_stop (sequence, arrival, departure, stop_id, trip_id) SELECT sequence, arrival, departure, stop_id, trip_id FROM __temp__trip_stop');
|
||||
$this->addSql('DROP TABLE __temp__trip_stop');
|
||||
}
|
||||
}
|
27
api/public/index.php
Normal file
27
api/public/index.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use App\Kernel;
|
||||
use Symfony\Component\ErrorHandler\Debug;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
require dirname(__DIR__).'/config/bootstrap.php';
|
||||
|
||||
if ($_SERVER['APP_DEBUG']) {
|
||||
umask(0000);
|
||||
|
||||
Debug::enable();
|
||||
}
|
||||
|
||||
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) {
|
||||
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO);
|
||||
}
|
||||
|
||||
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) {
|
||||
Request::setTrustedHosts([$trustedHosts]);
|
||||
}
|
||||
|
||||
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
|
||||
$request = Request::createFromGlobals();
|
||||
$response = $kernel->handle($request);
|
||||
$response->send();
|
||||
$kernel->terminate($request, $response);
|
29
api/rr.Dockerfile
Normal file
29
api/rr.Dockerfile
Normal file
@ -0,0 +1,29 @@
|
||||
FROM cojedzie/api:latest-rr
|
||||
|
||||
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
|
||||
RUN install-php-extensions xdebug-^3.0;
|
||||
RUN apk add git;
|
||||
|
||||
# XDebug
|
||||
RUN echo "xdebug.mode=debug" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \
|
||||
echo "xdebug.client_host=172.17.0.1" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \
|
||||
echo "xdebug.start_with_request=On" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini;
|
||||
|
||||
# Blackfire
|
||||
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
|
||||
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \
|
||||
&& mkdir -p /tmp/blackfire \
|
||||
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
|
||||
&& mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
|
||||
&& printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
|
||||
&& rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz
|
||||
|
||||
# Timezone
|
||||
RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && \
|
||||
echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini;
|
||||
|
||||
WORKDIR /var/www
|
||||
|
||||
EXPOSE 9001
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<rulset name="Kadet.CzyDojade">
|
||||
<description>Czy Dojadę ruleset</description>
|
||||
<rulset name="CoJedzie">
|
||||
<description>Co Jedzie ruleset</description>
|
||||
|
||||
<arg name="colors"/>
|
||||
<arg name="parallel" value="75"/>
|
48
api/src/Command/UpdateCommand.php
Normal file
48
api/src/Command/UpdateCommand.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Message\UpdateDataMessage;
|
||||
use App\Service\DataUpdater;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
class UpdateCommand extends Command
|
||||
{
|
||||
/** @var DataUpdater */
|
||||
private $updater;
|
||||
/** @var MessageBusInterface */
|
||||
private $bus;
|
||||
|
||||
public function __construct(DataUpdater $updater, MessageBusInterface $bus)
|
||||
{
|
||||
parent::__construct('app:update');
|
||||
|
||||
$this->updater = $updater;
|
||||
$this->bus = $bus;
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->addOption(
|
||||
'async', 'a',
|
||||
InputOption::VALUE_NONE,
|
||||
'Run in worker process via message queue.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('async')) {
|
||||
$this->bus->dispatch(new UpdateDataMessage());
|
||||
$output->writeln("Update request sent to message queue.");
|
||||
} else {
|
||||
$this->updater->update($output);
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
@ -5,8 +5,13 @@ namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Model\Departure;
|
||||
use App\Modifier\FieldFilter;
|
||||
use App\Modifier\IdFilter;
|
||||
use App\Modifier\Limit;
|
||||
use App\Modifier\With;
|
||||
use App\Provider\DepartureRepository;
|
||||
use App\Provider\StopRepository;
|
||||
use App\Service\SerializerContextFactory;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@ -31,11 +36,11 @@ class DeparturesController extends Controller
|
||||
* @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Departure::class)))
|
||||
* )
|
||||
*/
|
||||
public function stop(DepartureRepository $departures, StopRepository $stops, $stop)
|
||||
public function stop(DepartureRepository $departures, StopRepository $stops, $stop, Request $request)
|
||||
{
|
||||
$stop = $stops->getById($stop);
|
||||
$stop = $stops->first(new IdFilter($stop));
|
||||
|
||||
return $this->json($departures->getForStop($stop));
|
||||
return $this->json($departures->current(collect($stop), ...$this->getModifiersFromRequest($request)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,11 +68,21 @@ class DeparturesController extends Controller
|
||||
*/
|
||||
public function stops(DepartureRepository $departures, StopRepository $stops, Request $request)
|
||||
{
|
||||
$stops = $stops
|
||||
->getManyById($request->query->get('stop'))
|
||||
->flatMap(ref([ $departures, 'getForStop' ]))
|
||||
->sortBy(property('departure'));
|
||||
$stops = $stops->all(new IdFilter($request->query->get('stop', [])));
|
||||
$result = $departures->current($stops, ...$this->getModifiersFromRequest($request));
|
||||
|
||||
return $this->json($stops->values()->slice(0, (int)$request->query->get('limit', 8)));
|
||||
return $this->json(
|
||||
$result->values()->slice(0, (int)$request->query->get('limit', 8)),
|
||||
200,
|
||||
[],
|
||||
$this->serializerContextFactory->create(Departure::class, ['Default'])
|
||||
);
|
||||
}
|
||||
|
||||
private function getModifiersFromRequest(Request $request)
|
||||
{
|
||||
if ($request->query->has('limit')) {
|
||||
yield Limit::count($request->query->getInt('limit'));
|
||||
}
|
||||
}
|
||||
}
|
34
api/src/Controller/Api/v1/ProviderController.php
Normal file
34
api/src/Controller/Api/v1/ProviderController.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Exception\NonExistentServiceException;
|
||||
use App\Service\Converter;
|
||||
use App\Service\ProviderResolver;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use function Kadet\Functional\ref;
|
||||
|
||||
class ProviderController extends Controller
|
||||
{
|
||||
public function index(ProviderResolver $resolver, Converter $converter)
|
||||
{
|
||||
$providers = $resolver
|
||||
->all()
|
||||
->map(ref([$converter, 'convert']))
|
||||
->values()
|
||||
->toArray()
|
||||
;
|
||||
return $this->json($providers);
|
||||
}
|
||||
|
||||
public function one(ProviderResolver $resolver, Converter $converter, $id)
|
||||
{
|
||||
try {
|
||||
$provider = $resolver->resolve($id);
|
||||
return $this->json($converter->convert($provider));
|
||||
} catch (NonExistentServiceException $exception) {
|
||||
throw new NotFoundHttpException($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,18 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Model\Stop;
|
||||
use App\Model\Track;
|
||||
use App\Model\StopGroup;
|
||||
use App\Model\TrackStop;
|
||||
use App\Modifier\FieldFilter;
|
||||
use App\Modifier\IdFilter;
|
||||
use App\Modifier\RelatedFilter;
|
||||
use App\Modifier\With;
|
||||
use App\Provider\StopRepository;
|
||||
use App\Provider\TrackRepository;
|
||||
use App\Service\Proxy\ReferenceFactory;
|
||||
use Illuminate\Support\Collection;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@ -37,7 +40,8 @@ class StopsController extends Controller
|
||||
* name="id",
|
||||
* in="query",
|
||||
* type="array",
|
||||
* description="Stop identificators to retrieve at once. Can be used to bulk load data. If not specified will return all data.",
|
||||
* description="Stop identificators to retrieve at once. Can be used to bulk load data. If not specified will
|
||||
* return all data.",
|
||||
* @SWG\Items(type="string")
|
||||
* )
|
||||
*
|
||||
@ -45,16 +49,9 @@ class StopsController extends Controller
|
||||
*/
|
||||
public function index(Request $request, StopRepository $stops)
|
||||
{
|
||||
switch (true) {
|
||||
case $request->query->has('id'):
|
||||
$result = $stops->getManyById($request->query->get('id'));
|
||||
break;
|
||||
$modifiers = $this->getModifiersFromRequest($request);
|
||||
|
||||
default:
|
||||
$result = $stops->getAllGroups();
|
||||
}
|
||||
|
||||
return $this->json($result->all());
|
||||
return $this->json($stops->all(...$modifiers)->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,16 +72,9 @@ class StopsController extends Controller
|
||||
*/
|
||||
public function groups(Request $request, StopRepository $stops)
|
||||
{
|
||||
switch (true) {
|
||||
case $request->query->has('name'):
|
||||
$result = $stops->findGroupsByName($request->query->get('name'));
|
||||
break;
|
||||
$modifiers = $this->getModifiersFromRequest($request);
|
||||
|
||||
default:
|
||||
$result = $stops->getAllGroups();
|
||||
}
|
||||
|
||||
return $this->json($result->all());
|
||||
return $this->json(static::group($stops->all(...$modifiers))->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,7 +95,7 @@ class StopsController extends Controller
|
||||
*/
|
||||
public function one(Request $request, StopRepository $stops, $id)
|
||||
{
|
||||
return $this->json($stops->getById($id));
|
||||
return $this->json($stops->first(new IdFilter($id), new With("destinations")));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,20 +104,40 @@ class StopsController extends Controller
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Returns specific stop referenced via identificator.",
|
||||
* @SWG\Schema(type="object", properties={
|
||||
* @SWG\Property(property="track", type="object", ref=@Model(type=Track::class)),
|
||||
* @SWG\Property(property="order", type="integer", minimum="0")
|
||||
* })
|
||||
* @SWG\Schema(ref=@Model(type=TrackStop::class))
|
||||
* )
|
||||
*
|
||||
* @SWG\Tag(name="Tracks")
|
||||
*/
|
||||
public function tracks(ReferenceFactory $reference, TrackRepository $tracks, $id)
|
||||
public function tracks(TrackRepository $tracks, $id)
|
||||
{
|
||||
$stop = $reference->get(Stop::class, $id);
|
||||
|
||||
return $this->json($tracks->getByStop($stop)->map(function ($tuple) {
|
||||
return array_combine(['track', 'order'], $tuple);
|
||||
}));
|
||||
return $this->json($tracks->stops(new RelatedFilter(Stop::reference($id))));
|
||||
}
|
||||
}
|
||||
|
||||
public static function group(Collection $stops)
|
||||
{
|
||||
return $stops->groupBy(function (Stop $stop) {
|
||||
return $stop->getGroup();
|
||||
})->map(function ($stops, $key) {
|
||||
$group = new StopGroup();
|
||||
|
||||
$group->setName($key);
|
||||
$group->setStops($stops);
|
||||
|
||||
return $group;
|
||||
})->values();
|
||||
}
|
||||
|
||||
private function getModifiersFromRequest(Request $request)
|
||||
{
|
||||
if ($request->query->has('name')) {
|
||||
yield FieldFilter::contains('name', $request->query->get('name'));
|
||||
}
|
||||
|
||||
if ($request->query->has('id')) {
|
||||
yield new IdFilter($request->query->get('id'));
|
||||
}
|
||||
|
||||
if ($request->query->has('include-destinations')) {
|
||||
yield new With("destinations");
|
||||
}
|
||||
}
|
||||
}
|
98
api/src/Controller/Api/v1/TracksController.php
Normal file
98
api/src/Controller/Api/v1/TracksController.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Model\Line;
|
||||
use App\Model\Stop;
|
||||
use App\Model\Track;
|
||||
use App\Modifier\IdFilter;
|
||||
use App\Modifier\RelatedFilter;
|
||||
use App\Provider\TrackRepository;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use function App\Functions\encapsulate;
|
||||
use function Kadet\Functional\ref;
|
||||
|
||||
/**
|
||||
* @Route("/tracks")
|
||||
* @SWG\Tag(name="Tracks")
|
||||
*/
|
||||
class TracksController extends Controller
|
||||
{
|
||||
/**
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Returns all tracks for specific provider, e.g. ZTM Gdańsk.",
|
||||
* )
|
||||
* @Route("/", methods={"GET"})
|
||||
*/
|
||||
public function index(Request $request, TrackRepository $repository)
|
||||
{
|
||||
$modifiers = $this->getModifiersFromRequest($request);
|
||||
|
||||
return $this->json($repository->all(...$modifiers));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/stops", methods={"GET"})
|
||||
* @Route("/{track}/stops", methods={"GET"})
|
||||
*
|
||||
* @SWG\Tag(name="Tracks")
|
||||
*
|
||||
* @SWG\Response(response=200, description="Stops related to specified query.")
|
||||
*/
|
||||
public function stops(Request $request, TrackRepository $repository)
|
||||
{
|
||||
$modifiers = $this->getStopsModifiersFromRequest($request);
|
||||
|
||||
return $this->json($repository->stops(...$modifiers));
|
||||
}
|
||||
|
||||
private function getModifiersFromRequest(Request $request)
|
||||
{
|
||||
if ($request->query->has('stop')) {
|
||||
$stop = encapsulate($request->query->get('stop'));
|
||||
$stop = collect($stop)->map([Stop::class, 'reference']);
|
||||
|
||||
yield new RelatedFilter($stop, Stop::class);
|
||||
}
|
||||
|
||||
if ($request->query->has('line')) {
|
||||
$line = encapsulate($request->query->get('line'));
|
||||
$line = collect($line)->map([Line::class, 'reference']);
|
||||
|
||||
yield new RelatedFilter($line, Line::class);
|
||||
}
|
||||
|
||||
if ($request->query->has('id')) {
|
||||
$id = encapsulate($request->query->get('id'));
|
||||
|
||||
yield new IdFilter($id);
|
||||
}
|
||||
}
|
||||
|
||||
private function getStopsModifiersFromRequest(Request $request)
|
||||
{
|
||||
if ($request->query->has('stop')) {
|
||||
$stop = encapsulate($request->query->get('stop'));
|
||||
$stop = collect($stop)->map(ref([Stop::class, 'reference']));
|
||||
|
||||
yield new RelatedFilter($stop);
|
||||
}
|
||||
|
||||
if ($request->query->has('track') || $request->attributes->has('track')) {
|
||||
$track = $request->get('track');
|
||||
$track = Track::reference($track);
|
||||
|
||||
yield new RelatedFilter($track);
|
||||
}
|
||||
|
||||
if ($request->query->has('id')) {
|
||||
$id = encapsulate($request->query->get('id'));
|
||||
|
||||
yield new IdFilter($id);
|
||||
}
|
||||
}
|
||||
}
|
27
api/src/Controller/Api/v1/TripController.php
Normal file
27
api/src/Controller/Api/v1/TripController.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Api\v1;
|
||||
|
||||
use App\Controller\Controller;
|
||||
use App\Model\Trip;
|
||||
use App\Modifier\IdFilter;
|
||||
use App\Modifier\With;
|
||||
use App\Provider\TripRepository;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* @Route("/trips")
|
||||
*/
|
||||
class TripController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Route("/{id}", methods={"GET"})
|
||||
*/
|
||||
public function one($id, TripRepository $repository)
|
||||
{
|
||||
$trip = $repository->first(new IdFilter($id), new With('schedule'));
|
||||
|
||||
return $this->json($trip, Response::HTTP_OK, [], $this->serializerContextFactory->create(Trip::class));
|
||||
}
|
||||
}
|
27
api/src/Controller/Controller.php
Normal file
27
api/src/Controller/Controller.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
|
||||
use App\Service\SerializerContextFactory;
|
||||
use JMS\Serializer\SerializerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
abstract class Controller extends AbstractController
|
||||
{
|
||||
protected $serializer;
|
||||
protected $serializerContextFactory;
|
||||
|
||||
public function __construct(SerializerInterface $serializer, SerializerContextFactory $serializerContextFactory)
|
||||
{
|
||||
$this->serializer = $serializer;
|
||||
$this->serializerContextFactory = $serializerContextFactory;
|
||||
}
|
||||
|
||||
protected function json($data, int $status = 200, array $headers = [], $context = null): JsonResponse
|
||||
{
|
||||
return new JsonResponse($this->serializer->serialize($data, "json", $context), $status, $headers, true);
|
||||
}
|
||||
}
|
@ -9,7 +9,9 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(readOnly=true)
|
||||
* @ORM\Table("stop")
|
||||
* @ORM\Table("stop", indexes={
|
||||
* @ORM\Index(name="group_idx", columns={"group_name"})
|
||||
* })
|
||||
*/
|
||||
class StopEntity implements Entity, Fillable
|
||||
{
|
||||
@ -27,10 +29,18 @@ class StopEntity implements Entity, Fillable
|
||||
* Stop name
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string")
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Stop group name
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true, name="group_name")
|
||||
*/
|
||||
private $group;
|
||||
|
||||
/**
|
||||
* Optional stop description, should not be longer than 255 chars
|
||||
* @var string|null
|
||||
@ -43,7 +53,7 @@ class StopEntity implements Entity, Fillable
|
||||
* Optional stop variant - for example number of shed
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", nullable=true)
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $variant;
|
||||
|
||||
@ -81,6 +91,16 @@ class StopEntity implements Entity, Fillable
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getGroup(): ?string
|
||||
{
|
||||
return $this->group;
|
||||
}
|
||||
|
||||
public function setGroup(?string $group): void
|
||||
{
|
||||
$this->group = $group;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
@ -130,4 +150,4 @@ class StopEntity implements Entity, Fillable
|
||||
{
|
||||
$this->onDemand = $onDemand;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace App\Entity;
|
||||
|
||||
use App\Model\Fillable;
|
||||
use App\Model\FillTrait;
|
||||
use App\Service\IterableUtils;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
@ -44,12 +45,20 @@ class TrackEntity implements Entity, Fillable
|
||||
|
||||
/**
|
||||
* Stops in track
|
||||
* @var Collection
|
||||
* @ORM\OneToMany(targetEntity=StopInTrack::class, fetch="LAZY", mappedBy="track", cascade={"persist"})
|
||||
*
|
||||
* @var TrackStopEntity[]|Collection
|
||||
* @ORM\OneToMany(targetEntity=TrackStopEntity::class, fetch="LAZY", mappedBy="track", cascade={"persist"})
|
||||
* @ORM\OrderBy({"order": "ASC"})
|
||||
*/
|
||||
private $stopsInTrack;
|
||||
|
||||
/**
|
||||
* Final stop in this track.
|
||||
*
|
||||
* @var TrackStopEntity
|
||||
* @ORM\OneToOne(targetEntity=TrackStopEntity::class, fetch="LAZY")
|
||||
*/
|
||||
private $final;
|
||||
|
||||
/**
|
||||
* Track constructor.
|
||||
@ -98,10 +107,17 @@ class TrackEntity implements Entity, Fillable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $stopsInTrack
|
||||
* @param iterable $stopsInTrack
|
||||
*/
|
||||
public function setStopsInTrack(array $stopsInTrack): void
|
||||
public function setStopsInTrack(iterable $stopsInTrack): void
|
||||
{
|
||||
$this->stopsInTrack = new ArrayCollection($stopsInTrack);
|
||||
$this->stopsInTrack = IterableUtils::toArrayCollection($stopsInTrack);
|
||||
|
||||
$this->final = $this->stopsInTrack->last();
|
||||
}
|
||||
|
||||
public function getFinal(): TrackStopEntity
|
||||
{
|
||||
return $this->final;
|
||||
}
|
||||
}
|
@ -4,32 +4,42 @@ namespace App\Entity;
|
||||
|
||||
use App\Model\Fillable;
|
||||
use App\Model\FillTrait;
|
||||
use App\Model\Referable;
|
||||
use App\Model\ReferableTrait;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table("track_stop")
|
||||
* @ORM\Table("track_stop", uniqueConstraints={
|
||||
* @ORM\UniqueConstraint(name="stop_in_track_idx", columns={"stop_id", "track_id", "sequence"})
|
||||
* })
|
||||
*/
|
||||
class StopInTrack implements Fillable
|
||||
class TrackStopEntity implements Fillable, Referable
|
||||
{
|
||||
use FillTrait;
|
||||
use FillTrait, ReferableEntityTrait;
|
||||
|
||||
/**
|
||||
* Identifier for stop coming from provider
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=StopEntity::class, fetch="EAGER")
|
||||
* @ORM\Id
|
||||
*/
|
||||
private $stop;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=TrackEntity::class, fetch="EAGER", inversedBy="stopsInTrack")
|
||||
* @ORM\Id
|
||||
*/
|
||||
private $track;
|
||||
|
||||
/**
|
||||
* Order in track
|
||||
* @var int
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="sequence", type="integer")
|
||||
*/
|
||||
private $order;
|
@ -4,6 +4,7 @@ namespace App\Entity;
|
||||
|
||||
use App\Model\Fillable;
|
||||
use App\Model\FillTrait;
|
||||
use App\Model\Referable;
|
||||
use App\Model\Trip;
|
||||
use App\Service\IdUtils;
|
||||
use Carbon\Carbon;
|
||||
@ -14,21 +15,28 @@ use JMS\Serializer\Tests\Fixtures\Discriminator\Car;
|
||||
* @ORM\Entity
|
||||
* @ORM\Table("trip_stop")
|
||||
*/
|
||||
class TripStopEntity implements Fillable
|
||||
class TripStopEntity implements Fillable, Referable
|
||||
{
|
||||
use FillTrait;
|
||||
use FillTrait, ReferableEntityTrait;
|
||||
|
||||
/**
|
||||
* Identifier for stop coming from provider
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var StopEntity
|
||||
* @ORM\ManyToOne(targetEntity=StopEntity::class, fetch="EAGER")
|
||||
* @ORM\Id
|
||||
*/
|
||||
private $stop;
|
||||
|
||||
/**
|
||||
* @var TripEntity
|
||||
* @ORM\ManyToOne(targetEntity=TripEntity::class, fetch="EAGER", inversedBy="stops")
|
||||
* @ORM\Id
|
||||
*/
|
||||
private $trip;
|
||||
|
||||
@ -37,7 +45,6 @@ class TripStopEntity implements Fillable
|
||||
* @var int
|
||||
*
|
||||
* @ORM\Column(name="sequence", type="integer")
|
||||
* @ORM\Id
|
||||
*/
|
||||
private $order;
|
||||
|
34
api/src/Event/HandleDatabaseModifierEvent.php
Normal file
34
api/src/Event/HandleDatabaseModifierEvent.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Event;
|
||||
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Modifier\Modifier;
|
||||
use App\Provider\Repository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
class HandleDatabaseModifierEvent extends HandleModifierEvent
|
||||
{
|
||||
private $builder;
|
||||
|
||||
public function __construct(
|
||||
Modifier $modifier,
|
||||
Repository $repository,
|
||||
QueryBuilder $builder,
|
||||
array $meta = []
|
||||
) {
|
||||
parent::__construct($modifier, $repository, $meta);
|
||||
|
||||
$this->builder = $builder;
|
||||
}
|
||||
|
||||
public function getBuilder(): QueryBuilder
|
||||
{
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
public function replaceBuilder(QueryBuilder $builder): void
|
||||
{
|
||||
$this->builder = $builder;
|
||||
}
|
||||
}
|
35
api/src/Event/HandleModifierEvent.php
Normal file
35
api/src/Event/HandleModifierEvent.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Event;
|
||||
|
||||
use App\Modifier\Modifier;
|
||||
use App\Provider\Repository;
|
||||
|
||||
class HandleModifierEvent
|
||||
{
|
||||
private $repository;
|
||||
private $modifier;
|
||||
private $meta = [];
|
||||
|
||||
public function __construct(Modifier $modifier, Repository $repository, array $meta = [])
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->modifier = $modifier;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getModifier(): Modifier
|
||||
{
|
||||
return $this->modifier;
|
||||
}
|
||||
|
||||
public function getRepository()
|
||||
{
|
||||
return $this->repository;
|
||||
}
|
||||
|
||||
public function getMeta(): array
|
||||
{
|
||||
return $this->meta;
|
||||
}
|
||||
}
|
27
api/src/Event/PostProcessEvent.php
Normal file
27
api/src/Event/PostProcessEvent.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Event;
|
||||
|
||||
use App\Modifier\Modifier;
|
||||
use App\Provider\Repository;
|
||||
|
||||
class PostProcessEvent extends HandleModifierEvent
|
||||
{
|
||||
private $data;
|
||||
|
||||
public function __construct($data, Modifier $modifier, Repository $repository, array $meta = [])
|
||||
{
|
||||
parent::__construct($modifier, $repository, $meta);
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function setData($data): void
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
13
api/src/Exception/InvalidArgumentException.php
Normal file
13
api/src/Exception/InvalidArgumentException.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exception;
|
||||
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
public static function invalidType($parameter, $value, array $expected = [])
|
||||
{
|
||||
return new static(
|
||||
sprintf('Expected %s to be of type: %s. %s given.', $parameter, implode(', ', $expected), gettype($value))
|
||||
);
|
||||
}
|
||||
}
|
9
api/src/Exception/NonExistentServiceException.php
Normal file
9
api/src/Exception/NonExistentServiceException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Exception;
|
||||
|
||||
|
||||
class NonExistentServiceException extends \LogicException
|
||||
{
|
||||
}
|
7
api/src/Exception/NotSupportedException.php
Normal file
7
api/src/Exception/NotSupportedException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exception;
|
||||
|
||||
class NotSupportedException extends \LogicException
|
||||
{
|
||||
}
|
13
api/src/Exception/UnsupportedModifierException.php
Normal file
13
api/src/Exception/UnsupportedModifierException.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exception;
|
||||
|
||||
use App\Modifier\Modifier;
|
||||
|
||||
class UnsupportedModifierException extends \LogicException
|
||||
{
|
||||
public static function createFromModifier(Modifier $modifier)
|
||||
{
|
||||
return new static(sprintf("Modifier %s is not supported.", get_class($modifier)));
|
||||
}
|
||||
}
|
@ -12,4 +12,10 @@ function encapsulate($value)
|
||||
default:
|
||||
return [ $value ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setup($value, $callback)
|
||||
{
|
||||
$callback($value);
|
||||
return $value;
|
||||
}
|
3
api/src/Functions/index.php
Normal file
3
api/src/Functions/index.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/helpers.php';
|
63
api/src/Handler/Database/FieldFilterDatabaseHandler.php
Normal file
63
api/src/Handler/Database/FieldFilterDatabaseHandler.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handler\Database;
|
||||
|
||||
use App\Event\HandleDatabaseModifierEvent;
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\Stop;
|
||||
use App\Modifier\FieldFilter;
|
||||
use function App\Functions\encapsulate;
|
||||
|
||||
class FieldFilterDatabaseHandler implements ModifierHandler
|
||||
{
|
||||
protected $mapping = [
|
||||
Stop::class => [
|
||||
'name' => 'name',
|
||||
],
|
||||
ScheduledStop::class => [
|
||||
'departure' => 'departure',
|
||||
'arrival' => 'arrival',
|
||||
]
|
||||
];
|
||||
|
||||
public function process(HandleModifierEvent $event)
|
||||
{
|
||||
if (!$event instanceof HandleDatabaseModifierEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var FieldFilter $modifier */
|
||||
$modifier = $event->getModifier();
|
||||
$builder = $event->getBuilder();
|
||||
$alias = $event->getMeta()['alias'];
|
||||
|
||||
$field = $this->mapFieldName($event->getMeta()['type'], $modifier->getField());
|
||||
$operator = $modifier->getOperator();
|
||||
$value = $modifier->getValue();
|
||||
|
||||
$parameter = sprintf(":%s_%s", $alias, $field);
|
||||
|
||||
if ($operator === 'in' || $operator === 'not in') {
|
||||
$parameter = "($parameter)";
|
||||
$value = encapsulate($value);
|
||||
}
|
||||
|
||||
$builder
|
||||
->andWhere(sprintf("%s.%s %s %s", $alias, $field, $operator, $parameter))
|
||||
->setParameter($parameter, $value)
|
||||
;
|
||||
}
|
||||
|
||||
protected function mapFieldName(string $class, string $field)
|
||||
{
|
||||
if (!isset($this->mapping[$class][$field])) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Unable to map field %s of %s into entity field.", $field, $class)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->mapping[$class][$field];
|
||||
}
|
||||
}
|
103
api/src/Handler/Database/GenericWithDatabaseHandler.php
Normal file
103
api/src/Handler/Database/GenericWithDatabaseHandler.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handler\Database;
|
||||
|
||||
use App\Event\HandleDatabaseModifierEvent;
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\Track;
|
||||
use App\Model\TrackStop;
|
||||
use App\Model\Trip;
|
||||
use App\Modifier\RelatedFilter;
|
||||
use App\Service\EntityReferenceFactory;
|
||||
use App\Service\IdUtils;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use function Kadet\Functional\Transforms\property;
|
||||
|
||||
class GenericWithDatabaseHandler implements ModifierHandler
|
||||
{
|
||||
protected $mapping = [
|
||||
Track::class => [
|
||||
'line' => 'line',
|
||||
'stops' => 'stopsInTrack',
|
||||
],
|
||||
Trip::class => [
|
||||
'schedule' => 'stops.stop',
|
||||
],
|
||||
TrackStop::class => [
|
||||
'track' => 'track',
|
||||
],
|
||||
ScheduledStop::class => [
|
||||
'trip' => 'trip',
|
||||
'track' => 'trip.track',
|
||||
'destination' => 'trip.track.final',
|
||||
],
|
||||
];
|
||||
|
||||
private $em;
|
||||
private $id;
|
||||
private $references;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
IdUtils $idUtils,
|
||||
EntityReferenceFactory $references
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->id = $idUtils;
|
||||
$this->references = $references;
|
||||
}
|
||||
|
||||
public function process(HandleModifierEvent $event)
|
||||
{
|
||||
if (!$event instanceof HandleDatabaseModifierEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var RelatedFilter $modifier */
|
||||
$modifier = $event->getModifier();
|
||||
$builder = $event->getBuilder();
|
||||
$alias = $event->getMeta()['alias'];
|
||||
$type = $event->getMeta()['type'];
|
||||
|
||||
if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Relationship %s is not supported for .", $type)
|
||||
);
|
||||
}
|
||||
|
||||
$relationship = $this->mapping[$type][$modifier->getRelationship()];
|
||||
|
||||
foreach ($this->getRelationships($relationship, $alias) as [$relationshipPath, $relationshipAlias]) {
|
||||
$selected = collect($builder->getDQLPart('select'))->flatMap(property('parts'));
|
||||
|
||||
if ($selected->contains($relationshipAlias)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$builder
|
||||
->join($relationshipPath, $relationshipAlias)
|
||||
->addSelect($relationshipAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedServices()
|
||||
{
|
||||
return [
|
||||
TrackByStopDatabaseHandler::class,
|
||||
];
|
||||
}
|
||||
|
||||
private function getRelationships($relationship, $alias)
|
||||
{
|
||||
$relationships = explode('.', $relationship);
|
||||
|
||||
foreach ($relationships as $current) {
|
||||
yield [sprintf("%s.%s", $alias, $current), $alias = sprintf('%s_%s', $alias, $current)];
|
||||
}
|
||||
}
|
||||
}
|
44
api/src/Handler/Database/IdFilterDatabaseHandler.php
Normal file
44
api/src/Handler/Database/IdFilterDatabaseHandler.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handler\Database;
|
||||
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Modifier\IdFilter;
|
||||
use App\Event\HandleDatabaseModifierEvent;
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Service\IdUtils;
|
||||
use function Kadet\Functional\apply;
|
||||
|
||||
class IdFilterDatabaseHandler implements ModifierHandler
|
||||
{
|
||||
/**
|
||||
* @var IdUtils
|
||||
*/
|
||||
private $id;
|
||||
|
||||
public function __construct(IdUtils $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function process(HandleModifierEvent $event)
|
||||
{
|
||||
if (!$event instanceof HandleDatabaseModifierEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var IdFilter $modifier */
|
||||
$modifier = $event->getModifier();
|
||||
$builder = $event->getBuilder();
|
||||
$alias = $event->getMeta()['alias'];
|
||||
$provider = $event->getMeta()['provider'];
|
||||
|
||||
$id = $modifier->getId();
|
||||
$mapper = apply([$this->id, 'generate'], $provider);
|
||||
|
||||
$builder
|
||||
->andWhere($modifier->isMultiple() ? "{$alias} in (:id)" : "{$alias} = :id")
|
||||
->setParameter(':id', $modifier->isMultiple() ? array_map($mapper, $id) : $mapper($id));
|
||||
;
|
||||
}
|
||||
}
|
27
api/src/Handler/Database/LimitDatabaseHandler.php
Normal file
27
api/src/Handler/Database/LimitDatabaseHandler.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handler\Database;
|
||||
|
||||
use App\Event\HandleDatabaseModifierEvent;
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Modifier\Limit;
|
||||
|
||||
class LimitDatabaseHandler implements ModifierHandler
|
||||
{
|
||||
public function process(HandleModifierEvent $event)
|
||||
{
|
||||
if (!$event instanceof HandleDatabaseModifierEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Limit $modifier */
|
||||
$modifier = $event->getModifier();
|
||||
$builder = $event->getBuilder();
|
||||
|
||||
$builder
|
||||
->setFirstResult($modifier->getOffset())
|
||||
->setMaxResults($modifier->getCount())
|
||||
;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user