diff --git a/.env.dev b/.env.dev index f359c83..90c9484 100644 --- a/.env.dev +++ b/.env.dev @@ -1,4 +1,4 @@ - +#APP_DEBUG=1 ###> symfony/framework-bundle ### APP_SECRET=e26b9552d9e7f969b160373effaa7690 ###< symfony/framework-bundle ### diff --git a/.idea/TijdVoorDeTest.iml b/.idea/TijdVoorDeTest.iml index a3b4ce0..a906c34 100644 --- a/.idea/TijdVoorDeTest.iml +++ b/.idea/TijdVoorDeTest.iml @@ -97,8 +97,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..5c91296 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/app + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..b843835 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml index 557a48c..f9cad3d 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -1,5 +1,10 @@ + + + + + @@ -121,6 +126,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -206,7 +248,7 @@ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 93d3dab..90c648c 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,5 +1,7 @@ in(__DIR__) ->exclude('var') @@ -9,6 +11,7 @@ return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, '@Symfony:risky' => true, + 'declare_strict_types' => true, 'linebreak_after_opening_tag' => true, 'mb_str_functions' => true, 'no_php4_constructor' => true, @@ -20,8 +23,8 @@ return (new PhpCsFixer\Config()) 'strict_comparison' => true, 'strict_param' => true, 'blank_line_between_import_groups' => false, + 'phpdoc_line_span' => ['const' => 'single', 'method' => 'single', 'property' => 'single'], ]) ->setRiskyAllowed(true) ->setFinder($finder) ; - diff --git a/Makefile b/Makefile index 648b18c..618c977 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,16 @@ .DEFAULT_GOAL := help +.PHONY: up +up: ## Start application + @docker compose up -d + +stop: ## Stop application + @docker compose stop .PHONY: shell -shell: +shell: ## Start a shell inside the container @docker compose exec php bash .PHONY: help help: - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-10s\033[0m %s\n", $$1, $$2}' diff --git a/compose.override.yaml b/compose.override.yaml index 22e80a5..ea5d8ca 100644 --- a/compose.override.yaml +++ b/compose.override.yaml @@ -19,12 +19,12 @@ services: # Ensure that host.docker.internal is correctly defined on Linux - host.docker.internal:host-gateway tty: true - -###> symfony/mercure-bundle ### -###< symfony/mercure-bundle ### - -###> doctrine/doctrine-bundle ### + + ###> symfony/mercure-bundle ### + ###< symfony/mercure-bundle ### + + ###> doctrine/doctrine-bundle ### database: ports: - - "5432" + - "5432:5432" ###< doctrine/doctrine-bundle ### diff --git a/composer.json b/composer.json index 890b507..c990556 100644 --- a/composer.json +++ b/composer.json @@ -13,25 +13,40 @@ "doctrine/doctrine-bundle": "^2.13", "doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/orm": "^3.3", + "easycorp/easyadmin-bundle": "^4.23", "runtime/frankenphp-symfony": "^0.2.0", + "symfony/asset": "7.2.*", "symfony/console": "7.2.*", "symfony/dotenv": "7.2.*", - "symfony/flex": "^2", + "symfony/flex": "^2.4.7", + "symfony/form": "7.2.*", "symfony/framework-bundle": "7.2.*", "symfony/runtime": "7.2.*", + "symfony/security-bundle": "7.2.*", "symfony/twig-bundle": "7.2.*", - "symfony/yaml": "7.2.*" + "symfony/uid": "7.2.*", + "symfony/yaml": "7.2.*", + "thecodingmachine/safe": "^2.5" }, "require-dev": { + "doctrine/doctrine-fixtures-bundle": "^4.0", "friendsofphp/php-cs-fixer": "^3.65", + "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2.0", + "phpstan/phpstan-doctrine": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-symfony": "^2.0", "phpunit/phpunit": "^11", "rector/rector": "^2.0", - "symfony/maker-bundle": "^1.61" + "symfony/maker-bundle": "^1.62.1", + "symfony/stopwatch": "7.2.*", + "symfony/web-profiler-bundle": "7.2.*", + "thecodingmachine/phpstan-safe-rule": "^1.3" }, "config": { "allow-plugins": { "php-http/discovery": true, + "phpstan/extension-installer": true, "symfony/flex": true, "symfony/runtime": true }, diff --git a/composer.lock b/composer.lock index b88f6d9..c6448e2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bf1f9bbdd9d288044439390960ecd0db", + "content-hash": "3ce6d5ed5a5a5eec50865b9e70c1f10a", "packages": [ { "name": "doctrine/cache", @@ -1229,6 +1229,107 @@ }, "time": "2024-10-21T18:21:57+00:00" }, + { + "name": "easycorp/easyadmin-bundle", + "version": "v4.23.0", + "source": { + "type": "git", + "url": "https://github.com/EasyCorp/EasyAdminBundle.git", + "reference": "d35918bf18dab8d33e7e1fa8a490c69555bd22e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/EasyCorp/EasyAdminBundle/zipball/d35918bf18dab8d33e7e1fa8a490c69555bd22e4", + "reference": "d35918bf18dab8d33e7e1fa8a490c69555bd22e4", + "shasum": "" + }, + "require": { + "doctrine/doctrine-bundle": "^2.5", + "doctrine/orm": "^2.12|^3.0", + "ext-json": "*", + "php": ">=8.1", + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^3.0", + "symfony/doctrine-bridge": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/security-bundle": "^5.4|^6.0|^7.0", + "symfony/string": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/ux-twig-component": "^2.21", + "symfony/validator": "^5.4|^6.0|^7.0", + "twig/extra-bundle": "^3.17", + "twig/html-extra": "^3.17", + "twig/twig": "^3.15" + }, + "require-dev": { + "doctrine/doctrine-fixtures-bundle": "^3.4|3.5.x-dev", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-phpunit": "^1.2", + "phpstan/phpstan-strict-rules": "^1.4", + "phpstan/phpstan-symfony": "^1.2", + "psr/log": "^1.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/debug-bundle": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.1|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/web-link": "^5.4|^6.0|^7.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "EasyCorp\\Bundle\\EasyAdminBundle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Project Contributors", + "homepage": "https://github.com/EasyCorp/EasyAdminBundle/graphs/contributors" + } + ], + "description": "Admin generator for Symfony applications", + "homepage": "https://github.com/EasyCorp/EasyAdminBundle", + "keywords": [ + "admin", + "backend", + "generator" + ], + "support": { + "issues": "https://github.com/EasyCorp/EasyAdminBundle/issues", + "source": "https://github.com/EasyCorp/EasyAdminBundle/tree/v4.23.0" + }, + "funding": [ + { + "url": "https://github.com/javiereguiluz", + "type": "github" + } + ], + "time": "2025-01-18T19:13:35+00:00" + }, { "name": "psr/cache", "version": "3.0.0", @@ -1278,6 +1379,54 @@ }, "time": "2021-02-03T23:26:27+00:00" }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, { "name": "psr/container", "version": "2.0.2", @@ -1484,17 +1633,86 @@ "time": "2023-12-12T12:06:11+00:00" }, { - "name": "symfony/cache", - "version": "v7.2.1", + "name": "symfony/asset", + "version": "v7.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "e7e983596b744c4539f31e79b0350a6cf5878a20" + "url": "https://github.com/symfony/asset.git", + "reference": "cb926cd59fefa1f9b4900b3695f0f846797ba5c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/e7e983596b744c4539f31e79b0350a6cf5878a20", - "reference": "e7e983596b744c4539f31e79b0350a6cf5878a20", + "url": "https://api.github.com/repos/symfony/asset/zipball/cb926cd59fefa1f9b4900b3695f0f846797ba5c0", + "reference": "cb926cd59fefa1f9b4900b3695f0f846797ba5c0", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "conflict": { + "symfony/http-foundation": "<6.4" + }, + "require-dev": { + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Asset\\": "" + }, + "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": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/asset/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-25T15:15:23+00:00" + }, + { + "name": "symfony/cache", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "d33cd9e14326e14a4145c21e600602eaf17cc9e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/d33cd9e14326e14a4145c21e600602eaf17cc9e7", + "reference": "d33cd9e14326e14a4145c21e600602eaf17cc9e7", "shasum": "" }, "require": { @@ -1563,7 +1781,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.2.1" + "source": "https://github.com/symfony/cache/tree/v7.2.4" }, "funding": [ { @@ -1579,7 +1797,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:08:50+00:00" + "time": "2025-02-26T09:57:54+00:00" }, { "name": "symfony/cache-contracts", @@ -1658,17 +1876,91 @@ "time": "2024-09-25T14:20:29+00:00" }, { - "name": "symfony/config", + "name": "symfony/clock", "version": "v7.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "bcd3c4adf0144dee5011bb35454728c38adec055" + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/bcd3c4adf0144dee5011bb35454728c38adec055", - "reference": "bcd3c4adf0144dee5011bb35454728c38adec055", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/config", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "7716594aaae91d9141be080240172a92ecca4d44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/7716594aaae91d9141be080240172a92ecca4d44", + "reference": "7716594aaae91d9141be080240172a92ecca4d44", "shasum": "" }, "require": { @@ -1714,7 +2006,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.2.0" + "source": "https://github.com/symfony/config/tree/v7.2.3" }, "funding": [ { @@ -1730,7 +2022,7 @@ "type": "tidelift" } ], - "time": "2024-11-04T11:36:24+00:00" + "time": "2025-01-22T12:07:01+00:00" }, { "name": "symfony/console", @@ -1827,16 +2119,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v7.2.0", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "a475747af1a1c98272a5471abc35f3da81197c5d" + "reference": "f0a1614cccb4b8431a97076f9debc08ddca321ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a475747af1a1c98272a5471abc35f3da81197c5d", - "reference": "a475747af1a1c98272a5471abc35f3da81197c5d", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f0a1614cccb4b8431a97076f9debc08ddca321ca", + "reference": "f0a1614cccb4b8431a97076f9debc08ddca321ca", "shasum": "" }, "require": { @@ -1887,7 +2179,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.2.0" + "source": "https://github.com/symfony/dependency-injection/tree/v7.2.4" }, "funding": [ { @@ -1903,7 +2195,7 @@ "type": "tidelift" } ], - "time": "2024-11-25T15:45:00+00:00" + "time": "2025-02-21T09:47:16+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1974,21 +2266,21 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v7.2.1", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "b492be51eb703723d682851a0c9fb39b9d1a7bfb" + "reference": "95bc5dde5202828bbc462bc06ba67cd244fa8a15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/b492be51eb703723d682851a0c9fb39b9d1a7bfb", - "reference": "b492be51eb703723d682851a0c9fb39b9d1a7bfb", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/95bc5dde5202828bbc462bc06ba67cd244fa8a15", + "reference": "95bc5dde5202828bbc462bc06ba67cd244fa8a15", "shasum": "" }, "require": { "doctrine/event-manager": "^2", - "doctrine/persistence": "^3.1", + "doctrine/persistence": "^3.1|^4", "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", @@ -2063,7 +2355,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.2.1" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.2.4" }, "funding": [ { @@ -2079,7 +2371,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:50:44+00:00" + "time": "2025-02-18T16:43:05+00:00" }, { "name": "symfony/dotenv", @@ -2157,16 +2449,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.2.1", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "6150b89186573046167796fa5f3f76601d5145f8" + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/6150b89186573046167796fa5f3f76601d5145f8", - "reference": "6150b89186573046167796fa5f3f76601d5145f8", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/aabf79938aa795350c07ce6464dd1985607d95d5", + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5", "shasum": "" }, "require": { @@ -2212,7 +2504,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.2.1" + "source": "https://github.com/symfony/error-handler/tree/v7.2.4" }, "funding": [ { @@ -2228,7 +2520,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:50:44+00:00" + "time": "2025-02-02T20:27:07+00:00" }, { "name": "symfony/event-dispatcher", @@ -2454,16 +2746,16 @@ }, { "name": "symfony/finder", - "version": "v7.2.0", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49" + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49", - "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", "shasum": "" }, "require": { @@ -2498,7 +2790,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.2.0" + "source": "https://github.com/symfony/finder/tree/v7.2.2" }, "funding": [ { @@ -2514,7 +2806,7 @@ "type": "tidelift" } ], - "time": "2024-10-23T06:56:12+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/flex", @@ -2585,17 +2877,114 @@ "time": "2024-10-07T08:51:54+00:00" }, { - "name": "symfony/framework-bundle", - "version": "v7.2.1", + "name": "symfony/form", + "version": "v7.2.4", "source": { "type": "git", - "url": "https://github.com/symfony/framework-bundle.git", - "reference": "1c630f4697c9bd87b342e8090cc9022071af4d77" + "url": "https://github.com/symfony/form.git", + "reference": "7209804c018b88cc2b0beabe38eef91b83f1d69a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/1c630f4697c9bd87b342e8090cc9022071af4d77", - "reference": "1c630f4697c9bd87b342e8090cc9022071af4d77", + "url": "https://api.github.com/repos/symfony/form/zipball/7209804c018b88cc2b0beabe38eef91b83f1d69a", + "reference": "7209804c018b88cc2b0beabe38eef91b83f1d69a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/options-resolver": "^6.4|^7.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/polyfill-mbstring": "~1.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/error-handler": "<6.4", + "symfony/framework-bundle": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "doctrine/collections": "^1.0|^2.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/security-csrf": "^6.4|^7.0", + "symfony/translation": "^6.4.3|^7.0.3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Form\\": "" + }, + "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": "Allows to easily create, process and reuse HTML forms", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/form/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-07T22:04:27+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "6d6614378cd8128eed0a037ce6ac51a26c5aaed5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/6d6614378cd8128eed0a037ce6ac51a26c5aaed5", + "reference": "6d6614378cd8128eed0a037ce6ac51a26c5aaed5", "shasum": "" }, "require": { @@ -2716,7 +3105,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v7.2.1" + "source": "https://github.com/symfony/framework-bundle/tree/v7.2.4" }, "funding": [ { @@ -2732,20 +3121,20 @@ "type": "tidelift" } ], - "time": "2024-12-07T13:24:01+00:00" + "time": "2025-02-26T08:19:39+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "e88a66c3997859532bc2ddd6dd8f35aba2711744" + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e88a66c3997859532bc2ddd6dd8f35aba2711744", - "reference": "e88a66c3997859532bc2ddd6dd8f35aba2711744", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ee1b504b8926198be89d05e5b6fc4c3810c090f0", + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0", "shasum": "" }, "require": { @@ -2794,7 +3183,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.2.0" + "source": "https://github.com/symfony/http-foundation/tree/v7.2.3" }, "funding": [ { @@ -2810,20 +3199,20 @@ "type": "tidelift" } ], - "time": "2024-11-13T18:58:46+00:00" + "time": "2025-01-17T10:56:55+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.2.1", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "d8ae58eecae44c8e66833e76cc50a4ad3c002d97" + "reference": "9f1103734c5789798fefb90e91de4586039003ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/d8ae58eecae44c8e66833e76cc50a4ad3c002d97", - "reference": "d8ae58eecae44c8e66833e76cc50a4ad3c002d97", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f1103734c5789798fefb90e91de4586039003ed", + "reference": "9f1103734c5789798fefb90e91de4586039003ed", "shasum": "" }, "require": { @@ -2908,7 +3297,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.2.1" + "source": "https://github.com/symfony/http-kernel/tree/v7.2.4" }, "funding": [ { @@ -2924,7 +3313,316 @@ "type": "tidelift" } ], - "time": "2024-12-11T12:09:10+00:00" + "time": "2025-02-26T11:01:22+00:00" + }, + { + "name": "symfony/intl", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/intl.git", + "reference": "76bb3462c6c308f8bd97d3c178c2626ae44d4dea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/intl/zipball/76bb3462c6c308f8bd97d3c178c2626ae44d4dea", + "reference": "76bb3462c6c308f8bd97d3c178c2626ae44d4dea", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/string": "<7.1" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Intl\\": "" + }, + "exclude-from-classmap": [ + "/Tests/", + "/Resources/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Eriksen Costa", + "email": "eriksen.costa@infranology.com.br" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides access to the localization data of the ICU library", + "homepage": "https://symfony.com", + "keywords": [ + "i18n", + "icu", + "internationalization", + "intl", + "l10n", + "localization" + ], + "support": { + "source": "https://github.com/symfony/intl/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-25T14:26:33+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/87ca22046b78c3feaff04b337f33b38510fd686b", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "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": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-19T08:51:20+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "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": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-20T11:17:29+00:00" + }, + { + "name": "symfony/password-hasher", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/password-hasher.git", + "reference": "d8bd3d66d074c0acba1214a0d42f5941a8e1e94d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/d8bd3d66d074c0acba1214a0d42f5941a8e1e94d", + "reference": "d8bd3d66d074c0acba1214a0d42f5941a8e1e94d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "conflict": { + "symfony/security-core": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/security-core": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PasswordHasher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Robin Chalas", + "email": "robin.chalas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides password hashing utilities", + "homepage": "https://symfony.com", + "keywords": [ + "hashing", + "password" + ], + "support": { + "source": "https://github.com/symfony/password-hasher/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -3004,6 +3702,173 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/polyfill-intl-icu", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-icu.git", + "reference": "d80a05e9904d2c2b9b95929f3e4b5d3a8f418d78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/d80a05e9904d2c2b9b95929f3e4b5d3a8f418d78", + "reference": "d80a05e9904d2c2b9b95929f3e4b5d3a8f418d78", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance and support of other locales than \"en\"" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Icu\\": "" + }, + "classmap": [ + "Resources/stubs" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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 intl's ICU-related data and classes", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "icu", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/polyfill-intl-normalizer", "version": "v1.31.0", @@ -3242,17 +4107,257 @@ "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/routing", - "version": "v7.2.0", + "name": "symfony/polyfill-uuid", + "version": "v1.31.0", "source": { "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e" + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e10a2450fa957af6c448b9b93c9010a4e4c0725e", - "reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/property-access", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "b28732e315d81fbec787f838034de7d6c9b2b902" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/b28732e315d81fbec787f838034de7d6c9b2b902", + "reference": "b28732e315d81fbec787f838034de7d6c9b2b902", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/property-info": "^6.4|^7.0" + }, + "require-dev": { + "symfony/cache": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "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": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property-path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T10:56:55+00:00" + }, + { + "name": "symfony/property-info", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "dedb118fd588a92f226b390250b384d25f4192fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/dedb118fd588a92f226b390250b384d25f4192fe", + "reference": "dedb118fd588a92f226b390250b384d25f4192fe", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/string": "^6.4|^7.0", + "symfony/type-info": "~7.1.9|^7.2.2" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/cache": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "symfony/cache": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-27T11:08:17+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/ee9a67edc6baa33e5fae662f94f91fd262930996", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996", "shasum": "" }, "require": { @@ -3304,7 +4409,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.2.0" + "source": "https://github.com/symfony/routing/tree/v7.2.3" }, "funding": [ { @@ -3320,20 +4425,20 @@ "type": "tidelift" } ], - "time": "2024-11-25T11:08:51+00:00" + "time": "2025-01-17T10:56:55+00:00" }, { "name": "symfony/runtime", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "2c350568f3eaccb25fbbbf962bd67cde273121a7" + "reference": "8e8d09bd69b7f6c0260dd3d58f37bd4fbdeab5ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/2c350568f3eaccb25fbbbf962bd67cde273121a7", - "reference": "2c350568f3eaccb25fbbbf962bd67cde273121a7", + "url": "https://api.github.com/repos/symfony/runtime/zipball/8e8d09bd69b7f6c0260dd3d58f37bd4fbdeab5ad", + "reference": "8e8d09bd69b7f6c0260dd3d58f37bd4fbdeab5ad", "shasum": "" }, "require": { @@ -3383,7 +4488,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v7.2.0" + "source": "https://github.com/symfony/runtime/tree/v7.2.3" }, "funding": [ { @@ -3399,7 +4504,358 @@ "type": "tidelift" } ], - "time": "2024-11-06T11:43:25+00:00" + "time": "2024-12-29T21:39:47+00:00" + }, + { + "name": "symfony/security-bundle", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "721de227035c6e4c322fb7dd4839586d58bc0cf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/721de227035c6e4c322fb7dd4839586d58bc0cf5", + "reference": "721de227035c6e4c322fb7dd4839586d58bc0cf5", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.2", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4.11|^7.1.4", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/password-hasher": "^6.4|^7.0", + "symfony/security-core": "^7.2", + "symfony/security-csrf": "^6.4|^7.0", + "symfony/security-http": "^7.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/console": "<6.4", + "symfony/framework-bundle": "<6.4", + "symfony/http-client": "<6.4", + "symfony/ldap": "<6.4", + "symfony/serializer": "<6.4", + "symfony/twig-bundle": "<6.4", + "symfony/validator": "<6.4" + }, + "require-dev": { + "symfony/asset": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/ldap": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.12", + "web-token/jwt-library": "^3.3.2|^4.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "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": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-07T09:39:55+00:00" + }, + { + "name": "symfony/security-core", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "466784ffcd0b5a16e05394335897f790b17d07e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/466784ffcd0b5a16e05394335897f790b17d07e4", + "reference": "466784ffcd0b5a16e05394335897f790b17d07e4", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher-contracts": "^2.5|^3", + "symfony/password-hasher": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/ldap": "<6.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/validator": "<6.4" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "psr/container": "^1.1|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/ldap": "^6.4|^7.0", + "symfony/string": "^6.4|^7.0", + "symfony/translation": "^6.4.3|^7.0.3", + "symfony/validator": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "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 Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-27T11:08:17+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "2b4b0c46c901729e4e90719eacd980381f53e0a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/2b4b0c46c901729e4e90719eacd980381f53e0a3", + "reference": "2b4b0c46c901729e4e90719eacd980381f53e0a3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/security-core": "^6.4|^7.0" + }, + "conflict": { + "symfony/http-foundation": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "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 Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T18:42:10+00:00" + }, + { + "name": "symfony/security-http", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "8478e95e273f8daa23bf4860dbad2a09d3fb3722" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/8478e95e273f8daa23bf4860dbad2a09d3fb3722", + "reference": "8478e95e273f8daa23bf4860dbad2a09d3fb3722", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/security-core": "^7.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/clock": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/http-client-contracts": "<3.0", + "symfony/security-bundle": "<6.4", + "symfony/security-csrf": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/cache": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/http-client-contracts": "^3.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/security-csrf": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "web-token/jwt-library": "^3.3.2|^4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "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 Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-11T16:46:20+00:00" }, { "name": "symfony/service-contracts", @@ -3486,16 +4942,16 @@ }, { "name": "symfony/stopwatch", - "version": "v7.2.0", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "696f418b0d722a4225e1c3d95489d262971ca924" + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/696f418b0d722a4225e1c3d95489d262971ca924", - "reference": "696f418b0d722a4225e1c3d95489d262971ca924", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", "shasum": "" }, "require": { @@ -3528,7 +4984,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.2.0" + "source": "https://github.com/symfony/stopwatch/tree/v7.2.4" }, "funding": [ { @@ -3544,7 +5000,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-02-24T10:49:57+00:00" }, { "name": "symfony/string", @@ -3633,6 +5089,101 @@ ], "time": "2024-11-13T13:31:26+00:00" }, + { + "name": "symfony/translation", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/283856e6981286cc0d800b53bd5703e8e363f05a", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^4.18|^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "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": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-13T10:27:23+00:00" + }, { "name": "symfony/translation-contracts", "version": "v3.5.1", @@ -3713,16 +5264,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v7.2.1", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "d5cdf4d59da5ab44ebd7503480c22d8235887de0" + "reference": "45c00afd4c9accf00a91215067c2858e5a9a3c4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/d5cdf4d59da5ab44ebd7503480c22d8235887de0", - "reference": "d5cdf4d59da5ab44ebd7503480c22d8235887de0", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/45c00afd4c9accf00a91215067c2858e5a9a3c4e", + "reference": "45c00afd4c9accf00a91215067c2858e5a9a3c4e", "shasum": "" }, "require": { @@ -3803,7 +5354,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v7.2.1" + "source": "https://github.com/symfony/twig-bridge/tree/v7.2.4" }, "funding": [ { @@ -3819,7 +5370,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T09:50:32+00:00" + "time": "2025-02-14T14:27:24+00:00" }, { "name": "symfony/twig-bundle", @@ -3906,17 +5457,346 @@ "time": "2024-10-23T08:11:15+00:00" }, { - "name": "symfony/var-dumper", - "version": "v7.2.0", + "name": "symfony/type-info", + "version": "v7.2.4", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c" + "url": "https://github.com/symfony/type-info.git", + "reference": "269344575181c326781382ed53f7262feae3c6a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c6a22929407dec8765d6e2b6ff85b800b245879c", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c", + "url": "https://api.github.com/repos/symfony/type-info/zipball/269344575181c326781382ed53f7262feae3c6a4", + "reference": "269344575181c326781382ed53f7262feae3c6a4", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0" + }, + "require-dev": { + "phpstan/phpdoc-parser": "^1.0|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\TypeInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathias Arlaud", + "email": "mathias.arlaud@gmail.com" + }, + { + "name": "Baptiste LEDUC", + "email": "baptiste.leduc@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts PHP types information.", + "homepage": "https://symfony.com", + "keywords": [ + "PHPStan", + "phpdoc", + "symfony", + "type" + ], + "support": { + "source": "https://github.com/symfony/type-info/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-25T15:19:41+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/ux-twig-component", + "version": "v2.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-twig-component.git", + "reference": "f29033b95e93aea2d498dc40eac185ed14b07800" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/f29033b95e93aea2d498dc40eac185ed14b07800", + "reference": "f29033b95e93aea2d498dc40eac185ed14b07800", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.2|^3.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "twig/twig": "^3.8" + }, + "conflict": { + "symfony/config": "<5.4.0" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.0|^7.0", + "symfony/stimulus-bundle": "^2.9.1", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/webpack-encore-bundle": "^1.15" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\TwigComponent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Twig components for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "components", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-twig-component/tree/v2.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-25T02:19:26+00:00" + }, + { + "name": "symfony/validator", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "00936b34ef29d0e0e9a5340bbce6e7562092da56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/00936b34ef29d0e0e9a5340bbce6e7562092da56", + "reference": "00936b34ef29d0e0e9a5340bbce6e7562092da56", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php83": "^1.27", + "symfony/translation-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/lexer": "<1.1", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<7.0", + "symfony/expression-language": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/intl": "<6.4", + "symfony/property-info": "<6.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3|^4", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/translation": "^6.4.3|^7.0.3", + "symfony/type-info": "^7.1", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "exclude-from-classmap": [ + "/Tests/", + "/Resources/bin/" + ] + }, + "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": "Provides tools to validate values", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/validator/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-21T09:47:16+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/82b478c69745d8878eb60f9a049a4d584996f73a", + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a", "shasum": "" }, "require": { @@ -3970,7 +5850,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.2.0" + "source": "https://github.com/symfony/var-dumper/tree/v7.2.3" }, "funding": [ { @@ -3986,20 +5866,20 @@ "type": "tidelift" } ], - "time": "2024-11-08T15:48:14+00:00" + "time": "2025-01-17T11:39:41+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.2.0", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d" + "reference": "4ede73aa7a73d81506002d2caadbbdad1ef5b69a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1a6a89f95a46af0f142874c9d650a6358d13070d", - "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/4ede73aa7a73d81506002d2caadbbdad1ef5b69a", + "reference": "4ede73aa7a73d81506002d2caadbbdad1ef5b69a", "shasum": "" }, "require": { @@ -4046,7 +5926,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.2.0" + "source": "https://github.com/symfony/var-exporter/tree/v7.2.4" }, "funding": [ { @@ -4062,20 +5942,20 @@ "type": "tidelift" } ], - "time": "2024-10-18T07:58:17+00:00" + "time": "2025-02-13T10:27:23+00:00" }, { "name": "symfony/yaml", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "099581e99f557e9f16b43c5916c26380b54abb22" + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/099581e99f557e9f16b43c5916c26380b54abb22", - "reference": "099581e99f557e9f16b43c5916c26380b54abb22", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ac238f173df0c9c1120f862d0f599e17535a87ec", + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec", "shasum": "" }, "require": { @@ -4118,7 +5998,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.2.0" + "source": "https://github.com/symfony/yaml/tree/v7.2.3" }, "funding": [ { @@ -4134,7 +6014,288 @@ "type": "tidelift" } ], - "time": "2024-10-23T06:56:12+00:00" + "time": "2025-01-07T12:55:42+00:00" + }, + { + "name": "thecodingmachine/safe", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/3115ecd6b4391662b4931daac4eba6b07a2ac1f0", + "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.5", + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "^3.2", + "thecodingmachine/phpstan-strict-rules": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "files": [ + "deprecated/apc.php", + "deprecated/array.php", + "deprecated/datetime.php", + "deprecated/libevent.php", + "deprecated/misc.php", + "deprecated/password.php", + "deprecated/mssql.php", + "deprecated/stats.php", + "deprecated/strings.php", + "lib/special_cases.php", + "deprecated/mysqli.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gettext.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/mysql.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "classmap": [ + "lib/DateTime.php", + "lib/DateTimeImmutable.php", + "lib/Exceptions/", + "deprecated/Exceptions/", + "generated/Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v2.5.0" + }, + "time": "2023-04-05T11:54:14+00:00" + }, + { + "name": "twig/extra-bundle", + "version": "v3.18.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/twig-extra-bundle.git", + "reference": "9746573ca4bc1cd03a767a183faadaf84e0c31fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/9746573ca4bc1cd03a767a183faadaf84e0c31fa", + "reference": "9746573ca4bc1cd03a767a183faadaf84e0c31fa", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/framework-bundle": "^5.4|^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0", + "twig/twig": "^3.2|^4.0" + }, + "require-dev": { + "league/commonmark": "^1.0|^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "twig/cache-extra": "^3.0", + "twig/cssinliner-extra": "^3.0", + "twig/html-extra": "^3.0", + "twig/inky-extra": "^3.0", + "twig/intl-extra": "^3.0", + "twig/markdown-extra": "^3.0", + "twig/string-extra": "^3.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Twig\\Extra\\TwigExtraBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Symfony bundle for extra Twig extensions", + "homepage": "https://twig.symfony.com", + "keywords": [ + "bundle", + "extra", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.18.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2024-09-26T19:22:23+00:00" + }, + { + "name": "twig/html-extra", + "version": "v3.18.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/html-extra.git", + "reference": "c63b28e192c1b7c15bb60f81d2e48b140846239a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/html-extra/zipball/c63b28e192c1b7c15bb60f81d2e48b140846239a", + "reference": "c63b28e192c1b7c15bb60f81d2e48b140846239a", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/mime": "^5.4|^6.4|^7.0", + "twig/twig": "^3.13|^4.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Twig\\Extra\\Html\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Twig extension for HTML", + "homepage": "https://twig.symfony.com", + "keywords": [ + "html", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/html-extra/tree/v3.18.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2024-12-29T10:29:59+00:00" }, { "name": "twig/twig", @@ -4508,6 +6669,175 @@ ], "time": "2024-05-06T16:37:16+00:00" }, + { + "name": "doctrine/data-fixtures", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/data-fixtures.git", + "reference": "f7f1e12d6bceb58c204b3e77210a103c1c57601e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/f7f1e12d6bceb58c204b3e77210a103c1c57601e", + "reference": "f7f1e12d6bceb58c204b3e77210a103c1c57601e", + "shasum": "" + }, + "require": { + "doctrine/persistence": "^3.1 || ^4.0", + "php": "^8.1", + "psr/log": "^1.1 || ^2 || ^3" + }, + "conflict": { + "doctrine/dbal": "<3.5 || >=5", + "doctrine/orm": "<2.14 || >=4", + "doctrine/phpcr-odm": "<1.3.0" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "doctrine/dbal": "^3.5 || ^4", + "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", + "doctrine/orm": "^2.14 || ^3", + "ext-sqlite3": "*", + "fig/log-test": "^1", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5.3", + "symfony/cache": "^6.4 || ^7", + "symfony/var-exporter": "^6.4 || ^7" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", + "doctrine/mongodb-odm": "For loading MongoDB ODM fixtures", + "doctrine/orm": "For loading ORM fixtures", + "doctrine/phpcr-odm": "For loading PHPCR ODM fixtures" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\DataFixtures\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Data Fixtures for all Doctrine Object Managers", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "database" + ], + "support": { + "issues": "https://github.com/doctrine/data-fixtures/issues", + "source": "https://github.com/doctrine/data-fixtures/tree/2.0.2" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdata-fixtures", + "type": "tidelift" + } + ], + "time": "2025-01-21T13:21:31+00:00" + }, + { + "name": "doctrine/doctrine-fixtures-bundle", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", + "reference": "90185317e6bb3d845667c5ebd444d9c83ae19a01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/90185317e6bb3d845667c5ebd444d9c83ae19a01", + "reference": "90185317e6bb3d845667c5ebd444d9c83ae19a01", + "shasum": "" + }, + "require": { + "doctrine/data-fixtures": "^2.0", + "doctrine/doctrine-bundle": "^2.2", + "doctrine/orm": "^2.14.0 || ^3.0", + "doctrine/persistence": "^2.4 || ^3.0", + "php": "^8.1", + "psr/log": "^2 || ^3", + "symfony/config": "^5.4 || ^6.0 || ^7.0", + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/deprecation-contracts": "^2.1 || ^3", + "symfony/doctrine-bridge": "^5.4.48 || ^6.4.16 || ^7.1.9", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0" + }, + "conflict": { + "doctrine/dbal": "< 3" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^10.5.38 || ^11" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\FixturesBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Doctrine Project", + "homepage": "https://www.doctrine-project.org" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DoctrineFixturesBundle", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "Fixture", + "persistence" + ], + "support": { + "issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues", + "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/4.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-fixtures-bundle", + "type": "tidelift" + } + ], + "time": "2024-12-05T18:35:55+00:00" + }, { "name": "evenement/evenement", "version": "v3.0.2", @@ -4955,6 +7285,54 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, { "name": "phpstan/phpstan", "version": "2.0.4", @@ -5013,6 +7391,199 @@ ], "time": "2024-12-17T17:14:01+00:00" }, + { + "name": "phpstan/phpstan-doctrine", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-doctrine.git", + "reference": "bdb6a835c5aa9725979694ae9b70591e180f4853" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/bdb6a835c5aa9725979694ae9b70591e180f4853", + "reference": "bdb6a835c5aa9725979694ae9b70591e180f4853", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0.3" + }, + "conflict": { + "doctrine/collections": "<1.0", + "doctrine/common": "<2.7", + "doctrine/mongodb-odm": "<1.2", + "doctrine/orm": "<2.5", + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "cache/array-adapter": "^1.1", + "composer/semver": "^3.3.2", + "cweagans/composer-patches": "^1.7.3", + "doctrine/annotations": "^2.0", + "doctrine/collections": "^1.6 || ^2.1", + "doctrine/common": "^2.7 || ^3.0", + "doctrine/dbal": "^3.3.8", + "doctrine/lexer": "^2.0 || ^3.0", + "doctrine/mongodb-odm": "^2.4.3", + "doctrine/orm": "^2.16.0", + "doctrine/persistence": "^2.2.1 || ^3.2", + "gedmo/doctrine-extensions": "^3.8", + "nesbot/carbon": "^2.49", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6.20", + "ramsey/uuid": "^4.2", + "symfony/cache": "^5.4" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Doctrine extensions for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-doctrine/issues", + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.1" + }, + "time": "2024-12-02T16:48:00+00:00" + }, + { + "name": "phpstan/phpstan-phpunit", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "e32ac656788a5bf3dedda89e6a2cad5643bf1a18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/e32ac656788a5bf3dedda89e6a2cad5643bf1a18", + "reference": "e32ac656788a5bf3dedda89e6a2cad5643bf1a18", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0.4" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-phpunit/issues", + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.3" + }, + "time": "2024-12-19T09:14:43+00:00" + }, + { + "name": "phpstan/phpstan-symfony", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-symfony.git", + "reference": "1ef4dce2baabd464c2dd3109d051bad94efa1e79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/1ef4dce2baabd464c2dd3109d051bad94efa1e79", + "reference": "1ef4dce2baabd464c2dd3109d051bad94efa1e79", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" + }, + "conflict": { + "symfony/framework-bundle": "<3.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "psr/container": "1.0 || 1.1.1", + "symfony/config": "^5.4 || ^6.1", + "symfony/console": "^5.4 || ^6.1", + "symfony/dependency-injection": "^5.4 || ^6.1", + "symfony/form": "^5.4 || ^6.1", + "symfony/framework-bundle": "^5.4 || ^6.1", + "symfony/http-foundation": "^5.4 || ^6.1", + "symfony/messenger": "^5.4", + "symfony/polyfill-php80": "^1.24", + "symfony/serializer": "^5.4", + "symfony/service-contracts": "^2.2.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lukáš Unger", + "email": "looky.msc@gmail.com", + "homepage": "https://lookyman.net" + } + ], + "description": "Symfony Framework extensions and rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-symfony/issues", + "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.0" + }, + "time": "2024-11-06T10:13:40+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "11.0.8", @@ -7003,16 +9574,16 @@ }, { "name": "symfony/maker-bundle", - "version": "v1.61.0", + "version": "v1.62.1", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "a3b7f14d349f8f44ed752d4dde2263f77510cc18" + "reference": "468ff2708200c95ebc0d85d3174b6c6711b8a590" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/a3b7f14d349f8f44ed752d4dde2263f77510cc18", - "reference": "a3b7f14d349f8f44ed752d4dde2263f77510cc18", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/468ff2708200c95ebc0d85d3174b6c6711b8a590", + "reference": "468ff2708200c95ebc0d85d3174b6c6711b8a590", "shasum": "" }, "require": { @@ -7075,7 +9646,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.61.0" + "source": "https://github.com/symfony/maker-bundle/tree/v1.62.1" }, "funding": [ { @@ -7091,87 +9662,20 @@ "type": "tidelift" } ], - "time": "2024-08-29T22:50:23+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v7.2.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "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": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-11-20T11:17:29+00:00" + "time": "2025-01-15T00:21:40+00:00" }, { "name": "symfony/process", - "version": "v7.2.0", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", "shasum": "" }, "require": { @@ -7203,7 +9707,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.0" + "source": "https://github.com/symfony/process/tree/v7.2.4" }, "funding": [ { @@ -7219,7 +9723,147 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:24:19+00:00" + "time": "2025-02-05T08:33:46+00:00" + }, + { + "name": "symfony/web-profiler-bundle", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/web-profiler-bundle.git", + "reference": "4ffde1c860a100533b02697d9aaf5f45759ec26a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/4ffde1c860a100533b02697d9aaf5f45759ec26a", + "reference": "4ffde1c860a100533b02697d9aaf5f45759ec26a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/config": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "conflict": { + "symfony/form": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/serializer": "<7.2" + }, + "require-dev": { + "symfony/browser-kit": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\WebProfilerBundle\\": "" + }, + "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": "Provides a development tool that gives detailed information about the execution of any request", + "homepage": "https://symfony.com", + "keywords": [ + "dev" + ], + "support": { + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-14T14:27:24+00:00" + }, + { + "name": "thecodingmachine/phpstan-safe-rule", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/phpstan-safe-rule.git", + "reference": "5b4522c3a9f3bd7bd09215e91c923a9e6d21a5a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/phpstan-safe-rule/zipball/5b4522c3a9f3bd7bd09215e91c923a9e6d21a5a6", + "reference": "5b4522c3a9f3bd7bd09215e91c923a9e6d21a5a6", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5", + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0", + "thecodingmachine/safe": "^1.0 || ^2.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "phpstan-safe-rule.neon" + ] + }, + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "TheCodingMachine\\Safe\\PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David Négrier", + "email": "d.negrier@thecodingmachine.com" + } + ], + "description": "A PHPStan rule to detect safety issues. Must be used in conjunction with thecodingmachine/safe", + "support": { + "issues": "https://github.com/thecodingmachine/phpstan-safe-rule/issues", + "source": "https://github.com/thecodingmachine/phpstan-safe-rule/tree/v1.3.0" + }, + "time": "2024-12-02T11:26:58+00:00" }, { "name": "theseer/tokenizer", diff --git a/config/bundles.php b/config/bundles.php index f8486d5..a60a43e 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -6,4 +6,10 @@ return [ Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], + Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], + Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], + Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], + Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true], + EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true], + Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], ]; diff --git a/config/packages/cache.yaml b/config/packages/cache.yaml deleted file mode 100644 index 6899b72..0000000 --- a/config/packages/cache.yaml +++ /dev/null @@ -1,19 +0,0 @@ -framework: - cache: - # Unique name of your app: used to compute stable namespaces for cache keys. - #prefix_seed: your_vendor_name/app_name - - # The "app" cache stores to the filesystem by default. - # The data in this cache should persist between deploys. - # Other options include: - - # Redis - #app: cache.adapter.redis - #default_redis_provider: redis://localhost - - # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) - #app: cache.adapter.apcu - - # Namespaced pools use the above "app" backend by default - #pools: - #my.dedicated.cache: null diff --git a/config/packages/csrf.yaml b/config/packages/csrf.yaml new file mode 100644 index 0000000..40d4040 --- /dev/null +++ b/config/packages/csrf.yaml @@ -0,0 +1,11 @@ +# Enable stateless CSRF protection for forms and logins/logouts +framework: + form: + csrf_protection: + token_id: submit + + csrf_protection: + stateless_token_ids: + - submit + - authenticate + - logout diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 25138b9..18e7d29 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -24,8 +24,6 @@ doctrine: dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App - controller_resolver: - auto_mapping: false when@test: doctrine: diff --git a/config/packages/security.yaml b/config/packages/security.yaml new file mode 100644 index 0000000..2fdb44c --- /dev/null +++ b/config/packages/security.yaml @@ -0,0 +1,52 @@ +security: + # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords + password_hashers: + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' + # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider + providers: + # used to reload user from session & other features (e.g. switch_user) + app_user_provider: + entity: + class: App\Entity\User + property: email + # used to reload user from session & other features (e.g. switch_user) + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + lazy: true + provider: app_user_provider + form_login: + login_path: app_login + check_path: app_login + enable_csrf: true + logout: + path: app_logout + # where to redirect after logout + # target: app_any_route + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#the-firewall + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true + + # Easy way to control access for large sections of your site + # Note: Only the *first* access control that matches will be used + access_control: + # - { path: ^/admin, roles: ROLE_ADMIN } + # - { path: ^/profile, roles: ROLE_USER } + +when@test: + security: + password_hashers: + # By default, password hashers are resource intensive and take time. This is + # important to generate secure password hashes. In tests however, secure hashes + # are not important, waste resources and increase test times. The following + # reduces the work factor to the lowest possible values. + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: + algorithm: auto + cost: 4 # Lowest possible value for bcrypt + time_cost: 3 # Lowest possible value for argon + memory_cost: 10 # Lowest possible value for argon diff --git a/config/packages/translation.yaml b/config/packages/translation.yaml new file mode 100644 index 0000000..a1df4db --- /dev/null +++ b/config/packages/translation.yaml @@ -0,0 +1,7 @@ +framework: + default_locale: nl + translator: + default_path: '%kernel.project_dir%/translations' + fallbacks: + - en + providers: diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 3f795d9..eb82507 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -1,5 +1,6 @@ twig: file_name_pattern: '*.twig' + form_themes: [ 'bootstrap_5_layout.html.twig' ] when@test: twig: diff --git a/config/packages/twig_component.yaml b/config/packages/twig_component.yaml new file mode 100644 index 0000000..fd17ac6 --- /dev/null +++ b/config/packages/twig_component.yaml @@ -0,0 +1,5 @@ +twig_component: + anonymous_template_directory: 'components/' + defaults: + # Namespace & directory for components + App\Twig\Components\: 'components/' diff --git a/config/packages/uid.yaml b/config/packages/uid.yaml new file mode 100644 index 0000000..0152094 --- /dev/null +++ b/config/packages/uid.yaml @@ -0,0 +1,4 @@ +framework: + uid: + default_uuid_version: 7 + time_based_uuid_version: 7 diff --git a/config/packages/validator.yaml b/config/packages/validator.yaml new file mode 100644 index 0000000..dd47a6a --- /dev/null +++ b/config/packages/validator.yaml @@ -0,0 +1,11 @@ +framework: + validation: + # Enables validator auto-mapping support. + # For instance, basic validation constraints will be inferred from Doctrine's metadata. + #auto_mapping: + # App\Entity\: [] + +when@test: + framework: + validation: + not_compromised_password: false diff --git a/config/packages/web_profiler.yaml b/config/packages/web_profiler.yaml new file mode 100644 index 0000000..b946111 --- /dev/null +++ b/config/packages/web_profiler.yaml @@ -0,0 +1,17 @@ +when@dev: + web_profiler: + toolbar: true + intercept_redirects: false + + framework: + profiler: + only_exceptions: false + collect_serializer_data: true + +when@test: + web_profiler: + toolbar: false + intercept_redirects: false + + framework: + profiler: { collect: false } diff --git a/config/preload.php b/config/preload.php index 5ebcdb2..7cbe578 100644 --- a/config/preload.php +++ b/config/preload.php @@ -1,5 +1,7 @@ =$PHP_VERSION" runtime/frankenphp-symfony - composer config --json extra.symfony.docker 'true' - - if grep -q ^DATABASE_URL= .env; then - echo 'To finish the installation please press Ctrl+C to stop Docker Compose and run: docker compose up --build -d --wait' - sleep infinity - fi - fi - if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then composer install --prefer-dist --no-progress --no-interaction fi diff --git a/migrations/Version20241229195702.php b/migrations/Version20241229195702.php new file mode 100644 index 0000000..9d5fcea --- /dev/null +++ b/migrations/Version20241229195702.php @@ -0,0 +1,90 @@ +addSql('CREATE TABLE answer (id UUID NOT NULL, question_id UUID NOT NULL, text VARCHAR(255) NOT NULL, is_right_answer BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_DADD4A251E27F6BF ON answer (question_id)'); + $this->addSql('COMMENT ON COLUMN answer.id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN answer.question_id IS \'(DC2Type:uuid)\''); + $this->addSql('CREATE TABLE answer_candidate (answer_id UUID NOT NULL, candidate_id UUID NOT NULL, PRIMARY KEY(answer_id, candidate_id))'); + $this->addSql('CREATE INDEX IDX_F54D5192AA334807 ON answer_candidate (answer_id)'); + $this->addSql('CREATE INDEX IDX_F54D519291BD8781 ON answer_candidate (candidate_id)'); + $this->addSql('COMMENT ON COLUMN answer_candidate.answer_id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN answer_candidate.candidate_id IS \'(DC2Type:uuid)\''); + $this->addSql('CREATE TABLE candidate (id UUID NOT NULL, season_id UUID NOT NULL, name VARCHAR(16) NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_C8B28E444EC001D1 ON candidate (season_id)'); + $this->addSql('COMMENT ON COLUMN candidate.id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN candidate.season_id IS \'(DC2Type:uuid)\''); + $this->addSql('CREATE TABLE given_answer (id UUID NOT NULL, candidate_id UUID NOT NULL, quiz_id UUID NOT NULL, answer_id UUID NOT NULL, created TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_9AC61A3091BD8781 ON given_answer (candidate_id)'); + $this->addSql('CREATE INDEX IDX_9AC61A30853CD175 ON given_answer (quiz_id)'); + $this->addSql('CREATE INDEX IDX_9AC61A30AA334807 ON given_answer (answer_id)'); + $this->addSql('COMMENT ON COLUMN given_answer.id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN given_answer.candidate_id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN given_answer.quiz_id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN given_answer.answer_id IS \'(DC2Type:uuid)\''); + $this->addSql('CREATE TABLE question (id UUID NOT NULL, quiz_id UUID NOT NULL, question VARCHAR(255) NOT NULL, enabled BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_B6F7494E853CD175 ON question (quiz_id)'); + $this->addSql('COMMENT ON COLUMN question.id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN question.quiz_id IS \'(DC2Type:uuid)\''); + $this->addSql('CREATE TABLE quiz (id UUID NOT NULL, season_id UUID NOT NULL, name VARCHAR(64) NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_A412FA924EC001D1 ON quiz (season_id)'); + $this->addSql('COMMENT ON COLUMN quiz.id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN quiz.season_id IS \'(DC2Type:uuid)\''); + $this->addSql('CREATE TABLE season (id UUID NOT NULL, name VARCHAR(64) NOT NULL, season_code VARCHAR(5) NOT NULL, preregister_candidates BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('COMMENT ON COLUMN season.id IS \'(DC2Type:uuid)\''); + $this->addSql('CREATE TABLE "user" (id UUID NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)'); + $this->addSql('COMMENT ON COLUMN "user".id IS \'(DC2Type:uuid)\''); + $this->addSql('ALTER TABLE answer ADD CONSTRAINT FK_DADD4A251E27F6BF FOREIGN KEY (question_id) REFERENCES question (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE answer_candidate ADD CONSTRAINT FK_F54D5192AA334807 FOREIGN KEY (answer_id) REFERENCES answer (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE answer_candidate ADD CONSTRAINT FK_F54D519291BD8781 FOREIGN KEY (candidate_id) REFERENCES candidate (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE candidate ADD CONSTRAINT FK_C8B28E444EC001D1 FOREIGN KEY (season_id) REFERENCES season (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE given_answer ADD CONSTRAINT FK_9AC61A3091BD8781 FOREIGN KEY (candidate_id) REFERENCES candidate (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE given_answer ADD CONSTRAINT FK_9AC61A30853CD175 FOREIGN KEY (quiz_id) REFERENCES quiz (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE given_answer ADD CONSTRAINT FK_9AC61A30AA334807 FOREIGN KEY (answer_id) REFERENCES answer (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE question ADD CONSTRAINT FK_B6F7494E853CD175 FOREIGN KEY (quiz_id) REFERENCES quiz (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE quiz ADD CONSTRAINT FK_A412FA924EC001D1 FOREIGN KEY (season_id) REFERENCES season (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE answer DROP CONSTRAINT FK_DADD4A251E27F6BF'); + $this->addSql('ALTER TABLE answer_candidate DROP CONSTRAINT FK_F54D5192AA334807'); + $this->addSql('ALTER TABLE answer_candidate DROP CONSTRAINT FK_F54D519291BD8781'); + $this->addSql('ALTER TABLE candidate DROP CONSTRAINT FK_C8B28E444EC001D1'); + $this->addSql('ALTER TABLE given_answer DROP CONSTRAINT FK_9AC61A3091BD8781'); + $this->addSql('ALTER TABLE given_answer DROP CONSTRAINT FK_9AC61A30853CD175'); + $this->addSql('ALTER TABLE given_answer DROP CONSTRAINT FK_9AC61A30AA334807'); + $this->addSql('ALTER TABLE question DROP CONSTRAINT FK_B6F7494E853CD175'); + $this->addSql('ALTER TABLE quiz DROP CONSTRAINT FK_A412FA924EC001D1'); + $this->addSql('DROP TABLE answer'); + $this->addSql('DROP TABLE answer_candidate'); + $this->addSql('DROP TABLE candidate'); + $this->addSql('DROP TABLE given_answer'); + $this->addSql('DROP TABLE question'); + $this->addSql('DROP TABLE quiz'); + $this->addSql('DROP TABLE season'); + $this->addSql('DROP TABLE "user"'); + } +} diff --git a/migrations/Version20241229201314.php b/migrations/Version20241229201314.php new file mode 100644 index 0000000..517da1c --- /dev/null +++ b/migrations/Version20241229201314.php @@ -0,0 +1,40 @@ +addSql('CREATE TABLE season_user (season_id UUID NOT NULL, user_id UUID NOT NULL, PRIMARY KEY(season_id, user_id))'); + $this->addSql('CREATE INDEX IDX_BDA4AD74EC001D1 ON season_user (season_id)'); + $this->addSql('CREATE INDEX IDX_BDA4AD7A76ED395 ON season_user (user_id)'); + $this->addSql('COMMENT ON COLUMN season_user.season_id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN season_user.user_id IS \'(DC2Type:uuid)\''); + $this->addSql('ALTER TABLE season_user ADD CONSTRAINT FK_BDA4AD74EC001D1 FOREIGN KEY (season_id) REFERENCES season (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE season_user ADD CONSTRAINT FK_BDA4AD7A76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE season_user DROP CONSTRAINT FK_BDA4AD74EC001D1'); + $this->addSql('ALTER TABLE season_user DROP CONSTRAINT FK_BDA4AD7A76ED395'); + $this->addSql('DROP TABLE season_user'); + } +} diff --git a/migrations/Version20241229202103.php b/migrations/Version20241229202103.php new file mode 100644 index 0000000..1175d69 --- /dev/null +++ b/migrations/Version20241229202103.php @@ -0,0 +1,41 @@ +addSql('CREATE TABLE correction (id UUID NOT NULL, candidate_id UUID NOT NULL, quiz_id UUID NOT NULL, amount DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_A29DA1B891BD8781 ON correction (candidate_id)'); + $this->addSql('CREATE INDEX IDX_A29DA1B8853CD175 ON correction (quiz_id)'); + $this->addSql('COMMENT ON COLUMN correction.id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN correction.candidate_id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN correction.quiz_id IS \'(DC2Type:uuid)\''); + $this->addSql('ALTER TABLE correction ADD CONSTRAINT FK_A29DA1B891BD8781 FOREIGN KEY (candidate_id) REFERENCES candidate (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE correction ADD CONSTRAINT FK_A29DA1B8853CD175 FOREIGN KEY (quiz_id) REFERENCES quiz (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE correction DROP CONSTRAINT FK_A29DA1B891BD8781'); + $this->addSql('ALTER TABLE correction DROP CONSTRAINT FK_A29DA1B8853CD175'); + $this->addSql('DROP TABLE correction'); + } +} diff --git a/migrations/Version20241229202155.php b/migrations/Version20241229202155.php new file mode 100644 index 0000000..2d29722 --- /dev/null +++ b/migrations/Version20241229202155.php @@ -0,0 +1,32 @@ +addSql('CREATE UNIQUE INDEX UNIQ_A29DA1B891BD8781853CD175 ON correction (candidate_id, quiz_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('DROP INDEX UNIQ_A29DA1B891BD8781853CD175'); + } +} diff --git a/migrations/Version20241229204335.php b/migrations/Version20241229204335.php new file mode 100644 index 0000000..41e5950 --- /dev/null +++ b/migrations/Version20241229204335.php @@ -0,0 +1,34 @@ +addSql('ALTER TABLE given_answer ALTER answer_id DROP NOT NULL'); + $this->addSql('ALTER TABLE given_answer ALTER created DROP NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE given_answer ALTER answer_id SET NOT NULL'); + $this->addSql('ALTER TABLE given_answer ALTER created SET NOT NULL'); + } +} diff --git a/migrations/Version20250303221227.php b/migrations/Version20250303221227.php new file mode 100644 index 0000000..8f389fb --- /dev/null +++ b/migrations/Version20250303221227.php @@ -0,0 +1,39 @@ +addSql('ALTER TABLE given_answer ALTER created SET NOT NULL'); + $this->addSql('ALTER TABLE season ADD active_quiz_id UUID DEFAULT NULL'); + $this->addSql('COMMENT ON COLUMN season.active_quiz_id IS \'(DC2Type:uuid)\''); + $this->addSql('ALTER TABLE season ADD CONSTRAINT FK_F0E45BA96706D6B FOREIGN KEY (active_quiz_id) REFERENCES quiz (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_F0E45BA96706D6B ON season (active_quiz_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE season DROP CONSTRAINT FK_F0E45BA96706D6B'); + $this->addSql('DROP INDEX IDX_F0E45BA96706D6B'); + $this->addSql('ALTER TABLE season DROP active_quiz_id'); + $this->addSql('ALTER TABLE given_answer ALTER created DROP NOT NULL'); + } +} diff --git a/phpstan.dist.neon b/phpstan.dist.neon index e0de575..e9bd41c 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,5 +1,5 @@ parameters: - level: 6 + level: 8 paths: - bin/ - config/ diff --git a/public/img/background.png b/public/img/background.png new file mode 100644 index 0000000..fabe57e Binary files /dev/null and b/public/img/background.png differ diff --git a/public/index.php b/public/index.php index 2b0418f..12db4f8 100644 --- a/public/index.php +++ b/public/index.php @@ -1,7 +1,14 @@ new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); +return static function (array $context): Kernel { + $appEnv = !empty($context['APP_ENV']) ? (string) $context['APP_ENV'] : 'prod'; + $appDebug = !empty($context['APP_DEBUG']) ? filter_var($context['APP_DEBUG'], \FILTER_VALIDATE_BOOL) : 'prod' !== $appEnv; + + return new Kernel($appEnv, $appDebug); +}; diff --git a/rector.php b/rector.php index 0ece580..f800278 100644 --- a/rector.php +++ b/rector.php @@ -12,5 +12,20 @@ return RectorConfig::configure() __DIR__.'/tests', ]) ->withPhpSets() - ->withPreparedSets(deadCode: true, codeQuality: true, codingStyle: true, typeDeclarations: true, privatization: true, instanceOf: true, earlyReturn: true, strictBooleans: true, phpunitCodeQuality: true, doctrineCodeQuality: true, symfonyCodeQuality: true) - ->withComposerBased(twig: true, doctrine: true, phpunit: true); + ->withPreparedSets( + deadCode: true, + codeQuality: true, + codingStyle: true, + typeDeclarations: true, + privatization: true, + instanceOf: true, + earlyReturn: true, + strictBooleans: true, + rectorPreset: true, + phpunitCodeQuality: true, + doctrineCodeQuality: true, + symfonyCodeQuality: true, + ) + ->withComposerBased(twig: true, doctrine: true, phpunit: true) + ->withAttributesSets() +; diff --git a/src/Controller/Admin/AnswerCrudController.php b/src/Controller/Admin/AnswerCrudController.php new file mode 100644 index 0000000..f50a78b --- /dev/null +++ b/src/Controller/Admin/AnswerCrudController.php @@ -0,0 +1,28 @@ +container->get(AdminUrlGenerator::class); + + return $this->redirect($adminUrlGenerator->setController(SeasonCrudController::class)->generateUrl()); + + // Option 2. You can make your dashboard redirect to different pages depending on the user + // + // if ('jane' === $this->getUser()->getUsername()) { + // return $this->redirect('...'); + // } + + // Option 3. You can render some custom template to display a proper dashboard with widgets, etc. + // (tip: it's easier if your template extends from @EasyAdmin/page/content.html.twig) + // + // return $this->render('some/path/my-dashboard.html.twig'); + } + + public function configureDashboard(): Dashboard + { + return Dashboard::new() + ->setTitle('TijdVoorDeTest'); + } + + public function configureMenuItems(): iterable + { + yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home'); + yield MenuItem::linkToCrud('Season', 'fas fa-list', Season::class); + yield MenuItem::linkToCrud('Quiz', 'fas fa-list', Quiz::class); + yield MenuItem::linkToCrud('Question', 'fas fa-list', Question::class); + yield MenuItem::linkToCrud('Candidate', 'fas fa-list', Candidate::class); + yield MenuItem::linkToCrud('Correction', 'fas fa-list', Correction::class); + yield MenuItem::linkToCrud('User', 'fas fa-list', User::class); + yield MenuItem::linkToCrud('Given Answer', 'fas fa-list', GivenAnswer::class); + yield MenuItem::linkToCrud('Answer', 'fas fa-list', Answer::class); + yield MenuItem::linkToLogout('Logout', 'fa fa-exit'); + } +} diff --git a/src/Controller/Admin/GivenAnswerCrudController.php b/src/Controller/Admin/GivenAnswerCrudController.php new file mode 100644 index 0000000..09ab7ed --- /dev/null +++ b/src/Controller/Admin/GivenAnswerCrudController.php @@ -0,0 +1,28 @@ +getLastAuthenticationError(); + + // last username entered by the user + $lastUsername = $authenticationUtils->getLastUsername(); + + return $this->render('login/login.html.twig', [ + 'last_username' => $lastUsername, + 'error' => $error, + ]); + } + + #[Route(path: '/logout', name: 'app_logout')] + public function logout(): void + { + throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.'); + } +} diff --git a/src/Controller/QuizController.php b/src/Controller/QuizController.php new file mode 100644 index 0000000..5a4e96b --- /dev/null +++ b/src/Controller/QuizController.php @@ -0,0 +1,72 @@ +createForm(SelectSeasonType::class); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $data = $form->getData(); + + return $this->redirectToRoute('enter_name', ['seasonCode' => $data['season_code']]); + } + + return $this->render('quiz/select_season.html.twig', ['form' => $form]); + } + + #[Route(path: '/{seasonCode}', name: 'enter_name', requirements: ['seasonCode' => self::SEASON_CODE_REGEX])] + public function enterName( + Request $request, + Season $season, + ): Response { + $form = $this->createForm(EnterNameType::class); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $data = $form->getData(); + $name = $data['name']; + + return $this->redirectToRoute('quiz_page', ['seasonCode' => $season->getSeasonCode(), 'nameHash' => Base64::base64_url_encode($name)]); + } + + return $this->render('quiz/enter_name.twig', ['season' => $season, 'form' => $form]); + } + + #[Route( + path: '/{seasonCode}/{nameHash}', + name: 'quiz_page', + requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'nameHash' => self::CANDIDATE_HASH_REGEX], + )] + public function quizPage(Season $season, string $nameHash) + { + try { + $name = Base64::base64_url_decode($nameHash); + } catch (UrlException $e) { + } + + return $this->render('quiz/question.twig', ['season' => $season, 'name' => $name]); + } +} diff --git a/src/DataFixtures/KrtekFixtures.php b/src/DataFixtures/KrtekFixtures.php new file mode 100644 index 0000000..e7e9912 --- /dev/null +++ b/src/DataFixtures/KrtekFixtures.php @@ -0,0 +1,185 @@ +persist($season); + + $season->setName('Krtek Weekend') + ->setSeasonCode('12345') + ->setPreregisterCandidates(true); + + $quiz1 = new Quiz(); + $manager->persist($quiz1); + $quiz1->setName('Quiz 1') + ->setSeason($season); + + $season->setActiveQuiz($quiz1) + ->addCandidate(new Candidate('Claudia')) + ->addCandidate(new Candidate('Eelco')) + ->addCandidate(new Candidate('Elise')) + ->addCandidate(new Candidate('Gert-Jan')) + ->addCandidate(new Candidate('Iris')) + ->addCandidate(new Candidate('Jari')) + ->addCandidate(new Candidate('Lara')) + ->addCandidate(new Candidate('Lotte')) + ->addCandidate(new Candidate('Myrthe')) + ->addCandidate(new Candidate('Philine')) + ->addCandidate(new Candidate('Remy')) + ->addCandidate(new Candidate('Robbert')) + ->addCandidate(new Candidate('Tom')) + ; + + $quiz1->addQuestion((new Question()) + ->setQuestion('Is de Krtek een man of een vrouw?') + ->addAnswer(new Answer('Ja', true)) + ->addAnswer(new Answer('Nee')) + ); + + $quiz1->addQuestion((new Question()) + ->setQuestion('Hoeveel broers heeft de Krtek?') + ->addAnswer(new Answer('Geen', true)) + ->addAnswer(new Answer('1')) + ->addAnswer(new Answer('2')) + ); + + $quiz1->addQuestion((new Question()) + ->setQuestion('Wat is de lievelingsfeestdag van de Krtek?') + ->addAnswer(new Answer('Geen')) + ->addAnswer(new Answer('Diens eigen verjaardag')) + ->addAnswer(new Answer('Koningsdag')) + ->addAnswer(new Answer('Kerst', true)) + ->addAnswer(new Answer('Oud en Nieuw')) + ); + $quiz1->addQuestion((new Question()) + ->setQuestion('Hoe kwam de Krtek naar Kersteren vandaag?') + ->addAnswer(new Answer('Met het OV', true)) + ->addAnswer(new Answer('Met de auto')) + ); + $quiz1->addQuestion((new Question()) + ->setQuestion('Met wie keek de Kretek video bij binnenkomst?') + ->addAnswer(new Answer('Claudia')) + ->addAnswer(new Answer('Eelco')) + ->addAnswer(new Answer('Elise')) + ->addAnswer(new Answer('Gert-Jan')) + ->addAnswer(new Answer('Iris')) + ->addAnswer(new Answer('Jari')) + ->addAnswer(new Answer('Lara')) + ->addAnswer(new Answer('Lotte')) + ->addAnswer(new Answer('Myrthe')) + ->addAnswer(new Answer('Philine')) + ->addAnswer(new Answer('Remy')) + ->addAnswer(new Answer('Robbert')) + ->addAnswer(new Answer('Tom', true)) + ); + + $quiz1->addQuestion((new Question()) + ->setQuestion('Welk advies zou de Krtek zichzelf als kind geven?') + ->addAnswer(new Answer('Geef je vader een knuffel.')) + ->addAnswer(new Answer('Trek je wat minder aan van anderen.')) + ->addAnswer(new Answer('Luister meer naar je eigen gevoel in plaats van naar wat anderen vinden.')) + ->addAnswer(new Answer('Stel niet alles tot het laatste moment uit.')) + ->addAnswer(new Answer('Altijd doorgaan.')) + ->addAnswer(new Answer('Probeer ook eens buiten de lijntjes te kleuren', true)) + ->addAnswer(new Answer('Ga als je groot bent op groepsreis! ')) + ->addAnswer(new Answer('Trek minder aan van de mening van anderen, het is oké om anders te zijn.')) + ); + + $quiz1->addQuestion((new Question()) + ->setQuestion('Wat voor soort schoenen droeg de Krtek bij het diner?') + ->addAnswer(new Answer('Sneakers')) + ->addAnswer(new Answer('Wandel-/bergschoenen', true)) + ->addAnswer(new Answer('Lederen schoenen')) + ->addAnswer(new Answer('Pantoffels')) + ->addAnswer(new Answer('Hakken')) + ->addAnswer(new Answer('Geen schoenen, alleen sokken')) + ); + + $quiz1->addQuestion((new Question()) + ->setQuestion('Met welk vervoersmiddel reist de Krtek het liefste?') + ->addAnswer(new Answer('Fiets', true)) + ->addAnswer(new Answer('Auto')) + ->addAnswer(new Answer('Trein')) + ); + + $quiz1->addQuestion((new Question()) + ->setQuestion('Heeft de Krtek een eigen auto?') + ->addAnswer(new Answer('Ja')) + ->addAnswer(new Answer('Nee', true)) + ); + + $quiz1->addQuestion((new Question()) + ->setQuestion('Van wie is de quote die de Krtek gepakt heeft') + ->addAnswer(new Answer('Karen')) + ->addAnswer(new Answer('Gilles de Coster')) + ->addAnswer(new Answer('Kees Tol')) + ->addAnswer(new Answer('Harry en John')) + ->addAnswer(new Answer('Georgina Verbaan')) + ->addAnswer(new Answer('Marc-Marie Huijbregts')) + ->addAnswer(new Answer('Fresia Cousiño Arias, Rik van de Westelaken')) + ->addAnswer(new Answer('Ellie Lust')) + ->addAnswer(new Answer('Bouba')) + ->addAnswer(new Answer('Jan Versteegh')) + ->addAnswer(new Answer('Dick Jol')) + ->addAnswer(new Answer('Karin de Groot')) + ->addAnswer(new Answer('Pieter')) + ->addAnswer(new Answer('Renée Fokker')) + ->addAnswer(new Answer('Sam, Davy', true)) + ); + $quiz1->addQuestion((new Question()) + ->setQuestion('Zou de Krtek molboekjes, jokers, vrijstellingen of topito’s uit iemands rugzak stelen om te kunnen winnen?') + ->addAnswer(new Answer('Ja')) + ->addAnswer(new Answer('Nee', true)) + ); + $quiz1->addQuestion((new Question()) + ->setQuestion('In wat voor bed slaapt de Krtek dit weekend?') + ->addAnswer(new Answer('Éénpersoons, losstaand bed')) + ->addAnswer(new Answer('Éénpersoonsbed, tegen een ander bed aan', true)) + ->addAnswer(new Answer('Tweepersoons bed')) + ); + $quiz1->addQuestion((new Question()) + ->setQuestion('Hoeveel jaar heeft de Krtek gedaan over de middelbare school?') + ->addAnswer(new Answer('5')) + ->addAnswer(new Answer('6', true)) + ->addAnswer(new Answer('7')) + ->addAnswer(new Answer('8')) + ); + $quiz1->addQuestion((new Question()) + ->setQuestion('Waar zat de Krtek aan tafel bij het diner?') + ->addAnswer(new Answer('Met de rug naar de accommodatie')) + ->addAnswer(new Answer('Met de rug naar de buitenmuur', true)) + ); + $quiz1->addQuestion((new Question()) + ->setQuestion('Wie is de Krtek?') + ->addAnswer(new Answer('Claudia', true)) + ->addAnswer(new Answer('Eelco')) + ->addAnswer(new Answer('Elise')) + ->addAnswer(new Answer('Gert-Jan')) + ->addAnswer(new Answer('Iris')) + ->addAnswer(new Answer('Jari')) + ->addAnswer(new Answer('Lara')) + ->addAnswer(new Answer('Lotte')) + ->addAnswer(new Answer('Myrthe')) + ->addAnswer(new Answer('Philine')) + ->addAnswer(new Answer('Remy')) + ->addAnswer(new Answer('Robbert')) + ->addAnswer(new Answer('Tom')) + ); + + $manager->flush(); + } +} diff --git a/src/Entity/Answer.php b/src/Entity/Answer.php new file mode 100644 index 0000000..3e5f13a --- /dev/null +++ b/src/Entity/Answer.php @@ -0,0 +1,124 @@ + */ + #[ORM\ManyToMany(targetEntity: Candidate::class, inversedBy: 'answersOnCandidate')] + private Collection $candidates; + + /** @var Collection */ + #[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'answer', orphanRemoval: true)] + private Collection $givenAnswers; + + public function __construct( + #[ORM\Column(length: 255)] + private string $text, + #[ORM\Column] + private bool $isRightAnswer = false, + ) { + $this->candidates = new ArrayCollection(); + $this->givenAnswers = new ArrayCollection(); + } + + public function getId(): Uuid + { + return $this->id; + } + + public function getText(): string + { + return $this->text; + } + + public function setText(string $text): static + { + $this->text = $text; + + return $this; + } + + public function getQuestion(): Question + { + return $this->question; + } + + public function setQuestion(Question $question): static + { + $this->question = $question; + + return $this; + } + + public function isRightAnswer(): ?bool + { + return $this->isRightAnswer; + } + + public function setRightAnswer(bool $isRightAnswer): static + { + $this->isRightAnswer = $isRightAnswer; + + return $this; + } + + /** @return Collection */ + public function getCandidates(): Collection + { + return $this->candidates; + } + + public function addCandidate(Candidate $candidate): static + { + if (!$this->candidates->contains($candidate)) { + $this->candidates->add($candidate); + } + + return $this; + } + + public function removeCandidate(Candidate $candidate): static + { + $this->candidates->removeElement($candidate); + + return $this; + } + + /** @return Collection */ + public function getGivenAnswers(): Collection + { + return $this->givenAnswers; + } + + public function addGivenAnswer(GivenAnswer $givenAnswer): static + { + if (!$this->givenAnswers->contains($givenAnswer)) { + $this->givenAnswers->add($givenAnswer); + $givenAnswer->setAnswer($this); + } + + return $this; + } +} diff --git a/src/Entity/Candidate.php b/src/Entity/Candidate.php new file mode 100644 index 0000000..b086ca9 --- /dev/null +++ b/src/Entity/Candidate.php @@ -0,0 +1,140 @@ + */ + #[ORM\ManyToMany(targetEntity: Answer::class, mappedBy: 'candidates')] + private Collection $answersOnCandidate; + + /** @var Collection */ + #[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'candidate', orphanRemoval: true)] + private Collection $givenAnswers; + + /** @var Collection */ + #[ORM\OneToMany(targetEntity: Correction::class, mappedBy: 'candidate', orphanRemoval: true)] + private Collection $corrections; + + public function __construct( + #[ORM\Column(length: 16)] + private string $name, + ) { + $this->answersOnCandidate = new ArrayCollection(); + $this->givenAnswers = new ArrayCollection(); + $this->corrections = new ArrayCollection(); + } + + public function getId(): ?Uuid + { + return $this->id; + } + + public function getSeason(): Season + { + return $this->season; + } + + public function setSeason(Season $season): static + { + $this->season = $season; + + return $this; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + /** @return Collection */ + public function getAnswersOnCandidate(): Collection + { + return $this->answersOnCandidate; + } + + public function addAnswersOnCandidate(Answer $answersOnCandidate): static + { + if (!$this->answersOnCandidate->contains($answersOnCandidate)) { + $this->answersOnCandidate->add($answersOnCandidate); + $answersOnCandidate->addCandidate($this); + } + + return $this; + } + + public function removeAnswersOnCandidate(Answer $answersOnCandidate): static + { + if ($this->answersOnCandidate->removeElement($answersOnCandidate)) { + $answersOnCandidate->removeCandidate($this); + } + + return $this; + } + + /** @return Collection */ + public function getGivenAnswers(): Collection + { + return $this->givenAnswers; + } + + public function addGivenAnswer(GivenAnswer $givenAnswer): static + { + if (!$this->givenAnswers->contains($givenAnswer)) { + $this->givenAnswers->add($givenAnswer); + $givenAnswer->setCandidate($this); + } + + return $this; + } + + /** @return Collection */ + public function getCorrections(): Collection + { + return $this->corrections; + } + + public function addCorrection(Correction $correction): static + { + if (!$this->corrections->contains($correction)) { + $this->corrections->add($correction); + $correction->setCandidate($this); + } + + return $this; + } + + public function getNameHash(): string + { + return Base64::base64_url_encode($this->name); + } +} diff --git a/src/Entity/Correction.php b/src/Entity/Correction.php new file mode 100644 index 0000000..5e9cd26 --- /dev/null +++ b/src/Entity/Correction.php @@ -0,0 +1,74 @@ +id; + } + + public function getCandidate(): Candidate + { + return $this->candidate; + } + + public function setCandidate(Candidate $candidate): static + { + $this->candidate = $candidate; + + return $this; + } + + public function getQuiz(): Quiz + { + return $this->quiz; + } + + public function setQuiz(Quiz $quiz): static + { + $this->quiz = $quiz; + + return $this; + } + + public function getAmount(): ?float + { + return $this->amount; + } + + public function setAmount(float $amount): static + { + $this->amount = $amount; + + return $this; + } +} diff --git a/src/Entity/GivenAnswer.php b/src/Entity/GivenAnswer.php new file mode 100644 index 0000000..4d907d5 --- /dev/null +++ b/src/Entity/GivenAnswer.php @@ -0,0 +1,91 @@ +id; + } + + public function getCandidate(): Candidate + { + return $this->candidate; + } + + public function setCandidate(Candidate $candidate): static + { + $this->candidate = $candidate; + + return $this; + } + + public function getQuiz(): ?Quiz + { + return $this->quiz; + } + + public function setQuiz(Quiz $quiz): static + { + $this->quiz = $quiz; + + return $this; + } + + public function getAnswer(): ?Answer + { + return $this->answer; + } + + public function setAnswer(?Answer $answer): static + { + $this->answer = $answer; + + return $this; + } + + public function getCreated(): ?\DateTimeInterface + { + return $this->created; + } + + #[ORM\PrePersist] + public function setCreatedAtValue(): void + { + $this->created = new DateTimeImmutable(); + } +} diff --git a/src/Entity/Question.php b/src/Entity/Question.php new file mode 100644 index 0000000..9ea7020 --- /dev/null +++ b/src/Entity/Question.php @@ -0,0 +1,99 @@ + */ + #[ORM\OneToMany(targetEntity: Answer::class, mappedBy: 'question', cascade: ['persist'], orphanRemoval: true)] + private Collection $answers; + + public function __construct() + { + $this->answers = new ArrayCollection(); + } + + public function getId(): ?Uuid + { + return $this->id; + } + + public function getQuestion(): string + { + return $this->question; + } + + public function setQuestion(string $question): static + { + $this->question = $question; + + return $this; + } + + public function getQuiz(): Quiz + { + return $this->quiz; + } + + public function setQuiz(Quiz $quiz): static + { + $this->quiz = $quiz; + + return $this; + } + + public function isEnabled(): ?bool + { + return $this->enabled; + } + + public function setEnabled(bool $enabled): static + { + $this->enabled = $enabled; + + return $this; + } + + /** @return Collection */ + public function getAnswers(): Collection + { + return $this->answers; + } + + public function addAnswer(Answer $answer): static + { + if (!$this->answers->contains($answer)) { + $this->answers->add($answer); + $answer->setQuestion($this); + } + + return $this; + } +} diff --git a/src/Entity/Quiz.php b/src/Entity/Quiz.php new file mode 100644 index 0000000..483dbac --- /dev/null +++ b/src/Entity/Quiz.php @@ -0,0 +1,105 @@ + */ + #[ORM\OneToMany(targetEntity: Question::class, mappedBy: 'quiz', cascade: ['persist'], orphanRemoval: true)] + private Collection $questions; + + /** @var Collection */ + #[ORM\OneToMany(targetEntity: Correction::class, mappedBy: 'quiz', orphanRemoval: true)] + private Collection $corrections; + + public function __construct() + { + $this->questions = new ArrayCollection(); + $this->corrections = new ArrayCollection(); + } + + public function getId(): ?Uuid + { + return $this->id; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + public function getSeason(): Season + { + return $this->season; + } + + public function setSeason(Season $season): static + { + $this->season = $season; + + return $this; + } + + /** @return Collection */ + public function getQuestions(): Collection + { + return $this->questions; + } + + public function addQuestion(Question $question): static + { + if (!$this->questions->contains($question)) { + $this->questions->add($question); + $question->setQuiz($this); + } + + return $this; + } + + /** @return Collection */ + public function getCorrections(): Collection + { + return $this->corrections; + } + + public function addCorrection(Correction $correction): static + { + if (!$this->corrections->contains($correction)) { + $this->corrections->add($correction); + $correction->setQuiz($this); + } + + return $this; + } +} diff --git a/src/Entity/Season.php b/src/Entity/Season.php new file mode 100644 index 0000000..50aead0 --- /dev/null +++ b/src/Entity/Season.php @@ -0,0 +1,161 @@ + */ + #[ORM\OneToMany(targetEntity: Quiz::class, mappedBy: 'season', orphanRemoval: true)] + private Collection $quizzes; + + /** @var Collection */ + #[ORM\OneToMany(targetEntity: Candidate::class, mappedBy: 'season', cascade: ['persist'], orphanRemoval: true)] + private Collection $candidates; + + /** @var Collection */ + #[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'seasons')] + private Collection $owners; + + #[ORM\ManyToOne] + private ?Quiz $ActiveQuiz = null; + + public function __construct() + { + $this->quizzes = new ArrayCollection(); + $this->candidates = new ArrayCollection(); + $this->owners = new ArrayCollection(); + } + + public function getId(): ?Uuid + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + public function getSeasonCode(): ?string + { + return $this->seasonCode; + } + + public function setSeasonCode(string $seasonCode): static + { + $this->seasonCode = $seasonCode; + + return $this; + } + + public function isPreregisterCandidates(): bool + { + return $this->preregisterCandidates; + } + + public function setPreregisterCandidates(bool $preregisterCandidates): static + { + $this->preregisterCandidates = $preregisterCandidates; + + return $this; + } + + /** @return Collection */ + public function getQuizzes(): Collection + { + return $this->quizzes; + } + + public function addQuiz(Quiz $quiz): static + { + if (!$this->quizzes->contains($quiz)) { + $this->quizzes->add($quiz); + $quiz->setSeason($this); + } + + return $this; + } + + /** @return Collection */ + public function getCandidates(): Collection + { + return $this->candidates; + } + + public function addCandidate(Candidate $candidate): static + { + if (!$this->candidates->contains($candidate)) { + $this->candidates->add($candidate); + $candidate->setSeason($this); + } + + return $this; + } + + /** @return Collection */ + public function getOwners(): Collection + { + return $this->owners; + } + + public function addOwner(User $owner): static + { + if (!$this->owners->contains($owner)) { + $this->owners->add($owner); + } + + return $this; + } + + public function removeOwner(User $owner): static + { + $this->owners->removeElement($owner); + + return $this; + } + + public function getActiveQuiz(): ?Quiz + { + return $this->ActiveQuiz; + } + + public function setActiveQuiz(?Quiz $ActiveQuiz): static + { + $this->ActiveQuiz = $ActiveQuiz; + + return $this; + } +} diff --git a/src/Entity/User.php b/src/Entity/User.php new file mode 100644 index 0000000..fb317a2 --- /dev/null +++ b/src/Entity/User.php @@ -0,0 +1,143 @@ + The user roles */ + #[ORM\Column] + private array $roles = []; + + /** @var string The hashed password */ + #[ORM\Column] + private string $password; + + /** @var Collection */ + #[ORM\ManyToMany(targetEntity: Season::class, mappedBy: 'owners')] + private Collection $seasons; + + public function __construct() + { + $this->seasons = new ArrayCollection(); + } + + public function getId(): ?Uuid + { + return $this->id; + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function setEmail(string $email): static + { + $this->email = $email; + + return $this; + } + + /** + * A visual identifier that represents this user. + * + * @see UserInterface + * + * @return non-empty-string + */ + public function getUserIdentifier(): string + { + return $this->email; + } + + /** + * @see UserInterface + * + * @return non-empty-list + */ + public function getRoles(): array + { + $roles = $this->roles; + // guarantee every user at least has ROLE_USER + $roles[] = 'ROLE_USER'; + + return array_unique($roles); + } + + /** @param list $roles */ + public function setRoles(array $roles): static + { + $this->roles = $roles; + + return $this; + } + + /** @see PasswordAuthenticatedUserInterface */ + public function getPassword(): ?string + { + return $this->password; + } + + public function setPassword(string $password): static + { + $this->password = $password; + + return $this; + } + + /** @see UserInterface */ + public function eraseCredentials(): void + { + // If you store any temporary, sensitive data on the user, clear it here + // $this->plainPassword = null; + } + + /** @return Collection */ + public function getSeasons(): Collection + { + return $this->seasons; + } + + public function addSeason(Season $season): static + { + if (!$this->seasons->contains($season)) { + $this->seasons->add($season); + $season->addOwner($this); + } + + return $this; + } + + public function removeSeason(Season $season): static + { + if ($this->seasons->removeElement($season)) { + $season->removeOwner($this); + } + + return $this; + } +} diff --git a/src/Form/EnterNameType.php b/src/Form/EnterNameType.php new file mode 100644 index 0000000..e5bdcd8 --- /dev/null +++ b/src/Form/EnterNameType.php @@ -0,0 +1,35 @@ +add('name', TextType::class, + ['required' => true, 'label' => $this->translator->trans('Enter your name')], + ) +// ->add('submit', SubmitType::class, ['label' => 'Start quiz']) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + // Configure your form options here + ]); + } +} diff --git a/src/Form/SelectSeasonType.php b/src/Form/SelectSeasonType.php new file mode 100644 index 0000000..0e96ea3 --- /dev/null +++ b/src/Form/SelectSeasonType.php @@ -0,0 +1,31 @@ +add('season_code', TextType::class, + ['required' => true, 'constraints' => new Regex(pattern: "/^[A-Za-z\d]{5}$/")], + ) +// ->add('submit', SubmitType::class, ['label' => 'Start quiz']) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + // Configure your form options here + ]); + } +} diff --git a/src/Helpers/Base64.php b/src/Helpers/Base64.php new file mode 100644 index 0000000..f9c5b27 --- /dev/null +++ b/src/Helpers/Base64.php @@ -0,0 +1,25 @@ + + */ +class AnswerRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Answer::class); + } +} diff --git a/src/Repository/CandidateRepository.php b/src/Repository/CandidateRepository.php new file mode 100644 index 0000000..5b2208a --- /dev/null +++ b/src/Repository/CandidateRepository.php @@ -0,0 +1,34 @@ + + */ +class CandidateRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Candidate::class); + } + + public function getCandidateByHash(Season $season, string $hash): ?Candidate + { + try { + $name = Base64::base64_url_decode($hash); + } catch (UrlException) { + return null; + } + + return $this->findOneBy(['season' => $season, 'name' => $name]); + } +} diff --git a/src/Repository/CorrectionRepository.php b/src/Repository/CorrectionRepository.php new file mode 100644 index 0000000..c9ae6e5 --- /dev/null +++ b/src/Repository/CorrectionRepository.php @@ -0,0 +1,20 @@ + + */ +class CorrectionRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Correction::class); + } +} diff --git a/src/Repository/GivenAnswerRepository.php b/src/Repository/GivenAnswerRepository.php new file mode 100644 index 0000000..598f1ed --- /dev/null +++ b/src/Repository/GivenAnswerRepository.php @@ -0,0 +1,20 @@ + + */ +class GivenAnswerRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, GivenAnswer::class); + } +} diff --git a/src/Repository/QuestionRepository.php b/src/Repository/QuestionRepository.php new file mode 100644 index 0000000..c8bc4b7 --- /dev/null +++ b/src/Repository/QuestionRepository.php @@ -0,0 +1,20 @@ + + */ +class QuestionRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Question::class); + } +} diff --git a/src/Repository/QuizRepository.php b/src/Repository/QuizRepository.php new file mode 100644 index 0000000..8d0421b --- /dev/null +++ b/src/Repository/QuizRepository.php @@ -0,0 +1,20 @@ + + */ +class QuizRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Quiz::class); + } +} diff --git a/src/Repository/SeasonRepository.php b/src/Repository/SeasonRepository.php new file mode 100644 index 0000000..62bd0b7 --- /dev/null +++ b/src/Repository/SeasonRepository.php @@ -0,0 +1,20 @@ + + */ +class SeasonRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Season::class); + } +} diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php new file mode 100644 index 0000000..5633a4e --- /dev/null +++ b/src/Repository/UserRepository.php @@ -0,0 +1,32 @@ + + * + * @implements PasswordUpgraderInterface + */ +class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, User::class); + } + + /** Used to upgrade (rehash) the user's password automatically over time. */ + public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void + { + $user->setPassword($newHashedPassword); + $this->getEntityManager()->persist($user); + $this->getEntityManager()->flush(); + } +} diff --git a/symfony.lock b/symfony.lock index 171e542..6b899c0 100644 --- a/symfony.lock +++ b/symfony.lock @@ -13,6 +13,18 @@ "src/Repository/.gitignore" ] }, + "doctrine/doctrine-fixtures-bundle": { + "version": "4.0", + "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": { @@ -26,6 +38,15 @@ "migrations/.gitignore" ] }, + "easycorp/easyadmin-bundle": { + "version": "4.23", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.0", + "ref": "b131e6cbfe1b898a508987851963fff485986285" + } + }, "friendsofphp/php-cs-fixer": { "version": "3.65", "recipe": { @@ -89,6 +110,18 @@ ".env.dev" ] }, + "symfony/form": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.2", + "ref": "7d86a6723f4a623f59e2bf966b6aad2fc461d36b" + }, + "files": [ + "config/packages/csrf.yaml" + ] + }, "symfony/framework-bundle": { "version": "7.2", "recipe": { @@ -130,6 +163,32 @@ "config/routes.yaml" ] }, + "symfony/security-bundle": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "2ae08430db28c8eb4476605894296c82a642028f" + }, + "files": [ + "config/packages/security.yaml", + "config/routes/security.yaml" + ] + }, + "symfony/translation": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.3", + "ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b" + }, + "files": [ + "config/packages/translation.yaml", + "translations/.gitignore" + ] + }, "symfony/twig-bundle": { "version": "7.2", "recipe": { @@ -142,5 +201,54 @@ "config/packages/twig.yaml", "templates/base.html.twig" ] + }, + "symfony/uid": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "0df5844274d871b37fc3816c57a768ffc60a43a5" + } + }, + "symfony/ux-twig-component": { + "version": "2.22", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.13", + "ref": "67814b5f9794798b885cec9d3f48631424449a01" + }, + "files": [ + "config/packages/twig_component.yaml" + ] + }, + "symfony/validator": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd" + }, + "files": [ + "config/packages/validator.yaml" + ] + }, + "symfony/web-profiler-bundle": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.1", + "ref": "e42b3f0177df239add25373083a564e5ead4e13a" + }, + "files": [ + "config/packages/web_profiler.yaml", + "config/routes/web_profiler.yaml" + ] + }, + "twig/extra-bundle": { + "version": "v3.18.0" } } diff --git a/templates/base.html.twig b/templates/base.html.twig index 1069c14..8b9aea3 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -1,16 +1,17 @@ - - - - {% block title %}Welcome!{% endblock %} - - {% block stylesheets %} - {% endblock %} + + + + {% block title %}Welcome!{% endblock %} + + {% block stylesheets %} + {% endblock %} - {% block javascripts %} - {% endblock %} - - - {% block body %}{% endblock %} - + {% block javascripts %} + {% endblock %} + + +{% block body %}{% endblock %} + diff --git a/templates/login/login.html.twig b/templates/login/login.html.twig new file mode 100644 index 0000000..07b5cd4 --- /dev/null +++ b/templates/login/login.html.twig @@ -0,0 +1,41 @@ +{% extends 'base.html.twig' %} + +{% block title %}Log in!{% endblock %} + +{% block body %} +
+ {% if error %} +
{{ error.messageKey|trans(error.messageData, 'security') }}
+ {% endif %} + + {% if app.user %} +
+ You are logged in as {{ app.user.userIdentifier }}, Logout +
+ {% endif %} + +

Please sign in

+ + + + + + + + {# + Uncomment this section and add a remember_me option below your firewall to activate remember me functionality. + See https://symfony.com/doc/current/security/remember_me.html + +
+ + +
+ #} + + +
+{% endblock %} diff --git a/templates/messages.html.twig b/templates/messages.html.twig new file mode 100644 index 0000000..e69de29 diff --git a/templates/quiz/base.html.twig b/templates/quiz/base.html.twig new file mode 100644 index 0000000..50184fc --- /dev/null +++ b/templates/quiz/base.html.twig @@ -0,0 +1,42 @@ + + + + + + + + {% block title %} + Tijd voor de test + {% endblock title %} + + + + +
+
+ {% block body %} + {% endblock body %} +
+ {% block script %} + {% endblock script %} +
+ + diff --git a/templates/quiz/enter_name.twig b/templates/quiz/enter_name.twig new file mode 100644 index 0000000..044a6fc --- /dev/null +++ b/templates/quiz/enter_name.twig @@ -0,0 +1,5 @@ +{% extends "quiz/base.html.twig" %} +{% block body %} + {{ season.name }} + {{ form(form) }} +{% endblock body %} diff --git a/templates/quiz/question.twig b/templates/quiz/question.twig new file mode 100644 index 0000000..d3e1db3 --- /dev/null +++ b/templates/quiz/question.twig @@ -0,0 +1,6 @@ +{% extends "quiz/base.html.twig" %} +{% block body %} + {{ season.name }} + {{ name }} +

Hello World!

+{% endblock body %} diff --git a/templates/quiz/select_season.html.twig b/templates/quiz/select_season.html.twig new file mode 100644 index 0000000..22a4453 --- /dev/null +++ b/templates/quiz/select_season.html.twig @@ -0,0 +1,4 @@ +{% extends "quiz/base.html.twig" %} +{% block body %} + {{ form(form) }} +{% endblock body %} diff --git a/tests/LoginControllerTest.php b/tests/LoginControllerTest.php new file mode 100644 index 0000000..ff6134a --- /dev/null +++ b/tests/LoginControllerTest.php @@ -0,0 +1,85 @@ +client = static::createClient(); + $container = static::getContainer(); + $em = $container->get('doctrine.orm.entity_manager'); + $userRepository = $em->getRepository(User::class); + + // Remove any existing users from the test database + foreach ($userRepository->findAll() as $user) { + $em->remove($user); + } + + $em->flush(); + + // Create a User fixture + /** @var UserPasswordHasherInterface $passwordHasher */ + $passwordHasher = $container->get('security.user_password_hasher'); + + $user = (new User())->setEmail('email@example.com'); + $user->setPassword($passwordHasher->hashPassword($user, 'password')); + + $em->persist($user); + $em->flush(); + } + + public function testLogin(): void + { + // Denied - Can't login with invalid email address. + $this->client->request('GET', '/login'); + $this->assertResponseIsSuccessful(); + + $this->client->submitForm('Sign in', [ + '_username' => 'doesNotExist@example.com', + '_password' => 'password', + ]); + + $this->assertResponseRedirects('/login'); + $this->client->followRedirect(); + + // Ensure we do not reveal if the user exists or not. + $this->assertSelectorTextContains('.alert-danger', 'Invalid credentials.'); + + // Denied - Can't login with invalid password. + $this->client->request('GET', '/login'); + $this->assertResponseIsSuccessful(); + + $this->client->submitForm('Sign in', [ + '_username' => 'email@example.com', + '_password' => 'bad-password', + ]); + + $this->assertResponseRedirects('/login'); + $this->client->followRedirect(); + + // Ensure we do not reveal the user exists but the password is wrong. + $this->assertSelectorTextContains('.alert-danger', 'Invalid credentials.'); + + // Success - Login with valid credentials is allowed. + $this->client->submitForm('Sign in', [ + '_username' => 'email@example.com', + '_password' => 'password', + ]); + + $this->assertResponseRedirects('/'); + $this->client->followRedirect(); + + $this->assertSelectorNotExists('.alert-danger'); + $this->assertResponseIsSuccessful(); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 47a5855..96185bd 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,12 +1,12 @@ bootEnv(dirname(__DIR__).'/.env'); -} +(new Dotenv())->bootEnv(dirname(__DIR__).'/.env'); if ($_SERVER['APP_DEBUG']) { umask(0000); diff --git a/translations/.gitignore b/translations/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/translations/messages+intl-icu.nl.xlf b/translations/messages+intl-icu.nl.xlf new file mode 100644 index 0000000..edb51e7 --- /dev/null +++ b/translations/messages+intl-icu.nl.xlf @@ -0,0 +1,14 @@ + + + +
+ +
+ + + Enter your name + Voor je naam in + + +
+