add database support for easy querying

This commit is contained in:
Kacper Donat 2018-09-08 12:49:32 +02:00
parent 9c18634d63
commit 7c5ee55612
53 changed files with 2902 additions and 613 deletions

View File

@ -6,3 +6,10 @@
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 ###

View File

@ -12,6 +12,7 @@
"symfony/console": "*",
"symfony/flex": "^1.1",
"symfony/framework-bundle": "*",
"symfony/orm-pack": "^1.0",
"symfony/serializer-pack": "^1.0",
"symfony/twig-bundle": "*",
"symfony/yaml": "*",

913
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f3ba745662faf21f8b44dd28a0eaf7b9",
"content-hash": "0af7567013958485d4223a33f8ba099a",
"packages": [
{
"name": "doctrine/annotations",
@ -299,6 +299,319 @@
],
"time": "2018-07-12T21:16:12+00:00"
},
{
"name": "doctrine/dbal",
"version": "v2.8.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "5140a64c08b4b607b9bedaae0cedd26f04a0e621"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/5140a64c08b4b607b9bedaae0cedd26f04a0e621",
"reference": "5140a64c08b4b607b9bedaae0cedd26f04a0e621",
"shasum": ""
},
"require": {
"doctrine/cache": "^1.0",
"doctrine/event-manager": "^1.0",
"ext-pdo": "*",
"php": "^7.1"
},
"require-dev": {
"doctrine/coding-standard": "^4.0",
"jetbrains/phpstorm-stubs": "^2018.1.2",
"phpstan/phpstan": "^0.10.1",
"phpunit/phpunit": "^7.1.2",
"phpunit/phpunit-mock-objects": "!=3.2.4,!=3.2.5",
"symfony/console": "^2.0.5|^3.0|^4.0",
"symfony/phpunit-bridge": "^3.4.5|^4.0.5"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8.x-dev",
"dev-develop": "3.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\DBAL\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Database Abstraction Layer",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"database",
"dbal",
"persistence",
"queryobject"
],
"time": "2018-07-13T03:16:35+00:00"
},
{
"name": "doctrine/doctrine-bundle",
"version": "1.9.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/DoctrineBundle.git",
"reference": "703fad32e4c8cbe609caf45a71a1d4266c830f0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/703fad32e4c8cbe609caf45a71a1d4266c830f0f",
"reference": "703fad32e4c8cbe609caf45a71a1d4266c830f0f",
"shasum": ""
},
"require": {
"doctrine/dbal": "^2.5.12",
"doctrine/doctrine-cache-bundle": "~1.2",
"jdorn/sql-formatter": "^1.2.16",
"php": "^5.5.9|^7.0",
"symfony/console": "~2.7|~3.0|~4.0",
"symfony/dependency-injection": "~2.7|~3.0|~4.0",
"symfony/doctrine-bridge": "~2.7|~3.0|~4.0",
"symfony/framework-bundle": "^2.7.22|~3.0|~4.0"
},
"conflict": {
"symfony/http-foundation": "<2.6"
},
"require-dev": {
"doctrine/orm": "~2.4",
"phpunit/phpunit": "^4.8.36|^5.7|^6.4",
"satooshi/php-coveralls": "^1.0",
"symfony/phpunit-bridge": "~2.7|~3.0|~4.0",
"symfony/property-info": "~2.8|~3.0|~4.0",
"symfony/validator": "~2.7|~3.0|~4.0",
"symfony/web-profiler-bundle": "~2.7|~3.0|~4.0",
"symfony/yaml": "~2.7|~3.0|~4.0",
"twig/twig": "~1.26|~2.0"
},
"suggest": {
"doctrine/orm": "The Doctrine ORM integration is optional in the bundle.",
"symfony/web-profiler-bundle": "To use the data collector."
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Bundle\\DoctrineBundle\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Doctrine Project",
"homepage": "http://www.doctrine-project.org/"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony DoctrineBundle",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"database",
"dbal",
"orm",
"persistence"
],
"time": "2018-04-19T14:07:39+00:00"
},
{
"name": "doctrine/doctrine-cache-bundle",
"version": "1.3.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/DoctrineCacheBundle.git",
"reference": "4c8e363f96427924e7e519c5b5119b4f54512697"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineCacheBundle/zipball/4c8e363f96427924e7e519c5b5119b4f54512697",
"reference": "4c8e363f96427924e7e519c5b5119b4f54512697",
"shasum": ""
},
"require": {
"doctrine/cache": "^1.4.2",
"doctrine/inflector": "~1.0",
"php": ">=5.3.2",
"symfony/doctrine-bridge": "~2.7|~3.3|~4.0"
},
"require-dev": {
"instaclick/coding-standard": "~1.1",
"instaclick/object-calisthenics-sniffs": "dev-master",
"instaclick/symfony2-coding-standard": "dev-remaster",
"phpunit/phpunit": "~4|~5",
"predis/predis": "~0.8",
"satooshi/php-coveralls": "^1.0",
"squizlabs/php_codesniffer": "~1.5",
"symfony/console": "~2.7|~3.3|~4.0",
"symfony/finder": "~2.7|~3.3|~4.0",
"symfony/framework-bundle": "~2.7|~3.3|~4.0",
"symfony/phpunit-bridge": "~2.7|~3.3|~4.0",
"symfony/security-acl": "~2.7|~3.3",
"symfony/validator": "~2.7|~3.3|~4.0",
"symfony/yaml": "~2.7|~3.3|~4.0"
},
"suggest": {
"symfony/security-acl": "For using this bundle to cache ACLs"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Bundle\\DoctrineCacheBundle\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Fabio B. Silva",
"email": "fabio.bat.silva@gmail.com"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@hotmail.com"
},
{
"name": "Doctrine Project",
"homepage": "http://www.doctrine-project.org/"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony Bundle for Doctrine Cache",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
],
"time": "2018-03-27T09:22:12+00:00"
},
{
"name": "doctrine/doctrine-migrations-bundle",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/DoctrineMigrationsBundle.git",
"reference": "a9e506369f931351a2a6dd2aef588a822802b1b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/a9e506369f931351a2a6dd2aef588a822802b1b7",
"reference": "a9e506369f931351a2a6dd2aef588a822802b1b7",
"shasum": ""
},
"require": {
"doctrine/doctrine-bundle": "~1.0",
"doctrine/migrations": "^1.1",
"php": ">=5.4.0",
"symfony/framework-bundle": "~2.7|~3.3|~4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Bundle\\MigrationsBundle\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Doctrine Project",
"homepage": "http://www.doctrine-project.org"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony DoctrineMigrationsBundle",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"dbal",
"migrations",
"schema"
],
"time": "2017-11-01T09:13:26+00:00"
},
{
"name": "doctrine/event-manager",
"version": "v1.0.0",
@ -440,6 +753,60 @@
],
"time": "2018-01-09T20:05:19+00:00"
},
{
"name": "doctrine/instantiator",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
"reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
"phpunit/phpunit": "^6.2.3",
"squizlabs/php_codesniffer": "^3.0.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.com/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://github.com/doctrine/instantiator",
"keywords": [
"constructor",
"instantiate"
],
"time": "2017-07-22T11:58:36+00:00"
},
{
"name": "doctrine/lexer",
"version": "v1.0.1",
@ -494,6 +861,162 @@
],
"time": "2014-09-09T13:34:57+00:00"
},
{
"name": "doctrine/migrations",
"version": "v1.8.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/migrations.git",
"reference": "215438c0eef3e5f9b7da7d09c6b90756071b43e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/migrations/zipball/215438c0eef3e5f9b7da7d09c6b90756071b43e6",
"reference": "215438c0eef3e5f9b7da7d09c6b90756071b43e6",
"shasum": ""
},
"require": {
"doctrine/dbal": "~2.6",
"ocramius/proxy-manager": "^1.0|^2.0",
"php": "^7.1",
"symfony/console": "~3.3|^4.0"
},
"require-dev": {
"doctrine/coding-standard": "^1.0",
"doctrine/orm": "~2.5",
"jdorn/sql-formatter": "~1.1",
"mikey179/vfsstream": "^1.6",
"phpunit/phpunit": "~7.0",
"squizlabs/php_codesniffer": "^3.0",
"symfony/yaml": "~3.3|^4.0"
},
"suggest": {
"jdorn/sql-formatter": "Allows to generate formatted SQL with the diff command.",
"symfony/yaml": "Allows the use of yaml for migration configuration files."
},
"bin": [
"bin/doctrine-migrations"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "v1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\DBAL\\Migrations\\": "lib/Doctrine/DBAL/Migrations",
"Doctrine\\Migrations\\": "lib/Doctrine/Migrations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Michael Simonson",
"email": "contact@mikesimonson.com"
}
],
"description": "Database Schema migrations using Doctrine DBAL",
"homepage": "https://www.doctrine-project.org/projects/migrations.html",
"keywords": [
"database",
"migrations"
],
"time": "2018-06-06T21:00:30+00:00"
},
{
"name": "doctrine/orm",
"version": "v2.6.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/doctrine2.git",
"reference": "d2b4dd71d2a276edd65d0c170375b445f8a4a4a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/doctrine2/zipball/d2b4dd71d2a276edd65d0c170375b445f8a4a4a8",
"reference": "d2b4dd71d2a276edd65d0c170375b445f8a4a4a8",
"shasum": ""
},
"require": {
"doctrine/annotations": "~1.5",
"doctrine/cache": "~1.6",
"doctrine/collections": "^1.4",
"doctrine/common": "^2.7.1",
"doctrine/dbal": "^2.6",
"doctrine/instantiator": "~1.1",
"ext-pdo": "*",
"php": "^7.1",
"symfony/console": "~3.0|~4.0"
},
"require-dev": {
"doctrine/coding-standard": "^1.0",
"phpunit/phpunit": "^6.5",
"squizlabs/php_codesniffer": "^3.2",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
},
"bin": [
"bin/doctrine"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\ORM\\": "lib/Doctrine/ORM"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "Object-Relational-Mapper for PHP",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"database",
"orm"
],
"time": "2018-07-12T20:47:13+00:00"
},
{
"name": "doctrine/persistence",
"version": "v1.0.1",
@ -647,6 +1170,56 @@
],
"time": "2018-06-14T14:45:07+00:00"
},
{
"name": "jdorn/sql-formatter",
"version": "v1.2.17",
"source": {
"type": "git",
"url": "https://github.com/jdorn/sql-formatter.git",
"reference": "64990d96e0959dff8e059dfcdc1af130728d92bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc",
"reference": "64990d96e0959dff8e059dfcdc1af130728d92bc",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"classmap": [
"lib"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jeremy Dorn",
"email": "jeremy@jeremydorn.com",
"homepage": "http://jeremydorn.com/"
}
],
"description": "a PHP SQL highlighting library",
"homepage": "https://github.com/jdorn/sql-formatter/",
"keywords": [
"highlight",
"sql"
],
"time": "2014-01-12T16:20:24+00:00"
},
{
"name": "nesbot/carbon",
"version": "1.33.0",
@ -702,6 +1275,125 @@
],
"time": "2018-08-07T08:39:47+00:00"
},
{
"name": "ocramius/package-versions",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/Ocramius/PackageVersions.git",
"reference": "4489d5002c49d55576fa0ba786f42dbb009be46f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/4489d5002c49d55576fa0ba786f42dbb009be46f",
"reference": "4489d5002c49d55576fa0ba786f42dbb009be46f",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0.0",
"php": "^7.1.0"
},
"require-dev": {
"composer/composer": "^1.6.3",
"ext-zip": "*",
"infection/infection": "^0.7.1",
"phpunit/phpunit": "^7.0.0"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"PackageVersions\\": "src/PackageVersions"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"time": "2018-02-05T13:05:30+00:00"
},
{
"name": "ocramius/proxy-manager",
"version": "2.2.1",
"source": {
"type": "git",
"url": "https://github.com/Ocramius/ProxyManager.git",
"reference": "306da837ddf12aa5a85a8ca343587ec822802ac3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/306da837ddf12aa5a85a8ca343587ec822802ac3",
"reference": "306da837ddf12aa5a85a8ca343587ec822802ac3",
"shasum": ""
},
"require": {
"ocramius/package-versions": "^1.1.3",
"php": "^7.2.0",
"zendframework/zend-code": "^3.3.0"
},
"require-dev": {
"couscous/couscous": "^1.6.1",
"ext-phar": "*",
"humbug/humbug": "1.0.0-RC.0@RC",
"nikic/php-parser": "^3.1.1",
"padraic/phpunit-accelerator": "dev-master@DEV",
"phpbench/phpbench": "^0.12.2",
"phpstan/phpstan": "dev-master#856eb10a81c1d27c701a83f167dc870fd8f4236a as 0.9.999",
"phpstan/phpstan-phpunit": "dev-master#5629c0a1f4a9c417cb1077cf6693ad9753895761",
"phpunit/phpunit": "^6.4.3",
"squizlabs/php_codesniffer": "^2.9.1"
},
"suggest": {
"ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects",
"zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)",
"zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)",
"zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev"
}
},
"autoload": {
"psr-0": {
"ProxyManager\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.io/"
}
],
"description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies",
"homepage": "https://github.com/Ocramius/ProxyManager",
"keywords": [
"aop",
"lazy loading",
"proxy",
"proxy pattern",
"service proxies"
],
"time": "2018-08-26T15:07:25+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "1.0.1",
@ -1442,6 +2134,86 @@
"homepage": "https://symfony.com",
"time": "2018-08-01T08:24:03+00:00"
},
{
"name": "symfony/doctrine-bridge",
"version": "v4.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/doctrine-bridge.git",
"reference": "58e331b3f6bbbd0beeb41cc924455bf85f660f50"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/58e331b3f6bbbd0beeb41cc924455bf85f660f50",
"reference": "58e331b3f6bbbd0beeb41cc924455bf85f660f50",
"shasum": ""
},
"require": {
"doctrine/common": "~2.4",
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/dependency-injection": "<3.4"
},
"require-dev": {
"doctrine/data-fixtures": "1.0.*",
"doctrine/dbal": "~2.4",
"doctrine/orm": "^2.4.5",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/expression-language": "~3.4|~4.0",
"symfony/form": "~3.4|~4.0",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/property-access": "~3.4|~4.0",
"symfony/property-info": "~3.4|~4.0",
"symfony/proxy-manager-bridge": "~3.4|~4.0",
"symfony/security": "~3.4|~4.0",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/translation": "~3.4|~4.0",
"symfony/validator": "~3.4|~4.0"
},
"suggest": {
"doctrine/data-fixtures": "",
"doctrine/dbal": "",
"doctrine/orm": "",
"symfony/form": "",
"symfony/property-info": "",
"symfony/validator": ""
},
"type": "symfony-bridge",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Bridge\\Doctrine\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Doctrine Bridge",
"homepage": "https://symfony.com",
"time": "2018-08-24T10:22:26+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v4.1.3",
@ -1966,6 +2738,34 @@
],
"time": "2018-07-26T08:55:25+00:00"
},
{
"name": "symfony/orm-pack",
"version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/orm-pack.git",
"reference": "1b58f752cd917a08c9c8df020781d9c46a2275b1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/orm-pack/zipball/1b58f752cd917a08c9c8df020781d9c46a2275b1",
"reference": "1b58f752cd917a08c9c8df020781d9c46a2275b1",
"shasum": ""
},
"require": {
"doctrine/doctrine-bundle": "^1.6.10",
"doctrine/doctrine-migrations-bundle": "^1.3",
"doctrine/orm": "^2.5.11",
"php": "^7.0"
},
"type": "symfony-pack",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A pack for the Doctrine ORM",
"time": "2017-12-12T01:47:50+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.9.0",
@ -2944,6 +3744,113 @@
"validate"
],
"time": "2018-01-29T19:49:41+00:00"
},
{
"name": "zendframework/zend-code",
"version": "3.3.1",
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-code.git",
"reference": "c21db169075c6ec4b342149f446e7b7b724f95eb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-code/zipball/c21db169075c6ec4b342149f446e7b7b724f95eb",
"reference": "c21db169075c6ec4b342149f446e7b7b724f95eb",
"shasum": ""
},
"require": {
"php": "^7.1",
"zendframework/zend-eventmanager": "^2.6 || ^3.0"
},
"require-dev": {
"doctrine/annotations": "~1.0",
"ext-phar": "*",
"phpunit/phpunit": "^6.2.3",
"zendframework/zend-coding-standard": "^1.0.0",
"zendframework/zend-stdlib": "^2.7 || ^3.0"
},
"suggest": {
"doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features",
"zendframework/zend-stdlib": "Zend\\Stdlib component"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.3.x-dev",
"dev-develop": "3.4.x-dev"
}
},
"autoload": {
"psr-4": {
"Zend\\Code\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "provides facilities to generate arbitrary code using an object oriented interface",
"homepage": "https://github.com/zendframework/zend-code",
"keywords": [
"code",
"zf2"
],
"time": "2018-08-13T20:36:59+00:00"
},
{
"name": "zendframework/zend-eventmanager",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-eventmanager.git",
"reference": "a5e2583a211f73604691586b8406ff7296a946dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/a5e2583a211f73604691586b8406ff7296a946dd",
"reference": "a5e2583a211f73604691586b8406ff7296a946dd",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0"
},
"require-dev": {
"athletic/athletic": "^0.1",
"container-interop/container-interop": "^1.1.0",
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2",
"zendframework/zend-coding-standard": "~1.0.0",
"zendframework/zend-stdlib": "^2.7.3 || ^3.0"
},
"suggest": {
"container-interop/container-interop": "^1.1.0, to use the lazy listeners feature",
"zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev",
"dev-develop": "3.3-dev"
}
},
"autoload": {
"psr-4": {
"Zend\\EventManager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Trigger and listen to events within a PHP application",
"homepage": "https://github.com/zendframework/zend-eventmanager",
"keywords": [
"event",
"eventmanager",
"events",
"zf2"
],
"time": "2018-04-25T15:33:34+00:00"
}
],
"packages-dev": [
@ -2953,7 +3860,7 @@
"source": {
"type": "git",
"url": "http://git.kadet.net/kadet/functional-php.git",
"reference": "f8ea3de9f7f6d2f2427488434d73edd8967b6856"
"reference": "0b58a4c6207d6e7b95902bb81e49b9ec207fc909"
},
"require": {
"php": ">=7.1"
@ -2982,7 +3889,7 @@
}
],
"description": "Functional library for PHP",
"time": "2018-09-02T18:26:49+00:00"
"time": "2018-09-08T09:28:23+00:00"
},
{
"name": "symfony/dotenv",

View File

@ -5,4 +5,7 @@ return [
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],
];

View File

@ -0,0 +1,19 @@
parameters:
env(DATABASE_URL): ''
doctrine:
dbal:
driver: 'pdo_sqlite'
url: '%env(resolve:DATABASE_URL)%'
orm:
auto_generate_proxy_classes: '%kernel.debug%'
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Entity

View File

@ -0,0 +1,3 @@
doctrine_migrations:
dir_name: '%kernel.project_dir%/src/Migrations'
namespace: DoctrineMigrations

View File

@ -0,0 +1,31 @@
doctrine:
orm:
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
services:
doctrine.result_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.result_cache_pool'
doctrine.system_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.system_cache_pool'
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system

View File

@ -19,7 +19,7 @@ services:
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
exclude: '../src/{DependencyInjection,Entity,Model,Migrations,Tests,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

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><title>tram</title><path d="M352,384a32,32,0,1,0-32-32A32,32,0,0,0,352,384ZM456,128H445c-9.24-23.77-39.56-43.48-89.25-54.49l26.77-26.77a257.81,257.81,0,0,1,33.11,11.12,8.16,8.16,0,0,0,8.95-1.75l11.86-11.87a8.17,8.17,0,0,0-2.27-13.16C393.42,12.07,329.1,0,256,0S118.59,12.07,77.85,31.08a8.16,8.16,0,0,0-2.28,13.16L87.44,56.11a8.16,8.16,0,0,0,9,1.76,256.5,256.5,0,0,1,33.1-11.13l26.77,26.77c-49.69,11-80,30.72-89.25,54.49H56a24,24,0,0,0-24,24v80a24,24,0,0,0,24,24h8V416a32,32,0,0,0,32,32h41.37L83.62,501.76A6,6,0,0,0,87.86,512h25.8a12,12,0,0,0,8.48-3.51L182.63,448H329.37l60.49,60.48a12,12,0,0,0,8.48,3.52h25.8a6,6,0,0,0,4.24-10.24L374.63,448H416a32,32,0,0,0,32-32V256h8a24,24,0,0,0,24-24V152A24,24,0,0,0,456,128ZM256,32a551.75,551.75,0,0,1,89.21,6.79L316.83,67.17A547.06,547.06,0,0,0,256,64a547.06,547.06,0,0,0-60.83,3.17L166.79,38.79A551.75,551.75,0,0,1,256,32Zm0,64c87.19,0,129.08,17.14,147.52,32h-295C126.92,113.14,168.81,96,256,96ZM416,416H96V288H416Zm0-160H96V160H416ZM160,384a32,32,0,1,0-32-32A32,32,0,0,0,160,384Z"/></svg>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><title>tram</title><path d="M384,384a32,32,0,1,0-32-32A32,32,0,0,0,384,384Zm-256,0a32,32,0,1,0-32-32A32,32,0,0,0,128,384ZM488,128H475.65c-12.55-22.73-51.43-41.74-105-53l24.58-24.59c23.07,7.28,38.61,15.47,46.61,22.09A8,8,0,0,0,452.69,72l11-11.22a8,8,0,0,0-.45-11.63C429.82,20.06,350.21,0,256,0S82.18,20.06,48.79,49.16a8,8,0,0,0-.45,11.63L59.31,72a8,8,0,0,0,10.89.51c8-6.62,23.54-14.81,46.61-22.09L141.39,75c-53.61,11.24-92.49,30.25-105,53H24A24,24,0,0,0,0,152v80a24,24,0,0,0,24,24h8V416a32,32,0,0,0,32,32h73.37L83.62,501.76A6,6,0,0,0,87.86,512h25.8a12,12,0,0,0,8.48-3.51L182.63,448H329.37l60.49,60.48a12,12,0,0,0,8.48,3.52h25.8a6,6,0,0,0,4.24-10.24L374.63,448H448a32,32,0,0,0,32-32V256h8a24,24,0,0,0,24-24V152A24,24,0,0,0,488,128ZM256,32c40.87,0,75.24,3.77,103.08,9.3L331.79,68.58a629.38,629.38,0,0,0-151.58,0L152.92,41.3C180.76,35.77,215.13,32,256,32ZM448,416H64V288H448Zm0-160H64V160h0V144.21C67.62,130.83,131.7,96,256,96s188.38,34.83,192,48.21V160h0Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,8 +1,9 @@
export type LineType = "tram" | "bus" | "trolleybus" | "train" | "other";
export interface Line {
id: any;
symbol: string;
variant?: string;
type: LineType;
id: any;
symbol: string;
type: LineType;
night: boolean;
fast: boolean;
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Command;
use App\Service\DataUpdater;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class UpdateCommand extends Command
{
/** @var DataUpdater */
private $updater;
/**
* UpdateCommand constructor.
*
* @param $updater
*/
public function __construct(DataUpdater $updater)
{
parent::__construct('app:update');
$this->updater = $updater;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->updater->update();
}
}

11
src/Entity/Entity.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace App\Entity;
use App\Model\Referable;
interface Entity extends Referable
{
public function getProvider(): ProviderEntity;
public function setProvider(ProviderEntity $provider): void;
}

129
src/Entity/LineEntity.php Normal file
View File

@ -0,0 +1,129 @@
<?php
namespace App\Entity;
use App\Model\Fillable;
use App\Model\FillTrait;
use App\Model\Referable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table("line")
*/
class LineEntity implements Fillable, Entity
{
use FillTrait, ReferableEntityTrait, ProviderReferenceTrait;
/**
* Line symbol, for example '10', or 'A'
* @var string
*
* @ORM\Column(type="string", length=16)
*/
private $symbol;
/**
* Line type tram, bus or whatever.
* @var string
*
* @ORM\Column(type="string", length=20)
*/
private $type;
/**
* Is line considered as fast line?
* @var boolean
*
* @ORM\Column(type="boolean")
*/
private $fast = false;
/**
* Is line considered as night line?
* @var boolean
*
* @ORM\Column(type="boolean")
*/
private $night = false;
/**
* Line operator
*
* @var OperatorEntity
* @ORM\ManyToOne(targetEntity=OperatorEntity::class)
*/
private $operator;
/**
* @ORM\OneToMany(targetEntity=TrackEntity::class, mappedBy="line")
*/
private $tracks;
public function __construct()
{
$this->tracks = new ArrayCollection();
}
public function getSymbol(): string
{
return $this->symbol;
}
public function setSymbol(string $symbol): void
{
$this->symbol = $symbol;
}
public function getType(): string
{
return $this->type;
}
public function setType(string $type): void
{
$this->type = $type;
}
public function isFast(): bool
{
return $this->fast;
}
public function setFast(bool $fast): void
{
$this->fast = $fast;
}
public function isNight(): bool
{
return $this->night;
}
public function setNight(bool $night): void
{
$this->night = $night;
}
public function getTracks()
{
return $this->tracks;
}
/**
* @return OperatorEntity
*/
public function getOperator(): ?OperatorEntity
{
return $this->operator;
}
/**
* @param OperatorEntity $operator
*/
public function setOperator(OperatorEntity $operator): void
{
$this->operator = $operator;
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace App\Entity;
use App\Model\Fillable;
use App\Model\FillTrait;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table("operator")
*/
class OperatorEntity implements Fillable, Entity
{
use ProviderReferenceTrait, FillTrait, ReferableEntityTrait;
/**
* Describes operator name
* @var string
*
* @ORM\Column(type="string")
*/
private $name;
/**
* Contact email to operator
* @var string|null
*
* @ORM\Column(type="string", nullable=true)
*/
private $email;
/**
* URL of operators page
* @var string|null
*
* @ORM\Column(type="string", nullable=true)
*/
private $url;
/**
* Contact phone to operator
* @var string|null
*
* @ORM\Column(type="string", nullable=true)
*/
private $phone;
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): void
{
$this->email = $email;
}
public function getUrl(): ?string
{
return $this->url;
}
public function setUrl(?string $url): void
{
$this->url = $url;
}
public function getPhone(): ?string
{
return $this->phone;
}
public function setPhone(?string $phone): void
{
$this->phone = $phone;
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Entity;
use App\Model\Fillable;
use App\Model\FillTrait;
use App\Model\Referable;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table("provider")
*/
class ProviderEntity implements Fillable, Referable
{
use ReferableEntityTrait, FillTrait;
/**
* Provider short name, for example. ZTM Gdańsk
*
* @ORM\Column(type="string")
*/
private $name;
/**
* Class that handles that provider
*
* @ORM\Column(type="string")
*/
private $class;
public function getName()
{
return $this->name;
}
public function setName($name): void
{
$this->name = $name;
}
public function getClass()
{
return $this->class;
}
public function setClass($class): void
{
$this->class = $class;
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
trait ProviderReferenceTrait
{
/**
* @ORM\ManyToOne(targetEntity=ProviderEntity::class, cascade={"persist", "remove"})
*
* @var ProviderEntity
*/
private $provider;
/**
* @return ProviderEntity
*/
public function getProvider(): ProviderEntity
{
return $this->provider;
}
/**
* @param ProviderEntity|null $provider
*/
public function setProvider(ProviderEntity $provider): void
{
$this->provider = $provider;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
trait ReferableEntityTrait
{
/**
* Identifier for stop coming from provider
*
* @ORM\Column(type="string")
* @ORM\Id
*/
private $id;
public function getId()
{
return $this->id;
}
public function setId($id): void
{
$this->id = $id;
}
}

133
src/Entity/StopEntity.php Normal file
View File

@ -0,0 +1,133 @@
<?php
namespace App\Entity;
use App\Model\Fillable;
use App\Model\FillTrait;
use App\Model\Referable;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(readOnly=true)
* @ORM\Table("stop")
*/
class StopEntity implements Entity, Fillable
{
use FillTrait, ReferableEntityTrait, ProviderReferenceTrait;
/**
* Identifier for stop coming from provider
*
* @ORM\Column(type="string")
* @ORM\Id
*/
private $id;
/**
* Stop name
* @var string
*
* @ORM\Column(type="string")
*/
private $name;
/**
* Optional stop description, should not be longer than 255 chars
* @var string|null
*
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $description;
/**
* Optional stop variant - for example number of shed
* @var string|null
*
* @ORM\Column(type="string", nullable=true)
*/
private $variant;
/**
* Latitude of stop
*
* @var float|null
* @ORM\Column(type="float", nullable=true)
*/
private $latitude;
/**
* Longitude of stop
*
* @var float|null
* @ORM\Column(type="float", nullable=true)
*/
private $longitude;
/**
* True if stop is available only on demand
* @var bool
*
* @ORM\Column(type="boolean")
*/
private $onDemand = false;
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
public function getVariant(): ?string
{
return $this->variant;
}
public function setVariant(?string $variant): void
{
$this->variant = $variant;
}
public function getLatitude(): ?float
{
return $this->latitude;
}
public function setLatitude(?float $latitude): void
{
$this->latitude = $latitude;
}
public function getLongitude(): ?float
{
return $this->longitude;
}
public function setLongitude(?float $longitude): void
{
$this->longitude = $longitude;
}
public function isOnDemand(): bool
{
return $this->onDemand;
}
public function setOnDemand(bool $onDemand): void
{
$this->onDemand = $onDemand;
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Entity;
use App\Model\Fillable;
use App\Model\FillTrait;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table("track_stop")
*/
class StopInTrack implements Fillable
{
use FillTrait;
/**
* @ORM\ManyToOne(targetEntity=StopEntity::class, fetch="EAGER")
* @ORM\Id
*/
private $stop;
/**
* @ORM\ManyToOne(targetEntity=TrackEntity::class, fetch="EAGER")
* @ORM\Id
*/
private $track;
/**
* Order in track
* @var int
*
* @ORM\Column(name="sequence", type="integer")
*/
private $order;
public function getStop(): StopEntity
{
return $this->stop;
}
public function setStop(StopEntity $stop): void
{
$this->stop = $stop;
}
public function getTrack(): TrackEntity
{
return $this->track;
}
public function setTrack(TrackEntity $track): void
{
$this->track = $track;
}
public function getOrder(): int
{
return $this->order;
}
public function setOrder(int $order): void
{
$this->order = $order;
}
}

112
src/Entity/TrackEntity.php Normal file
View File

@ -0,0 +1,112 @@
<?php
namespace App\Entity;
use App\Model\Fillable;
use App\Model\FillTrait;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Kadet\Functional\Transforms as t;
/**
* @ORM\Entity
* @ORM\Table("track")
*/
class TrackEntity implements Entity, Fillable
{
use ReferableEntityTrait, FillTrait, ProviderReferenceTrait;
/**
* Line variant describing track, for example 'a'
* @var string|null
*
* @ORM\Column(type="string", length=16, nullable=true)
*/
private $variant;
/**
* Track description
* @var string|null
*
* @ORM\Column(type="string", length=256, nullable=true)
*/
private $description;
/**
* Line reference
*
* @var LineEntity
*
* @ORM\ManyToOne(targetEntity=LineEntity::class, fetch="EAGER")
*/
private $line;
/**
* Stops in track
* @var Collection
* @ORM\OneToMany(targetEntity=StopInTrack::class, mappedBy="track", cascade={"persist"})
* @ORM\OrderBy({"order"})
*/
private $stopsInTrack;
/**
* Track constructor.
*/
public function __construct()
{
$this->setStopsInTrack([]);
}
public function getVariant(): ?string
{
return $this->variant;
}
public function setVariant(?string $variant): void
{
$this->variant = $variant;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
public function getLine(): LineEntity
{
return $this->line;
}
public function setLine(LineEntity $line): void
{
$this->line = $line;
}
/**
* @return Collection
*/
public function getStopsInTrack(): Collection
{
return $this->stopsInTrack;
}
/**
* @param Collection $stopsInTrack
*/
public function setStopsInTrack(array $stopsInTrack): void
{
$this->stopsInTrack = new ArrayCollection($stopsInTrack);
}
public function getStops()
{
return $this->getStopsInTrack()->map(t\property('stop'));
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Event;
use Symfony\Component\EventDispatcher\Event;
class DataUpdateEvent extends Event
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace App\Exception;
class NotSupportedException extends \RuntimeException
{
}

0
src/Migrations/.gitignore vendored Normal file
View File

View File

@ -0,0 +1,46 @@
<?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 Version20180907212032 extends AbstractMigration
{
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 TABLE track (id VARCHAR(255) NOT NULL, line_id VARCHAR(255) DEFAULT NULL, provider_id VARCHAR(255) DEFAULT NULL, variant VARCHAR(16) DEFAULT NULL, description VARCHAR(256) DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_D6E3F8A64D7B7542 ON track (line_id)');
$this->addSql('CREATE INDEX IDX_D6E3F8A6A53A8AA ON track (provider_id)');
$this->addSql('CREATE TABLE track_stop (stop_id VARCHAR(255) NOT NULL, track_id VARCHAR(255) NOT NULL, sequence INTEGER NOT NULL, PRIMARY KEY(stop_id, track_id))');
$this->addSql('CREATE INDEX IDX_24003EB33902063D ON track_stop (stop_id)');
$this->addSql('CREATE INDEX IDX_24003EB35ED23C43 ON track_stop (track_id)');
$this->addSql('CREATE TABLE operator (id VARCHAR(255) NOT NULL, provider_id VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, email VARCHAR(255) DEFAULT NULL, url VARCHAR(255) DEFAULT NULL, phone VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_D7A6A781A53A8AA ON operator (provider_id)');
$this->addSql('CREATE TABLE provider (id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, class VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE line (id VARCHAR(255) NOT NULL, operator_id VARCHAR(255) DEFAULT NULL, provider_id VARCHAR(255) DEFAULT NULL, symbol VARCHAR(16) NOT NULL, type VARCHAR(20) NOT NULL, fast BOOLEAN NOT NULL, night BOOLEAN NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_D114B4F6584598A3 ON line (operator_id)');
$this->addSql('CREATE INDEX IDX_D114B4F6A53A8AA ON line (provider_id)');
$this->addSql('CREATE TABLE stop (id VARCHAR(255) NOT NULL, provider_id VARCHAR(255) DEFAULT 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, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_B95616B6A53A8AA ON stop (provider_id)');
}
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 TABLE track');
$this->addSql('DROP TABLE track_stop');
$this->addSql('DROP TABLE operator');
$this->addSql('DROP TABLE provider');
$this->addSql('DROP TABLE line');
$this->addSql('DROP TABLE stop');
}
}

View File

@ -1,26 +0,0 @@
<?php
namespace App\Model;
abstract class AbstractModel implements Fillable, Referable
{
use FillTrait;
private $id;
protected function setId($id)
{
$this->id = $id;
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
}

View File

@ -1,9 +1,7 @@
<?php
namespace App\Model;
use Carbon\Carbon;
class Departure implements Fillable
@ -12,7 +10,6 @@ class Departure implements Fillable
/**
* Information about line
*
* @var \App\Model\Line
*/
private $line;

View File

@ -1,9 +1,7 @@
<?php
namespace App\Model;
interface Fillable
{
public function fill(array $vars = []);

View File

@ -0,0 +1,8 @@
<?php
namespace App\Model;
interface JustReference
{
}

View File

@ -1,13 +1,14 @@
<?php
namespace App\Model;
use Symfony\Component\Serializer\Normalizer\NormalizableInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Tightenco\Collect\Support\Collection;
class Line implements Fillable, Referable
class Line implements Fillable, Referable, NormalizableInterface
{
use FillTrait, ReferenceTrait;
const TYPE_TRAM = 'tram';
const TYPE_BUS = 'bus';
const TYPE_TRAIN = 'train';
@ -15,11 +16,7 @@ class Line implements Fillable, Referable
const TYPE_TROLLEYBUS = 'trolleybus';
const TYPE_UNKNOWN = 'unknown';
/**
* Some kind of identification for provider
* @var mixed
*/
private $id;
use FillTrait, ReferableTrait;
/**
* Line symbol, for example '10', or 'A'
@ -27,27 +24,36 @@ class Line implements Fillable, Referable
*/
private $symbol;
/**
* Line variant, for example 'a'
* @var string|null
*/
private $variant;
/**
* Line type tram, bus or whatever.
* @var string
*/
private $type;
public function getId()
{
return $this->id;
}
/**
* Is line considered as fast line?
* @var boolean
*/
private $fast = false;
/**
* Is line considered as night line?
* @var boolean
*/
private $night = false;
/**
* Line operator
* @var Operator
*/
private $operator;
/**
* Tracks for this line
* @var Collection<Track>|Track[]
*/
private $tracks;
public function setId($id): void
{
$this->id = $id;
}
public function getSymbol(): string
{
@ -59,16 +65,6 @@ class Line implements Fillable, Referable
$this->symbol = $symbol;
}
public function getVariant(): ?string
{
return $this->variant;
}
public function setVariant(?string $variant): void
{
$this->variant = $variant;
}
public function getType(): string
{
return $this->type;
@ -78,4 +74,58 @@ class Line implements Fillable, Referable
{
$this->type = $type;
}
public function isFast(): bool
{
return $this->fast;
}
public function setFast(bool $fast): void
{
$this->fast = $fast;
}
public function isNight(): bool
{
return $this->night;
}
public function setNight(bool $night): void
{
$this->night = $night;
}
public function getTracks(): ?Collection
{
return $this->tracks;
}
public function setTracks($tracks)
{
$this->tracks = collect($tracks);
}
/**
* @return Operator
*/
public function getOperator(): ?Operator
{
return $this->operator;
}
/**
* @param Operator $operator
*/
public function setOperator(Operator $operator): void
{
$this->operator = $operator;
}
public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
{
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(['tracks']);
return $normalizer->normalize($this);
}
}

View File

@ -1,9 +1,7 @@
<?php
namespace App\Model;
use Carbon\Carbon;
class Message implements Fillable
@ -38,65 +36,41 @@ class Message implements Fillable
*/
private $validTo;
/**
* @return string
*/
public function getMessage(): string
{
return $this->message;
}
/**
* @param string $message
*/
public function setMessage(string $message): void
{
$this->message = $message;
}
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param mixed $type
*/
public function setType($type): void
{
$this->type = $type;
}
/**
* @return Carbon|null
*/
public function getValidFrom(): ?Carbon
{
return $this->validFrom;
}
/**
* @param Carbon|null $validFrom
*/
public function setValidFrom(?Carbon $validFrom): void
{
$this->validFrom = $validFrom;
}
/**
* @return Carbon|null
*/
public function getValidTo(): ?Carbon
{
return $this->validTo;
}
/**
* @param Carbon|null $validTo
*/
public function setValidTo(?Carbon $validTo): void
{
$this->validTo = $validTo;

72
src/Model/Operator.php Normal file
View File

@ -0,0 +1,72 @@
<?php
namespace App\Model;
class Operator implements Fillable, Referable
{
use FillTrait, ReferableTrait;
/**
* Describes operator name
* @var string
*/
private $name;
/**
* Contact email to operator
* @var string|null
*/
private $email;
/**
* URL of operators page
* @var string|null
*/
private $url;
/**
* Contact phone to operator
* @var string|null
*/
private $phone;
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): void
{
$this->email = $email;
}
public function getUrl(): ?string
{
return $this->url;
}
public function setUrl(?string $url): void
{
$this->url = $url;
}
public function getPhone(): ?string
{
return $this->phone;
}
public function setPhone(?string $phone): void
{
$this->phone = $phone;
}
}

View File

@ -1,9 +1,7 @@
<?php
namespace App\Model;
interface Referable
{
public function getId();

View File

@ -0,0 +1,34 @@
<?php
namespace App\Model;
trait ReferableTrait
{
/**
* Identifier coming from provider service
* @var string
*/
private $id;
public function getId()
{
return $this->id;
}
public function setId($id): void
{
$this->id = $id;
}
public static function reference($id)
{
if (!is_array($id)) {
$id = ['id' => $id];
}
$result = new static();
$result->fill($id);
return $result;
}
}

View File

@ -1,18 +0,0 @@
<?php
namespace App\Model;
trait ReferenceTrait
{
abstract protected function setId($id);
public static function reference($id)
{
$reference = new static();
$reference->setId($id);
return $reference;
}
}

View File

@ -1,18 +1,14 @@
<?php
namespace App\Model;
use Symfony\Component\Serializer\Normalizer\NormalizableInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Tightenco\Collect\Support\Arr;
class Stop implements Fillable, Referable
class Stop implements Referable, Fillable, NormalizableInterface
{
use FillTrait, ReferenceTrait;
/**
* Some unique stop identification
* @var mixed
*/
private $id;
use FillTrait, ReferableTrait;
/**
* Stop name
@ -21,7 +17,7 @@ class Stop implements Fillable, Referable
private $name;
/**
* Optional stop description
* Optional stop description, should not be longer than 255 chars
* @var string|null
*/
private $description;
@ -33,110 +29,95 @@ class Stop implements Fillable, Referable
private $variant;
/**
* Tuple of lat and long
* @var [float, float]
* Latitude of stop
* @var float|null
*/
private $location;
private $latitude;
/**
* Longitude of stop
* @var float|null
*/
private $longitude;
/**
* True if stop is available only on demand
* @var bool
*/
private $onDemand;
private $onDemand = false;
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $id
*/
public function setId($id): void
{
$this->id = $id;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @return null|string
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @param null|string $description
*/
public function setDescription(?string $description): void
{
$this->description = $description;
}
/**
* @return mixed
*/
public function getLocation()
{
return $this->location;
}
/**
* @param mixed $location
*/
public function setLocation($location): void
{
$this->location = $location;
}
/**
* @return null|string
*/
public function getVariant(): ?string
{
return $this->variant;
}
/**
* @param null|string $variant
*/
public function setVariant(?string $variant): void
{
$this->variant = $variant;
}
/**
* @return bool
*/
public function getLatitude(): ?float
{
return $this->latitude;
}
public function setLatitude(?float $latitude): void
{
$this->latitude = $latitude;
}
public function getLongitude(): ?float
{
return $this->longitude;
}
public function setLongitude(?float $longitude): void
{
$this->longitude = $longitude;
}
public function getLocation(): array
{
return [ $this->latitude, $this->longitude ];
}
public function setLocation(array $location)
{
list($this->latitude, $this->longitude) = $location;
}
public function isOnDemand(): bool
{
return $this->onDemand;
}
/**
* @param bool $onDemand
*/
public function setOnDemand(bool $onDemand): void
{
$this->onDemand = $onDemand;
}
public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
{
return Arr::except($normalizer->normalize($this), ['latitude', 'longitude']);
}
}

View File

@ -1,9 +1,7 @@
<?php
namespace App\Model;
use Tightenco\Collect\Support\Collection;
class StopGroup extends Collection
@ -14,17 +12,11 @@ class StopGroup extends Collection
*/
private $name;
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;

84
src/Model/Track.php Normal file
View File

@ -0,0 +1,84 @@
<?php
namespace App\Model;
use Tightenco\Collect\Support\Collection;
class Track implements Referable, Fillable
{
use ReferableTrait, FillTrait;
/**
* Line variant describing track, for example 'a'
* @var string|null
*
*/
private $variant;
/**
* Track description
* @var string|null
*/
private $description;
/**
* Line reference
* @var Line
*/
private $line;
/**
* Stops in track
* @var Collection
*/
private $stops;
/**
* Track constructor.
*/
public function __construct()
{
$this->setStops([]);
}
public function getVariant(): ?string
{
return $this->variant;
}
public function setVariant(?string $variant): void
{
$this->variant = $variant;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
public function getLine(): Line
{
return $this->line;
}
public function setLine(Line $line): void
{
$this->line = $line;
}
public function getStops(): Collection
{
return $this->stops;
}
public function setStops($stops = [])
{
return $this->stops = collect($stops);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Provider\Database;
use App\Entity\ProviderEntity;
use App\Service\IdUtils;
use Doctrine\ORM\EntityManagerInterface;
class DatabaseRepository
{
/** @var EntityManagerInterface */
protected $em;
/** @var ProviderEntity */
protected $provider;
/** @var IdUtils */
protected $id;
/**
* DatabaseRepository constructor.
*
* @param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em, IdUtils $id)
{
$this->em = $em;
$this->id = $id;
}
/** @return static */
public function withProvider(ProviderEntity $provider)
{
$result = clone $this;
$result->provider = $provider;
return $result;
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Provider\Database;
use App\Entity\LineEntity;
use App\Model\Line;
use App\Provider\LineRepository;
use Tightenco\Collect\Support\Collection;
use Kadet\Functional as f;
class GenericLineRepository extends DatabaseRepository implements LineRepository
{
public function getAll(): Collection
{
$repository = $this->em->getRepository(LineEntity::class);
$lines = $repository->findAll();
return collect($lines)->map(f\ref([$this, 'convert']));
}
public function getById($id): ?Line
{
$repository = $this->em->getRepository(LineEntity::class);
return $this->convert($repository->find($id));
}
public function getManyById($ids): Collection
{
$ids = collect($ids)->map(f\apply(f\ref([$this->id, 'generate']), $this->provider));
$repository = $this->em->getRepository(LineEntity::class);
$lines = $repository->findBy(['id' => $ids->all()]);
return collect($lines)->map(f\ref([$this, 'convert']));
}
private function convert(LineEntity $line): Line
{
return Line::createFromArray([
'id' => $this->id->of($line),
'symbol' => $line->getSymbol(),
'night' => $line->isNight(),
'fast' => $line->isFast(),
'type' => $line->getType()
]);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Provider\Database;
use App\Model\Operator;
use App\Provider\OperatorRepository;
use Tightenco\Collect\Support\Collection;
class GenericOperatorRepository extends DatabaseRepository implements OperatorRepository
{
public function getAll(): Collection
{
$repository = $this->em->getRepository(Operator::class);
$operators = $repository->findAll();
return collect($operators);
}
public function getById($id): ?Operator
{
$repository = $this->em->getRepository(Operator::class);
return $repository->find($id);
}
public function getManyById($ids): Collection
{
$repository = $this->em->getRepository(Operator::class);
$operators = $repository->findBy(['id' => $ids]);
return collect($operators);
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace App\Provider\Database;
use App\Entity\StopEntity;
use App\Model\Stop;
use App\Model\StopGroup;
use App\Provider\StopRepository;
use Tightenco\Collect\Support\Collection;
use Kadet\Functional as f;
class GenericStopRepository extends DatabaseRepository implements StopRepository
{
public function getAll(): Collection
{
$stops = $this->em->getRepository(StopEntity::class)->findAll();
return collect($stops)->map(\Closure::fromCallable([$this, 'convert']));
}
public function getAllGroups(): Collection
{
return $this->group($this->getAll());
}
public function getById($id): ?Stop
{
$id = $this->id->generate($this->provider, $id);
$stop = $this->em->getRepository(StopEntity::class)->find($id);
return $this->convert($stop);
}
public function getManyById($ids): Collection
{
$ids = collect($ids)->map(f\apply(f\ref([$this->id, 'generate']), $this->provider));
$stops = $this->em->getRepository(StopEntity::class)->findBy(['id' => $ids->all()]);
return collect($stops)->map(\Closure::fromCallable([$this, 'convert']));
}
public function findGroupsByName(string $name): Collection
{
$query = $this->em->createQueryBuilder()
->select('s')
->from(StopEntity::class, 's')
->where('s.name LIKE :name')
->getQuery();
$stops = collect($query->execute([':name' => "%$name%"]))->map(\Closure::fromCallable([$this, 'convert']));
return $this->group($stops);
}
private function convert(StopEntity $entity): Stop
{
return Stop::createFromArray([
'id' => $this->id->of($entity),
'name' => $entity->getName(),
'description' => $entity->getDescription(),
'variant' => $entity->getVariant(),
'onDemand' => $entity->isOnDemand(),
'location' => [
$entity->getLatitude(),
$entity->getLongitude(),
],
]);
}
private function group(Collection $stops)
{
return $stops->groupBy(function (Stop $stop) {
return $stop->getName();
})->map(function ($group, $key) {
$group = new StopGroup($group);
$group->setName($key);
return $group;
});
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Provider;
use App\Model\Operator;
use Tightenco\Collect\Support\Collection;
interface OperatorRepository
{
public function getAll(): Collection;
public function getById($id): ?Operator;
public function getManyById($ids): Collection;
}

View File

@ -9,6 +9,7 @@ use Tightenco\Collect\Support\Collection;
interface StopRepository extends Repository
{
public function getAll(): Collection;
public function getAllGroups(): Collection;
public function getById($id): ?Stop;

View File

@ -0,0 +1,189 @@
<?php
namespace App\Provider\ZtmGdansk;
use App\Entity\LineEntity;
use App\Entity\OperatorEntity;
use App\Entity\ProviderEntity;
use App\Entity\StopEntity;
use App\Entity\StopInTrack;
use App\Entity\TrackEntity;
use App\Model\Line as LineModel;
use App\Provider\ZtmGdanskProvider;
use App\Service\DataUpdater;
use App\Service\IdUtils;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ZtmGdanskDataUpdateSubscriber implements EventSubscriberInterface
{
const OPERATORS_URL = "http://91.244.248.30/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/dff5f71f-0134-4ef3-8116-73c1a8e929a5/download/agency.json";
const LINES_URL = "http://91.244.248.30/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/22313c56-5acf-41c7-a5fd-dc5dc72b3851/download/routes.json";
const STOPS_URL = 'http://91.244.248.19/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/cd4c08b5-460e-40db-b920-ab9fc93c1a92/download/stops.json';
const TRACKS_URL = "http://91.244.248.30/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/b15bb11c-7e06-4685-964e-3db7775f912f/download/trips.json";
const STOPS_IN_TRACKS_URL = "http://91.244.248.19/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/0f2de200-e78b-4183-ae0d-071d7f07fc3f/download/stopsintrips.json";
private $em;
private $ids;
private $logger;
/**
* ZtmGdanskDataUpdateSubscriber constructor.
*
* @param $provider
* @param $em
*/
public function __construct(EntityManagerInterface $em, IdUtils $ids, LoggerInterface $logger)
{
$this->em = $em;
$this->ids = $ids;
$this->logger = $logger;
}
public function update()
{
$provider = ProviderEntity::createFromArray([
'name' => 'ZTM Gdańsk',
'class' => ZtmGdanskProvider::class,
'id' => 'ztm-gdansk',
]);
$this->em->persist($provider);
$save = [$this->em, 'persist'];
$this->getOperators($provider)->each($save);
$this->getLines($provider)->each($save);
$this->getStops($provider)->each($save);
$this->getTracks($provider)->each($save);
$this->em->flush();
}
private function getOperators(ProviderEntity $provider)
{
$this->logger->info('Obtaining operators from ZTM Gdańsk');
$operators = file_get_contents(self::OPERATORS_URL);
$operators = json_decode($operators, true)['agency'];
$this->logger->info(sprintf('Saving %s operators from ZTM Gdańsk', count($operators)));
return collect($operators)->map(function ($operator) use ($provider) {
return OperatorEntity::createFromArray([
'id' => $this->ids->generate($provider, $operator['agencyId']),
'name' => $operator['agencyName'],
'provider' => $provider,
]);
});
}
private function getLines(ProviderEntity $provider)
{
$this->logger->info('Obtaining lines from ZTM Gdańsk');
$lines = file_get_contents(self::LINES_URL);
$lines = json_decode($lines, true)[date('Y-m-d')]['routes'];
$this->logger->info(sprintf('Saving %s lines from ZTM Gdańsk', count($lines)));
return collect($lines)->map(function ($line) use ($provider) {
$symbol = $line['routeShortName'];
$operator = $this->em->getReference(
OperatorEntity::class,
$this->ids->generate($provider, $line['agencyId'])
);
$type = [
2 => LineModel::TYPE_TRAM,
5 => LineModel::TYPE_TROLLEYBUS,
];
return LineEntity::createFromArray([
'id' => $this->ids->generate($provider, $line['routeId']),
'symbol' => $symbol,
'description' => $line['routeLongName'],
'type' => $type[$line['agencyId']] ?? LineModel::TYPE_BUS,
'night' => preg_match('/^N\d{1,3}$/', $symbol),
'fast' => preg_match('/^[A-MO-Z]$/', $symbol),
'operator' => $operator,
'provider' => $provider,
]);
});
}
private function getStops(ProviderEntity $provider)
{
$this->logger->info('Obtaining stops from ZTM Gdańsk');
$stops = file_get_contents(self::STOPS_URL);
$stops = json_decode($stops, true)[date('Y-m-d')]['stops'];
$this->logger->info(sprintf('Saving %d stops from ZTM Gdańsk', count($stops)));
return collect($stops)->map(function ($stop) use ($provider) {
return StopEntity::createFromArray([
'id' => $this->ids->generate($provider, $stop['stopId']),
'name' => trim($stop['stopName'] ?? $stop['stopDesc']),
'variant' => trim($stop['zoneName'] == 'Gdańsk' ? $stop['subName'] : null),
'latitude' => $stop['stopLat'],
'longitude' => $stop['stopLon'],
'onDemand' => (bool)$stop['onDemand'],
'provider' => $provider,
]);
});
}
public function getTracks(ProviderEntity $provider)
{
$this->logger->info('Obtaining tracks from ZTM Gdańsk');
$tracks = file_get_contents(self::TRACKS_URL);
$tracks = json_decode($tracks, true)[date('Y-m-d')]['trips'];
$this->logger->info('Obtaining stops associations from ZTM Gdańsk');
$stops = file_get_contents(self::STOPS_IN_TRACKS_URL);
$stops = json_decode($stops, true)[date('Y-m-d')]['stopsInTrip'];
$stops = collect($stops)->groupBy(function ($stop) {
return sprintf("R%sT%s", $stop['routeId'], $stop['tripId']);
});
$this->logger->info(sprintf('Saving %d tracks from ZTM Gdańsk', count($stops)));
return collect($tracks)->map(function ($track) use ($provider, $stops) {
$track = TrackEntity::createFromArray([
'id' => $track['id'],
'line' => $this->em->getReference(
LineEntity::class,
$this->ids->generate($provider, $track['routeId'])
),
'description' => preg_replace('/\(\d+\)/', '', $track['tripHeadsign']),
'provider' => $provider,
]);
$stops = $stops->get($track->getId())->map(function ($stop) use ($track, $provider) {
return StopInTrack::createFromArray([
'stop' => $this->em->getReference(
StopEntity::class,
$this->ids->generate($provider, $stop['stopId'])
),
'track' => $track,
'order' => $stop['stopSequence'],
]);
});
$track->setStopsInTrack($stops->all());
return $track;
});
}
public static function getSubscribedEvents()
{
return [
DataUpdater::UPDATE_EVENT => 'update',
];
}
}

View File

@ -1,56 +1,50 @@
<?php
namespace App\Provider\ZtmGdansk;
use App\Model\Departure;
use App\Model\Line;
use App\Model\Stop;
use App\Provider\DepartureRepository;
use App\Provider\LineRepository;
use Carbon\Carbon;
use Tightenco\Collect\Support\Collection;
use Kadet\Functional\Transforms as t;
class ZtmGdanskDepartureRepository implements DepartureRepository
{
const ESTIMATES_URL = 'http://87.98.237.99:88/delays';
/** @var LineRepository */
private $lines;
/**
* ZtmGdanskDepartureRepository constructor.
*
* @param $lines
* @param LineRepository $lines
*/
public function __construct(ZtmGdanskLineRepository $lines)
public function __construct(LineRepository $lines)
{
$this->lines = $lines;
}
public function getForStop(Stop $stop): Collection
{
try {
$estimates = json_decode(file_get_contents(static::ESTIMATES_URL . "?stopId=" . $stop->getId()), true)['delay'];
$estimates = json_decode(file_get_contents(static::ESTIMATES_URL . "?stopId=" . $stop->getId()), true)['delay'];
$estimates = collect($estimates);
return collect($estimates)->map(function ($delay) use ($stop) {
$scheduled = new Carbon($delay['theoreticalTime']);
$estimated = (clone $scheduled)->addSeconds($delay['delayInSeconds']);
$lines = $estimates->map(function ($delay) { return $delay['routeId']; })->unique();
$lines = $this->lines->getManyById($lines)->keyBy(t\property('id'));
return Departure::createFromArray([
'scheduled' => $scheduled,
'estimated' => $estimated,
'stop' => $stop,
'display' => trim($delay['headsign']),
'vehicle' => $delay['vehicleCode'],
'line' => Line::createFromArray([
'id' => $delay['id'],
'symbol' => $delay['routeId'],
'type' => $delay['routeId'] > 1 && $delay['routeId'] <= 12 ? Line::TYPE_TRAM : Line::TYPE_BUS
])
]);
})->values();
} catch (\Throwable $error) {
return collect();
}
return collect($estimates)->map(function ($delay) use ($stop, $lines) {
$scheduled = new Carbon($delay['theoreticalTime']);
$estimated = (clone $scheduled)->addSeconds($delay['delayInSeconds']);
return Departure::createFromArray([
'scheduled' => $scheduled,
'estimated' => $estimated,
'stop' => $stop,
'display' => trim($delay['headsign']),
'vehicle' => $delay['vehicleCode'],
'line' => $lines->get($delay['routeId']),
]);
})->values();
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace App\Provider\ZtmGdansk;
use App\Model\Line;
use App\Provider\LineRepository;
use Tightenco\Collect\Support\Collection;
class ZtmGdanskLineRepository implements LineRepository
{
public function getAll(): Collection
{
// TODO: Implement getAll() method.
}
public function getById($id): Line
{
// TODO: Implement getById() method.
}
public function getManyById($ids): Collection
{
// TODO: Implement getManyById() method.
}
}

View File

@ -7,6 +7,8 @@ namespace App\Provider\ZtmGdansk;
use App\Model\Message;
use App\Model\Stop;
use App\Provider\MessageRepository;
use App\Provider\ZtmGdanskProvider;
use App\Service\IdUtils;
use Carbon\Carbon;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Tightenco\Collect\Support\Collection;

View File

@ -1,108 +0,0 @@
<?php
namespace App\Provider\ZtmGdansk;
use App\Model\Stop;
use App\Model\StopGroup;
use App\Provider\StopRepository;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Tightenco\Collect\Support\Collection;
class ZtmGdanskStopRepository implements StopRepository
{
const STOPS_URL = 'http://91.244.248.19/dataset/c24aa637-3619-4dc2-a171-a23eec8f2172/resource/cd4c08b5-460e-40db-b920-ab9fc93c1a92/download/stops.json';
private $cache;
/**
* ZtmGdanskStopRepository constructor.
*/
public function __construct(AdapterInterface $cache)
{
$this->cache = $cache;
}
public function getAllGroups(): Collection
{
$stops = $this->getAllStops();
return $this->group($stops);
}
public function findGroupsByName(string $name): Collection
{
if (empty($name)) {
return collect();
}
$stops = $this->getAllStops();
$stops = $stops->filter(function (Stop $stop) use ($name) {
return stripos($stop->getName(), $name) !== false;
});
return $this->group($stops);
}
public function getAllStops(): Collection
{
static $stops = null;
if ($stops === null) {
$stops = collect($this->queryZtmApi())->map(function ($stop) {
return Stop::createFromArray([
'id' => $stop['stopId'],
'name' => trim($stop['stopName'] ?? $stop['stopDesc']),
'variant' => trim($stop['zoneName'] == 'Gdańsk' ? $stop['subName'] : null),
'location' => [$stop['stopLat'], $stop['stopLon']],
'onDemand' => (bool)$stop['onDemand'],
]);
})->keyBy(function (Stop $stop) {
return $stop->getId();
})->sort(function (Stop $a, Stop $b) {
return (int)$a->getVariant() <=> (int)$b->getVariant();
});
}
return $stops;
}
public function getById($id): ?Stop
{
return $this->getAllStops()->get($id);
}
public function getManyById($ids): Collection
{
$stops = $this->getAllStops();
return collect($ids)->mapWithKeys(function ($id) use ($stops) {
return [$id => $stops[$id]];
});
}
private function queryZtmApi()
{
$item = $this->cache->getItem('ztm-gdansk.stops');
if (!$item->isHit()) {
$stops = json_decode(file_get_contents(static::STOPS_URL), true);
$item->expiresAfter(24 * 60 * 60);
$item->set($stops[date('Y-m-d')]['stops']);
$this->cache->save($item);
}
return $item->get();
}
private function group(Collection $stops)
{
return $stops->groupBy(function (Stop $stop) {
return $stop->getName();
})->map(function ($group, $key) {
$group = new StopGroup($group);
$group->setName($key);
return $group;
});
}
}

View File

@ -3,10 +3,11 @@
namespace App\Provider;
use App\Provider\ZtmGdansk\{ZtmGdanskDepartureRepository,
ZtmGdanskLineRepository,
ZtmGdanskMessageRepository,
ZtmGdanskStopRepository};
use App\Entity\ProviderEntity;
use App\Provider\Database\GenericLineRepository;
use App\Provider\Database\GenericStopRepository;
use App\Provider\ZtmGdansk\{ZtmGdanskDepartureRepository, ZtmGdanskMessageRepository};
use Doctrine\ORM\EntityManagerInterface;
class ZtmGdanskProvider implements Provider
{
@ -16,13 +17,18 @@ class ZtmGdanskProvider implements Provider
private $messages;
public function __construct(
ZtmGdanskLineRepository $lines,
ZtmGdanskDepartureRepository $departures,
ZtmGdanskStopRepository $stops,
EntityManagerInterface $em,
GenericLineRepository $lines,
GenericStopRepository $stops,
ZtmGdanskMessageRepository $messages
) {
$provider = $em->getReference(ProviderEntity::class, 'ztm-gdansk');
$lines = $lines->withProvider($provider);
$stops = $stops->withProvider($provider);
$this->lines = $lines;
$this->departures = $departures;
$this->departures = new ZtmGdanskDepartureRepository($lines);
$this->stops = $stops;
$this->messages = $messages;
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Service;
use App\Event\DataUpdateEvent;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class DataUpdater
{
const UPDATE_EVENT = 'app.data_update';
/** @var EventDispatcherInterface */
private $dispatcher;
/** @var EntityManagerInterface */
private $em;
/**
* DataUpdater constructor.
*
* @param EventDispatcherInterface $dispatcher
*/
public function __construct(EventDispatcherInterface $dispatcher, EntityManagerInterface $em)
{
$this->dispatcher = $dispatcher;
$this->em = $em;
}
public function update()
{
$schema = $this->em->getConnection()->getSchemaManager();
collect($schema->listTables())->each([$schema, 'dropAndCreateTable']);
$this->dispatcher->dispatch(self::UPDATE_EVENT, new DataUpdateEvent());
}
}

24
src/Service/IdUtils.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace App\Service;
use App\Entity\Entity;
use App\Entity\ProviderEntity;
class IdUtils
{
public function generate(ProviderEntity $provider, $id)
{
return sprintf('%s-%s', $provider->getId(), $id);
}
public function strip(ProviderEntity $provider, $id)
{
return substr($id, strlen($provider->getId()) + 1);
}
public function of(Entity $entity)
{
return $this->strip($entity->getProvider(), $entity->getId());
}
}

View File

@ -17,27 +17,69 @@
"doctrine/common": {
"version": "v2.9.0"
},
"doctrine/dbal": {
"version": "v2.8.0"
},
"doctrine/doctrine-bundle": {
"version": "1.6",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "1.6",
"ref": "ae205d5114e719deb64d2110f56ef910787d1e04"
}
},
"doctrine/doctrine-cache-bundle": {
"version": "1.3.3"
},
"doctrine/doctrine-migrations-bundle": {
"version": "1.2",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "1.2",
"ref": "c1431086fec31f17fbcfe6d6d7e92059458facc1"
}
},
"doctrine/event-manager": {
"version": "v1.0.0"
},
"doctrine/inflector": {
"version": "v1.3.0"
},
"doctrine/instantiator": {
"version": "1.1.0"
},
"doctrine/lexer": {
"version": "v1.0.1"
},
"doctrine/migrations": {
"version": "v1.8.1"
},
"doctrine/orm": {
"version": "v2.6.2"
},
"doctrine/persistence": {
"version": "v1.0.0"
},
"doctrine/reflection": {
"version": "v1.0.0"
},
"jdorn/sql-formatter": {
"version": "v1.2.17"
},
"kadet/functional": {
"version": "dev-master"
},
"nesbot/carbon": {
"version": "1.33.0"
},
"ocramius/package-versions": {
"version": "1.3.0"
},
"ocramius/proxy-manager": {
"version": "2.2.1"
},
"phpdocumentor/reflection-common": {
"version": "1.0.1"
},
@ -89,6 +131,9 @@
"symfony/dependency-injection": {
"version": "v4.1.3"
},
"symfony/doctrine-bridge": {
"version": "v4.1.4"
},
"symfony/dotenv": {
"version": "v4.1.3"
},
@ -128,6 +173,9 @@
"symfony/inflector": {
"version": "v4.1.3"
},
"symfony/orm-pack": {
"version": "v1.0.5"
},
"symfony/polyfill-mbstring": {
"version": "v1.9.0"
},
@ -202,5 +250,11 @@
},
"webmozart/assert": {
"version": "1.3.0"
},
"zendframework/zend-code": {
"version": "3.3.1"
},
"zendframework/zend-eventmanager": {
"version": "3.2.1"
}
}