This commit is contained in:
Jonas 2024-02-05 16:16:43 +01:00
commit 203233d2ed
71 changed files with 8213 additions and 0 deletions

30
.env Normal file
View file

@ -0,0 +1,30 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=4293c0675d5638816d9140f45bd2515b
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
# DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
###< doctrine/doctrine-bundle ###

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
/.php-styler.cache

8
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

33
.idea/codeception.xml Normal file
View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Codeception">
<option name="configurations">
<list>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
</list>
</option>
</component>
</project>

12
.idea/dataSources.xml Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="data.db" uuid="a97e0c0d-1a88-4e27-b1c3-36b7079cc563">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/var/data.db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

89
.idea/futtern.iml Normal file
View file

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="App\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/dealerdirect/phpcodesniffer-composer-installer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/lubiana/code-quality" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpstan/phpdoc-parser" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpstan/phpstan" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
<excludeFolder url="file://$MODULE_DIR$/vendor/rector/rector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/slevomat/coding-standard" />
<excludeFolder url="file://$MODULE_DIR$/vendor/squizlabs/php_codesniffer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/config" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dependency-injection" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dotenv" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/error-handler" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/filesystem" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/flex" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/framework-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-kernel" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/runtime" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symplify/easy-coding-standard" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/collections" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/common" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/dbal" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/deprecations" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/event-manager" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/migrations" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/orm" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/persistence" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/sql-formatter" />
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
<excludeFolder url="file://$MODULE_DIR$/vendor/pmjones/auto-shell" />
<excludeFolder url="file://$MODULE_DIR$/vendor/pmjones/php-styler" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/doctrine-bridge" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/form" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/maker-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/options-resolver" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/password-hasher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-icu" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-access" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-info" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-core" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-csrf" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/stopwatch" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bridge" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/validator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/data-fixtures" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/fakerphp/faker" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-uuid" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/uid" />
<excludeFolder url="file://$MODULE_DIR$/var" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/futtern.iml" filepath="$PROJECT_DIR$/.idea/futtern.iml" />
</modules>
</component>
</project>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpDockerContainerSettings">
<list>
<map>
<entry key="de9b5aa7-e4b3-472b-9be8-63313022c875">
<value>
<DockerContainerSettings>
<option name="version" value="1" />
<option name="volumeBindings">
<list>
<DockerVolumeBindingImpl>
<option name="containerPath" value="/opt/project" />
<option name="hostPath" value="$PROJECT_DIR$" />
</DockerVolumeBindingImpl>
</list>
</option>
</DockerContainerSettings>
</value>
</entry>
</map>
</list>
</component>
</project>

116
.idea/php.xml Normal file
View file

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpCodeSniffer">
<phpcs_settings>
<PhpCSConfiguration beautifier_path="$PROJECT_DIR$/vendor/bin/phpcbf" tool_path="$PROJECT_DIR$/vendor/bin/phpcs" />
</phpcs_settings>
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/vendor/psr/container" />
<path value="$PROJECT_DIR$/vendor/psr/cache" />
<path value="$PROJECT_DIR$/vendor/rector/rector" />
<path value="$PROJECT_DIR$/vendor/lubiana/code-quality" />
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/psr/log" />
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
<path value="$PROJECT_DIR$/vendor/phpstan/phpstan" />
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
<path value="$PROJECT_DIR$/vendor/symfony/config" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/console" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/vendor/symfony/string" />
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/vendor/slevomat/coding-standard" />
<path value="$PROJECT_DIR$/vendor/symplify/easy-coding-standard" />
<path value="$PROJECT_DIR$/vendor/composer" />
<path value="$PROJECT_DIR$/vendor/dealerdirect/phpcodesniffer-composer-installer" />
<path value="$PROJECT_DIR$/vendor/squizlabs/php_codesniffer" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-icu" />
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
<path value="$PROJECT_DIR$/vendor/symfony/form" />
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
<path value="$PROJECT_DIR$/vendor/doctrine/cache" />
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/process" />
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
<path value="$PROJECT_DIR$/vendor/twig/twig" />
<path value="$PROJECT_DIR$/vendor/pmjones/php-styler" />
<path value="$PROJECT_DIR$/vendor/pmjones/auto-shell" />
<path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
<path value="$PROJECT_DIR$/vendor/fakerphp/faker" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.3" />
<component name="PhpStan">
<PhpStan_settings>
<PhpStanConfiguration tool_path="$PROJECT_DIR$/vendor/bin/phpstan" />
</PhpStan_settings>
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
</phpunit_settings>
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

31
.idea/phpspec.xml Normal file
View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PHPSpec">
<suites>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
</suites>
</component>
</project>

10
.idea/phpunit.xml Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PHPUnit">
<option name="directories">
<list>
<option value="$PROJECT_DIR$/tests" />
</list>
</option>
</component>
</project>

6
.idea/symfony2.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Symfony2PluginSettings">
<option name="pluginEnabled" value="true" />
</component>
</project>

0
README.md Normal file
View file

17
bin/console Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
};

92
composer.json Normal file
View file

@ -0,0 +1,92 @@
{
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.3",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/doctrine-bundle": "^2.11",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/orm": "^2.17",
"lubiana/code-quality": "^1.4",
"symfony/console": "7.0.*",
"symfony/dotenv": "7.0.*",
"symfony/flex": "^2",
"symfony/form": "7.0.*",
"symfony/framework-bundle": "7.0.*",
"symfony/runtime": "7.0.*",
"symfony/security-csrf": "7.0.*",
"symfony/twig-bundle": "7.0.*",
"symfony/uid": "7.0.*",
"symfony/validator": "7.0.*",
"symfony/yaml": "7.0.*"
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.5",
"fakerphp/faker": "^1.23",
"pmjones/php-styler": "0.x-dev",
"symfony/maker-bundle": "^1.53"
},
"config": {
"allow-plugins": {
"php-http/discovery": true,
"symfony/flex": true,
"symfony/runtime": true,
"dealerdirect/phpcodesniffer-composer-installer": true
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*",
"symfony/polyfill-php82": "*",
"symfony/polyfill-php83": "*",
"symfony/polyfill-intl-grapheme": "*",
"symfony/polyfill-intl-normalizer": "*",
"symfony/polyfill-intl-mbstring": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
],
"lint": [
"rector",
"php-styler apply",
"ecs --fix",
"ecs --fix"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "7.0.*"
}
}
}

5926
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

30
config/bundles.php Normal file
View file

@ -0,0 +1,30 @@
<?php declare(strict_types=1);
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle;
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\MakerBundle\MakerBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
return [
FrameworkBundle::class => [
'all' => true,
],
DoctrineBundle::class => [
'all' => true,
],
DoctrineMigrationsBundle::class => [
'all' => true,
],
MakerBundle::class => [
'dev' => true,
],
TwigBundle::class => [
'all' => true,
],
DoctrineFixturesBundle::class => [
'dev' => true,
'test' => true,
],
];

View file

@ -0,0 +1,9 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension('framework', [
'cache' => null,
]);
};

View file

@ -0,0 +1,78 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension(
'doctrine',
[
'dbal' => [
'url' => '%env(resolve:DATABASE_URL)%',
'profiling_collect_backtrace' => '%kernel.debug%',
],
'orm' => [
'auto_generate_proxy_classes' => true,
'enable_lazy_ghost_objects' => true,
'report_fields_where_declared' => true,
'validate_xml_mapping' => true,
'naming_strategy' => 'doctrine.orm.naming_strategy.underscore_number_aware',
'auto_mapping' => true,
'mappings' => [
'App' => [
'type' => 'attribute',
'is_bundle' => false,
'dir' => '%kernel.project_dir%/src/Entity',
'prefix' => 'App\Entity',
'alias' => 'App',
],
],
],
],
);
if ($containerConfigurator->env() === 'test') {
$containerConfigurator->extension(
'doctrine',
[
'dbal' => [
'dbname_suffix' => '_test%env(default::TEST_TOKEN)%',
],
],
);
}
if ($containerConfigurator->env() === 'prod') {
$containerConfigurator->extension(
'doctrine',
[
'orm' => [
'auto_generate_proxy_classes' => false,
'proxy_dir' => '%kernel.build_dir%/doctrine/orm/Proxies',
'query_cache_driver' => [
'type' => 'pool',
'pool' => 'doctrine.system_cache_pool',
],
'result_cache_driver' => [
'type' => 'pool',
'pool' => 'doctrine.result_cache_pool',
],
],
],
);
$containerConfigurator->extension(
'framework',
[
'cache' => [
'pools' => [
'doctrine.result_cache_pool' => [
'adapter' => 'cache.app',
],
'doctrine.system_cache_pool' => [
'adapter' => 'cache.system',
],
],
],
],
);
}
};

View file

@ -0,0 +1,15 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension(
'doctrine_migrations',
[
'migrations_paths' => [
'DoctrineMigrations' => '%kernel.project_dir%/migrations',
],
'enable_profiler' => false,
],
);
};

View file

@ -0,0 +1,25 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension(
'framework',
[
'secret' => '%env(APP_SECRET)%',
'session' => true,
],
);
if ($containerConfigurator->env() === 'test') {
$containerConfigurator->extension(
'framework',
[
'test' => true,
'session' => [
'storage_factory_id' => 'session.storage.factory.mock_file',
],
],
);
}
};

View file

@ -0,0 +1,20 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension('framework', [
'router' => null,
]);
if ($containerConfigurator->env() === 'prod') {
$containerConfigurator->extension(
'framework',
[
'router' => [
'strict_requirements' => null,
],
],
);
}
};

15
config/packages/twig.php Normal file
View file

@ -0,0 +1,15 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension('twig', [
'file_name_pattern' => '*.twig',
]);
if ($containerConfigurator->env() === 'test') {
$containerConfigurator->extension('twig', [
'strict_variables' => true,
]);
}
};

View file

@ -0,0 +1,20 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension('framework', [
'validation' => null,
]);
if ($containerConfigurator->env() === 'test') {
$containerConfigurator->extension(
'framework',
[
'validation' => [
'not_compromised_password' => false,
],
],
);
}
};

9
config/preload.php Normal file
View file

@ -0,0 +1,9 @@
<?php declare(strict_types=1);
if (
file_exists(
dirname(__DIR__) . '/var/cache/prod/App_KernelProdContainer.preload.php',
)
) {
require dirname(__DIR__) . '/var/cache/prod/App_KernelProdContainer.preload.php';
}

13
config/routes.php Normal file
View file

@ -0,0 +1,13 @@
<?php declare(strict_types=1);
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
return static function (RoutingConfigurator $routingConfigurator): void {
$routingConfigurator->import(
[
'path' => '../src/Controller/',
'namespace' => 'App\Controller',
],
'attribute',
);
};

View file

@ -0,0 +1,11 @@
<?php declare(strict_types=1);
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
return static function (RoutingConfigurator $routingConfigurator): void {
if ($routingConfigurator->env() === 'dev') {
$routingConfigurator
->import('@FrameworkBundle/Resources/config/routing/errors.xml')
->prefix('/_error');
}
};

17
config/services.php Normal file
View file

@ -0,0 +1,17 @@
<?php declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->defaults()
->autowire()
->autoconfigure();
$services
->load('App\\', __DIR__ . '/../src/')
->exclude([
__DIR__ . '/../src/DependencyInjection/',
__DIR__ . '/../src/Entity/',
__DIR__ . '/../src/Kernel.php',
]);
};

18
ecs.php Normal file
View file

@ -0,0 +1,18 @@
<?php declare(strict_types=1);
use Lubiana\CodeQuality\LubiSetList;
use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
return ECSConfig::configure()
->withPaths([
__DIR__ . '/config',
__DIR__ . '/public',
__DIR__ . '/src',
])
->withRootFiles()
->withSets([
LubiSetList::ECS,
])
->withSkip([LineLengthFixer::class])
;

0
migrations/.gitignore vendored Normal file
View file

View file

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240203164757 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE food_order (id BLOB NOT NULL --(DC2Type:ulid)
, vendor_id BLOB NOT NULL --(DC2Type:ulid)
, started_by_name VARCHAR(255) NOT NULL, closed_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable)
, started_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
, PRIMARY KEY(id), CONSTRAINT FK_4485672F603EE73 FOREIGN KEY (vendor_id) REFERENCES vendor (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_4485672F603EE73 ON food_order (vendor_id)');
$this->addSql('CREATE TABLE menu_item (id BLOB NOT NULL --(DC2Type:ulid)
, vendor_id BLOB NOT NULL --(DC2Type:ulid)
, price INTEGER DEFAULT NULL, PRIMARY KEY(id), CONSTRAINT FK_D754D550F603EE73 FOREIGN KEY (vendor_id) REFERENCES vendor (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_D754D550F603EE73 ON menu_item (vendor_id)');
$this->addSql('CREATE TABLE menu_item_alias (id BLOB NOT NULL --(DC2Type:ulid)
, menu_item_id BLOB NOT NULL --(DC2Type:ulid)
, name VARCHAR(255) NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_EA66C4969AB44FE0 FOREIGN KEY (menu_item_id) REFERENCES menu_item (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_EA66C4969AB44FE0 ON menu_item_alias (menu_item_id)');
$this->addSql('CREATE TABLE order_item (id BLOB NOT NULL --(DC2Type:ulid)
, food_order_id BLOB NOT NULL --(DC2Type:ulid)
, menu_item_id BLOB NOT NULL --(DC2Type:ulid)
, PRIMARY KEY(id), CONSTRAINT FK_52EA1F09A5D24A7A FOREIGN KEY (food_order_id) REFERENCES food_order (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_52EA1F099AB44FE0 FOREIGN KEY (menu_item_id) REFERENCES menu_item (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_52EA1F09A5D24A7A ON order_item (food_order_id)');
$this->addSql('CREATE INDEX IDX_52EA1F099AB44FE0 ON order_item (menu_item_id)');
$this->addSql('CREATE TABLE vendor (id BLOB NOT NULL --(DC2Type:ulid)
, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE food_order');
$this->addSql('DROP TABLE menu_item');
$this->addSql('DROP TABLE menu_item_alias');
$this->addSql('DROP TABLE order_item');
$this->addSql('DROP TABLE vendor');
}
}

11
php-styler.php Normal file
View file

@ -0,0 +1,11 @@
<?php declare(strict_types=1);
use PhpStyler\Config;
use PhpStyler\Files;
use PhpStyler\Styler;
return new Config(
files: new Files(__DIR__ . '/src', __DIR__ . '/config', __DIR__ . '/public'),
styler: new Styler,
cache: __DIR__ . '/.php-styler.cache',
);

1
public/css/simple.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
public/index.php Normal file
View file

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
use App\Kernel;
require_once dirname(__DIR__) . '/vendor/autoload_runtime.php';
return static fn(array $context): Kernel
=> new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);

15
rector.php Normal file
View file

@ -0,0 +1,15 @@
<?php declare(strict_types=1);
use Lubiana\CodeQuality\LubiSetList;
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/config',
__DIR__ . '/public',
__DIR__ . '/src',
])
->withRootFiles()
->withSets([
LubiSetList::RECTOR,
]);

0
src/Controller/.gitignore vendored Normal file
View file

View file

@ -0,0 +1,167 @@
<?php declare(strict_types=1);
namespace App\Controller;
use App\Entity\FoodOrder;
use App\Entity\MenuItem;
use App\Entity\OrderItem;
use App\Form\FoodOrderType;
use App\Repository\FoodOrderRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/order')]
class FoodOrderController extends AbstractController
{
final public const APP_FOOD_ORDER_SHOW = 'app_food_order_show';
final public const APP_FOODORDER_ADD_ITEM = 'app_foodorder_add_item';
#[Route('/', name: 'app_food_order_index', methods: ['GET'])]
public function index(FoodOrderRepository $foodOrderRepository): Response
{
return $this->render(
'food_order/index.html.twig',
[
'food_orders' => $foodOrderRepository->findAll(),
],
);
}
#[Route(
'/new',
name: 'app_food_order_new',
methods: [Request::METHOD_GET, Request::METHOD_POST],
)]
public function new(
Request $request,
EntityManagerInterface $entityManager,
): Response {
$foodOrder = new FoodOrder;
$form = $this->createForm(FoodOrderType::class, $foodOrder);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($foodOrder);
$entityManager->flush();
return $this->redirectToRoute(
'app_food_order_index',
[],
Response::HTTP_SEE_OTHER,
);
}
return $this->render(
'food_order/new.html.twig',
[
'food_order' => $foodOrder,
'form' => $form,
],
);
}
#[Route('/{id}', name: self::APP_FOOD_ORDER_SHOW, methods: ['GET'])]
public function show(FoodOrder $foodOrder): Response
{
$menuItems = $foodOrder->vendor->menuItems;
return $this->render(
'food_order/show.html.twig',
[
'food_order' => $foodOrder,
'menu_items' => $menuItems,
],
);
}
#[Route(
'/{foodOrder}/add/{menuItem}',
name: self::APP_FOODORDER_ADD_ITEM,
methods: [Request::METHOD_GET],
)]
public function add(
FoodOrder $foodOrder,
MenuItem $menuItem,
EntityManagerInterface $entityManager,
): Response {
$orderItem = new OrderItem(foodOrder: $foodOrder, menuItem: $menuItem);
$entityManager->persist($orderItem);
$entityManager->flush();
return $this->redirectToRoute(
self::APP_FOOD_ORDER_SHOW,
[
'id' => $foodOrder->id,
],
Response::HTTP_SEE_OTHER,
);
}
#[Route(
'/{foodOrder}/remove_item/{orderItem}',
name: 'app_foodorder_remove_item',
methods: [Request::METHOD_GET],
)]
public function remove(
FoodOrder $foodOrder,
OrderItem $orderItem,
EntityManagerInterface $entityManager,
): Response {
$entityManager->remove($orderItem);
$entityManager->flush();
return $this->redirectToRoute(
self::APP_FOOD_ORDER_SHOW,
[
'id' => $foodOrder->id,
],
Response::HTTP_SEE_OTHER,
);
}
#[Route('/{id}/edit', name: 'app_food_order_edit', methods: ['GET', 'POST'])]
public function edit(
Request $request,
FoodOrder $foodOrder,
EntityManagerInterface $entityManager,
): Response {
$form = $this->createForm(FoodOrderType::class, $foodOrder);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
return $this->redirectToRoute(''[], Response::HTTP_SEE_OTHER);
}
return $this->render(
'food_order/edit.html.twig',
[
'food_order' => $foodOrder,
'form' => $form,
],
);
}
#[Route('/{id}', name: 'app_food_order_delete', methods: ['POST'])]
public function delete(
Request $request,
FoodOrder $foodOrder,
EntityManagerInterface $entityManager,
): Response {
if (
$this->isCsrfTokenValid(
'delete' . $foodOrder->id ?? '',
$request->request->get('_token'),
)
) {
$entityManager->remove($foodOrder);
$entityManager->flush();
}
return $this->redirectToRoute(
'app_food_order_index',
[],
Response::HTTP_SEE_OTHER,
);
}
}

45
src/Controller/Start.php Normal file
View file

@ -0,0 +1,45 @@
<?php declare(strict_types=1);
namespace App\Controller;
use App\Entity\FoodOrder;
use App\Form\FoodOrderType;
use App\Repository\FoodOrderRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class Start extends AbstractController
{
#[Route('/')]
public function index(
FoodOrderRepository $foodOrderRepository,
EntityManagerInterface $em,
Request $request,
): Response {
$openOrders = $foodOrderRepository->findOpen();
$order = new FoodOrder('');
$form = $this->createForm(FoodOrderType::class, $order);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($order);
$em->flush();
return $this->redirectToRoute(
'app_food_order_index',
[],
Response::HTTP_SEE_OTHER,
);
}
return $this->render(
'start/index.html.twig',
[
'orders' => $openOrders,
'form' => $form,
],
);
}
}

View file

@ -0,0 +1,109 @@
<?php declare(strict_types=1);
namespace App\Controller;
use App\Entity\Vendor;
use App\Form\VendorType;
use App\Repository\VendorRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/vendor')]
class VendorController extends AbstractController
{
#[Route('/', name: 'app_vendor_index', methods: ['GET'])]
public function index(VendorRepository $vendorRepository): Response
{
return $this->render(
'vendor/index.html.twig',
[
'vendors' => $vendorRepository->findAll(),
],
);
}
#[Route('/new', name: 'app_vendor_new', methods: ['GET', 'POST'])]
public function new(
Request $request,
EntityManagerInterface $entityManager,
): Response {
$vendor = new Vendor;
$form = $this->createForm(VendorType::class, $vendor);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($vendor);
$entityManager->flush();
return $this->redirectToRoute(
'app_vendor_index',
[],
Response::HTTP_SEE_OTHER,
);
}
return $this->render(
'vendor/new.html.twig',
[
'vendor' => $vendor,
'form' => $form,
],
);
}
#[Route('/{id}', name: 'app_vendor_show', methods: ['GET'])]
public function show(Vendor $vendor): Response
{
return $this->render('vendor/show.html.twig', [
'vendor' => $vendor,
]);
}
#[Route('/{id}/edit', name: 'app_vendor_edit', methods: ['GET', 'POST'])]
public function edit(
Request $request,
Vendor $vendor,
EntityManagerInterface $entityManager,
): Response {
$form = $this->createForm(VendorType::class, $vendor);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
return $this->redirectToRoute(
'app_vendor_index',
[],
Response::HTTP_SEE_OTHER,
);
}
return $this->render(
'vendor/edit.html.twig',
[
'vendor' => $vendor,
'form' => $form,
],
);
}
#[Route('/{id}', name: 'app_vendor_delete', methods: ['POST'])]
public function delete(
Request $request,
Vendor $vendor,
EntityManagerInterface $entityManager,
): Response {
if (
$this->isCsrfTokenValid(
'delete' . $vendor->getId(),
$request->request->get('_token'),
)
) {
$entityManager->remove($vendor);
$entityManager->flush();
}
return $this->redirectToRoute('app_vendor_index', [], Response::HTTP_SEE_OTHER);
}
}

View file

@ -0,0 +1,51 @@
<?php declare(strict_types=1);
namespace App\DataFixtures;
use App\Entity\MenuItem;
use App\Entity\MenuItemAlias;
use App\Entity\Vendor;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory;
use Faker\Generator;
use Override;
use function random_int;
use function range;
class AppFixtures extends Fixture
{
private readonly Generator $faker;
public function __construct()
{
$this->faker = Factory::create();
}
#[Override]
public function load(ObjectManager $manager): void
{
foreach (range(0, 10) as $counter) {
$vendor = new Vendor(name: $this->faker->company());
$this->addMenuItemsToVendor($vendor, $manager);
$manager->persist($vendor);
}
$manager->flush();
}
private function addMenuItemsToVendor(Vendor $vendor, ObjectManager $manager): void
{
foreach (range(0, 100) as $counter) {
$aliasOne = MenuItemAlias::new($this->faker->lastName());
$aliasTwo = MenuItemAlias::new($this->faker->lastName());
$manager->persist($aliasOne);
$manager->persist($aliasTwo);
$item = MenuItem::new([$aliasOne, $aliasTwo]);
$item->price = random_int(500, 2000);
$manager->persist($item);
$vendor->addMenuItem($item);
}
}
}

0
src/Entity/.gitignore vendored Normal file
View file

85
src/Entity/FoodOrder.php Normal file
View file

@ -0,0 +1,85 @@
<?php declare(strict_types=1);
namespace App\Entity;
use App\Repository\FoodOrderRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Uid\Ulid;
#[ORM\Entity(repositoryClass: FoodOrderRepository::class)]
class FoodOrder
{
public function __construct(
#[ORM\Column]
public string $startedByName,
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Column(type: UlidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: UlidGenerator::class)]
public Ulid $id = new Ulid,
#[ORM\Column(nullable: true)]
public DateTimeImmutable|null $closedAt = null,
/** @var Collection<int, OrderItem> $orderItems */
#[ORM\OneToMany(
mappedBy: 'foodOrder',
targetEntity: OrderItem::class,
orphanRemoval: true,
)]
public Collection $orderItems = new ArrayCollection,
#[ORM\ManyToOne(inversedBy: 'foodOrders')]
#[ORM\JoinColumn(nullable: false)]
public Vendor|null $vendor = null,
#[ORM\Column]
public DateTimeImmutable $startedAt = new DateTimeImmutable,
)
{
}
public function addOrderItem(OrderItem $orderItem): static
{
if (!$this->orderItems->contains($orderItem)) {
$this->orderItems->add($orderItem);
$orderItem->foodOrder = $this;
}
return $this;
}
public function removeOrderItem(OrderItem $orderItem): static
{
// set the owning side to null (unless already changed)
if (
$this->orderItems->removeElement($orderItem)
&& $orderItem->foodOrder === $this
) {
$orderItem->foodOrder = null;
}
return $this;
}
public function groupedOrderItems(): array
{
return $this->orderItems->reduce(
function (array $carry, OrderItem $item): array {
$menuItemStringId = (string)$item->menuItem->id;
if (isset($carry[$menuItemStringId])) {
$carry[$menuItemStringId]['amount']++;
} else {
$carry[$menuItemStringId] = [
'item' => $item,
'amount' => 1,
];
}
return $carry;
},
[]
);
}
}

67
src/Entity/MenuItem.php Normal file
View file

@ -0,0 +1,67 @@
<?php declare(strict_types=1);
namespace App\Entity;
use App\Repository\MenuItemRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Uid\Ulid;
#[ORM\Entity(repositoryClass: MenuItemRepository::class)]
class MenuItem
{
public function __construct(
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Column(type: UlidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: UlidGenerator::class)]
public Ulid $id = new Ulid,
#[ORM\ManyToOne(inversedBy: 'menuItems')]
#[ORM\JoinColumn(nullable: false)]
public Vendor|null $vendor = null,
#[ORM\Column(nullable: true)]
public int|null $price = null,
/** @var Collection<int, MenuItemAlias> $aliases */
#[ORM\OneToMany(
mappedBy: 'menuItem',
targetEntity: MenuItemAlias::class,
orphanRemoval: true,
)]
public Collection $aliases = new ArrayCollection,
) {}
public function addAlias(MenuItemAlias $alias): static
{
if (! $this->aliases->contains($alias)) {
$this->aliases->add($alias);
$alias->menuItem = $this;
}
return false;
}
public function removeAlias(MenuItemAlias $alias): static
{
// set the owning side to null (unless already changed)
if ($this->aliases->removeElement($alias) && $alias->menuItem === $this) {
$alias->menuItem = null;
}
return $this;
}
public static function new(array $aliases): self
{
$menuItem = new self;
foreach ($aliases as $alias) {
$menuItem->addAlias($alias);
}
return $menuItem;
}
}

View file

@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace App\Entity;
use App\Repository\MenuItemAliasRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Uid\Ulid;
#[ORM\Entity(repositoryClass: MenuItemAliasRepository::class)]
class MenuItemAlias
{
public function __construct(
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Column(type: UlidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: UlidGenerator::class)]
public Ulid $id = new Ulid,
#[ORM\ManyToOne(inversedBy: 'aliases')]
#[ORM\JoinColumn(nullable: false)]
public MenuItem|null $menuItem = null,
#[ORM\Column(length: 255)]
public string|null $name = null,
) {}
public static function new(string $name): self
{
$new = new self;
$new->name = $name;
return $new;
}
}

27
src/Entity/OrderItem.php Normal file
View file

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
namespace App\Entity;
use App\Repository\OrderItemRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Uid\Ulid;
#[ORM\Entity(repositoryClass: OrderItemRepository::class)]
class OrderItem
{
public function __construct(
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Column(type: UlidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: UlidGenerator::class)]
public Ulid $id = new Ulid,
#[ORM\ManyToOne(inversedBy: 'orderItems')]
#[ORM\JoinColumn(nullable: false)]
public FoodOrder|null $foodOrder = null,
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
public MenuItem|null $menuItem = null,
) {}
}

78
src/Entity/Vendor.php Normal file
View file

@ -0,0 +1,78 @@
<?php declare(strict_types=1);
namespace App\Entity;
use App\Repository\VendorRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Uid\Ulid;
#[ORM\Entity(repositoryClass: VendorRepository::class)]
class Vendor
{
public function __construct(
#[ORM\Column]
public string $name,
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Column(type: UlidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: UlidGenerator::class)]
public Ulid $id = new Ulid,
/** @var Collection<int, MenuItem> $menuItems */
#[ORM\OneToMany(mappedBy: 'vendor', targetEntity: MenuItem::class)]
public Collection $menuItems = new ArrayCollection,
/** @var Collection<int, FoodOrder> $foodOrders */
#[ORM\OneToMany(
mappedBy: 'vendor',
targetEntity: FoodOrder::class,
orphanRemoval: true,
)]
private Collection $foodOrders = new ArrayCollection,
) {}
public function addMenuItem(MenuItem $menuItem): static
{
if (! $this->menuItems->contains($menuItem)) {
$this->menuItems->add($menuItem);
$menuItem->vendor = $this;
}
return $this;
}
public function removeMenuItem(MenuItem $menuItem): static
{
// set the owning side to null (unless already changed)
if ($this->menuItems->removeElement($menuItem) && $menuItem->vendor === $this) {
$menuItem->vendor = null;
}
return $this;
}
public function addFoodOrder(FoodOrder $foodOrder): static
{
if (! $this->foodOrders->contains($foodOrder)) {
$this->foodOrders->add($foodOrder);
$foodOrder->vendor = $this;
}
return $this;
}
public function removeFoodOrder(FoodOrder $foodOrder): static
{
if (
$this->foodOrders->removeElement($foodOrder) && $foodOrder->vendor === $this
) {
$foodOrder->vendor = null;
}
return $this;
}
}

View file

@ -0,0 +1,39 @@
<?php declare(strict_types=1);
namespace App\Form;
use App\Entity\FoodOrder;
use App\Entity\Vendor;
use Override;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FoodOrderType extends AbstractType
{
#[Override]
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('startedByName')
->add(
'vendor',
EntityType::class,
[
'class' => Vendor::class,
'choice_label' => 'name',
'multiple' => false,
],
)
->add('startedAt');
}
#[Override]
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => FoodOrder::class,
]);
}
}

26
src/Form/VendorType.php Normal file
View file

@ -0,0 +1,26 @@
<?php declare(strict_types=1);
namespace App\Form;
use App\Entity\Vendor;
use Override;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class VendorType extends AbstractType
{
#[Override]
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('name');
}
#[Override]
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Vendor::class,
]);
}
}

11
src/Kernel.php Normal file
View file

@ -0,0 +1,11 @@
<?php declare(strict_types=1);
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
}

0
src/Repository/.gitignore vendored Normal file
View file

View file

@ -0,0 +1,41 @@
<?php declare(strict_types=1);
namespace App\Repository;
use App\Entity\FoodOrder;
use DateTime;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<FoodOrder>
*
* @method FoodOrder|null find($id, $lockMode = null, $lockVersion = null)
* @method FoodOrder|null findOneBy(array $criteria, array $orderBy = null)
* @method FoodOrder[] findAll()
* @method FoodOrder[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class FoodOrderRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, FoodOrder::class);
}
/**
* @return Collection<int, FoodOrder>
*/
public function findOpen(int $limit = 10): Collection
{
$yesterday = new DateTime;
$yesterday->modify('-1 day');
$queryBuilder = $this->createQueryBuilder('e');
$queryBuilder
->where('e.closedAt IS NULL')
->andWhere($queryBuilder->expr()->gte('e.startedAt', ':yesterday'))
->setParameter('yesterday', $yesterday);
return new ArrayCollection($queryBuilder->getQuery()->getResult());
}
}

View file

@ -0,0 +1,47 @@
<?php declare(strict_types=1);
namespace App\Repository;
use App\Entity\MenuItemAlias;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<MenuItemAlias>
*
* @method MenuItemAlias|null find($id, $lockMode = null, $lockVersion = null)
* @method MenuItemAlias|null findOneBy(array $criteria, array $orderBy = null)
* @method MenuItemAlias[] findAll()
* @method MenuItemAlias[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class MenuItemAliasRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, MenuItemAlias::class);
}
// /**
// * @return MenuItemAlias[] Returns an array of MenuItemAlias objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('m')
// ->andWhere('m.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('m.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?MenuItemAlias
// {
// return $this->createQueryBuilder('m')
// ->andWhere('m.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View file

@ -0,0 +1,47 @@
<?php declare(strict_types=1);
namespace App\Repository;
use App\Entity\MenuItem;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<MenuItem>
*
* @method MenuItem|null find($id, $lockMode = null, $lockVersion = null)
* @method MenuItem|null findOneBy(array $criteria, array $orderBy = null)
* @method MenuItem[] findAll()
* @method MenuItem[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class MenuItemRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, MenuItem::class);
}
// /**
// * @return MenuItem[] Returns an array of MenuItem objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('m')
// ->andWhere('m.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('m.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?MenuItem
// {
// return $this->createQueryBuilder('m')
// ->andWhere('m.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View file

@ -0,0 +1,47 @@
<?php declare(strict_types=1);
namespace App\Repository;
use App\Entity\OrderItem;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<OrderItem>
*
* @method OrderItem|null find($id, $lockMode = null, $lockVersion = null)
* @method OrderItem|null findOneBy(array $criteria, array $orderBy = null)
* @method OrderItem[] findAll()
* @method OrderItem[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class OrderItemRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, OrderItem::class);
}
// /**
// * @return OrderItem[] Returns an array of OrderItem objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('o')
// ->andWhere('o.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('o.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?OrderItem
// {
// return $this->createQueryBuilder('o')
// ->andWhere('o.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View file

@ -0,0 +1,47 @@
<?php declare(strict_types=1);
namespace App\Repository;
use App\Entity\Vendor;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Vendor>
*
* @method Vendor|null find($id, $lockMode = null, $lockVersion = null)
* @method Vendor|null findOneBy(array $criteria, array $orderBy = null)
* @method Vendor[] findAll()
* @method Vendor[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class VendorRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Vendor::class);
}
// /**
// * @return Vendor[] Returns an array of Vendor objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('v')
// ->andWhere('v.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('v.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Vendor
// {
// return $this->createQueryBuilder('v')
// ->andWhere('v.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

158
symfony.lock Normal file
View file

@ -0,0 +1,158 @@
{
"doctrine/doctrine-bundle": {
"version": "2.11",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.10",
"ref": "310a02a22033e35640468f48ff6bf31a25891537"
},
"files": [
"config/packages/doctrine.yaml",
"src/Entity/.gitignore",
"src/Repository/.gitignore"
]
},
"doctrine/doctrine-fixtures-bundle": {
"version": "3.5",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.0",
"ref": "1f5514cfa15b947298df4d771e694e578d4c204d"
},
"files": [
"src/DataFixtures/AppFixtures.php"
]
},
"doctrine/doctrine-migrations-bundle": {
"version": "3.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.1",
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
},
"files": [
"config/packages/doctrine_migrations.yaml",
"migrations/.gitignore"
]
},
"phpstan/phpstan": {
"version": "1.10",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "main",
"version": "1.0",
"ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767"
}
},
"squizlabs/php_codesniffer": {
"version": "3.8",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "main",
"version": "3.6",
"ref": "1019e5c08d4821cb9b77f4891f8e9c31ff20ac6f"
}
},
"symfony/console": {
"version": "7.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "da0c8be8157600ad34f10ff0c9cc91232522e047"
},
"files": [
"bin/console"
]
},
"symfony/flex": {
"version": "2.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
},
"files": [
".env"
]
},
"symfony/framework-bundle": {
"version": "7.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.0",
"ref": "6356c19b9ae08e7763e4ba2d9ae63043efc75db5"
},
"files": [
"config/packages/cache.yaml",
"config/packages/framework.yaml",
"config/preload.php",
"config/routes/framework.yaml",
"config/services.yaml",
"public/index.php",
"src/Controller/.gitignore",
"src/Kernel.php"
]
},
"symfony/maker-bundle": {
"version": "1.53",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
}
},
"symfony/routing": {
"version": "7.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.0",
"ref": "21b72649d5622d8f7da329ffb5afb232a023619d"
},
"files": [
"config/packages/routing.yaml",
"config/routes.yaml"
]
},
"symfony/twig-bundle": {
"version": "7.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877"
},
"files": [
"config/packages/twig.yaml",
"templates/base.html.twig"
]
},
"symfony/uid": {
"version": "7.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.0",
"ref": "0df5844274d871b37fc3816c57a768ffc60a43a5"
}
},
"symfony/validator": {
"version": "7.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.0",
"ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd"
},
"files": [
"config/packages/validator.yaml"
]
}
}

View file

@ -0,0 +1,4 @@
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

17
templates/base.html.twig Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
<link rel="stylesheet" href="/css/simple.min.css">
{% block stylesheets %}
{% endblock %}
{% block javascripts %}
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

View file

@ -0,0 +1,4 @@
<form method="post" action="{{ path('app_food_order_delete', {'id': food_order.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ food_order.id) }}">
<button class="btn">Delete</button>
</form>

View file

@ -0,0 +1,4 @@
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

View file

@ -0,0 +1,13 @@
{% extends 'base.html.twig' %}
{% block title %}Edit FoodOrder{% endblock %}
{% block body %}
<h1>Edit FoodOrder</h1>
{{ include('food_order/_form.html.twig', {'button_label': 'Update'}) }}
<a href="{{ path('app_food_order_index') }}">back to list</a>
{{ include('food_order/_delete_form.html.twig') }}
{% endblock %}

View file

@ -0,0 +1,39 @@
{% extends 'base.html.twig' %}
{% block title %}FoodOrder index{% endblock %}
{% block body %}
<h1>FoodOrder index</h1>
<table class="table">
<thead>
<tr>
<th>StartedByName</th>
<th>Id</th>
<th>StartedAt</th>
<th>ClosedAt</th>
<th>actions</th>
</tr>
</thead>
<tbody>
{% for food_order in food_orders %}
<tr>
<td>{{ food_order.startedByName }}</td>
<td>{{ food_order.id }}</td>
<td>{{ food_order.startedAt ? food_order.startedAt|date('Y-m-d H:i:s') : '' }}</td>
<td>{{ food_order.closedAt ? food_order.closedAt|date('Y-m-d H:i:s') : '' }}</td>
<td>
<a href="{{ path('app_food_order_show', {'id': food_order.id}) }}">show</a>
<a href="{{ path('app_food_order_edit', {'id': food_order.id}) }}">edit</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="5">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ path('app_food_order_new') }}">Create new</a>
{% endblock %}

View file

@ -0,0 +1,11 @@
{% extends 'base.html.twig' %}
{% block title %}New FoodOrder{% endblock %}
{% block body %}
<h1>Create new FoodOrder</h1>
{{ include('food_order/_form.html.twig') }}
<a href="{{ path('app_food_order_index') }}">back to list</a>
{% endblock %}

View file

@ -0,0 +1,85 @@
{% extends 'base.html.twig' %}
{% block title %}FoodOrder{% endblock %}
{% block body %}
<h1>FoodOrder</h1>
<table class="table">
<tbody>
<tr>
<th>StartedByName</th>
<td>{{ food_order.startedByName }}</td>
</tr>
<tr>
<th>Id</th>
<td>{{ food_order.id }}</td>
</tr>
<tr>
<th>StartedAt</th>
<td>{{ food_order.startedAt ? food_order.startedAt|date('Y-m-d H:i:s') : '' }}</td>
</tr>
<tr>
<th>ClosedAt</th>
<td>{{ food_order.closedAt ? food_order.closedAt|date('Y-m-d H:i:s') : '' }}</td>
</tr>
</tbody>
</table>
<table class="table">
<thead>
<tr>
<th>Name(s)</th>
<th>possible price</th>
<th>actions</th>
</tr>
</thead>
<tbody>
{% for lel in food_order.groupedOrderItems %}
<tr>
<td>
{{ lel.item.menuItem.aliases|map(i => i.name)|join(' / ') }}
</td>
<td>
{{ lel.item.menuItem.price }}
</td>
<td>
{{ lel.amount }} |
<a href="{{ path('app_foodorder_add_item', {foodOrder: food_order.id, menuItem: lel.item.menuItem.id}) }}">+1</a> |
<a href="{{ path('app_foodorder_remove_item', {foodOrder: food_order.id, orderItem: lel.item.id}) }}">-1</a> |
</td>
</tr>
{% endfor %}
</tbody>
</tbody>
</table>
<table class="table">
<thead>
<tr>
<th>Name(s)</th>
<th>possible price</th>
<th>actions</th>
</tr>
</thead>
{% for item in menu_items %}
<tr>
<td>
{{ item.aliases|map(i => i.name)|join(' / ') }}
</td>
<td>
{{ item.price }}
</td>
<td>
<a href="{{ path('app_foodorder_add_item', {foodOrder: food_order.id, menuItem: item.id}) }}">join</a>
</td>
</tr>
{% endfor %}
</table>
<a href="{{ path('app_food_order_index') }}">back to list</a>
<a href="{{ path('app_food_order_edit', {'id': food_order.id}) }}">edit</a>
{{ include('food_order/_delete_form.html.twig') }}
{% endblock %}

View file

@ -0,0 +1,35 @@
{% extends 'base.html.twig' %}
{% block title %}Futtern{% endblock %}
{% block body %}
<h1>Open Orders</h1>
<table class="table">
<thead>
<tr>
<th>StartedBy</th>
<th>Vendor</th>
<th>StartedAt</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for order in orders %}
<tr>
<td>{{ order.startedByName }}</td>
<td>{{ order.vendor.name }}</td>
<td>{{ order.startedAt|date("Y-m-d H:i") }}</td>
<td><a href="{{ path('app_food_order_show', {'id': order.id}) }}">show</a></td>
</tr>
{% else %}
<tr>
<td colspan="3">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
<h2>New Order:</h2>
{{ include('_form.html.twig') }}
{% endblock %}

View file

@ -0,0 +1,4 @@
<form method="post" action="{{ path('app_vendor_delete', {'id': vendor.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ vendor.id) }}">
<button class="btn">Delete</button>
</form>

4
templates/vendor/_form.html.twig vendored Normal file
View file

@ -0,0 +1,4 @@
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

13
templates/vendor/edit.html.twig vendored Normal file
View file

@ -0,0 +1,13 @@
{% extends 'base.html.twig' %}
{% block title %}Edit Vendor{% endblock %}
{% block body %}
<h1>Edit Vendor</h1>
{{ include('vendor/_form.html.twig', {'button_label': 'Update'}) }}
<a href="{{ path('app_vendor_index') }}">back to list</a>
{{ include('vendor/_delete_form.html.twig') }}
{% endblock %}

35
templates/vendor/index.html.twig vendored Normal file
View file

@ -0,0 +1,35 @@
{% extends 'base.html.twig' %}
{% block title %}Vendor index{% endblock %}
{% block body %}
<h1>Vendor index</h1>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>actions</th>
</tr>
</thead>
<tbody>
{% for vendor in vendors %}
<tr>
<td>{{ vendor.id }}</td>
<td>{{ vendor.name }}</td>
<td>
<a href="{{ path('app_vendor_show', {'id': vendor.id}) }}">show</a>
<a href="{{ path('app_vendor_edit', {'id': vendor.id}) }}">edit</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="3">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ path('app_vendor_new') }}">Create new</a>
{% endblock %}

11
templates/vendor/new.html.twig vendored Normal file
View file

@ -0,0 +1,11 @@
{% extends 'base.html.twig' %}
{% block title %}New Vendor{% endblock %}
{% block body %}
<h1>Create new Vendor</h1>
{{ include('vendor/_form.html.twig') }}
<a href="{{ path('app_vendor_index') }}">back to list</a>
{% endblock %}

26
templates/vendor/show.html.twig vendored Normal file
View file

@ -0,0 +1,26 @@
{% extends 'base.html.twig' %}
{% block title %}Vendor{% endblock %}
{% block body %}
<h1>Vendor</h1>
<table class="table">
<tbody>
<tr>
<th>Id</th>
<td>{{ vendor.id }}</td>
</tr>
<tr>
<th>Name</th>
<td>{{ vendor.name }}</td>
</tr>
</tbody>
</table>
<a href="{{ path('app_vendor_index') }}">back to list</a>
<a href="{{ path('app_vendor_edit', {'id': vendor.id}) }}">edit</a>
{{ include('vendor/_delete_form.html.twig') }}
{% endblock %}