Reorganize project part 2

This commit is contained in:
Bernd Bestel 2018-04-11 19:49:35 +02:00
parent bcd5092427
commit feb88ab685
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
56 changed files with 1988 additions and 826 deletions

View File

@ -1,66 +0,0 @@
<?php
class GrocyPhpHelper
{
public static function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
{
foreach($array as $object)
{
if($object->{$propertyName} == $propertyValue)
{
return $object;
}
}
return null;
}
public static function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==')
{
$returnArray = array();
foreach($array as $object)
{
switch($operator)
{
case '==':
if($object->{$propertyName} == $propertyValue)
{
$returnArray[] = $object;
}
break;
case '>':
if($object->{$propertyName} > $propertyValue)
{
$returnArray[] = $object;
}
break;
case '<':
if($object->{$propertyName} < $propertyValue)
{
$returnArray[] = $object;
}
break;
}
}
return $returnArray;
}
public static function SumArrayValue($array, $propertyName)
{
$sum = 0;
foreach($array as $object)
{
$sum += $object->{$propertyName};
}
return $sum;
}
public static function GetClassConstants($className)
{
$r = new ReflectionClass($className);
return $r->getConstants();
}
}

View File

@ -1,8 +1,15 @@
{
"require": {
"slim/slim": "^3.8",
"slim/php-view": "^2.2",
"morris/lessql": "^0.3.4",
"pavlakis/slim-cli": "^1.0"
"pavlakis/slim-cli": "^1.0",
"rubellum/slim-blade-view": "^0.1.1"
},
"autoload": {
"psr-4": {
"Grocy\\Services\\": "services/",
"Grocy\\Controllers\\": "controllers/",
"Grocy\\Middleware\\": "middleware/"
}
}
}

807
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "bf75d2487343249c600746a03f63cfd2",
"content-hash": "12ebab60e283dfdab831d1cc22430d05",
"packages": [
{
"name": "container-interop/container-interop",
@ -37,6 +37,363 @@
"homepage": "https://github.com/container-interop/container-interop",
"time": "2017-02-14T19:40:03+00:00"
},
{
"name": "doctrine/inflector",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "5527a48b7313d15261292c149e55e26eae771b0a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a",
"reference": "5527a48b7313d15261292c149e55e26eae771b0a",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^6.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector"
}
},
"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": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"inflection",
"pluralize",
"singularize",
"string"
],
"time": "2018-01-09T20:05:19+00:00"
},
{
"name": "illuminate/container",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
"reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
"reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.6.*",
"php": "^7.1.3",
"psr/container": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Container\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Container package.",
"homepage": "https://laravel.com",
"time": "2018-01-21T02:13:38+00:00"
},
{
"name": "illuminate/contracts",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
"reference": "322ec80498b3bf85bc4025d028e130a9b50242b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/322ec80498b3bf85bc4025d028e130a9b50242b9",
"reference": "322ec80498b3bf85bc4025d028e130a9b50242b9",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/container": "~1.0",
"psr/simple-cache": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Contracts\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Contracts package.",
"homepage": "https://laravel.com",
"time": "2018-04-07T17:05:26+00:00"
},
{
"name": "illuminate/events",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/events.git",
"reference": "b6e73ed40478cef2ef98d5ddb27f333291606cea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/events/zipball/b6e73ed40478cef2ef98d5ddb27f333291606cea",
"reference": "b6e73ed40478cef2ef98d5ddb27f333291606cea",
"shasum": ""
},
"require": {
"illuminate/container": "5.6.*",
"illuminate/contracts": "5.6.*",
"illuminate/support": "5.6.*",
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Events\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Events package.",
"homepage": "https://laravel.com",
"time": "2018-02-26T19:00:55+00:00"
},
{
"name": "illuminate/filesystem",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/filesystem.git",
"reference": "c9ab9376076cedd88a374d7281d62b619634d578"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/c9ab9376076cedd88a374d7281d62b619634d578",
"reference": "c9ab9376076cedd88a374d7281d62b619634d578",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.6.*",
"illuminate/support": "5.6.*",
"php": "^7.1.3",
"symfony/finder": "~4.0"
},
"suggest": {
"league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
"league/flysystem-cached-adapter": "Required to use the Flysystem cache (~1.0).",
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
"league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Filesystem package.",
"homepage": "https://laravel.com",
"time": "2018-04-06T13:15:37+00:00"
},
{
"name": "illuminate/support",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
"reference": "fad0669f858423679497a17f973261cc32f9a5a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/fad0669f858423679497a17f973261cc32f9a5a8",
"reference": "fad0669f858423679497a17f973261cc32f9a5a8",
"shasum": ""
},
"require": {
"doctrine/inflector": "~1.1",
"ext-mbstring": "*",
"illuminate/contracts": "5.6.*",
"nesbot/carbon": "^1.24.1",
"php": "^7.1.3"
},
"conflict": {
"tightenco/collect": "<5.5.33"
},
"suggest": {
"illuminate/filesystem": "Required to use the composer class (5.6.*).",
"symfony/process": "Required to use the composer class (~4.0).",
"symfony/var-dumper": "Required to use the dd function (~4.0)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Support\\": ""
},
"files": [
"helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Support package.",
"homepage": "https://laravel.com",
"time": "2018-04-05T21:19:22+00:00"
},
{
"name": "illuminate/view",
"version": "v5.6.16",
"source": {
"type": "git",
"url": "https://github.com/illuminate/view.git",
"reference": "54eaf45ee7946d8f8cde13d5e89c5ea2e997040d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/view/zipball/54eaf45ee7946d8f8cde13d5e89c5ea2e997040d",
"reference": "54eaf45ee7946d8f8cde13d5e89c5ea2e997040d",
"shasum": ""
},
"require": {
"illuminate/container": "5.6.*",
"illuminate/contracts": "5.6.*",
"illuminate/events": "5.6.*",
"illuminate/filesystem": "5.6.*",
"illuminate/support": "5.6.*",
"php": "^7.1.3",
"symfony/debug": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.6-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\View\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate View package.",
"homepage": "https://laravel.com",
"time": "2018-04-03T12:56:35+00:00"
},
{
"name": "morris/lessql",
"version": "v0.3.5",
@ -85,6 +442,59 @@
],
"time": "2018-01-27T13:18:21+00:00"
},
{
"name": "nesbot/carbon",
"version": "1.25.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4",
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/translation": "~2.6 || ~3.0 || ~4.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2",
"phpunit/phpunit": "^4.8.35 || ^5.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.23-dev"
}
},
"autoload": {
"psr-4": {
"Carbon\\": "src/Carbon/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brian Nesbitt",
"email": "brian@nesbot.com",
"homepage": "http://nesbot.com"
}
],
"description": "A simple API extension for DateTime.",
"homepage": "http://carbon.nesbot.com",
"keywords": [
"date",
"datetime",
"time"
],
"time": "2018-03-19T15:50:49+00:00"
},
{
"name": "nikic/fast-route",
"version": "v1.3.0",
@ -180,6 +590,47 @@
],
"time": "2017-01-30T22:50:06+00:00"
},
{
"name": "philo/laravel-blade",
"version": "v3.1",
"source": {
"type": "git",
"url": "https://github.com/PhiloNL/Laravel-Blade.git",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PhiloNL/Laravel-Blade/zipball/3f0ce2ee198604c53c25188110e6d7b5e887527a",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a",
"shasum": ""
},
"require": {
"illuminate/events": "~5",
"illuminate/view": "~5"
},
"type": "library",
"autoload": {
"psr-4": {
"Philo\\Blade\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Philo Hermans",
"email": "me@philohermans.com"
}
],
"description": "Use the simple and yet powerful Laravel Blade templating engine as a standalone component.",
"keywords": [
"blade",
"laravel"
],
"time": "2015-12-04T09:42:42+00:00"
},
{
"name": "pimple/pimple",
"version": "v3.2.3",
@ -330,24 +781,121 @@
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "slim/php-view",
"version": "2.2.0",
"name": "psr/log",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/slimphp/PHP-View.git",
"reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f"
"url": "https://github.com/php-fig/log.git",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/PHP-View/zipball/122ed121a8d9cf91a94020814d2a3ee6c836754f",
"reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2016-10-10T12:19:37+00:00"
},
{
"name": "psr/simple-cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"time": "2017-10-23T01:57:42+00:00"
},
{
"name": "rubellum/slim-blade-view",
"version": "0.1.1",
"source": {
"type": "git",
"url": "https://github.com/rubellum/Slim-Blade-View.git",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rubellum/Slim-Blade-View/zipball/9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"shasum": ""
},
"require": {
"illuminate/view": "5.*",
"philo/laravel-blade": "3.*",
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8",
"phpunit/phpunit": "^5.0",
"slim/slim": "^3.0"
},
"type": "library",
@ -362,21 +910,20 @@
],
"authors": [
{
"name": "Glenn Eggleton",
"email": "geggleto@gmail.com"
"name": "Hiroaki Matsuura",
"email": "hiropeke.jp@gmail.com"
}
],
"description": "Render PHP view scripts into a PSR-7 Response object.",
"description": "Slim Framework 3 view helper built on the Blade component",
"keywords": [
"blade",
"framework",
"php",
"phtml",
"renderer",
"slim",
"template",
"view"
],
"time": "2016-10-11T07:43:08+00:00"
"time": "2016-03-11T02:32:00+00:00"
},
{
"name": "slim/slim",
@ -448,6 +995,238 @@
"router"
],
"time": "2017-11-26T19:13:09+00:00"
},
{
"name": "symfony/debug",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "5961d02d48828671f5d8a7805e06579d692f6ede"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/5961d02d48828671f5d8a7805e06579d692f6ede",
"reference": "5961d02d48828671f5d8a7805e06579d692f6ede",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"psr/log": "~1.0"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "~3.4|~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"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 Debug Component",
"homepage": "https://symfony.com",
"time": "2018-04-03T05:24:00+00:00"
},
{
"name": "symfony/finder",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
"reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
},
"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 Finder Component",
"homepage": "https://symfony.com",
"time": "2018-04-04T05:10:37+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"time": "2018-01-30T19:27:44+00:00"
},
{
"name": "symfony/translation",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/e20a9b7f9f62cb33a11638b345c248e7d510c938",
"reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/config": "<3.4",
"symfony/dependency-injection": "<3.4",
"symfony/yaml": "<3.4"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/finder": "~2.8|~3.0|~4.0",
"symfony/intl": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"psr/log": "To use logging capability in translator",
"symfony/config": "",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Translation\\": ""
},
"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 Translation Component",
"homepage": "https://symfony.com",
"time": "2018-02-22T10:50:29+00:00"
}
],
"packages-dev": [],

View File

@ -0,0 +1,11 @@
<?php
namespace Grocy\Controllers;
class BaseApiController extends BaseController
{
protected function ApiEncode($response)
{
return json_encode($response);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\DatabaseService;
class BaseController
{
public function __construct(\Slim\Container $container) {
$this->AppContainer = $container;
$databaseService = new DatabaseService();
$this->Database = $databaseService->GetDbConnection();
}
protected $AppContainer;
protected $Database;
}

View File

@ -0,0 +1,32 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\BatteriesService;
class BatteriesApiController extends BaseApiController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->BatteriesService = new BatteriesService();
}
protected $BatteriesService;
public function TrackChargeCycle($request, $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
return $this->ApiEncode(array('success' => $this->BatteriesService->TrackChargeCycle($args['batteryId'], $trackedTime)));
}
public function BatteryDetails($request, $response, $args)
{
return $this->ApiEncode($this->BatteriesService->GetBatteryDetails($args['batteryId']));
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\BatteriesService;
class BatteriesController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->BatteriesService = new BatteriesService();
}
protected $BatteriesService;
public function Overview($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'batteriesoverview', [
'title' => 'Batteries overview',
'contentPage' => 'batteriesoverview.php',
'batteries' => $this->Database->batteries(),
'current' => $this->BatteriesService->GetCurrent(),
]);
}
public function TrackChargeCycle($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'batterytracking', [
'title' => 'Battery tracking',
'contentPage' => 'batterytracking.php',
'batteries' => $this->Database->batteries()
]);
}
public function BatteriesList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'batteries', [
'title' => 'Batteries',
'contentPage' => 'batteries.php',
'batteries' => $this->Database->batteries()
]);
}
public function BatteryEditForm($request, $response, $args)
{
if ($args['batteryId'] == 'new')
{
return $this->AppContainer->view->render($response, 'batteryform', [
'title' => 'Create battery',
'contentPage' => 'batteryform.php',
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'batteryform', [
'title' => 'Edit battery',
'contentPage' => 'batteryform.php',
'battery' => $this->Database->batteries($args['batteryId']),
'mode' => 'edit'
]);
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\ApplicationService;
use Grocy\Services\DatabaseMigrationService;
class CliController extends BaseController
{
public function RecreateDemo($request, $response, $args)
{
$applicationService = new ApplicationService();
if ($applicationService->IsDemoInstallation())
{
$databaseMigrationService = new DatabaseMigrationService();
$databaseMigrationService->RecreateDemo();
}
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Grocy\Controllers;
class GenericEntityApiController extends BaseApiController
{
public function GetObjects($request, $response, $args)
{
return $this->ApiEncode($this->Database->{$args['entity']}());
}
public function GetObject($request, $response, $args)
{
return $this->ApiEncode($this->Database->{$args['entity']}($args['objectId']));
}
public function AddObject($request, $response, $args)
{
$newRow = $this->Database->{$args['entity']}()->createRow($request->getParsedBody());
$newRow->save();
$success = $newRow->isClean();
return $this->ApiEncode(array('success' => $success));
}
public function EditObject($request, $response, $args)
{
$row = $this->Database->{$args['entity']}($args['objectId']);
$row->update($request->getParsedBody());
$success = $row->isClean();
return $this->ApiEncode(array('success' => $success));
}
public function DeleteObject($request, $response, $args)
{
$row = $this->Database->{$args['entity']}($args['objectId']);
$row->delete();
$success = $row->isClean();
return $this->ApiEncode(array('success' => $success));
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\HabitsService;
class HabitsApiController extends BaseApiController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->HabitsService = new HabitsService();
}
protected $HabitsService;
public function TrackHabitExecution($request, $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
return $this->ApiEncode(array('success' => $this->HabitsService->TrackHabit($args['habitId'], $trackedTime)));
}
public function HabitDetails($request, $response, $args)
{
return $this->ApiEncode($this->HabitsService->GetHabitDetails($args['habitId']));
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\HabitsService;
class HabitsController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->HabitsService = new HabitsService();
}
protected $HabitsService;
public function Overview($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'habitsoverview', [
'title' => 'Habits overview',
'contentPage' => 'habitsoverview.php',
'habits' => $this->Database->habits(),
'currentHabits' => $this->HabitsService->GetCurrentHabits(),
]);
}
public function TrackHabitExecution($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'habittracking', [
'title' => 'Habit tracking',
'contentPage' => 'habittracking.php',
'habits' => $this->Database->habits()
]);
}
public function HabitsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'habits', [
'title' => 'Habits',
'contentPage' => 'habits.php',
'habits' => $this->Database->habits()
]);
}
public function HabitEditForm($request, $response, $args)
{
if ($args['habitId'] == 'new')
{
return $this->AppContainer->view->render($response, 'habitform', [
'title' => 'Create habit',
'contentPage' => 'habitform.php',
'periodTypes' => GetClassConstants('Grocy\Services\HabitsService'),
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'habitform', [
'title' => 'Edit habit',
'contentPage' => 'habitform.php',
'habit' => $this->Database->habits($args['habitId']),
'periodTypes' => GetClassConstants('Grocy\Services\HabitsService'),
'mode' => 'edit'
]);
}
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\SessionService;
use Grocy\Services\DatabaseService;
use Grocy\Services\ApplicationService;
use Grocy\Services\DatabaseMigrationService;
use Grocy\Services\DemoDataGeneratorService;
class LoginController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->SessionService = new SessionService();
}
protected $SessionService;
public function ProcessLogin($request, $response, $args)
{
$postParams = $request->getParsedBody();
if (isset($postParams['username']) && isset($postParams['password']))
{
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD)
{
$sessionKey = $this->SessionService->CreateSession();
setcookie('grocy_session', $sessionKey, time()+2592000); //30 days
return $response->withRedirect('/');
}
else
{
return $response->withRedirect('/login?invalid=true');
}
}
else
{
return $response->withRedirect('/login?invalid=true');
}
}
public function LoginPage($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'login', [
'title' => 'Login',
'contentPage' => 'login.php'
]);
}
public function Logout($request, $response, $args)
{
$this->SessionService->RemoveSession($_COOKIE['grocy_session']);
return $response->withRedirect('/');
}
public function Root($request, $response, $args)
{
// Schema migration is done here
$databaseMigrationService = new DatabaseMigrationService();
$databaseMigrationService->MigrateDatabase();
$applicationService = new ApplicationService();
if ($applicationService->IsDemoInstallation())
{
$demoDataGeneratorService = new DemoDataGeneratorService();
$demoDataGeneratorService->PopulateDemoData();
}
return $response->withRedirect('/stockoverview');
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\StockService;
class StockApiController extends BaseApiController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->StockService = new StockService();
}
protected $StockService;
public function ProductDetails($request, $response, $args)
{
return $this->ApiEncode($this->StockService->GetProductDetails($args['productId']));
}
public function AddProduct($request, $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
}
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
{
$transactionType = $request->getQueryParams()['transactiontype'];
}
return $this->ApiEncode(array('success' => $this->StockService->AddProduct($args['productId'], $args['amount'], $bestBeforeDate, $transactionType)));
}
public function ConsumeProduct($request, $response, $args)
{
$spoiled = false;
if (isset($request->getQueryParams()['spoiled']) && !empty($request->getQueryParams()['spoiled']) && $request->getQueryParams()['spoiled'] == '1')
{
$spoiled = true;
}
$transactionType = StockService::TRANSACTION_TYPE_CONSUME;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
{
$transactionType = $request->getQueryParams()['transactiontype'];
}
return $this->ApiEncode(array('success' => $this->StockService->ConsumeProduct($args['productId'], $args['amount'], $spoiled, $transactionType)));
}
public function InventoryProduct($request, $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
}
return $this->ApiEncode(array('success' => $this->StockService->InventoryProduct($args['productId'], $args['newAmount'], $bestBeforeDate)));
}
public function CurrentStock($request, $response, $args)
{
return $this->ApiEncode($this->StockService->GetCurrentStock());
}
public function AddmissingProductsToShoppingList($request, $response, $args)
{
$this->StockService->AddMissingProductsToShoppingList();
return $this->ApiEncode(array('success' => true));
}
}

View File

@ -0,0 +1,187 @@
<?php
namespace Grocy\Controllers;
use Grocy\Services\StockService;
class StockController extends BaseController
{
public function __construct(\Slim\Container $container)
{
parent::__construct($container);
$this->StockService = new StockService();
}
protected $StockService;
public function Overview($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'stockoverview', [
'title' => 'Stock overview',
'contentPage' => 'stockoverview.php',
'products' => $this->Database->products(),
'quantityunits' => $this->Database->quantity_units(),
'currentStock' => $this->StockService->GetCurrentStock(),
'missingProducts' => $this->StockService->GetMissingProducts()
]);
}
public function Purchase($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'purchase', [
'title' => 'Purchase',
'contentPage' => 'purchase.php',
'products' => $this->Database->products()
]);
}
public function Consume($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'consume', [
'title' => 'Consume',
'contentPage' => 'consume.php',
'products' => $this->Database->products()
]);
}
public function Inventory($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'inventory', [
'title' => 'Inventory',
'contentPage' => 'inventory.php',
'products' => $this->Database->products()
]);
}
public function ShoppingList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'shoppinglist', [
'title' => 'Shopping list',
'contentPage' => 'shoppinglist.php',
'listItems' => $this->Database->shopping_list(),
'products' => $this->Database->products(),
'quantityunits' => $this->Database->quantity_units(),
'missingProducts' => $this->StockService->GetMissingProducts()
]);
}
public function ProductsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'products', [
'title' => 'Products',
'contentPage' => 'products.php',
'products' => $this->Database->products(),
'locations' => $this->Database->locations(),
'quantityunits' => $this->Database->quantity_units()
]);
}
public function LocationsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'locations', [
'title' => 'Locations',
'contentPage' => 'locations.php',
'locations' => $this->Database->locations()
]);
}
public function QuantityUnitsList($request, $response, $args)
{
return $this->AppContainer->view->render($response, 'quantityunits', [
'title' => 'Quantity units',
'contentPage' => 'quantityunits.php',
'quantityunits' => $this->Database->quantity_units()
]);
}
public function ProductEditForm($request, $response, $args)
{
if ($args['productId'] == 'new')
{
return $this->AppContainer->view->render($response, 'productform', [
'title' => 'Create product',
'contentPage' => 'productform.php',
'locations' => $this->Database->locations(),
'quantityunits' => $this->Database->quantity_units(),
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'productform', [
'title' => 'Edit product',
'contentPage' => 'productform.php',
'product' => $this->Database->products($args['productId']),
'locations' => $this->Database->locations(),
'quantityunits' => $this->Database->quantity_units(),
'mode' => 'edit'
]);
}
}
public function LocationEditForm($request, $response, $args)
{
if ($args['locationId'] == 'new')
{
return $this->AppContainer->view->render($response, 'locationform', [
'title' => 'Create location',
'contentPage' => 'locationform.php',
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'locationform', [
'title' => 'Edit location',
'contentPage' => 'locationform.php',
'location' => $this->Database->locations($args['locationId']),
'mode' => 'edit'
]);
}
}
public function QuantityUnitEditForm($request, $response, $args)
{
if ($args['quantityunitId'] == 'new')
{
return $this->AppContainer->view->render($response, 'quantityunitform', [
'title' => 'Create quantity unit',
'contentPage' => 'quantityunitform.php',
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'quantityunitform', [
'title' => 'Edit quantity unit',
'contentPage' => 'quantityunitform.php',
'quantityunit' => $this->Database->quantity_units($args['quantityunitId']),
'mode' => 'edit'
]);
}
}
public function ShoppingListItemEditForm($request, $response, $args)
{
if ($args['itemId'] == 'new')
{
return $this->AppContainer->view->render($response, 'shoppinglistform', [
'title' => 'Add shopping list item',
'contentPage' => 'shoppinglistform.php',
'products' => $this->Database->products(),
'mode' => 'create'
]);
}
else
{
return $this->AppContainer->view->render($response, 'shoppinglistform', [
'title' => 'Edit shopping list item',
'contentPage' => 'shoppinglistform.php',
'listItem' => $this->Database->shopping_list($args['itemId']),
'products' => $this->Database->products(),
'mode' => 'edit'
]);
}
}
}

1
data/.gitignore vendored
View File

@ -1,2 +1,3 @@
*
!.gitignore
!viewcache

2
data/viewcache/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

63
extensions.php Normal file
View File

@ -0,0 +1,63 @@
<?php
function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
{
foreach($array as $object)
{
if($object->{$propertyName} == $propertyValue)
{
return $object;
}
}
return null;
}
function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==')
{
$returnArray = array();
foreach($array as $object)
{
switch($operator)
{
case '==':
if($object->{$propertyName} == $propertyValue)
{
$returnArray[] = $object;
}
break;
case '>':
if($object->{$propertyName} > $propertyValue)
{
$returnArray[] = $object;
}
break;
case '<':
if($object->{$propertyName} < $propertyValue)
{
$returnArray[] = $object;
}
break;
}
}
return $returnArray;
}
function SumArrayValue($array, $propertyName)
{
$sum = 0;
foreach($array as $object)
{
$sum += $object->{$propertyName};
}
return $sum;
}
function GetClassConstants($className)
{
$r = new ReflectionClass($className);
return $r->getConstants();
}

553
index.php
View File

@ -2,22 +2,19 @@
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Slim\Views\PhpRenderer;
use Grocy\Middleware\SessionMiddleware;
use Grocy\Middleware\JsonMiddleware;
use Grocy\Middleware\CliMiddleware;
use Grocy\Services\ApplicationService;
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/data/config.php';
require_once __DIR__ . '/services/ApplicationService.php';
require_once __DIR__ . '/services/DatabaseService.php';
require_once __DIR__ . '/services/SessionService.php';
require_once __DIR__ . '/GrocyDbMigrator.php';
require_once __DIR__ . '/GrocyDemoDataGenerator.php';
require_once __DIR__ . '/services/StockService.php';
require_once __DIR__ . '/services/HabitsService.php';
require_once __DIR__ . '/services/BatteriesService.php';
require_once __DIR__ . '/GrocyPhpHelper.php';
require_once __DIR__ . '/extensions.php';
// Setup base application
$app = new \Slim\App;
if (PHP_SAPI !== 'cli')
{
$app = new \Slim\App(new \Slim\Container([
@ -26,508 +23,92 @@ if (PHP_SAPI !== 'cli')
'determineRouteBeforeAppMiddleware' => true
],
]));
$container = $app->getContainer();
$container['renderer'] = new PhpRenderer('./views');
}
if (PHP_SAPI === 'cli')
$container['view'] = function($container)
{
$app->add(new \pavlakis\cli\CliRequest());
}
if (!ApplicationService::IsDemoInstallation())
{
$sessionMiddleware = function(Request $request, Response $response, callable $next)
{
$route = $request->getAttribute('route');
$routeName = $route->getName();
if ((!isset($_COOKIE['grocy_session']) || !SessionService::IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login')
{
$response = $response->withRedirect('/login');
}
else
{
$response = $next($request, $response);
}
return $response;
return new \Slim\Views\Blade(__DIR__ . '/views', __DIR__ . '/data/viewcache');
};
$app->add($sessionMiddleware);
}
$db = DatabaseService::GetDbConnection();
$app->get('/login', function(Request $request, Response $response)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Login',
'contentPage' => 'login.php'
]);
})->setName('login');
$app->post('/login', function(Request $request, Response $response)
{
$postParams = $request->getParsedBody();
if (isset($postParams['username']) && isset($postParams['password']))
{
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD)
{
$sessionKey = SessionService::CreateSession();
setcookie('grocy_session', $sessionKey, time()+2592000); //30 days
return $response->withRedirect('/');
}
else
{
return $response->withRedirect('/login?invalid=true');
}
}
else
{
return $response->withRedirect('/login?invalid=true');
}
})->setName('login');
$app->get('/logout', function(Request $request, Response $response)
{
SessionService::RemoveSession($_COOKIE['grocy_session']);
return $response->withRedirect('/');
});
$app->get('/', function(Request $request, Response $response) use($db)
{
$db = DatabaseService::GetDbConnection(true); //For database schema migration
return $response->withRedirect('/stockoverview');
});
$app->get('/stockoverview', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Stock overview',
'contentPage' => 'stockoverview.php',
'products' => $db->products(),
'quantityunits' => $db->quantity_units(),
'currentStock' => StockService::GetCurrentStock(),
'missingProducts' => StockService::GetMissingProducts()
]);
});
$app->get('/habitsoverview', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Habits overview',
'contentPage' => 'habitsoverview.php',
'habits' => $db->habits(),
'currentHabits' => HabitsService::GetCurrentHabits(),
]);
});
$app->get('/batteriesoverview', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Batteries overview',
'contentPage' => 'batteriesoverview.php',
'batteries' => $db->batteries(),
'current' => BatteriesService::GetCurrent(),
]);
});
$app->get('/purchase', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Purchase',
'contentPage' => 'purchase.php',
'products' => $db->products()
]);
});
$app->get('/consume', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Consume',
'contentPage' => 'consume.php',
'products' => $db->products()
]);
});
$app->get('/inventory', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Inventory',
'contentPage' => 'inventory.php',
'products' => $db->products()
]);
});
$app->get('/shoppinglist', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Shopping list',
'contentPage' => 'shoppinglist.php',
'listItems' => $db->shopping_list(),
'products' => $db->products(),
'quantityunits' => $db->quantity_units(),
'missingProducts' => StockService::GetMissingProducts()
]);
});
$app->get('/habittracking', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Habit tracking',
'contentPage' => 'habittracking.php',
'habits' => $db->habits()
]);
});
$app->get('/batterytracking', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Battery tracking',
'contentPage' => 'batterytracking.php',
'batteries' => $db->batteries()
]);
});
$app->get('/products', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Products',
'contentPage' => 'products.php',
'products' => $db->products(),
'locations' => $db->locations(),
'quantityunits' => $db->quantity_units()
]);
});
$app->get('/locations', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Locations',
'contentPage' => 'locations.php',
'locations' => $db->locations()
]);
});
$app->get('/quantityunits', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Quantity units',
'contentPage' => 'quantityunits.php',
'quantityunits' => $db->quantity_units()
]);
});
$app->get('/habits', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Habits',
'contentPage' => 'habits.php',
'habits' => $db->habits()
]);
});
$app->get('/batteries', function(Request $request, Response $response) use($db)
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Batteries',
'contentPage' => 'batteries.php',
'batteries' => $db->batteries()
]);
});
$app->get('/product/{productId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['productId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create product',
'contentPage' => 'productform.php',
'locations' => $db->locations(),
'quantityunits' => $db->quantity_units(),
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit product',
'contentPage' => 'productform.php',
'product' => $db->products($args['productId']),
'locations' => $db->locations(),
'quantityunits' => $db->quantity_units(),
'mode' => 'edit'
]);
}
});
$app->get('/location/{locationId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['locationId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create location',
'contentPage' => 'locationform.php',
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit location',
'contentPage' => 'locationform.php',
'location' => $db->locations($args['locationId']),
'mode' => 'edit'
]);
}
});
$app->get('/quantityunit/{quantityunitId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['quantityunitId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create quantity unit',
'contentPage' => 'quantityunitform.php',
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit quantity unit',
'contentPage' => 'quantityunitform.php',
'quantityunit' => $db->quantity_units($args['quantityunitId']),
'mode' => 'edit'
]);
}
});
$app->get('/habit/{habitId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['habitId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create habit',
'contentPage' => 'habitform.php',
'periodTypes' => GrocyPhpHelper::GetClassConstants('HabitsService'),
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit habit',
'contentPage' => 'habitform.php',
'habit' => $db->habits($args['habitId']),
'periodTypes' => GrocyPhpHelper::GetClassConstants('HabitsService'),
'mode' => 'edit'
]);
}
});
$app->get('/battery/{batteryId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['batteryId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Create battery',
'contentPage' => 'batteryform.php',
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit battery',
'contentPage' => 'batteryform.php',
'battery' => $db->batteries($args['batteryId']),
'mode' => 'edit'
]);
}
});
$app->get('/shoppinglistitem/{itemId}', function(Request $request, Response $response, $args) use($db)
{
if ($args['itemId'] == 'new')
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Add shopping list item',
'contentPage' => 'shoppinglistform.php',
'products' => $db->products(),
'mode' => 'create'
]);
}
else
{
return $this->renderer->render($response, 'layout/default.php', [
'title' => 'Edit shopping list item',
'contentPage' => 'shoppinglistform.php',
'listItem' => $db->shopping_list($args['itemId']),
'products' => $db->products(),
'mode' => 'edit'
]);
}
});
$app->group('/api', function() use($db)
{
$this->get('/get-objects/{entity}', function(Request $request, Response $response, $args) use($db)
{
echo json_encode($db->{$args['entity']}());
});
$this->get('/get-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
{
echo json_encode($db->{$args['entity']}($args['objectId']));
});
$this->post('/add-object/{entity}', function(Request $request, Response $response, $args) use($db)
{
$newRow = $db->{$args['entity']}()->createRow($request->getParsedBody());
$newRow->save();
$success = $newRow->isClean();
echo json_encode(array('success' => $success));
});
$this->post('/edit-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
{
$row = $db->{$args['entity']}($args['objectId']);
$row->update($request->getParsedBody());
$success = $row->isClean();
echo json_encode(array('success' => $success));
});
$this->get('/delete-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
{
$row = $db->{$args['entity']}($args['objectId']);
$row->delete();
$success = $row->isClean();
echo json_encode(array('success' => $success));
});
$this->get('/stock/add-product/{productId}/{amount}', function(Request $request, Response $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
$app->add(\pavlakis\cli\CliRequest::class);
}
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
// Add session handling if this is not a demo installation
$applicationService = new ApplicationService();
if (!$applicationService->IsDemoInstallation())
{
$transactionType = $request->getQueryParams()['transactiontype'];
$app->add(SessionMiddleware::class);
}
echo json_encode(array('success' => StockService::AddProduct($args['productId'], $args['amount'], $bestBeforeDate, $transactionType)));
});
// Base route
$app->get('/', 'Grocy\Controllers\LoginController:Root');
$this->get('/stock/consume-product/{productId}/{amount}', function(Request $request, Response $response, $args)
{
$spoiled = false;
if (isset($request->getQueryParams()['spoiled']) && !empty($request->getQueryParams()['spoiled']) && $request->getQueryParams()['spoiled'] == '1')
{
$spoiled = true;
}
// Login routes
$app->get('/login', 'Grocy\Controllers\LoginController:LoginPage')->setName('login');
$app->post('/login', 'Grocy\Controllers\LoginController:ProcessLogin')->setName('login');
$app->get('/logout', 'Grocy\Controllers\LoginController:Logout');
$transactionType = StockService::TRANSACTION_TYPE_CONSUME;
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
{
$transactionType = $request->getQueryParams()['transactiontype'];
}
// Stock routes
$app->get('/stockoverview', 'Grocy\Controllers\StockController:Overview');
$app->get('/purchase', 'Grocy\Controllers\StockController:Purchase');
$app->get('/consume', 'Grocy\Controllers\StockController:Consume');
$app->get('/inventory', 'Grocy\Controllers\StockController:Inventory');
echo json_encode(array('success' => StockService::ConsumeProduct($args['productId'], $args['amount'], $spoiled, $transactionType)));
});
$app->get('/products', 'Grocy\Controllers\StockController:ProductsList');
$app->get('/product/{productId}', 'Grocy\Controllers\StockController:ProductEditForm');
$this->get('/stock/inventory-product/{productId}/{newAmount}', function(Request $request, Response $response, $args)
{
$bestBeforeDate = date('Y-m-d');
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
{
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
}
$app->get('/locations', 'Grocy\Controllers\StockController:LocationsList');
$app->get('/location/{locationId}', 'Grocy\Controllers\StockController:LocationEditForm');
echo json_encode(array('success' => StockService::InventoryProduct($args['productId'], $args['newAmount'], $bestBeforeDate)));
});
$app->get('/quantityunits', 'Grocy\Controllers\StockController:QuantityUnitsList');
$app->get('/quantityunit/{quantityunitId}', 'Grocy\Controllers\StockController:QuantityUnitEditForm');
$this->get('/stock/get-product-details/{productId}', function(Request $request, Response $response, $args)
{
echo json_encode(StockService::GetProductDetails($args['productId']));
});
$app->get('/shoppinglist', 'Grocy\Controllers\StockController:ShoppingList');
$app->get('/shoppinglistitem/{itemId}', 'Grocy\Controllers\StockController:ShoppingListItemEditForm');
$this->get('/stock/get-current-stock', function(Request $request, Response $response)
{
echo json_encode(StockService::GetCurrentStock());
});
$this->get('/stock/add-missing-products-to-shoppinglist', function(Request $request, Response $response)
{
StockService::AddMissingProductsToShoppingList();
echo json_encode(array('success' => true));
});
// Habit routes
$app->get('/habitsoverview', 'Grocy\Controllers\HabitsController:Overview');
$app->get('/habittracking', 'Grocy\Controllers\HabitsController:TrackHabitExecution');
$this->get('/habits/track-habit/{habitId}', function(Request $request, Response $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
$app->get('/habits', 'Grocy\Controllers\HabitsController:HabitsList');
$app->get('/habit/{habitId}', 'Grocy\Controllers\HabitsController:HabitEditForm');
echo json_encode(array('success' => HabitsService::TrackHabit($args['habitId'], $trackedTime)));
});
// Batterry routes
$app->get('/batteriesoverview', 'Grocy\Controllers\BatteriesController:Overview');
$app->get('/batterytracking', 'Grocy\Controllers\BatteriesController:TrackChargeCycle');
$this->get('/habits/get-habit-details/{habitId}', function(Request $request, Response $response, $args)
{
echo json_encode(HabitsService::GetHabitDetails($args['habitId']));
});
$app->get('/batteries', 'Grocy\Controllers\BatteriesController:BatteriesList');
$app->get('/battery/{batteryId}', 'Grocy\Controllers\BatteriesController:BatteryEditForm');
$this->get('/batteries/track-charge-cycle/{batteryId}', function(Request $request, Response $response, $args)
{
$trackedTime = date('Y-m-d H:i:s');
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
{
$trackedTime = $request->getQueryParams()['tracked_time'];
}
echo json_encode(array('success' => BatteriesService::TrackChargeCycle($args['batteryId'], $trackedTime)));
});
$app->group('/api', function()
{
$this->get('/get-objects/{entity}', 'Grocy\Controllers\GenericEntityApiController:GetObjects');
$this->get('/get-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:GetObject');
$this->post('/add-object/{entity}', 'Grocy\Controllers\GenericEntityApiController:AddObject');
$this->post('/edit-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:EditObject');
$this->get('/delete-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:DeleteObject');
$this->get('/batteries/get-battery-details/{batteryId}', function(Request $request, Response $response, $args)
{
echo json_encode(BatteriesService::GetBatteryDetails($args['batteryId']));
});
})->add(function($request, $response, $next)
{
$response = $next($request, $response);
return $response->withHeader('Content-Type', 'application/json');
});
$this->get('/stock/add-product/{productId}/{amount}', 'Grocy\Controllers\StockApiController:AddProduct');
$this->get('/stock/consume-product/{productId}/{amount}', 'Grocy\Controllers\StockApiController:ConsumeProduct');
$this->get('/stock/inventory-product/{productId}/{newAmount}', 'Grocy\Controllers\StockApiController:InventoryProduct');
$this->get('/stock/get-product-details/{productId}', 'Grocy\Controllers\StockApiController:ProductDetails');
$this->get('/stock/get-current-stock', 'Grocy\Controllers\StockApiController:CurrentStock');
$this->get('/stock/add-missing-products-to-shoppinglist', 'Grocy\Controllers\StockApiController:AddMissingProductsToShoppingList');
$this->get('/habits/track-habit-execution/{habitId}', 'Grocy\Controllers\HabitsApiController:TrackHabitExecution');
$this->get('/habits/get-habit-details/{habitId}', 'Grocy\Controllers\HabitsApiController:HabitDetails');
$this->get('/batteries/track-charge-cycle/{batteryId}', 'Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
$this->get('/batteries/get-battery-details/{batteryId}', 'Grocy\Controllers\BatteriesApiController:BatteryDetails');
})->add(JsonMiddleware::class);
$app->group('/cli', function()
{
$this->get('/recreatedemo', function(Request $request, Response $response)
{
if (ApplicationService::IsDemoInstallation())
{
GrocyDemoDataGenerator::RecreateDemo();
}
});
})->add(function($request, $response, $next)
{
$response = $next($request, $response);
if (PHP_SAPI !== 'cli')
{
echo 'Please call this only from CLI';
return $response->withHeader('Content-Type', 'text/plain')->withStatus(400);
}
return $response->withHeader('Content-Type', 'text/plain');
});
$this->get('/recreatedemo', 'Grocy\Controllers\CliController:RecreateDemo');
})->add(CliMiddleware::class);
$app->run();

View File

@ -0,0 +1,25 @@
<?php
namespace Grocy\Middleware;
class CliMiddleware
{
public function __construct(\Slim\Container $container) {
$this->container = $container;
}
protected $container;
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
{
$response = $next($request, $response);
if (PHP_SAPI !== 'cli')
{
$response->write('Please call this only from CLI');
return $response->withHeader('Content-Type', 'text/plain')->withStatus(400);
}
return $response->withHeader('Content-Type', 'text/plain');
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Grocy\Middleware;
class JsonMiddleware
{
public function __construct(\Slim\Container $container) {
$this->container = $container;
}
protected $container;
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
{
$response = $next($request, $response, $next);
return $response->withHeader('Content-Type', 'application/json');
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Grocy\Middleware;
use Grocy\Services\SessionService;
class SessionMiddleware
{
public function __construct(\Slim\Container $container) {
$this->container = $container;
}
protected $container;
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
{
$route = $request->getAttribute('route');
$routeName = $route->getName();
$sessionService = new SessionService();
if ((!isset($_COOKIE['grocy_session']) || !$sessionService->IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login')
{
$response = $response->withRedirect('/login');
}
else
{
$response = $next($request, $response);
}
return $response;
}
}

View File

@ -1,26 +1,28 @@
<?php
class ApplicationService
namespace Grocy\Services;
class ApplicationService extends BaseService
{
/**
* @return boolean
*/
public static function IsDemoInstallation()
public function IsDemoInstallation()
{
return file_exists(__DIR__ . '/../data/demo.txt');
}
private static $InstalledVersion;
private $InstalledVersion;
/**
* @return string
*/
public static function GetInstalledVersion()
public function GetInstalledVersion()
{
if (self::$InstalledVersion == null)
if ($this->InstalledVersion == null)
{
self::$InstalledVersion = preg_replace("/\r|\n/", '', file_get_contents(__DIR__ . '/../version.txt'));
$this->InstalledVersion = preg_replace("/\r|\n/", '', file_get_contents(__DIR__ . '/../version.txt'));
}
return self::$InstalledVersion;
return $this->InstalledVersion;
}
}

16
services/BaseService.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace Grocy\Services;
use Grocy\Services\DatabaseService;
class BaseService
{
public function __construct() {
$this->DatabaseService = new DatabaseService();
$this->Database = $this->DatabaseService->GetDbConnection();
}
protected $DatabaseService;
protected $Database;
}

View File

@ -1,19 +1,19 @@
<?php
class BatteriesService
namespace Grocy\Services;
class BatteriesService extends BaseService
{
public static function GetCurrent()
public function GetCurrent()
{
$sql = 'SELECT * from batteries_current';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
}
public static function GetNextChargeTime(int $batteryId)
public function GetNextChargeTime(int $batteryId)
{
$db = DatabaseService::GetDbConnection();
$battery = $db->batteries($batteryId);
$batteryLastLogRow = DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), "SELECT * from batteries_current WHERE battery_id = $batteryId LIMIT 1")->fetch(PDO::FETCH_OBJ);
$battery = $this->Database->batteries($batteryId);
$batteryLastLogRow = $this->DatabaseService->ExecuteDbQuery("SELECT * from batteries_current WHERE battery_id = $batteryId LIMIT 1")->fetch(\PDO::FETCH_OBJ);
if ($battery->charge_interval_days > 0)
{
@ -27,13 +27,11 @@ class BatteriesService
return null;
}
public static function GetBatteryDetails(int $batteryId)
public function GetBatteryDetails(int $batteryId)
{
$db = DatabaseService::GetDbConnection();
$battery = $db->batteries($batteryId);
$batteryChargeCylcesCount = $db->battery_charge_cycles()->where('battery_id', $batteryId)->count();
$batteryLastChargedTime = $db->battery_charge_cycles()->where('battery_id', $batteryId)->max('tracked_time');
$battery = $this->Database->batteries($batteryId);
$batteryChargeCylcesCount = $this->Database->battery_charge_cycles()->where('battery_id', $batteryId)->count();
$batteryLastChargedTime = $this->Database->battery_charge_cycles()->where('battery_id', $batteryId)->max('tracked_time');
return array(
'battery' => $battery,
@ -42,11 +40,9 @@ class BatteriesService
);
}
public static function TrackChargeCycle(int $batteryId, string $trackedTime)
public function TrackChargeCycle(int $batteryId, string $trackedTime)
{
$db = DatabaseService::GetDbConnection();
$logRow = $db->battery_charge_cycles()->createRow(array(
$logRow = $this->Database->battery_charge_cycles()->createRow(array(
'battery_id' => $batteryId,
'tracked_time' => $trackedTime
));

View File

@ -1,10 +1,14 @@
<?php
class GrocyDbMigrator
namespace Grocy\Services;
class DatabaseMigrationService extends BaseService
{
public static function MigrateDb(PDO $pdo)
public function MigrateDatabase()
{
self::ExecuteMigrationWhenNeeded($pdo, 1, "
$this->DatabaseService->ExecuteDbStatement("CREATE TABLE IF NOT EXISTS migrations (migration INTEGER NOT NULL PRIMARY KEY UNIQUE, execution_time_timestamp DATETIME DEFAULT (datetime('now', 'localtime')))");
$this->ExecuteMigrationWhenNeeded(1, "
CREATE TABLE products (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE,
@ -20,7 +24,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 2, "
$this->ExecuteMigrationWhenNeeded(2, "
CREATE TABLE locations (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE,
@ -29,7 +33,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 3, "
$this->ExecuteMigrationWhenNeeded(3, "
CREATE TABLE quantity_units (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE,
@ -38,7 +42,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 4, "
$this->ExecuteMigrationWhenNeeded(4, "
CREATE TABLE stock (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER NOT NULL,
@ -50,7 +54,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 5, "
$this->ExecuteMigrationWhenNeeded(5, "
CREATE TABLE stock_log (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER NOT NULL,
@ -65,14 +69,14 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 6, "
$this->ExecuteMigrationWhenNeeded(6, "
INSERT INTO locations (name, description) VALUES ('DefaultLocation', 'This is the first default location, edit or delete it');
INSERT INTO quantity_units (name, description) VALUES ('DefaultQuantityUnit', 'This is the first default quantity unit, edit or delete it');
INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct1', 'This is the first default product, edit or delete it', 1, 1, 1, 1);
INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct2', 'This is the second default product, edit or delete it', 1, 1, 1, 1);"
);
self::ExecuteMigrationWhenNeeded($pdo, 7, "
$this->ExecuteMigrationWhenNeeded(7, "
CREATE VIEW stock_missing_products
AS
SELECT p.id, MAX(p.name) AS name, p.min_stock_amount - IFNULL(SUM(s.amount), 0) AS amount_missing
@ -84,7 +88,7 @@ class GrocyDbMigrator
HAVING IFNULL(SUM(s.amount), 0) < p.min_stock_amount;"
);
self::ExecuteMigrationWhenNeeded($pdo, 8, "
$this->ExecuteMigrationWhenNeeded(8, "
CREATE VIEW stock_current
AS
SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date
@ -93,7 +97,7 @@ class GrocyDbMigrator
ORDER BY MIN(best_before_date) ASC;"
);
self::ExecuteMigrationWhenNeeded($pdo, 9, "
$this->ExecuteMigrationWhenNeeded(9, "
CREATE TABLE shopping_list (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER NOT NULL UNIQUE,
@ -103,7 +107,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 10, "
$this->ExecuteMigrationWhenNeeded(10, "
CREATE TABLE habits (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE,
@ -114,7 +118,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 11, "
$this->ExecuteMigrationWhenNeeded(11, "
CREATE TABLE habits_log (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
habit_id INTEGER NOT NULL,
@ -123,7 +127,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 12, "
$this->ExecuteMigrationWhenNeeded(12, "
CREATE VIEW habits_current
AS
SELECT habit_id, MAX(tracked_time) AS last_tracked_time
@ -132,7 +136,7 @@ class GrocyDbMigrator
ORDER BY MAX(tracked_time) DESC;"
);
self::ExecuteMigrationWhenNeeded($pdo, 13, "
$this->ExecuteMigrationWhenNeeded(13, "
CREATE TABLE batteries (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE,
@ -143,7 +147,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 14, "
$this->ExecuteMigrationWhenNeeded(14, "
CREATE TABLE battery_charge_cycles (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
battery_id TEXT NOT NULL,
@ -152,7 +156,7 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 15, "
$this->ExecuteMigrationWhenNeeded(15, "
CREATE VIEW batteries_current
AS
SELECT battery_id, MAX(tracked_time) AS last_tracked_time
@ -161,11 +165,11 @@ class GrocyDbMigrator
ORDER BY MAX(tracked_time) DESC;"
);
self::ExecuteMigrationWhenNeeded($pdo, 16, "
$this->ExecuteMigrationWhenNeeded(16, "
ALTER TABLE shopping_list RENAME TO shopping_list_old;"
);
self::ExecuteMigrationWhenNeeded($pdo, 17, "
$this->ExecuteMigrationWhenNeeded(17, "
CREATE TABLE shopping_list (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
product_id INTEGER,
@ -176,25 +180,25 @@ class GrocyDbMigrator
)"
);
self::ExecuteMigrationWhenNeeded($pdo, 18, "
$this->ExecuteMigrationWhenNeeded(18, "
INSERT INTO shopping_list
(product_id, amount, amount_autoadded, row_created_timestamp)
SELECT product_id, amount, amount_autoadded, row_created_timestamp
FROM shopping_list_old"
);
self::ExecuteMigrationWhenNeeded($pdo, 19, "
$this->ExecuteMigrationWhenNeeded(19, "
DROP TABLE shopping_list_old;"
);
}
private static function ExecuteMigrationWhenNeeded(PDO $pdo, int $migrationId, string $sql)
private function ExecuteMigrationWhenNeeded(int $migrationId, string $sql)
{
$rowCount = DatabaseService::ExecuteDbQuery($pdo, 'SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn();
$rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn();
if (intval($rowCount) === 0)
{
DatabaseService::ExecuteDbStatement($pdo, $sql);
DatabaseService::ExecuteDbStatement($pdo, 'INSERT INTO migrations (migration) VALUES (' . $migrationId . ')');
$this->DatabaseService->ExecuteDbStatement($sql);
$this->DatabaseService->ExecuteDbStatement('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')');
}
}
}

View File

@ -1,64 +1,47 @@
<?php
namespace Grocy\Services;
use Grocy\Services\ApplicationService;
class DatabaseService
{
private static $DbConnectionRaw;
private $DbConnectionRaw;
/**
* @return PDO
* @return \PDO
*/
public static function GetDbConnectionRaw($doMigrations = false)
public function GetDbConnectionRaw()
{
if ($doMigrations === true)
if ($this->DbConnectionRaw == null)
{
self::$DbConnectionRaw = null;
$pdo = new \PDO('sqlite:' . __DIR__ . '/../data/grocy.db');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->DbConnectionRaw = $pdo;
}
if (self::$DbConnectionRaw == null)
{
$pdo = new PDO('sqlite:' . __DIR__ . '/../data/grocy.db');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($doMigrations === true)
{
self::ExecuteDbStatement($pdo, "CREATE TABLE IF NOT EXISTS migrations (migration INTEGER NOT NULL PRIMARY KEY UNIQUE, execution_time_timestamp DATETIME DEFAULT (datetime('now', 'localtime')))");
GrocyDbMigrator::MigrateDb($pdo);
if (ApplicationService::IsDemoInstallation())
{
GrocyDemoDataGenerator::PopulateDemoData($pdo);
}
return $this->DbConnectionRaw;
}
self::$DbConnectionRaw = $pdo;
}
return self::$DbConnectionRaw;
}
private static $DbConnection;
private $DbConnection;
/**
* @return LessQL\Database
* @return \LessQL\Database
*/
public static function GetDbConnection($doMigrations = false)
public function GetDbConnection()
{
if ($doMigrations === true)
if ($this->DbConnection == null)
{
self::$DbConnection = null;
$this->DbConnection = new \LessQL\Database($this->GetDbConnectionRaw());
}
if (self::$DbConnection == null)
{
self::$DbConnection = new LessQL\Database(self::GetDbConnectionRaw($doMigrations));
}
return self::$DbConnection;
return $this->DbConnection;
}
/**
* @return boolean
*/
public static function ExecuteDbStatement(PDO $pdo, string $sql)
public function ExecuteDbStatement(string $sql)
{
$pdo = $this->GetDbConnectionRaw();
if ($pdo->exec($sql) === false)
{
throw new Exception($pdo->errorInfo());
@ -68,11 +51,12 @@ class DatabaseService
}
/**
* @return boolean|PDOStatement
* @return boolean|\PDOStatement
*/
public static function ExecuteDbQuery(PDO $pdo, string $sql)
public function ExecuteDbQuery(string $sql)
{
if (self::ExecuteDbStatement($pdo, $sql) === true)
$pdo = $this->GetDbConnectionRaw();
if ($this->ExecuteDbStatement($sql) === true)
{
return $pdo->query($sql);
}

View File

@ -1,10 +1,12 @@
<?php
class GrocyDemoDataGenerator
namespace Grocy\Services;
class DemoDataGeneratorService extends BaseService
{
public static function PopulateDemoData(PDO $pdo)
public function PopulateDemoData()
{
$rowCount = DatabaseService::ExecuteDbQuery($pdo, 'SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn();
$rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn();
if (intval($rowCount) === 0)
{
$sql = "
@ -45,46 +47,47 @@ class GrocyDemoDataGenerator
INSERT INTO migrations (migration) VALUES (-1);
";
DatabaseService::ExecuteDbStatement($pdo, $sql);
$this->DatabaseService->ExecuteDbStatement($sql);
StockService::AddProduct(3, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(4, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(5, 5, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(6, 5, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(7, 5, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(8, 5, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(9, 5, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(10, 5, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(11, 5, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(12, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(13, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
StockService::AddMissingProductsToShoppingList();
$stockService = new StockService();
$stockService->AddProduct(3, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(4, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(5, 5, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(6, 5, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(7, 5, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(8, 5, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(9, 5, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(10, 5, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(11, 5, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(12, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(13, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
$stockService->AddMissingProductsToShoppingList();
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days')));
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days')));
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days')));
HabitsService::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days')));
HabitsService::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days')));
$habitsService = new HabitsService();
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days')));
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days')));
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days')));
$habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days')));
$habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days')));
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-200 days')));
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-150 days')));
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-100 days')));
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-50 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-200 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-150 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-100 days')));
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-50 days')));
BatteriesService::TrackChargeCycle(3, date('Y-m-d H:i:s', strtotime('-65 days')));
$batteriesService = new BatteriesService();
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-200 days')));
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-150 days')));
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-100 days')));
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-50 days')));
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-200 days')));
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-150 days')));
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-100 days')));
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-50 days')));
$batteriesService->TrackChargeCycle(3, date('Y-m-d H:i:s', strtotime('-65 days')));
}
}
public static function RecreateDemo()
public function RecreateDemo()
{
unlink(__DIR__ . '/data/grocy.db');
$db = DatabaseService::GetDbConnectionRaw(true);
self::PopulateDemoData($db);
$this->PopulateDemoData($this->DatabaseService->GetDbConnectionRaw(true));
}
}

View File

@ -1,22 +1,22 @@
<?php
class HabitsService
namespace Grocy\Services;
class HabitsService extends BaseService
{
const HABIT_TYPE_MANUALLY = 'manually';
const HABIT_TYPE_DYNAMIC_REGULAR = 'dynamic-regular';
public static function GetCurrentHabits()
public function GetCurrentHabits()
{
$sql = 'SELECT * from habits_current';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
}
public static function GetNextHabitTime(int $habitId)
public function GetNextHabitTime(int $habitId)
{
$db = DatabaseService::GetDbConnection();
$habit = $db->habits($habitId);
$habitLastLogRow = DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), "SELECT * from habits_current WHERE habit_id = $habitId LIMIT 1")->fetch(PDO::FETCH_OBJ);
$habit = $this->Database->habits($habitId);
$habitLastLogRow = $this->DatabaseService->ExecuteDbQuery("SELECT * from habits_current WHERE habit_id = $habitId LIMIT 1")->fetch(\PDO::FETCH_OBJ);
switch ($habit->period_type)
{
@ -29,13 +29,11 @@ class HabitsService
return null;
}
public static function GetHabitDetails(int $habitId)
public function GetHabitDetails(int $habitId)
{
$db = DatabaseService::GetDbConnection();
$habit = $db->habits($habitId);
$habitTrackedCount = $db->habits_log()->where('habit_id', $habitId)->count();
$habitLastTrackedTime = $db->habits_log()->where('habit_id', $habitId)->max('tracked_time');
$habit = $this->Database->habits($habitId);
$habitTrackedCount = $this->Database->habits_log()->where('habit_id', $habitId)->count();
$habitLastTrackedTime = $this->Database->habits_log()->where('habit_id', $habitId)->max('tracked_time');
return array(
'habit' => $habit,
@ -44,11 +42,9 @@ class HabitsService
);
}
public static function TrackHabit(int $habitId, string $trackedTime)
public function TrackHabit(int $habitId, string $trackedTime)
{
$db = DatabaseService::GetDbConnection();
$logRow = $db->habits_log()->createRow(array(
$logRow = $this->Database->habits_log()->createRow(array(
'habit_id' => $habitId,
'tracked_time' => $trackedTime
));

View File

@ -1,11 +1,13 @@
<?php
class SessionService
namespace Grocy\Services;
class SessionService extends BaseService
{
/**
* @return boolean
*/
public static function IsValidSession($sessionKey)
public function IsValidSession($sessionKey)
{
if ($sessionKey === null || empty($sessionKey))
{
@ -20,7 +22,7 @@ class SessionService
/**
* @return string
*/
public static function CreateSession()
public function CreateSession()
{
if (!file_exists(__DIR__ . '/../data/sessions'))
{
@ -28,7 +30,7 @@ class SessionService
}
$now = time();
foreach (new FilesystemIterator(__DIR__ . '/../data/sessions') as $file)
foreach (new \FilesystemIterator(__DIR__ . '/../data/sessions') as $file)
{
if ($now - $file->getCTime() >= 2678400) //31 days
{
@ -41,7 +43,7 @@ class SessionService
return $newSessionKey;
}
public static function RemoveSession($sessionKey)
public function RemoveSession($sessionKey)
{
unlink(__DIR__ . "/../data/sessions/$sessionKey.txt");
}

View File

@ -1,33 +1,33 @@
<?php
class StockService
namespace Grocy\Services;
class StockService extends BaseService
{
const TRANSACTION_TYPE_PURCHASE = 'purchase';
const TRANSACTION_TYPE_CONSUME = 'consume';
const TRANSACTION_TYPE_INVENTORY_CORRECTION = 'inventory-correction';
public static function GetCurrentStock()
public function GetCurrentStock()
{
$sql = 'SELECT * from stock_current';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
}
public static function GetMissingProducts()
public function GetMissingProducts()
{
$sql = 'SELECT * from stock_missing_products';
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
}
public static function GetProductDetails(int $productId)
public function GetProductDetails(int $productId)
{
$db = DatabaseService::GetDbConnection();
$product = $db->products($productId);
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
$productLastPurchased = $db->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_PURCHASE)->max('purchased_date');
$productLastUsed = $db->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->max('used_date');
$quPurchase = $db->quantity_units($product->qu_id_purchase);
$quStock = $db->quantity_units($product->qu_id_stock);
$product = $this->Database->products($productId);
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
$productLastPurchased = $this->Database->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_PURCHASE)->max('purchased_date');
$productLastUsed = $this->Database->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->max('used_date');
$quPurchase = $this->Database->quantity_units($product->qu_id_purchase);
$quStock = $this->Database->quantity_units($product->qu_id_stock);
return array(
'product' => $product,
@ -39,14 +39,13 @@ class StockService
);
}
public static function AddProduct(int $productId, int $amount, string $bestBeforeDate, $transactionType)
public function AddProduct(int $productId, int $amount, string $bestBeforeDate, $transactionType)
{
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
{
$db = DatabaseService::GetDbConnection();
$stockId = uniqid();
$logRow = $db->stock_log()->createRow(array(
$logRow = $this->Database->stock_log()->createRow(array(
'product_id' => $productId,
'amount' => $amount,
'best_before_date' => $bestBeforeDate,
@ -56,7 +55,7 @@ class StockService
));
$logRow->save();
$stockRow = $db->stock()->createRow(array(
$stockRow = $this->Database->stock()->createRow(array(
'product_id' => $productId,
'amount' => $amount,
'best_before_date' => $bestBeforeDate,
@ -73,14 +72,12 @@ class StockService
}
}
public static function ConsumeProduct(int $productId, int $amount, bool $spoiled, $transactionType)
public function ConsumeProduct(int $productId, int $amount, bool $spoiled, $transactionType)
{
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
{
$db = DatabaseService::GetDbConnection();
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
$potentialStockEntries = $db->stock()->where('product_id', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll(); //First expiring first, then first in first out
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
$potentialStockEntries = $this->Database->stock()->where('product_id', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll(); //First expiring first, then first in first out
if ($amount > $productStockAmount)
{
@ -96,7 +93,7 @@ class StockService
if ($amount >= $stockEntry->amount) //Take the whole stock entry
{
$logRow = $db->stock_log()->createRow(array(
$logRow = $this->Database->stock_log()->createRow(array(
'product_id' => $stockEntry->product_id,
'amount' => $stockEntry->amount * -1,
'best_before_date' => $stockEntry->best_before_date,
@ -113,7 +110,7 @@ class StockService
}
else //Stock entry amount is > than needed amount -> split the stock entry resp. update the amount
{
$logRow = $db->stock_log()->createRow(array(
$logRow = $this->Database->stock_log()->createRow(array(
'product_id' => $stockEntry->product_id,
'amount' => $amount * -1,
'best_before_date' => $stockEntry->best_before_date,
@ -142,36 +139,33 @@ class StockService
}
}
public static function InventoryProduct(int $productId, int $newAmount, string $bestBeforeDate)
public function InventoryProduct(int $productId, int $newAmount, string $bestBeforeDate)
{
$db = DatabaseService::GetDbConnection();
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
if ($newAmount > $productStockAmount)
{
$amountToAdd = $newAmount - $productStockAmount;
self::AddProduct($productId, $amountToAdd, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
$this->AddProduct($productId, $amountToAdd, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
}
else if ($newAmount < $productStockAmount)
{
$amountToRemove = $productStockAmount - $newAmount;
self::ConsumeProduct($productId, $amountToRemove, false, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
$this->ConsumeProduct($productId, $amountToRemove, false, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
}
return true;
}
public static function AddMissingProductsToShoppingList()
public function AddMissingProductsToShoppingList()
{
$db = DatabaseService::GetDbConnection();
$missingProducts = self::GetMissingProducts();
$missingProducts = $this->GetMissingProducts();
foreach ($missingProducts as $missingProduct)
{
$product = $db->products()->where('id', $missingProduct->id)->fetch();
$product = $this->Database->products()->where('id', $missingProduct->id)->fetch();
$amount = ceil($missingProduct->amount_missing / $product->qu_factor_purchase_to_stock);
$alreadyExistingEntry = $db->shopping_list()->where('product_id', $missingProduct->id)->fetch();
$alreadyExistingEntry = $this->Database->shopping_list()->where('product_id', $missingProduct->id)->fetch();
if ($alreadyExistingEntry) //Update
{
$alreadyExistingEntry->update(array(
@ -180,7 +174,7 @@ class StockService
}
else //Insert
{
$shoppinglistRow = $db->shopping_list()->createRow(array(
$shoppinglistRow = $this->Database->shopping_list()->createRow(array(
'product_id' => $missingProduct->id,
'amount_autoadded' => $amount
));

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
@ -44,3 +47,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,11 @@
<?php
use Grocy\Services\BatteriesService;
$batteriesService = new BatteriesService();
?>
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Batteries overview</h1>
@ -13,18 +21,18 @@
</thead>
<tbody>
<?php foreach ($current as $curentBatteryEntry) : ?>
<tr class="<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0 && BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
<tr class="<?php if (FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0 && $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
<td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->name; ?>
<?php echo FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->name; ?>
</td>
<td>
<?php echo $curentBatteryEntry->last_tracked_time; ?>
<time class="timeago timeago-contextual" datetime="<?php echo $curentBatteryEntry->last_tracked_time; ?>"></time>
</td>
<td>
<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0): ?>
<?php echo BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id); ?>
<time class="timeago timeago-contextual" datetime="<?php echo BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id); ?>"></time>
<?php if (FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0): ?>
<?php echo $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id); ?>
<time class="timeago timeago-contextual" datetime="<?php echo $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id); ?>"></time>
<?php else: ?>
...
<?php endif; ?>
@ -36,3 +44,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1>
@ -31,3 +34,4 @@
</form>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Battery tracking</h1>
@ -40,3 +43,4 @@
<strong>Last charged:</strong> <span id="selected-battery-last-charged"></span> <time id="selected-battery-last-charged-timeago" class="timeago timeago-contextual"></time><br>
</p>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Consume</h1>
@ -43,3 +46,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1>
@ -44,3 +47,4 @@
</form>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
@ -48,3 +51,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,11 @@
<?php
use Grocy\Services\HabitsService;
$habitsService = new HabitsService();
?>
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Habits overview</h1>
@ -13,14 +21,14 @@
</thead>
<tbody>
<?php foreach ($currentHabits as $curentHabitEntry) : ?>
<tr class="<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && HabitsService::GetNextHabitTime($curentHabitEntry->habit_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
<tr class="<?php if (FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && $habitsService->GetNextHabitTime($curentHabitEntry->habit_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
<td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name; ?>
<?php echo FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name; ?>
</td>
<td>
<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR): ?>
<?php echo HabitsService::GetNextHabitTime($curentHabitEntry->habit_id); ?>
<time class="timeago timeago-contextual" datetime="<?php echo HabitsService::GetNextHabitTime($curentHabitEntry->habit_id); ?>"></time>
<?php if (FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR): ?>
<?php echo $habitsService->GetNextHabitTime($curentHabitEntry->habit_id); ?>
<time class="timeago timeago-contextual" datetime="<?php echo $habitsService->GetNextHabitTime($curentHabitEntry->habit_id); ?>"></time>
<?php else: ?>
...
<?php endif; ?>
@ -36,3 +44,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Habit tracking</h1>
@ -40,3 +43,4 @@
<strong>Last tracked:</strong> <span id="selected-habit-last-tracked"></span> <time id="selected-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br>
</p>
</div>
@stop

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Inventory</h1>
@ -50,3 +53,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p>
</div>
@stop

View File

@ -1,3 +1,10 @@
<?php
use Grocy\Services\ApplicationService;
$applicationService = new ApplicationService();
?>
<!DOCTYPE html>
<html lang="en">
<head>
@ -9,24 +16,24 @@
<meta name="format-detection" content="telephone=no">
<meta name="author" content="Bernd Bestel (bernd@berrnd.de)">
<link rel="icon" type="image/png" sizes="200x200" href="/grocy.png">
<link rel="icon" type="image/png" sizes="200x200" href="/views/img/grocy.png">
<title><?php echo $title; ?> | grocy</title>
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/font-awesome/css/font-awesome.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/vendor_unmanaged/noto-sans-v6-latin/noto-sans-v6-latin.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/style.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/font-awesome/css/font-awesome.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/vendor_unmanaged/noto-sans-v6-latin/noto-sans-v6-latin.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<link href="/views/css/grocy.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/grocy.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/views/js/grocy.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
</head>
<body>
@ -116,7 +123,7 @@
<br>
Created with passion since 2017
<br>
Version <?php echo ApplicationService::GetInstalledVersion(); ?>
Version <?php echo $applicationService->GetInstalledVersion(); ?>
<br>
Life runs on code
<br>
@ -193,7 +200,7 @@
<br>
Created with passion since 2017
<br>
Version <?php echo ApplicationService::GetInstalledVersion(); ?>
Version <?php echo $applicationService->GetInstalledVersion(); ?>
<br>
Life runs on code
<br>
@ -204,30 +211,31 @@
</div>
<script>Grocy.ContentPage = '<?php echo $contentPage; ?>';</script>
<?php include __DIR__ . '/../' . $contentPage; ?>
<script>Grocy.ContentPage = '{{ $contentPage }}';</script>
@section('content')
@show
</div>
</div>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootbox/bootbox.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/moment/min/moment.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-validator/dist/validator.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootbox/bootbox.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/moment/min/moment.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-validator/dist/validator.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
<?php if (file_exists(__DIR__ . '/' . str_replace('.php', '.js', $contentPage))) : ?>
<script src="/views/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . ApplicationService::GetInstalledVersion(); ?>"></script>
<?php if (file_exists(__DIR__ . '/../../views/viewjs/' . str_replace('.php', '.js', $contentPage))) : ?>
<script src="/views/viewjs/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . $applicationService->GetInstalledVersion(); ?>"></script>
<?php endif; ?>
<?php if (file_exists(__DIR__ . '/../data/add_before_end_body.html')) include __DIR__ . '/../data/add_before_end_body.html' ?>

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1>
@ -26,3 +29,4 @@
</form>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
@ -40,3 +43,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-md-4 col-md-offset-5 main">
<h1 class="page-header text-center">Login</h1>
@ -21,3 +24,4 @@
</form>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1>
@ -81,3 +84,4 @@
</form>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
@ -36,16 +39,16 @@
<?php echo $product->name; ?>
</td>
<td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name; ?>
<?php echo FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name; ?>
</td>
<td>
<?php echo $product->min_stock_amount; ?>
</td>
<td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name; ?>
<?php echo FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name; ?>
</td>
<td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name; ?>
<?php echo FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name; ?>
</td>
<td>
<?php echo $product->qu_factor_purchase_to_stock; ?>
@ -60,3 +63,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header">Purchase</h1>
@ -49,3 +52,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1>
@ -26,3 +29,4 @@
</form>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
@ -40,3 +43,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">
@ -31,10 +34,10 @@
</a>
</td>
<td>
<?php if (!empty($listItem->product_id)) echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name . '<br>'; ?><em><?php echo $listItem->note; ?></em>
<?php if (!empty($listItem->product_id)) echo FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name . '<br>'; ?><em><?php echo $listItem->note; ?></em>
</td>
<td>
<?php echo $listItem->amount + $listItem->amount_autoadded; if (!empty($listItem->product_id)) echo ' ' . GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name; ?>
<?php echo $listItem->amount + $listItem->amount_autoadded; if (!empty($listItem->product_id)) echo ' ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name; ?>
</td>
</tr>
<?php endforeach; ?>
@ -43,3 +46,4 @@
</div>
</div>
@stop

View File

@ -1,3 +1,6 @@
@extends('layout.default')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
<h1 class="page-header"><?php echo $title; ?></h1>
@ -48,3 +51,4 @@
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p>
</div>
@stop

View File

@ -1,11 +1,14 @@
@extends('layout.default')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo GrocyPhpHelper::SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h1>
<h1 class="page-header">Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h1>
<div class="container-fluid">
<div class="row">
<p class="btn btn-lg btn-warning no-real-button"><strong><?php echo count(GrocyPhpHelper::FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')); ?></strong> products expiring within the next 5 days</p>
<p class="btn btn-lg btn-danger no-real-button"><strong><?php echo count(GrocyPhpHelper::FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')); ?></strong> products are already expired</p>
<p class="btn btn-lg btn-warning no-real-button"><strong><?php echo count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')); ?></strong> products expiring within the next 5 days</p>
<p class="btn btn-lg btn-danger no-real-button"><strong><?php echo count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')); ?></strong> products are already expired</p>
<p class="btn btn-lg btn-info no-real-button"><strong><?php echo count($missingProducts); ?></strong> products are below defined min. stock amount</p>
</div>
</div>
@ -23,12 +26,12 @@
</thead>
<tbody>
<?php foreach ($currentStock as $currentStockEntry) : ?>
<tr class="<?php if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) echo 'error-bg'; else if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('+5 days'))) echo 'warning-bg'; else if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) echo 'info-bg'; ?>">
<tr class="<?php if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) echo 'error-bg'; else if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('+5 days'))) echo 'warning-bg'; else if (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) echo 'info-bg'; ?>">
<td>
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name; ?>
<?php echo FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name; ?>
</td>
<td>
<?php echo $currentStockEntry->amount . ' ' . GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name; ?>
<?php echo $currentStockEntry->amount . ' ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name; ?>
</td>
<td>
<?php echo $currentStockEntry->best_before_date; ?>
@ -41,3 +44,4 @@
</div>
</div>
@stop

View File

@ -7,7 +7,7 @@
Grocy.FetchJson('/api/habits/get-habit-details/' + jsonForm.habit_id,
function (habitDetails)
{
Grocy.FetchJson('/api/habits/track-habit/' + jsonForm.habit_id + '?tracked_time=' + $('#tracked_time').val(),
Grocy.FetchJson('/api/habits/track-habit-exeuction/' + jsonForm.habit_id + '?tracked_time=' + $('#tracked_time').val(),
function(result)
{
toastr.success('Tracked execution of habit ' + habitDetails.habit.name + ' on ' + $('#tracked_time').val());