Merge branch 'master' of gitlab.com:jankstudio/resq into 419-resq-search-optimization

This commit is contained in:
Korina Cordero 2020-05-27 04:56:17 +00:00
commit 8b2a1cd09c
7 changed files with 628 additions and 97 deletions

209
composer.lock generated
View file

@ -367,20 +367,21 @@
},
{
"name": "doctrine/annotations",
"version": "v1.8.0",
"version": "1.10.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc"
"reference": "b9d758e831c70751155c698c2f7df4665314a1cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc",
"reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b9d758e831c70751155c698c2f7df4665314a1cb",
"reference": "b9d758e831c70751155c698c2f7df4665314a1cb",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"ext-tokenizer": "*",
"php": "^7.1"
},
"require-dev": {
@ -390,7 +391,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7.x-dev"
"dev-master": "1.9.x-dev"
}
},
"autoload": {
@ -431,7 +432,7 @@
"docblock",
"parser"
],
"time": "2019-10-01T18:55:10+00:00"
"time": "2020-04-20T09:18:32+00:00"
},
{
"name": "doctrine/cache",
@ -587,16 +588,16 @@
},
{
"name": "doctrine/common",
"version": "2.12.0",
"version": "2.13.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6"
"reference": "308728eae8d90412d850c155d40b1cfbede549da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/2053eafdf60c2172ee1373d1b9289ba1db7f1fc6",
"reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6",
"url": "https://api.github.com/repos/doctrine/common/zipball/308728eae8d90412d850c155d40b1cfbede549da",
"reference": "308728eae8d90412d850c155d40b1cfbede549da",
"shasum": ""
},
"require": {
@ -606,7 +607,7 @@
"doctrine/event-manager": "^1.0",
"doctrine/inflector": "^1.0",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^1.1",
"doctrine/persistence": "^1.3.3",
"doctrine/reflection": "^1.0",
"php": "^7.1"
},
@ -666,20 +667,20 @@
"doctrine",
"php"
],
"time": "2020-01-10T15:49:25+00:00"
"time": "2020-05-15T05:51:54+00:00"
},
{
"name": "doctrine/dbal",
"version": "v2.10.1",
"version": "2.10.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8"
"reference": "aab745e7b6b2de3b47019da81e7225e14dcfdac8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8",
"reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/aab745e7b6b2de3b47019da81e7225e14dcfdac8",
"reference": "aab745e7b6b2de3b47019da81e7225e14dcfdac8",
"shasum": ""
},
"require": {
@ -691,9 +692,11 @@
"require-dev": {
"doctrine/coding-standard": "^6.0",
"jetbrains/phpstorm-stubs": "^2019.1",
"phpstan/phpstan": "^0.11.3",
"nikic/php-parser": "^4.4",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^8.4.1",
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0"
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0",
"vimeo/psalm": "^3.11"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
@ -758,20 +761,20 @@
"sqlserver",
"sqlsrv"
],
"time": "2020-01-04T12:56:21+00:00"
"time": "2020-04-20T17:19:26+00:00"
},
{
"name": "doctrine/doctrine-bundle",
"version": "2.0.7",
"version": "2.0.8",
"source": {
"type": "git",
"url": "https://github.com/doctrine/DoctrineBundle.git",
"reference": "6926771140ee87a823c3b2c72602de9dda4490d3"
"reference": "b0e0deb6e700438401ede433a15a6372d2285202"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/6926771140ee87a823c3b2c72602de9dda4490d3",
"reference": "6926771140ee87a823c3b2c72602de9dda4490d3",
"url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/b0e0deb6e700438401ede433a15a6372d2285202",
"reference": "b0e0deb6e700438401ede433a15a6372d2285202",
"shasum": ""
},
"require": {
@ -850,7 +853,7 @@
"orm",
"persistence"
],
"time": "2020-01-18T11:56:15+00:00"
"time": "2020-04-23T10:52:09+00:00"
},
{
"name": "doctrine/doctrine-cache-bundle",
@ -1089,33 +1092,38 @@
},
{
"name": "doctrine/inflector",
"version": "1.3.1",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1"
"reference": "4111f6853aea6f28b2b1dcfdde83d12dd3d5e6e3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/ec3a55242203ffa6a4b27c58176da97ff0a7aec1",
"reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/4111f6853aea6f28b2b1dcfdde83d12dd3d5e6e3",
"reference": "4111f6853aea6f28b2b1dcfdde83d12dd3d5e6e3",
"shasum": ""
},
"require": {
"php": "^7.1"
"php": "^7.2"
},
"require-dev": {
"phpunit/phpunit": "^6.2"
"doctrine/coding-standard": "^7.0",
"phpstan/phpstan": "^0.11",
"phpstan/phpstan-phpunit": "^0.11",
"phpstan/phpstan-strict-rules": "^0.11",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector"
"Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector",
"Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -1144,15 +1152,21 @@
"email": "schmittjoh@gmail.com"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.",
"homepage": "https://www.doctrine-project.org/projects/inflector.html",
"keywords": [
"inflection",
"pluralize",
"singularize",
"string"
"inflector",
"lowercase",
"manipulation",
"php",
"plural",
"singular",
"strings",
"uppercase",
"words"
],
"time": "2019-10-30T19:59:35+00:00"
"time": "2020-05-09T15:09:09+00:00"
},
{
"name": "doctrine/instantiator",
@ -1356,16 +1370,16 @@
},
{
"name": "doctrine/orm",
"version": "v2.7.0",
"version": "v2.7.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/orm.git",
"reference": "4d763ca4c925f647b248b9fa01b5f47aa3685d62"
"reference": "dafe298ce5d0b995ebe1746670704c0a35868a6a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/orm/zipball/4d763ca4c925f647b248b9fa01b5f47aa3685d62",
"reference": "4d763ca4c925f647b248b9fa01b5f47aa3685d62",
"url": "https://api.github.com/repos/doctrine/orm/zipball/dafe298ce5d0b995ebe1746670704c0a35868a6a",
"reference": "dafe298ce5d0b995ebe1746670704c0a35868a6a",
"shasum": ""
},
"require": {
@ -1378,6 +1392,7 @@
"doctrine/instantiator": "^1.3",
"doctrine/persistence": "^1.2",
"ext-pdo": "*",
"ocramius/package-versions": "^1.2",
"php": "^7.1",
"symfony/console": "^3.0|^4.0|^5.0"
},
@ -1435,20 +1450,20 @@
"database",
"orm"
],
"time": "2019-11-19T08:38:05+00:00"
"time": "2020-03-19T06:41:02+00:00"
},
{
"name": "doctrine/persistence",
"version": "1.3.6",
"version": "1.3.7",
"source": {
"type": "git",
"url": "https://github.com/doctrine/persistence.git",
"reference": "5dd3ac5eebef2d0b074daa4440bb18f93132dee4"
"reference": "0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/persistence/zipball/5dd3ac5eebef2d0b074daa4440bb18f93132dee4",
"reference": "5dd3ac5eebef2d0b074daa4440bb18f93132dee4",
"url": "https://api.github.com/repos/doctrine/persistence/zipball/0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0",
"reference": "0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0",
"shasum": ""
},
"require": {
@ -1456,7 +1471,7 @@
"doctrine/cache": "^1.0",
"doctrine/collections": "^1.0",
"doctrine/event-manager": "^1.0",
"doctrine/reflection": "^1.1",
"doctrine/reflection": "^1.2",
"php": "^7.1"
},
"conflict": {
@ -1518,20 +1533,20 @@
"orm",
"persistence"
],
"time": "2020-01-16T22:06:23+00:00"
"time": "2020-03-21T15:13:52+00:00"
},
{
"name": "doctrine/reflection",
"version": "v1.1.0",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/reflection.git",
"reference": "bc420ead87fdfe08c03ecc3549db603a45b06d4c"
"reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/reflection/zipball/bc420ead87fdfe08c03ecc3549db603a45b06d4c",
"reference": "bc420ead87fdfe08c03ecc3549db603a45b06d4c",
"url": "https://api.github.com/repos/doctrine/reflection/zipball/55e71912dfcd824b2fdd16f2d9afe15684cfce79",
"reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79",
"shasum": ""
},
"require": {
@ -1552,7 +1567,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.2.x-dev"
}
},
"autoload": {
@ -1596,7 +1611,7 @@
"reflection",
"static"
],
"time": "2020-01-08T19:53:19+00:00"
"time": "2020-03-27T11:06:43+00:00"
},
{
"name": "edwinhoksberg/php-fcm",
@ -2255,16 +2270,16 @@
},
{
"name": "psr/log",
"version": "1.1.2",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
"shasum": ""
},
"require": {
@ -2298,7 +2313,7 @@
"psr",
"psr-3"
],
"time": "2019-11-01T11:05:21+00:00"
"time": "2020-03-23T09:12:05+00:00"
},
{
"name": "ralouphie/getallheaders",
@ -2515,16 +2530,16 @@
},
{
"name": "symfony/cache",
"version": "v5.0.4",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "4572116c640a6bc9fc0047180fe7f9362e5923fc"
"reference": "0c5f5b1882dc82b255a4bdead4ed3c7738cddc04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/4572116c640a6bc9fc0047180fe7f9362e5923fc",
"reference": "4572116c640a6bc9fc0047180fe7f9362e5923fc",
"url": "https://api.github.com/repos/symfony/cache/zipball/0c5f5b1882dc82b255a4bdead4ed3c7738cddc04",
"reference": "0c5f5b1882dc82b255a4bdead4ed3c7738cddc04",
"shasum": ""
},
"require": {
@ -2590,7 +2605,7 @@
"caching",
"psr6"
],
"time": "2020-01-31T09:13:47+00:00"
"time": "2020-04-28T17:58:55+00:00"
},
{
"name": "symfony/cache-contracts",
@ -2652,16 +2667,16 @@
},
{
"name": "symfony/config",
"version": "v5.0.4",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "7640c6704f56bf64045066bc5d93fd9d664baa63"
"reference": "db1674e1a261148429f123871f30d211992294e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/7640c6704f56bf64045066bc5d93fd9d664baa63",
"reference": "7640c6704f56bf64045066bc5d93fd9d664baa63",
"url": "https://api.github.com/repos/symfony/config/zipball/db1674e1a261148429f123871f30d211992294e7",
"reference": "db1674e1a261148429f123871f30d211992294e7",
"shasum": ""
},
"require": {
@ -2712,7 +2727,7 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2020-01-04T14:08:26+00:00"
"time": "2020-04-15T15:59:10+00:00"
},
{
"name": "symfony/console",
@ -2848,16 +2863,16 @@
},
{
"name": "symfony/dependency-injection",
"version": "v5.0.4",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "86338f459313525dd95f5a012f8a9ea118002f94"
"reference": "92d8b3bd896a87cdd8aba0a3dd041bc072e8cfba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/86338f459313525dd95f5a012f8a9ea118002f94",
"reference": "86338f459313525dd95f5a012f8a9ea118002f94",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/92d8b3bd896a87cdd8aba0a3dd041bc072e8cfba",
"reference": "92d8b3bd896a87cdd8aba0a3dd041bc072e8cfba",
"shasum": ""
},
"require": {
@ -2917,20 +2932,20 @@
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
"time": "2020-01-31T09:49:43+00:00"
"time": "2020-04-28T17:58:55+00:00"
},
{
"name": "symfony/doctrine-bridge",
"version": "v4.4.4",
"version": "v4.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/doctrine-bridge.git",
"reference": "b8d43116f0e5abef4b7abcbeec81c3b9328ca7b7"
"reference": "642cb1000331b8dc5568587f60aeb299070f9a55"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/b8d43116f0e5abef4b7abcbeec81c3b9328ca7b7",
"reference": "b8d43116f0e5abef4b7abcbeec81c3b9328ca7b7",
"url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/642cb1000331b8dc5568587f60aeb299070f9a55",
"reference": "642cb1000331b8dc5568587f60aeb299070f9a55",
"shasum": ""
},
"require": {
@ -3011,7 +3026,7 @@
],
"description": "Symfony Doctrine Bridge",
"homepage": "https://symfony.com",
"time": "2020-01-23T10:56:47+00:00"
"time": "2020-04-12T16:45:36+00:00"
},
{
"name": "symfony/error-handler",
@ -3838,16 +3853,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.13.1",
"version": "v1.17.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
"reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
"reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
"shasum": ""
},
"require": {
@ -3859,7 +3874,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.13-dev"
"dev-master": "1.17-dev"
}
},
"autoload": {
@ -3892,7 +3907,7 @@
"polyfill",
"portable"
],
"time": "2019-11-27T13:56:44+00:00"
"time": "2020-05-12T16:14:59+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
@ -3958,16 +3973,16 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.13.1",
"version": "v1.17.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "7b4aab9743c30be783b73de055d24a39cf4b954f"
"reference": "fa79b11539418b02fc5e1897267673ba2c19419c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f",
"reference": "7b4aab9743c30be783b73de055d24a39cf4b954f",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c",
"reference": "fa79b11539418b02fc5e1897267673ba2c19419c",
"shasum": ""
},
"require": {
@ -3979,7 +3994,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.13-dev"
"dev-master": "1.17-dev"
}
},
"autoload": {
@ -4013,7 +4028,7 @@
"portable",
"shim"
],
"time": "2019-11-27T14:18:11+00:00"
"time": "2020-05-12T16:47:27+00:00"
},
{
"name": "symfony/polyfill-php72",
@ -5222,16 +5237,16 @@
},
{
"name": "symfony/var-exporter",
"version": "v5.0.4",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "960f9ac0fdbd642461ed29d7717aeb2a94d428b9"
"reference": "5d18811da9e1ae2bb86b0a97fb2d784e27ffd59f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/960f9ac0fdbd642461ed29d7717aeb2a94d428b9",
"reference": "960f9ac0fdbd642461ed29d7717aeb2a94d428b9",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/5d18811da9e1ae2bb86b0a97fb2d784e27ffd59f",
"reference": "5d18811da9e1ae2bb86b0a97fb2d784e27ffd59f",
"shasum": ""
},
"require": {
@ -5278,7 +5293,7 @@
"instantiate",
"serialize"
],
"time": "2020-01-04T14:08:26+00:00"
"time": "2020-04-15T15:59:10+00:00"
},
{
"name": "symfony/web-profiler-bundle",

View file

@ -420,3 +420,12 @@ access_keys:
label: Update
- id: static_content.delete
label: Delete
- id: analytics
label: Analytics
acls:
- id: analytics.menu
label: Menu
- id: analytics.forecast
label: Forecasting

View file

@ -185,3 +185,12 @@ main_menu:
acl: review.list
label: Reviews
parent: partner
- id: analytics
acl: analytics.menu
label: Analytics
icon: flaticon-graphic
- id: analytics_forecast_form
acl: analytics.forecast
label: Forecasting
parent: analytics

View file

@ -0,0 +1,11 @@
# analytics
analytics_forecast_form:
path: /analytics/forecast
controller: App\Controller\AnalyticsController::forecastForm
methods: [GET]
analytics_forecast_submit:
path: /analytics/forecast
controller: App\Controller\AnalyticsController::forecastSubmit
methods: [POST]

View file

@ -0,0 +1,253 @@
<?php
namespace App\Controller;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Catalyst\MenuBundle\Annotation\Menu;
use CrEOF\Spatial\PHP\Types\Geometry\Point;
use DateTime;
use DateInterval;
use App\Entity\JobOrder;
use App\Entity\Hub;
class AnalyticsController extends Controller
{
/**
* @Menu(selected="analytics_forecast")
* @IsGranted("analytics.forecast")
*/
public function forecastForm(EntityManagerInterface $em)
{
$hub_ids = [ 6, 4, 36, 7, 8, 126, 127, 18, 12, 9, 60, 10, 21, 135 ];
$all_hubs = $em->getRepository(Hub::class)->findAll();
$hub_list = [];
foreach ($all_hubs as $hub)
{
$hub_list[$hub->getID()] = $hub->getName() . ' - ' . $hub->getBranch();
}
$params = [
'hub_list' => $hub_list,
'default_hubs' => $hub_ids,
];
return $this->render('analytics/forecast_form.html.twig', $params);
}
/**
* @Menu(selected="analytics_forecast")
* @IsGranted("analytics.forecast")
*/
public function forecastSubmit(EntityManagerInterface $em, Request $req)
{
$hub_list = $req->request->get('hub_ids', []);
$distances = $req->request->get('distances', []);
$today = DateTime::createFromFormat('d M Y', $req->request->get('date'));
error_log(print_r($hub_list, true));
// $hub_list = [ 6, 4, 36, 7, 8, 126, 127, 18, 12, 9, 60, 10, 21, 135 ];
$hub_data = [];
$hub_coverage = [];
foreach ($hub_list as $key => $hub_id)
{
$hub = $em->getRepository(Hub::class)->find($hub_id);
$coords = $hub->getCoordinates();
$dist = $distances[$key];
$hub_data[$hub_id] = $this->generateHubData($em, $hub, $dist, $today);
$hub_coverage[] = [
'longitude' => $coords->getLongitude(),
'latitude' => $coords->getLatitude(),
'distance' => $dist,
];
}
$params = [
'date' => $today,
'hub_list' => $hub_data,
'hub_coverage' => $hub_coverage,
];
return $this->render('analytics/forecast_submit.html.twig', $params);
}
protected function generateHubData($em, $hub, $distance_limit, DateTime $today)
{
$date_start = DateTime::createFromFormat('Y-m-d H:i:s', '2018-01-01 00:00:00');
$date_end = new DateTime();
// get hub to analyze
// $hub = $em->getRepository(Hub::class)->find($hub_id);
$conn = $em->getConnection();
// get job order data
$jos = $this->generateJobOrderData($conn, $hub, $distance_limit);
// initialize counters
$c_weekday = [];
$c_day = [];
// counter to check instances of hourly weekdays, so we can get average
$c_week_count = [];
// loop through job orders
foreach ($jos as $jo)
{
$date = DateTime::createFromFormat('Y-m-d H:i:s', $jo['date_schedule']);
$year = $date->format('Y');
$month = $date->format('m');
$day = $date->format('d');
$weekday = $date->format('l');
$hour = $date->format('H');
$week = $date->format('W');
// year day
if (!isset($c_day[$year][$month][$day]))
$c_day[$year][$month][$day] = 0;
$c_day[$year][$month][$day]++;
// weekday
if (!isset($c_weekday[$year][$month][$weekday][$hour]))
{
$c_weekday[$year][$month][$weekday][$hour]['total'] = 0;
$c_weekday[$year][$month][$weekday][$hour]['count'] = 0;
}
$c_weekday[$year][$month][$weekday][$hour]['total']++;
if (!isset($c_week_count[$year][$month][$week][$weekday][$hour]))
{
// error_log('week detected - ' . $week);
$c_week_count[$year][$month][$week][$weekday][$hour] = 1;
$c_weekday[$year][$month][$weekday][$hour]['count']++;
}
}
// error_log(print_r($c_weekday, true));
$chart_year = $this->generateYearData($date_start, $date_end, $c_day);
$chart_weekday = $this->generateWeekdayData($c_weekday, $today);
// error_log(print_r($chart_weekday, true));
$params = [
'id' => $hub->getID(),
'label' => $hub->getName(),
'data_year' => $chart_year,
'data_weekday' => $chart_weekday,
];
return $params;
}
protected function generateJobOrderData($conn, $hub, $distance_limit)
{
$hub_coord = $hub->getCoordinates();
// create query
// formula to convert to km is 111195 * st_distance
$sql = "select id, round(st_distance(coordinates, Point(:lng, :lat)) * 111195) as dist, date_schedule from job_order where st_distance(coordinates, Point(:lng, :lat)) * 111195 <= :distance_limit and status <> 'cancelled' order by date_schedule asc";
$stmt = $conn->prepare($sql);
$stmt->bindValue('lng', $hub_coord->getLongitude());
$stmt->bindValue('lat', $hub_coord->getLatitude());
$stmt->bindValue('distance_limit', $distance_limit);
// $stmt->bindValue('date_start', $date_start->format('Y-m-d H:i:s'));
// $stmt->bindValue('date_end', $date_end->format('Y-m-d H:i:s'));
$stmt->execute();
$jos = $stmt->fetchAll();
error_log(count($jos));
return $jos;
}
protected function generateYearData($date_start, $date_end, $c_day)
{
$res_year = [];
$date_loop = clone $date_start;
for (; $date_loop <= $date_end; $date_loop->add(new DateInterval('P1D')))
{
$year = $date_loop->format('Y');
$month = $date_loop->format('m');
$day = $date_loop->format('d');
$year_field = 'y' . $date_loop->format('Y');
$id = $date_loop->format('m-d');
// NOTE: toss aside feb 29
// TODO: handle april 29
if ($id == '02-29')
continue;
if (!isset($res_year[$id][$year_field]))
{
$res_year[$id]['date'] = $date_loop->format('M j');
$res_year[$id][$year_field] = 0;
}
if (isset($c_day[$year][$month][$day]))
$res_year[$id][$year_field] = $c_day[$year][$month][$day];
}
// error_log(print_r($res_year, true));
$chart_year = [];
foreach ($res_year as $day => $day_data)
$chart_year[] = $day_data;
return $chart_year;
}
protected function generateWeekdayData($all_weekday_data, $today)
{
$data = [];
// build hours
$hours = [];
for ($i = 0; $i < 24; $i++)
$hours[] = sprintf('%02d', $i);
$month = $today->format('m');
$weekday = $today->format('l');
$year_data = [];
foreach ($all_weekday_data as $year => $year_data)
{
// go through the hours
foreach ($hours as $hour)
{
$id = $hour + 0;
if (!isset($data[$id]))
$data[$id] = [
'hour' => $hour,
];
// get hour data
if (isset($year_data[$month][$weekday][$hour]))
{
$year_id = 'y' . $year;
$data[$id][$year_id] = $year_data[$month][$weekday][$hour]['total'];
$data[$id][$year_id . '_count'] = $year_data[$month][$weekday][$hour]['count'];
$data[$id][$year_id . '_average'] = ceil($year_data[$month][$weekday][$hour]['total'] / $year_data[$month][$weekday][$hour]['count']);
}
}
}
return $data;
}
}

View file

@ -0,0 +1,96 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">Analytics - Forecasting</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-12">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<span class="m-portlet__head-icon">
<i class="fa fa-building"></i>
</span>
<h3 class="m-portlet__head-text">
Forecasting Variables
</h3>
</div>
</div>
</div>
<form id="row-form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ url('analytics_forecast_submit') }}">
<div class="m-portlet__body">
<div class="form-group m-form__group row no-border">
<div class="col-lg-6">
<label data-field="date">Date</label>
<div class="input-group date dp">
<input type="text" name="date" id="date" class="form-control m-input" value="{{ "now"|date('d M Y') }}" readonly placeholder="Select a date" >
<span class="input-group-addon">
<i class="la la-calendar glyphicon-th"></i>
</span>
</div>
<div class="form-control-feedback hide" data-field="date"></div>
</div>
</div>
{% for hub_id in default_hubs %}
<div class="row no-border" style="padding-left: 30px; padding-right: 30px; padding-bottom: 10px;">
<div class="col-lg-6">
<select name="hub_ids[]" class="form-control m-input">
{% for key, label in hub_list %}
<option value="{{ key }}" {{ hub_id == key ? ' selected' : ''}}>{{ label }}</option>
{% endfor %}
</select>
<div class="form-control-feedback hide" data-field="name"></div>
</div>
<div class="col-lg-3">
<input type="text" name="distances[]" class="form-control m-input" value="5000">
<div class="form-control-feedback hide" data-field="branch"></div>
</div>
</div>
{% endfor %}
</div>
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
<div class="row">
<div class="col-lg-12">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
$(function() {
// datepicker
$(".dp").datepicker({
format: "dd M yyyy",
todayHighlight: true,
autoclose: true,
pickerPosition: 'top-left',
bootcssVer: 3,
clearBtn: true
});
});
</script>
{% endblock %}

View file

@ -0,0 +1,138 @@
{% extends 'base.html.twig' %}
{% block stylesheets %}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
{% endblock %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">Analytics Forecasting - {{ date | date('M - l') }}</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div id="map_coverage" style="height:600px; margin-bottom: 15px;">
</div>
{% for hub in hub_list %}
<div class="row">
<div class="col-xl-12">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title col-xl-12">
<h3 class="m-portlet__head-text col-xl-4">
{{ hub.label }}
</h3>
</div>
</div>
</div>
<div id="year-day-chart-{{ hub.id }}" style="height: 400px;">
</div>
<div id="month-weekday-chart-{{ hub.id }}" style="height: 400px;">
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{% block scripts %}
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/maps.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script>
<script>
// map
var map = L.map('map_coverage').setView([{% trans %}default_lat{% endtrans %}, {% trans %}default_long{% endtrans %}], 13);
L.tileLayer('https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key={{ maptiler_api_key }}',{
tileSize: 512,
zoomOffset: -1,
minZoom: 1,
crossOrigin: true
}).addTo(map);
{% for cover in hub_coverage %}
L.circle([{{ cover.latitude }}, {{ cover.longitude }}], { radius: {{ cover.distance }} }).addTo(map);
{% endfor %}
{% for hub in hub_list %}
// create chart instance
var chart = am4core.create("year-day-chart-{{ hub.id }}", am4charts.XYChart);
// add data
chart.data = {{ hub.data_year|json_encode|raw }};
// create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "date";
categoryAxis.title.text = "Date";
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.title.text = "Orders";
valueAxis.maxPrecision = 0;
// year day
var s2018 = chart.series.push(new am4charts.LineSeries());
s2018.name = "2018";
s2018.stroke = am4core.color("#0000FF");
s2018.strokeWidth = 2;
s2018.dataFields.valueY = "y2018";
s2018.dataFields.categoryX = "date";
var s2019 = chart.series.push(new am4charts.LineSeries());
s2019.name = "2019";
s2019.stroke = am4core.color("#FF0000");
s2019.strokeWidth = 2;
s2019.dataFields.valueY = "y2019";
s2019.dataFields.categoryX = "date";
var s2020 = chart.series.push(new am4charts.LineSeries());
s2020.name = "2020";
s2020.stroke = am4core.color("#00FF00");
s2020.strokeWidth = 2;
s2020.dataFields.valueY = "y2020";
s2020.dataFields.categoryX = "date";
//------------------------------------------------------------------------
var chart2 = am4core.create("month-weekday-chart-{{ hub.id }}", am4charts.XYChart);
chart2.data = {{ hub.data_weekday|json_encode|raw }};
var xAxis = chart2.xAxes.push(new am4charts.CategoryAxis());
xAxis.dataFields.category = "hour";
xAxis.title.text = "Hour";
var yAxis = chart2.yAxes.push(new am4charts.ValueAxis());
yAxis.title.text = "Orders";
yAxis.maxPrecision = 0;
var l2018 = chart2.series.push(new am4charts.LineSeries());
l2018.name = "2018";
l2018.stroke = am4core.color("#0000FF");
l2018.strokeWidth = 2;
l2018.dataFields.valueY = "y2018_average";
l2018.dataFields.categoryX = "hour";
var l2019 = chart2.series.push(new am4charts.LineSeries());
l2019.name = "2019";
l2019.stroke = am4core.color("#FF0000");
l2019.strokeWidth = 3;
l2019.dataFields.valueY = "y2019_average";
l2019.dataFields.categoryX = "hour";
{% endfor %}
</script>
{% endblock %}