9 Commits

Author SHA1 Message Date
dependabot[bot]
9f08209d39 Bump rector/rector from 2.1.7 to 2.2.3
Some checks failed
CI / Tests (push) Failing after 41s
CI / Build and deploy to ${{ startsWith(github.ref, 'refs/tags/') && 'production' || (github.ref == 'refs/heads/main' && 'acceptance' || '') }} (push) Has been skipped
Bumps [rector/rector](https://github.com/rectorphp/rector) from 2.1.7 to 2.2.3.
- [Release notes](https://github.com/rectorphp/rector/releases)
- [Commits](https://github.com/rectorphp/rector/compare/2.1.7...2.2.3)

---
updated-dependencies:
- dependency-name: rector/rector
  dependency-version: 2.2.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-21 08:06:11 +02:00
dependabot[bot]
a1fc86a6a0 Bump doctrine/doctrine-fixtures-bundle from 4.1.0 to 4.3.0
Bumps [doctrine/doctrine-fixtures-bundle](https://github.com/doctrine/DoctrineFixturesBundle) from 4.1.0 to 4.3.0.
- [Release notes](https://github.com/doctrine/DoctrineFixturesBundle/releases)
- [Commits](https://github.com/doctrine/DoctrineFixturesBundle/compare/4.1.0...4.3.0)

---
updated-dependencies:
- dependency-name: doctrine/doctrine-fixtures-bundle
  dependency-version: 4.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-21 08:05:35 +02:00
dependabot[bot]
961c7434ac Bump phpstan/phpstan-doctrine from 2.0.6 to 2.0.10
Bumps [phpstan/phpstan-doctrine](https://github.com/phpstan/phpstan-doctrine) from 2.0.6 to 2.0.10.
- [Release notes](https://github.com/phpstan/phpstan-doctrine/releases)
- [Commits](https://github.com/phpstan/phpstan-doctrine/compare/2.0.6...2.0.10)

---
updated-dependencies:
- dependency-name: phpstan/phpstan-doctrine
  dependency-version: 2.0.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-21 08:04:57 +02:00
ee1a15ee78 New pipeline
Some checks failed
CI / Tests (push) Failing after 36s
CI / Build and deploy to ${{ startsWith(github.ref, 'refs/tags/') && 'production' || (github.ref == 'refs/heads/main' && 'acceptance' || '') }} (push) Has been skipped
2025-10-21 00:06:23 +02:00
253729abc0 Add completions 2025-10-20 21:41:46 +02:00
b66d2f9e86 Refactor entities and codebase for native property usage
Some checks failed
CI / Tests (push) Failing after 35s
CI / Deploy (push) Has been skipped
- Replaced getters/setters with direct property access across entities and repositories.
- Added and configured `martin-georgiev/postgresql-for-doctrine` for PostgreSQL enhancements.
- Updated Doctrine configuration with types, mappings, and JSONB query functions.
- Removed unused `EliminationService` and related YAML configurations.
2025-10-08 20:50:33 +02:00
ab187a28b9 Add Symfony container support for Rector configuration
- Introduced `tests/symfony-container.php` for bootstrapping Symfony.
  - Updated `rector.php` with new container PHP path and kernel modifications.
  - Registered Symfony routes provider service in Rector.
2025-10-08 20:50:33 +02:00
ca460cca7f - Refactor ORM annotations across entities for consistency.
- Adjusted migrations to align with refactored ORM annotations.
- Added new PHPStan and PHP-CS-Fixer configurations, including stricter rules.
- Introduced `tests/object-manager.php` to improve test environment setup.
2025-10-04 12:40:45 +02:00
3e39550c90 Remove EasyAdmin integration
- Removed EasyAdmin controllers and configurations.
- Uninstalled `easycorp/easyadmin-bundle` and related dependencies.
- Cleaned up all associated routes, bundles, and vendor references.
2025-10-03 22:37:45 +02:00
84 changed files with 1122 additions and 1759 deletions

View File

@@ -13,6 +13,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
permissions:
contents: read
packages: write
jobs: jobs:
tests: tests:
name: Tests name: Tests
@@ -57,17 +61,62 @@ jobs:
run: docker compose exec -T php vendor/bin/phpunit run: docker compose exec -T php vendor/bin/phpunit
- name: Doctrine Schema Validator - name: Doctrine Schema Validator
run: docker compose exec -T php bin/console -e test doctrine:schema:validate run: docker compose exec -T php bin/console -e test doctrine:schema:validate
deploy:
name: Deploy build-deploy:
name: Build and deploy to ${{ startsWith(github.ref, 'refs/tags/') && 'production' || (github.ref == 'refs/heads/main' && 'acceptance' || '') }}
environment: environment:
name: ${{ startsWith(github.ref, 'refs/tags/') && 'production' || (github.ref == 'refs/heads/main' && 'acceptance' || '') }} name: ${{ startsWith(github.ref, 'refs/tags/') && 'production' || (github.ref == 'refs/heads/main' && 'acceptance' || '') }}
url: ${{ vars.URL }} url: ${{ vars.URL }}
needs: tests needs: tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/') if: (github.ref == 'refs/heads/main' && false) || startsWith(github.ref, 'refs/tags/')
steps: steps:
- shell: bash - name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
run: |
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
TAG="${GITHUB_REF#refs/tags/}"
{
echo "tag=$TAG"
echo "full_name=ghcr.io/${REPO_LOWER}:$TAG"
} >> "$GITHUB_OUTPUT"
else
SHORT_SHA=$(git rev-parse --short HEAD)
{
echo "tag=$SHORT_SHA"
echo "full_name=ghcr.io/${REPO_LOWER}:$SHORT_SHA"
} >> "$GITHUB_OUTPUT"
fi
- name: Build and Push Docker images
uses: docker/bake-action@v5
with:
pull: true
push: true
files: |
compose.yaml
compose.build.yaml
set: |
*.cache-from=type=gha,scope=${{github.ref}}
*.cache-from=type=gha,scope=refs/heads/main
*.cache-to=type=gha,scope=${{github.ref}},mode=max
*.tags=${{ steps.meta.outputs.full_name }}
- name: Trigger Portainer Deployment
shell: bash
env: env:
PORTAINER_WEBHOOK: ${{secrets.PORTAINER_WEBHOOK}} PORTAINER_WEBHOOK: ${{secrets.PORTAINER_WEBHOOK}}
run: | run: |
curl -v -X POST "$PORTAINER_WEBHOOK" curl -v -X POST "$PORTAINER_WEBHOOK"?IMAGE_TAG=${{steps.meta.outputs.tag}} --fail-with-body

View File

@@ -116,15 +116,12 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/phpstan-safe-rule" /> <excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/phpstan-safe-rule" />
<excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/safe" /> <excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/safe" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" /> <excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
<excludeFolder url="file://$MODULE_DIR$/vendor/easycorp/easyadmin-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/intl" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/intl" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mime" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mime" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/ux-twig-component" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/validator" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/validator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/extra-bundle" /> <excludeFolder url="file://$MODULE_DIR$/vendor/twig/extra-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/html-extra" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/data-fixtures" /> <excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/data-fixtures" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-fixtures-bundle" /> <excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/vincentlanglet/twig-cs-fixer" /> <excludeFolder url="file://$MODULE_DIR$/vendor/vincentlanglet/twig-cs-fixer" />
@@ -167,6 +164,7 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/ux-turbo" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/ux-turbo" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-uuid" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-uuid" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/brevo-mailer" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/brevo-mailer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/martin-georgiev/postgresql-for-doctrine" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />

8
.idea/php.xml generated
View File

@@ -68,7 +68,6 @@
<path value="$PROJECT_DIR$/vendor/symfony/form" /> <path value="$PROJECT_DIR$/vendor/symfony/form" />
<path value="$PROJECT_DIR$/vendor/runtime/frankenphp-symfony" /> <path value="$PROJECT_DIR$/vendor/runtime/frankenphp-symfony" />
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" /> <path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
<path value="$PROJECT_DIR$/vendor/symfony/cache" /> <path value="$PROJECT_DIR$/vendor/symfony/cache" />
<path value="$PROJECT_DIR$/vendor/symfony/serializer" /> <path value="$PROJECT_DIR$/vendor/symfony/serializer" />
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" /> <path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
@@ -78,7 +77,6 @@
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" /> <path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
<path value="$PROJECT_DIR$/vendor/symfony/config" /> <path value="$PROJECT_DIR$/vendor/symfony/config" />
<path value="$PROJECT_DIR$/vendor/symfony/security-http" /> <path value="$PROJECT_DIR$/vendor/symfony/security-http" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" /> <path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" /> <path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/symfony/runtime" /> <path value="$PROJECT_DIR$/vendor/symfony/runtime" />
@@ -124,7 +122,6 @@
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" /> <path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" /> <path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/console" /> <path value="$PROJECT_DIR$/vendor/symfony/console" />
<path value="$PROJECT_DIR$/vendor/symfony/ux-twig-component" />
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" /> <path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
<path value="$PROJECT_DIR$/vendor/symfony/process" /> <path value="$PROJECT_DIR$/vendor/symfony/process" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" /> <path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
@@ -142,7 +139,6 @@
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" /> <path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
<path value="$PROJECT_DIR$/vendor/doctrine/orm" /> <path value="$PROJECT_DIR$/vendor/doctrine/orm" />
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" /> <path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
<path value="$PROJECT_DIR$/vendor/easycorp/easyadmin-bundle" />
<path value="$PROJECT_DIR$/vendor/evenement/evenement" /> <path value="$PROJECT_DIR$/vendor/evenement/evenement" />
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" /> <path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" /> <path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
@@ -191,13 +187,15 @@
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" /> <path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" /> <path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" /> <path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/vendor/twig/html-extra" />
<path value="$PROJECT_DIR$/vendor/twig/twig" /> <path value="$PROJECT_DIR$/vendor/twig/twig" />
<path value="$PROJECT_DIR$/vendor/symfony/ux-turbo" /> <path value="$PROJECT_DIR$/vendor/symfony/ux-turbo" />
<path value="$PROJECT_DIR$/vendor/symfony/stimulus-bundle" /> <path value="$PROJECT_DIR$/vendor/symfony/stimulus-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" /> <path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php84" /> <path value="$PROJECT_DIR$/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/vendor/symfony/brevo-mailer" /> <path value="$PROJECT_DIR$/vendor/symfony/brevo-mailer" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
<path value="$PROJECT_DIR$/vendor/martin-georgiev/postgresql-for-doctrine" />
</include_path> </include_path>
</component> </component>
<component name="PhpInterpreters"> <component name="PhpInterpreters">

View File

@@ -5,13 +5,13 @@ use PhpCsFixer\Config;
use PhpCsFixer\Finder; use PhpCsFixer\Finder;
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory; use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
$finder = (new Finder()) $finder = new Finder()
->in(__DIR__) ->in(__DIR__)
->exclude('var') ->exclude('var')
->exclude('bin') ->exclude('bin')
; ;
return (new Config()) return new Config()
->setParallelConfig(ParallelConfigFactory::detect()) ->setParallelConfig(ParallelConfigFactory::detect())
->setRules([ ->setRules([
'@Symfony' => true, '@Symfony' => true,
@@ -30,8 +30,9 @@ return (new Config())
'single_line_empty_body' => true, 'single_line_empty_body' => true,
'strict_comparison' => true, 'strict_comparison' => true,
'strict_param' => true, 'strict_param' => true,
'ordered_attributes' => true,
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'array_destructuring', 'arrays', 'match', 'parameters']], 'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'array_destructuring', 'arrays', 'match', 'parameters']],
]) ])
->setRiskyAllowed(true) ->setRiskyAllowed(true)
->setFinder($finder) ->setFinder($finder)

View File

@@ -32,7 +32,7 @@ RUN set -eux; \
opcache \ opcache \
zip \ zip \
gd \ gd \
excimer-1.2.3 \ excimer \
; ;
# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser # https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
@@ -60,6 +60,14 @@ FROM frankenphp_base AS frankenphp_dev
ENV APP_ENV=dev XDEBUG_MODE=off ENV APP_ENV=dev XDEBUG_MODE=off
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends \
bash-completion \
&& rm -rf /var/lib/apt/lists/*
COPY --link frankenphp/console-complete.bash /usr/share/bash-completion/completions/console
COPY --link frankenphp/composer-complete.bash /usr/share/bash-completion/completions/composer
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
RUN set -eux; \ RUN set -eux; \
@@ -76,6 +84,8 @@ CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--watch" ]
# Prod FrankenPHP image # Prod FrankenPHP image
FROM frankenphp_base AS frankenphp_prod FROM frankenphp_base AS frankenphp_prod
RUN rm -rf /var/lib/apt/lists/*
ENV APP_ENV=prod ENV APP_ENV=prod
ENV FRANKENPHP_CONFIG="import worker.Caddyfile" ENV FRANKENPHP_CONFIG="import worker.Caddyfile"

View File

@@ -1,8 +1,8 @@
up: up *args:
docker compose up -d docker compose up -d {{ args }}
down *args: down *args:
docker compose down {{ args }} --remove-orphans docker compose down --remove-orphans {{ args }}
stop: stop:
docker compose stop docker compose stop

5
compose.build.yaml Normal file
View File

@@ -0,0 +1,5 @@
services:
php:
build:
context: .
target: frankenphp_prod

View File

@@ -15,7 +15,6 @@ services:
# See https://xdebug.org/docs/all_settings#mode # See https://xdebug.org/docs/all_settings#mode
XDEBUG_MODE: "${XDEBUG_MODE:-off}" XDEBUG_MODE: "${XDEBUG_MODE:-off}"
MAILER_DSN: "smtp://mailer:1025" MAILER_DSN: "smtp://mailer:1025"
PHP_CS_FIXER_IGNORE_ENV: 1
extra_hosts: extra_hosts:
# Ensure that host.docker.internal is correctly defined on Linux # Ensure that host.docker.internal is correctly defined on Linux
- host.docker.internal:host-gateway - host.docker.internal:host-gateway

View File

@@ -1,9 +1,7 @@
# Production environment override # Production environment override
services: services:
php: php:
build: image: ghcr.io/marijndoeve/tijdvoordetest:${IMAGE_TAG}
context: .
target: frankenphp_prod
environment: environment:
APP_SECRET: ${APP_SECRET} APP_SECRET: ${APP_SECRET}
MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}

View File

@@ -13,7 +13,7 @@
"doctrine/doctrine-bundle": "^2.16.2", "doctrine/doctrine-bundle": "^2.16.2",
"doctrine/doctrine-migrations-bundle": "^3.4.2", "doctrine/doctrine-migrations-bundle": "^3.4.2",
"doctrine/orm": "^3.5.2", "doctrine/orm": "^3.5.2",
"easycorp/easyadmin-bundle": "^4.25.1", "martin-georgiev/postgresql-for-doctrine": "^3.5",
"phpdocumentor/reflection-docblock": "^5.6.3", "phpdocumentor/reflection-docblock": "^5.6.3",
"phpoffice/phpspreadsheet": "^5.1", "phpoffice/phpspreadsheet": "^5.1",
"phpstan/phpdoc-parser": "^2.3", "phpstan/phpdoc-parser": "^2.3",
@@ -34,9 +34,11 @@
"symfony/security-bundle": "7.3.*", "symfony/security-bundle": "7.3.*",
"symfony/security-csrf": "7.3.*", "symfony/security-csrf": "7.3.*",
"symfony/serializer": "7.3.*", "symfony/serializer": "7.3.*",
"symfony/translation": "7.3.*",
"symfony/twig-bundle": "7.3.*", "symfony/twig-bundle": "7.3.*",
"symfony/uid": "7.3.*", "symfony/uid": "7.3.*",
"symfony/ux-turbo": "^2.30.0", "symfony/ux-turbo": "^2.30.0",
"symfony/validator": "7.3.*",
"symfony/yaml": "7.3.*", "symfony/yaml": "7.3.*",
"symfonycasts/sass-bundle": "^0.8.3", "symfonycasts/sass-bundle": "^0.8.3",
"symfonycasts/verify-email-bundle": "^1.17.4", "symfonycasts/verify-email-bundle": "^1.17.4",
@@ -49,11 +51,11 @@
"doctrine/doctrine-fixtures-bundle": "^4.1", "doctrine/doctrine-fixtures-bundle": "^4.1",
"friendsofphp/php-cs-fixer": "^3.88.2", "friendsofphp/php-cs-fixer": "^3.88.2",
"phpstan/extension-installer": "^1.4.3", "phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.1.29", "phpstan/phpstan": "^2.1.30",
"phpstan/phpstan-doctrine": "^2.0.6", "phpstan/phpstan-doctrine": "^2.0.6",
"phpstan/phpstan-phpunit": "^2.0.7", "phpstan/phpstan-phpunit": "^2.0.7",
"phpstan/phpstan-symfony": "^2.0.8", "phpstan/phpstan-symfony": "^2.0.8",
"phpunit/phpunit": "^12.3.15", "phpunit/phpunit": "^12.4.0",
"rector/rector": "^2.1.7", "rector/rector": "^2.1.7",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"symfony/browser-kit": "7.3.*", "symfony/browser-kit": "7.3.*",

522
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "b0035e3726f72e1549e382ed9b170ae3", "content-hash": "d9b29aa569964f735b9f65fe5e9a59f9",
"packages": [ "packages": [
{ {
"name": "composer/pcre", "name": "composer/pcre",
@@ -250,16 +250,16 @@
}, },
{ {
"name": "doctrine/dbal", "name": "doctrine/dbal",
"version": "4.3.3", "version": "4.3.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/dbal.git", "url": "https://github.com/doctrine/dbal.git",
"reference": "231959669bb2173194c95636eae7f1b41b2a8b19" "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/231959669bb2173194c95636eae7f1b41b2a8b19", "url": "https://api.github.com/repos/doctrine/dbal/zipball/1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc",
"reference": "231959669bb2173194c95636eae7f1b41b2a8b19", "reference": "1a2fbd0e93b8dec7c3d1ac2b6396a7b929b130dc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -269,15 +269,15 @@
"psr/log": "^1|^2|^3" "psr/log": "^1|^2|^3"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "13.0.1", "doctrine/coding-standard": "14.0.0",
"fig/log-test": "^1", "fig/log-test": "^1",
"jetbrains/phpstorm-stubs": "2023.2", "jetbrains/phpstorm-stubs": "2023.2",
"phpstan/phpstan": "2.1.22", "phpstan/phpstan": "2.1.30",
"phpstan/phpstan-phpunit": "2.0.6", "phpstan/phpstan-phpunit": "2.0.7",
"phpstan/phpstan-strict-rules": "^2", "phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "11.5.23", "phpunit/phpunit": "11.5.23",
"slevomat/coding-standard": "8.16.2", "slevomat/coding-standard": "8.24.0",
"squizlabs/php_codesniffer": "3.13.1", "squizlabs/php_codesniffer": "4.0.0",
"symfony/cache": "^6.3.8|^7.0", "symfony/cache": "^6.3.8|^7.0",
"symfony/console": "^5.4|^6.3|^7.0" "symfony/console": "^5.4|^6.3|^7.0"
}, },
@@ -336,7 +336,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/dbal/issues", "issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/4.3.3" "source": "https://github.com/doctrine/dbal/tree/4.3.4"
}, },
"funding": [ "funding": [
{ {
@@ -352,7 +352,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-09-04T23:52:42+00:00" "time": "2025-10-09T09:11:36+00:00"
}, },
{ {
"name": "doctrine/deprecations", "name": "doctrine/deprecations",
@@ -404,20 +404,21 @@
}, },
{ {
"name": "doctrine/doctrine-bundle", "name": "doctrine/doctrine-bundle",
"version": "2.16.2", "version": "2.18.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/DoctrineBundle.git", "url": "https://github.com/doctrine/DoctrineBundle.git",
"reference": "1c10de0fe995f01eca6b073d1c2549ef0b603a7f" "reference": "cd5d4da6a5f7cf3d8708e17211234657b5eb4e95"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/1c10de0fe995f01eca6b073d1c2549ef0b603a7f", "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/cd5d4da6a5f7cf3d8708e17211234657b5eb4e95",
"reference": "1c10de0fe995f01eca6b073d1c2549ef0b603a7f", "reference": "cd5d4da6a5f7cf3d8708e17211234657b5eb4e95",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/dbal": "^3.7.0 || ^4.0", "doctrine/dbal": "^3.7.0 || ^4.0",
"doctrine/deprecations": "^1.0",
"doctrine/persistence": "^3.1 || ^4", "doctrine/persistence": "^3.1 || ^4",
"doctrine/sql-formatter": "^1.0.1", "doctrine/sql-formatter": "^1.0.1",
"php": "^8.1", "php": "^8.1",
@@ -425,7 +426,6 @@
"symfony/config": "^6.4 || ^7.0", "symfony/config": "^6.4 || ^7.0",
"symfony/console": "^6.4 || ^7.0", "symfony/console": "^6.4 || ^7.0",
"symfony/dependency-injection": "^6.4 || ^7.0", "symfony/dependency-injection": "^6.4 || ^7.0",
"symfony/deprecation-contracts": "^2.1 || ^3",
"symfony/doctrine-bridge": "^6.4.3 || ^7.0.3", "symfony/doctrine-bridge": "^6.4.3 || ^7.0.3",
"symfony/framework-bundle": "^6.4 || ^7.0", "symfony/framework-bundle": "^6.4 || ^7.0",
"symfony/service-contracts": "^2.5 || ^3" "symfony/service-contracts": "^2.5 || ^3"
@@ -440,14 +440,13 @@
"require-dev": { "require-dev": {
"doctrine/annotations": "^1 || ^2", "doctrine/annotations": "^1 || ^2",
"doctrine/cache": "^1.11 || ^2.0", "doctrine/cache": "^1.11 || ^2.0",
"doctrine/coding-standard": "^13", "doctrine/coding-standard": "^14",
"doctrine/deprecations": "^1.0",
"doctrine/orm": "^2.17 || ^3.1", "doctrine/orm": "^2.17 || ^3.1",
"friendsofphp/proxy-manager-lts": "^1.0", "friendsofphp/proxy-manager-lts": "^1.0",
"phpstan/phpstan": "2.1.1", "phpstan/phpstan": "2.1.1",
"phpstan/phpstan-phpunit": "2.0.3", "phpstan/phpstan-phpunit": "2.0.3",
"phpstan/phpstan-strict-rules": "^2", "phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "^10.5.53", "phpunit/phpunit": "^10.5.53 || ^12.3.10",
"psr/log": "^1.1.4 || ^2.0 || ^3.0", "psr/log": "^1.1.4 || ^2.0 || ^3.0",
"symfony/doctrine-messenger": "^6.4 || ^7.0", "symfony/doctrine-messenger": "^6.4 || ^7.0",
"symfony/expression-language": "^6.4 || ^7.0", "symfony/expression-language": "^6.4 || ^7.0",
@@ -461,7 +460,7 @@
"symfony/var-exporter": "^6.4.1 || ^7.0.1", "symfony/var-exporter": "^6.4.1 || ^7.0.1",
"symfony/web-profiler-bundle": "^6.4 || ^7.0", "symfony/web-profiler-bundle": "^6.4 || ^7.0",
"symfony/yaml": "^6.4 || ^7.0", "symfony/yaml": "^6.4 || ^7.0",
"twig/twig": "^2.13 || ^3.0.4" "twig/twig": "^2.14.7 || ^3.0.4"
}, },
"suggest": { "suggest": {
"doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.",
@@ -506,7 +505,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/DoctrineBundle/issues", "issues": "https://github.com/doctrine/DoctrineBundle/issues",
"source": "https://github.com/doctrine/DoctrineBundle/tree/2.16.2" "source": "https://github.com/doctrine/DoctrineBundle/tree/2.18.0"
}, },
"funding": [ "funding": [
{ {
@@ -522,7 +521,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-09-10T19:14:48+00:00" "time": "2025-10-11T04:43:27+00:00"
}, },
{ {
"name": "doctrine/doctrine-migrations-bundle", "name": "doctrine/doctrine-migrations-bundle",
@@ -1132,16 +1131,16 @@
}, },
{ {
"name": "doctrine/persistence", "name": "doctrine/persistence",
"version": "4.1.0", "version": "4.1.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/persistence.git", "url": "https://github.com/doctrine/persistence.git",
"reference": "dcbdfe4b211ae09478e192289cae7ab0987b29a4" "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/persistence/zipball/dcbdfe4b211ae09478e192289cae7ab0987b29a4", "url": "https://api.github.com/repos/doctrine/persistence/zipball/b9c49ad3558bb77ef973f4e173f2e9c2eca9be09",
"reference": "dcbdfe4b211ae09478e192289cae7ab0987b29a4", "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1150,11 +1149,11 @@
"psr/cache": "^1.0 || ^2.0 || ^3.0" "psr/cache": "^1.0 || ^2.0 || ^3.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^12", "doctrine/coding-standard": "^14",
"phpstan/phpstan": "1.12.7", "phpstan/phpstan": "2.1.30",
"phpstan/phpstan-phpunit": "^1", "phpstan/phpstan-phpunit": "^2",
"phpstan/phpstan-strict-rules": "^1.6", "phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "^9.6", "phpunit/phpunit": "^10.5.58 || ^12",
"symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0", "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0",
"symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0" "symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0"
}, },
@@ -1205,7 +1204,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/persistence/issues", "issues": "https://github.com/doctrine/persistence/issues",
"source": "https://github.com/doctrine/persistence/tree/4.1.0" "source": "https://github.com/doctrine/persistence/tree/4.1.1"
}, },
"funding": [ "funding": [
{ {
@@ -1221,7 +1220,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-08-21T16:00:31+00:00" "time": "2025-10-16T20:13:18+00:00"
}, },
{ {
"name": "doctrine/sql-formatter", "name": "doctrine/sql-formatter",
@@ -1278,108 +1277,6 @@
}, },
"time": "2025-01-24T11:45:48+00:00" "time": "2025-01-24T11:45:48+00:00"
}, },
{
"name": "easycorp/easyadmin-bundle",
"version": "v4.25.1",
"source": {
"type": "git",
"url": "https://github.com/EasyCorp/EasyAdminBundle.git",
"reference": "954e88c9cb004c3861b6ec6ae52241642995fb86"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/EasyCorp/EasyAdminBundle/zipball/954e88c9cb004c3861b6ec6ae52241642995fb86",
"reference": "954e88c9cb004c3861b6ec6ae52241642995fb86",
"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-bridge": "^5.4.48|^6.4.16|^7.1.9",
"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.20"
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4|3.5.x-dev",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0",
"phpstan/phpstan-symfony": "^2.0",
"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.25.1"
},
"funding": [
{
"url": "https://github.com/javiereguiluz",
"type": "github"
}
],
"time": "2025-09-10T05:00:12+00:00"
},
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
"version": "4.0.4", "version": "4.0.4",
@@ -1808,6 +1705,90 @@
}, },
"time": "2022-12-02T22:17:43+00:00" "time": "2022-12-02T22:17:43+00:00"
}, },
{
"name": "martin-georgiev/postgresql-for-doctrine",
"version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/martin-georgiev/postgresql-for-doctrine.git",
"reference": "5d1621e48edd7c7306cf2b9e73e374727867d6af"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/martin-georgiev/postgresql-for-doctrine/zipball/5d1621e48edd7c7306cf2b9e73e374727867d6af",
"reference": "5d1621e48edd7c7306cf2b9e73e374727867d6af",
"shasum": ""
},
"require": {
"doctrine/dbal": "~2.10||~3.0||~4.0",
"ext-ctype": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": "^8.1"
},
"require-dev": {
"deptrac/deptrac": "^4.0",
"doctrine/orm": "~2.14||~3.0",
"ekino/phpstan-banned-code": "^3.0",
"friendsofphp/php-cs-fixer": "^3.87.1",
"phpstan/phpstan": "^2.1.22",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-doctrine": "^2.0.4",
"phpstan/phpstan-phpunit": "^2.0.7",
"phpunit/phpunit": "^10.5.53",
"rector/rector": "^2.1.5",
"symfony/cache": "^6.4||^7.0"
},
"suggest": {
"doctrine/orm": "~2.14||~3.0",
"php": "^8.3"
},
"type": "library",
"autoload": {
"psr-4": {
"MartinGeorgiev\\": "src/MartinGeorgiev/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Martin Georgiev",
"email": "martin.georgiev@gmail.com",
"role": "author"
}
],
"description": "Adds PostgreSQL enhancements to Doctrine. Provides support for JSON, JSONB and some array data types. Provides functions, operators and common expressions used when working with JSON data, arrays and features related to text search.",
"keywords": [
"array data types",
"dbal",
"doctrine",
"json",
"jsonb",
"martin georgiev",
"postgres",
"postgresql",
"text search",
"tsvector"
],
"support": {
"issues": "https://github.com/martin-georgiev/postgresql-for-doctrine/issues",
"source": "https://github.com/martin-georgiev/postgresql-for-doctrine/tree/v3.5.1"
},
"funding": [
{
"url": "https://github.com/sponsors/martin-georgiev",
"type": "custom"
},
{
"url": "https://github.com/martin-georgiev",
"type": "github"
}
],
"time": "2025-09-12T10:54:26+00:00"
},
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
"version": "2.2.0", "version": "2.2.0",
@@ -7701,93 +7682,6 @@
], ],
"time": "2025-08-27T15:25:48+00:00" "time": "2025-08-27T15:25:48+00:00"
}, },
{
"name": "symfony/ux-twig-component",
"version": "v2.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/ux-twig-component.git",
"reference": "2f445efda4d4400d4d1911ddf9710c366f339614"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/2f445efda4d4400d4d1911ddf9710c366f339614",
"reference": "2f445efda4d4400d4d1911ddf9710c366f339614",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/dependency-injection": "^5.4|^6.0|^7.0|^8.0",
"symfony/deprecation-contracts": "^2.2|^3.0",
"symfony/event-dispatcher": "^5.4|^6.0|^7.0|^8.0",
"symfony/property-access": "^5.4|^6.0|^7.0|^8.0",
"twig/twig": "^3.10.3"
},
"conflict": {
"symfony/config": "<5.4.0"
},
"require-dev": {
"symfony/console": "^5.4|^6.0|^7.0|^8.0",
"symfony/css-selector": "^5.4|^6.0|^7.0|^8.0",
"symfony/dom-crawler": "^5.4|^6.0|^7.0|^8.0",
"symfony/framework-bundle": "^5.4|^6.0|^7.0|^8.0",
"symfony/phpunit-bridge": "^6.0|^7.0|^8.0",
"symfony/stimulus-bundle": "^2.9.1",
"symfony/twig-bundle": "^5.4|^6.0|^7.0|^8.0",
"symfony/webpack-encore-bundle": "^1.15|^2.3.0"
},
"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.30.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-08-27T15:25:48+00:00"
},
{ {
"name": "symfony/validator", "name": "symfony/validator",
"version": "v7.3.4", "version": "v7.3.4",
@@ -8447,74 +8341,6 @@
], ],
"time": "2025-02-19T14:29:33+00:00" "time": "2025-02-19T14:29:33+00:00"
}, },
{
"name": "twig/html-extra",
"version": "v3.21.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/html-extra.git",
"reference": "5442dd707601c83b8cd4233e37bb10ab8489a90f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/html-extra/zipball/5442dd707601c83b8cd4233e37bb10ab8489a90f",
"reference": "5442dd707601c83b8cd4233e37bb10ab8489a90f",
"shasum": ""
},
"require": {
"php": ">=8.1.0",
"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.21.0"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2025-02-19T14:29:33+00:00"
},
{ {
"name": "twig/intl-extra", "name": "twig/intl-extra",
"version": "v3.21.0", "version": "v3.21.0",
@@ -8850,16 +8676,16 @@
}, },
{ {
"name": "doctrine/data-fixtures", "name": "doctrine/data-fixtures",
"version": "2.1.0", "version": "2.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/data-fixtures.git", "url": "https://github.com/doctrine/data-fixtures.git",
"reference": "f161e20f04ba5440a09330e156b40f04dd70d47f" "reference": "7a615ba135e45d67674bb623d90f34f6c7b6bd97"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/f161e20f04ba5440a09330e156b40f04dd70d47f", "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/7a615ba135e45d67674bb623d90f34f6c7b6bd97",
"reference": "f161e20f04ba5440a09330e156b40f04dd70d47f", "reference": "7a615ba135e45d67674bb623d90f34f6c7b6bd97",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -8873,14 +8699,14 @@
"doctrine/phpcr-odm": "<1.3.0" "doctrine/phpcr-odm": "<1.3.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^13", "doctrine/coding-standard": "^14",
"doctrine/dbal": "^3.5 || ^4", "doctrine/dbal": "^3.5 || ^4",
"doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0",
"doctrine/orm": "^2.14 || ^3", "doctrine/orm": "^2.14 || ^3",
"ext-sqlite3": "*", "ext-sqlite3": "*",
"fig/log-test": "^1", "fig/log-test": "^1",
"phpstan/phpstan": "2.1.17", "phpstan/phpstan": "2.1.31",
"phpunit/phpunit": "10.5.45", "phpunit/phpunit": "10.5.45 || 12.4.0",
"symfony/cache": "^6.4 || ^7", "symfony/cache": "^6.4 || ^7",
"symfony/var-exporter": "^6.4 || ^7" "symfony/var-exporter": "^6.4 || ^7"
}, },
@@ -8913,7 +8739,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/data-fixtures/issues", "issues": "https://github.com/doctrine/data-fixtures/issues",
"source": "https://github.com/doctrine/data-fixtures/tree/2.1.0" "source": "https://github.com/doctrine/data-fixtures/tree/2.2.0"
}, },
"funding": [ "funding": [
{ {
@@ -8929,25 +8755,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-08T17:48:20+00:00" "time": "2025-10-17T20:06:20+00:00"
}, },
{ {
"name": "doctrine/doctrine-fixtures-bundle", "name": "doctrine/doctrine-fixtures-bundle",
"version": "4.1.0", "version": "4.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/DoctrineFixturesBundle.git", "url": "https://github.com/doctrine/DoctrineFixturesBundle.git",
"reference": "a06db6b81ff20a2980bf92063d80c013bb8b4b7c" "reference": "11941deb6f2899b91e8b8680b07ffe63899d864b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/a06db6b81ff20a2980bf92063d80c013bb8b4b7c", "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/11941deb6f2899b91e8b8680b07ffe63899d864b",
"reference": "a06db6b81ff20a2980bf92063d80c013bb8b4b7c", "reference": "11941deb6f2899b91e8b8680b07ffe63899d864b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/data-fixtures": "^2.0", "doctrine/data-fixtures": "^2.2",
"doctrine/doctrine-bundle": "^2.2", "doctrine/doctrine-bundle": "^2.2 || ^3.0",
"doctrine/orm": "^2.14.0 || ^3.0", "doctrine/orm": "^2.14.0 || ^3.0",
"doctrine/persistence": "^2.4 || ^3.0 || ^4.0", "doctrine/persistence": "^2.4 || ^3.0 || ^4.0",
"php": "^8.1", "php": "^8.1",
@@ -8963,7 +8789,7 @@
"doctrine/dbal": "< 3" "doctrine/dbal": "< 3"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "13.0.0", "doctrine/coding-standard": "14.0.0",
"phpstan/phpstan": "2.1.11", "phpstan/phpstan": "2.1.11",
"phpunit/phpunit": "^10.5.38 || 11.4.14" "phpunit/phpunit": "^10.5.38 || 11.4.14"
}, },
@@ -8999,7 +8825,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues", "issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues",
"source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/4.1.0" "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/4.3.0"
}, },
"funding": [ "funding": [
{ {
@@ -9015,7 +8841,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-03-26T10:56:26+00:00" "time": "2025-10-20T06:18:40+00:00"
}, },
{ {
"name": "evenement/evenement", "name": "evenement/evenement",
@@ -9582,16 +9408,11 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "2.1.29", "version": "2.1.31",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phar-composer-source.git",
"reference": "git"
},
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d618573eed4a1b6b75e37b2e0b65ac65c885d88e", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96",
"reference": "d618573eed4a1b6b75e37b2e0b65ac65c885d88e", "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9636,20 +9457,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-09-25T06:58:18+00:00" "time": "2025-10-10T14:14:11+00:00"
}, },
{ {
"name": "phpstan/phpstan-doctrine", "name": "phpstan/phpstan-doctrine",
"version": "2.0.6", "version": "2.0.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan-doctrine.git", "url": "https://github.com/phpstan/phpstan-doctrine.git",
"reference": "934f5734812341358fc41c44006b30fa00c785f0" "reference": "5eaf37b87288474051469aee9f937fc9d862f330"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/934f5734812341358fc41c44006b30fa00c785f0", "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/5eaf37b87288474051469aee9f937fc9d862f330",
"reference": "934f5734812341358fc41c44006b30fa00c785f0", "reference": "5eaf37b87288474051469aee9f937fc9d862f330",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9683,7 +9504,8 @@
"phpstan/phpstan-strict-rules": "^2.0", "phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^9.6.20", "phpunit/phpunit": "^9.6.20",
"ramsey/uuid": "^4.2", "ramsey/uuid": "^4.2",
"symfony/cache": "^5.4" "symfony/cache": "^5.4",
"symfony/uid": "^5.4 || ^6.4 || ^7.3"
}, },
"type": "phpstan-extension", "type": "phpstan-extension",
"extra": { "extra": {
@@ -9706,9 +9528,9 @@
"description": "Doctrine extensions for PHPStan", "description": "Doctrine extensions for PHPStan",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan-doctrine/issues", "issues": "https://github.com/phpstan/phpstan-doctrine/issues",
"source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.6" "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.10"
}, },
"time": "2025-09-10T07:06:30+00:00" "time": "2025-10-06T10:01:02+00:00"
}, },
{ {
"name": "phpstan/phpstan-phpunit", "name": "phpstan/phpstan-phpunit",
@@ -10170,16 +9992,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "12.3.15", "version": "12.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "b035ee2cd8ecad4091885b61017ebb1d80eb0e57" "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b035ee2cd8ecad4091885b61017ebb1d80eb0e57", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9",
"reference": "b035ee2cd8ecad4091885b61017ebb1d80eb0e57", "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10215,7 +10037,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "12.3-dev" "dev-main": "12.4-dev"
} }
}, },
"autoload": { "autoload": {
@@ -10247,7 +10069,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.15" "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -10271,7 +10093,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-09-28T12:10:54+00:00" "time": "2025-10-03T04:28:03+00:00"
}, },
{ {
"name": "react/cache", "name": "react/cache",
@@ -10801,21 +10623,21 @@
}, },
{ {
"name": "rector/rector", "name": "rector/rector",
"version": "2.1.7", "version": "2.2.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/rectorphp/rector.git", "url": "https://github.com/rectorphp/rector.git",
"reference": "c34cc07c4698f007a20dc5c99ff820089ae413ce" "reference": "d27f976a332a87b5d03553c2e6f04adbe5da034f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/c34cc07c4698f007a20dc5c99ff820089ae413ce", "url": "https://api.github.com/repos/rectorphp/rector/zipball/d27f976a332a87b5d03553c2e6f04adbe5da034f",
"reference": "c34cc07c4698f007a20dc5c99ff820089ae413ce", "reference": "d27f976a332a87b5d03553c2e6f04adbe5da034f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.4|^8.0", "php": "^7.4|^8.0",
"phpstan/phpstan": "^2.1.18" "phpstan/phpstan": "^2.1.26"
}, },
"conflict": { "conflict": {
"rector/rector-doctrine": "*", "rector/rector-doctrine": "*",
@@ -10849,7 +10671,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/rectorphp/rector/issues", "issues": "https://github.com/rectorphp/rector/issues",
"source": "https://github.com/rectorphp/rector/tree/2.1.7" "source": "https://github.com/rectorphp/rector/tree/2.2.3"
}, },
"funding": [ "funding": [
{ {
@@ -10857,7 +10679,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-09-10T11:13:58+00:00" "time": "2025-10-11T21:50:23+00:00"
}, },
{ {
"name": "roave/security-advisories", "name": "roave/security-advisories",
@@ -10865,12 +10687,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git", "url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "684ef27cdce62b6562f77a92dc76bdfb46542a2d" "reference": "60ac6a710b7b0527786041ba96200bd49aa8de7e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/684ef27cdce62b6562f77a92dc76bdfb46542a2d", "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/60ac6a710b7b0527786041ba96200bd49aa8de7e",
"reference": "684ef27cdce62b6562f77a92dc76bdfb46542a2d", "reference": "60ac6a710b7b0527786041ba96200bd49aa8de7e",
"shasum": "" "shasum": ""
}, },
"conflict": { "conflict": {
@@ -10912,10 +10734,10 @@
"athlon1600/php-proxy-app": "<=3", "athlon1600/php-proxy-app": "<=3",
"athlon1600/youtube-downloader": "<=4", "athlon1600/youtube-downloader": "<=4",
"austintoddj/canvas": "<=3.4.2", "austintoddj/canvas": "<=3.4.2",
"auth0/auth0-php": ">=8.0.0.0-beta1,<8.14", "auth0/auth0-php": ">=3.3,<=8.16",
"auth0/login": "<7.17", "auth0/login": "<=7.18",
"auth0/symfony": "<5.4", "auth0/symfony": "<=5.4.1",
"auth0/wordpress": "<5.3", "auth0/wordpress": "<=5.3",
"automad/automad": "<2.0.0.0-alpha5", "automad/automad": "<2.0.0.0-alpha5",
"automattic/jetpack": "<9.8", "automattic/jetpack": "<9.8",
"awesome-support/awesome-support": "<=6.0.7", "awesome-support/awesome-support": "<=6.0.7",
@@ -11032,7 +10854,7 @@
"doctrine/mongodb-odm": "<1.0.2", "doctrine/mongodb-odm": "<1.0.2",
"doctrine/mongodb-odm-bundle": "<3.0.1", "doctrine/mongodb-odm-bundle": "<3.0.1",
"doctrine/orm": ">=1,<1.2.4|>=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", "doctrine/orm": ">=1,<1.2.4|>=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4",
"dolibarr/dolibarr": "<=21.0.2", "dolibarr/dolibarr": "<21.0.3",
"dompdf/dompdf": "<2.0.4", "dompdf/dompdf": "<2.0.4",
"doublethreedigital/guest-entries": "<3.1.2", "doublethreedigital/guest-entries": "<3.1.2",
"drupal/admin_audit_trail": "<1.0.5", "drupal/admin_audit_trail": "<1.0.5",
@@ -11221,7 +11043,7 @@
"joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/archive": "<1.1.12|>=2,<2.0.1",
"joomla/database": ">=1,<2.2|>=3,<3.4", "joomla/database": ">=1,<2.2|>=3,<3.4",
"joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1",
"joomla/filter": "<1.4.4|>=2,<2.0.1", "joomla/filter": "<2.0.6|>=3,<3.0.5|==4",
"joomla/framework": "<1.5.7|>=2.5.4,<=3.8.12", "joomla/framework": "<1.5.7|>=2.5.4,<=3.8.12",
"joomla/input": ">=2,<2.0.2", "joomla/input": ">=2,<2.0.2",
"joomla/joomla-cms": "<3.9.12|>=4,<4.4.13|>=5,<5.2.6", "joomla/joomla-cms": "<3.9.12|>=4,<4.4.13|>=5,<5.2.6",
@@ -11639,7 +11461,7 @@
"thelia/thelia": ">=2.1,<2.1.3", "thelia/thelia": ">=2.1,<2.1.3",
"theonedemon/phpwhois": "<=4.2.5", "theonedemon/phpwhois": "<=4.2.5",
"thinkcmf/thinkcmf": "<6.0.8", "thinkcmf/thinkcmf": "<6.0.8",
"thorsten/phpmyfaq": "<=4.0.1", "thorsten/phpmyfaq": "<=4.0.1|>=4.0.7,<4.0.13",
"tikiwiki/tiki-manager": "<=17.1", "tikiwiki/tiki-manager": "<=17.1",
"timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1",
"tinymce/tinymce": "<7.2", "tinymce/tinymce": "<7.2",
@@ -11831,7 +11653,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-09-24T21:05:21+00:00" "time": "2025-10-03T15:05:30+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle; use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle;
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle; use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
use EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle;
use Sentry\SentryBundle\SentryBundle; use Sentry\SentryBundle\SentryBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\MakerBundle\MakerBundle; use Symfony\Bundle\MakerBundle\MakerBundle;
@@ -14,7 +13,6 @@ use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle; use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle;
use Symfony\UX\StimulusBundle\StimulusBundle; use Symfony\UX\StimulusBundle\StimulusBundle;
use Symfony\UX\Turbo\TurboBundle; use Symfony\UX\Turbo\TurboBundle;
use Symfony\UX\TwigComponent\TwigComponentBundle;
use SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle; use SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle;
use Symfonycasts\SassBundle\SymfonycastsSassBundle; use Symfonycasts\SassBundle\SymfonycastsSassBundle;
use Twig\Extra\TwigExtraBundle\TwigExtraBundle; use Twig\Extra\TwigExtraBundle\TwigExtraBundle;
@@ -28,8 +26,6 @@ return [
SecurityBundle::class => ['all' => true], SecurityBundle::class => ['all' => true],
WebProfilerBundle::class => ['dev' => true, 'test' => true], WebProfilerBundle::class => ['dev' => true, 'test' => true],
TwigExtraBundle::class => ['all' => true], TwigExtraBundle::class => ['all' => true],
TwigComponentBundle::class => ['all' => true],
EasyAdminBundle::class => ['all' => true],
DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
SymfonyCastsVerifyEmailBundle::class => ['all' => true], SymfonyCastsVerifyEmailBundle::class => ['all' => true],
SentryBundle::class => ['prod' => true], SentryBundle::class => ['prod' => true],

View File

@@ -8,9 +8,22 @@ doctrine:
profiling_collect_backtrace: '%kernel.debug%' profiling_collect_backtrace: '%kernel.debug%'
use_savepoints: true use_savepoints: true
types:
# JSON types
jsonb: MartinGeorgiev\Doctrine\DBAL\Types\Jsonb
'jsonb[]': MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray
tsrange: MartinGeorgiev\Doctrine\DBAL\Types\TsRange
mapping_types:
# JSON type mappings
jsonb: jsonb
'jsonb[]': 'jsonb[]'
_jsonb: 'jsonb[]'
tsrange: tsrange
orm: orm:
auto_generate_proxy_classes: true auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true enable_native_lazy_objects: true
report_fields_where_declared: true report_fields_where_declared: true
validate_xml_mapping: true validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware

View File

@@ -1,5 +0,0 @@
twig_component:
anonymous_template_directory: 'components/'
defaults:
# Namespace & directory for components
Tvdt\Twig\Components\: 'components/'

View File

@@ -1,4 +0,0 @@
framework:
uid:
default_uuid_version: 7
time_based_uuid_version: 7

View File

@@ -1,3 +0,0 @@
easyadmin:
resource: .
type: easyadmin.routes

View File

@@ -0,0 +1,84 @@
# This file is part of the Symfony package.
#
# (c) Fabien Potencier <fabien@symfony.com>
#
# For the full copyright and license information, please view
# https://symfony.com/doc/current/contributing/code/license.html
_sf_composer() {
# Use newline as only separator to allow space in completion values
local IFS=$'\n'
local sf_cmd="${COMP_WORDS[0]}"
# for an alias, get the real script behind it
sf_cmd_type=$(type -t $sf_cmd)
if [[ $sf_cmd_type == "alias" ]]; then
sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/")
elif [[ $sf_cmd_type == "file" ]]; then
sf_cmd=$(type -p $sf_cmd)
fi
if [[ $sf_cmd_type != "function" && ! -x $sf_cmd ]]; then
return 1
fi
local cur prev words cword
_get_comp_words_by_ref -n := cur prev words cword
local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-S2.8.11")
for w in ${words[@]}; do
w=$(printf -- '%b' "$w")
# remove quotes from typed values
quote="${w:0:1}"
if [ "$quote" == \' ]; then
w="${w%\'}"
w="${w#\'}"
elif [ "$quote" == \" ]; then
w="${w%\"}"
w="${w#\"}"
fi
# empty values are ignored
if [ ! -z "$w" ]; then
completecmd+=("-i$w")
fi
done
local sfcomplete
if sfcomplete=$(${completecmd[@]} 2>&1); then
local quote suggestions
quote=${cur:0:1}
# Use single quotes by default if suggestions contains backslash (FQCN)
if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then
quote=\'
fi
if [ "$quote" == \' ]; then
# single quotes: no additional escaping (does not accept ' in values)
suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done)
elif [ "$quote" == \" ]; then
# double quotes: double escaping for \ $ ` "
suggestions=$(for s in $sfcomplete; do
s=${s//\\/\\\\}
s=${s//\$/\\\$}
s=${s//\`/\\\`}
s=${s//\"/\\\"}
printf $'%q%q%q\n' "$quote" "$s" "$quote";
done)
else
# no quotes: double escaping
suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done)
fi
COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur")))
__ltrim_colon_completions "$cur"
else
if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then
>&2 echo
>&2 echo $sfcomplete
fi
return 1
fi
}
complete -F _sf_composer composer

View File

@@ -0,0 +1,94 @@
# This file is part of the Symfony package.
#
# (c) Fabien Potencier <fabien@symfony.com>
#
# For the full copyright and license information, please view
# https://symfony.com/doc/current/contributing/code/license.html
_sf_console() {
# Use the default completion for shell redirect operators.
for w in '>' '>>' '&>' '<'; do
if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then
compopt -o filenames
COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}"))
return 0
fi
done
# Use newline as only separator to allow space in completion values
local IFS=$'\n'
local sf_cmd="${COMP_WORDS[0]}"
# for an alias, get the real script behind it
sf_cmd_type=$(type -t $sf_cmd)
if [[ $sf_cmd_type == "alias" ]]; then
sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/")
elif [[ $sf_cmd_type == "file" ]]; then
sf_cmd=$(type -p $sf_cmd)
fi
if [[ $sf_cmd_type != "function" && ! -x $sf_cmd ]]; then
return 1
fi
local cur prev words cword
_get_comp_words_by_ref -n := cur prev words cword
local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-a1")
for w in ${words[@]}; do
w="${w//\\\\/\\}"
# remove quotes from typed values
quote="${w:0:1}"
if [ "$quote" == \' ]; then
w="${w%\'}"
w="${w#\'}"
elif [ "$quote" == \" ]; then
w="${w%\"}"
w="${w#\"}"
fi
# empty values are ignored
if [ ! -z "$w" ]; then
completecmd+=("-i$w")
fi
done
local sfcomplete
if sfcomplete=$(${completecmd[@]} 2>&1); then
local quote suggestions
quote=${cur:0:1}
# Use single quotes by default if suggestions contains backslash (FQCN)
if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then
quote=\'
fi
if [ "$quote" == \' ]; then
# single quotes: no additional escaping (does not accept ' in values)
suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done)
elif [ "$quote" == \" ]; then
# double quotes: double escaping for \ $ ` "
suggestions=$(for s in $sfcomplete; do
s=${s//\\/\\\\}
s=${s//\$/\\\$}
s=${s//\`/\\\`}
s=${s//\"/\\\"}
printf $'%q%q%q\n' "$quote" "$s" "$quote";
done)
else
# no quotes: double escaping
suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done)
fi
COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur")))
__ltrim_colon_completions "$cur"
else
if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then
>&2 echo
>&2 echo $sfcomplete
fi
return 1
fi
}
complete -F _sf_console console

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241229195702 extends AbstractMigration final class Version20241229195702 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20241229195702 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->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 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('CREATE INDEX IDX_DADD4A251E27F6BF ON answer (question_id)');
$this->addSql('COMMENT ON COLUMN answer.id IS \'(DC2Type:uuid)\''); $this->addSql('COMMENT ON COLUMN answer.id IS \'(DC2Type:uuid)\'');
@@ -67,7 +63,6 @@ final class Version20241229195702 extends AbstractMigration
public function down(Schema $schema): void 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('CREATE SCHEMA public');
$this->addSql('ALTER TABLE answer DROP CONSTRAINT FK_DADD4A251E27F6BF'); $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_F54D5192AA334807');

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241229201314 extends AbstractMigration final class Version20241229201314 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20241229201314 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE season_user (season_id UUID NOT NULL, user_id UUID NOT NULL, PRIMARY KEY(season_id, user_id))'); $this->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_BDA4AD74EC001D1 ON season_user (season_id)');
$this->addSql('CREATE INDEX IDX_BDA4AD7A76ED395 ON season_user (user_id)'); $this->addSql('CREATE INDEX IDX_BDA4AD7A76ED395 ON season_user (user_id)');
@@ -31,7 +27,6 @@ final class Version20241229201314 extends AbstractMigration
public function down(Schema $schema): void 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('CREATE SCHEMA public');
$this->addSql('ALTER TABLE season_user DROP CONSTRAINT FK_BDA4AD74EC001D1'); $this->addSql('ALTER TABLE season_user DROP CONSTRAINT FK_BDA4AD74EC001D1');
$this->addSql('ALTER TABLE season_user DROP CONSTRAINT FK_BDA4AD7A76ED395'); $this->addSql('ALTER TABLE season_user DROP CONSTRAINT FK_BDA4AD7A76ED395');

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241229202103 extends AbstractMigration final class Version20241229202103 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20241229202103 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->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 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_A29DA1B891BD8781 ON correction (candidate_id)');
$this->addSql('CREATE INDEX IDX_A29DA1B8853CD175 ON correction (quiz_id)'); $this->addSql('CREATE INDEX IDX_A29DA1B8853CD175 ON correction (quiz_id)');
@@ -32,7 +28,6 @@ final class Version20241229202103 extends AbstractMigration
public function down(Schema $schema): void 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('CREATE SCHEMA public');
$this->addSql('ALTER TABLE correction DROP CONSTRAINT FK_A29DA1B891BD8781'); $this->addSql('ALTER TABLE correction DROP CONSTRAINT FK_A29DA1B891BD8781');
$this->addSql('ALTER TABLE correction DROP CONSTRAINT FK_A29DA1B8853CD175'); $this->addSql('ALTER TABLE correction DROP CONSTRAINT FK_A29DA1B8853CD175');

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241229202155 extends AbstractMigration final class Version20241229202155 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,13 +16,11 @@ final class Version20241229202155 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE UNIQUE INDEX UNIQ_A29DA1B891BD8781853CD175 ON correction (candidate_id, quiz_id)'); $this->addSql('CREATE UNIQUE INDEX UNIQ_A29DA1B891BD8781853CD175 ON correction (candidate_id, quiz_id)');
} }
public function down(Schema $schema): void 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('CREATE SCHEMA public');
$this->addSql('DROP INDEX UNIQ_A29DA1B891BD8781853CD175'); $this->addSql('DROP INDEX UNIQ_A29DA1B891BD8781853CD175');
} }

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241229204335 extends AbstractMigration final class Version20241229204335 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,14 +16,12 @@ final class Version20241229204335 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE given_answer ALTER answer_id DROP NOT NULL'); $this->addSql('ALTER TABLE given_answer ALTER answer_id DROP NOT NULL');
$this->addSql('ALTER TABLE given_answer ALTER created DROP NOT NULL'); $this->addSql('ALTER TABLE given_answer ALTER created DROP NOT NULL');
} }
public function down(Schema $schema): void 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('CREATE SCHEMA public');
$this->addSql('ALTER TABLE given_answer ALTER answer_id SET NOT NULL'); $this->addSql('ALTER TABLE given_answer ALTER answer_id SET NOT NULL');
$this->addSql('ALTER TABLE given_answer ALTER created SET NOT NULL'); $this->addSql('ALTER TABLE given_answer ALTER created SET NOT NULL');

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250303221227 extends AbstractMigration final class Version20250303221227 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20250303221227 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE given_answer ALTER created SET NOT NULL'); $this->addSql('ALTER TABLE given_answer ALTER created SET NOT NULL');
$this->addSql('ALTER TABLE season ADD active_quiz_id UUID DEFAULT 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('COMMENT ON COLUMN season.active_quiz_id IS \'(DC2Type:uuid)\'');
@@ -29,7 +25,6 @@ final class Version20250303221227 extends AbstractMigration
public function down(Schema $schema): void 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('CREATE SCHEMA public');
$this->addSql('ALTER TABLE season DROP CONSTRAINT FK_F0E45BA96706D6B'); $this->addSql('ALTER TABLE season DROP CONSTRAINT FK_F0E45BA96706D6B');
$this->addSql('DROP INDEX IDX_F0E45BA96706D6B'); $this->addSql('DROP INDEX IDX_F0E45BA96706D6B');

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250311213417 extends AbstractMigration final class Version20250311213417 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20250311213417 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE answer ALTER id TYPE UUID'); $this->addSql('ALTER TABLE answer ALTER id TYPE UUID');
$this->addSql('ALTER TABLE answer ALTER question_id TYPE UUID'); $this->addSql('ALTER TABLE answer ALTER question_id TYPE UUID');
$this->addSql('COMMENT ON COLUMN answer.id IS \'\''); $this->addSql('COMMENT ON COLUMN answer.id IS \'\'');
@@ -69,7 +65,6 @@ final class Version20250311213417 extends AbstractMigration
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE candidate ALTER id TYPE UUID'); $this->addSql('ALTER TABLE candidate ALTER id TYPE UUID');
$this->addSql('ALTER TABLE candidate ALTER season_id TYPE UUID'); $this->addSql('ALTER TABLE candidate ALTER season_id TYPE UUID');
$this->addSql('COMMENT ON COLUMN candidate.id IS \'(DC2Type:uuid)\''); $this->addSql('COMMENT ON COLUMN candidate.id IS \'(DC2Type:uuid)\'');

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250402185128 extends AbstractMigration final class Version20250402185128 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,13 +16,11 @@ final class Version20250402185128 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE elimination (id UUID NOT NULL, data JSON NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE TABLE elimination (id UUID NOT NULL, data JSON NOT NULL, PRIMARY KEY(id))');
} }
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE elimination'); $this->addSql('DROP TABLE elimination');
} }
} }

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250427174822 extends AbstractMigration final class Version20250427174822 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20250427174822 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
ALTER TABLE answer ADD ordering SMALLINT DEFAULT 0 NOT NULL ALTER TABLE answer ADD ordering SMALLINT DEFAULT 0 NOT NULL
SQL); SQL);
@@ -30,7 +26,6 @@ final class Version20250427174822 extends AbstractMigration
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
ALTER TABLE answer DROP ordering ALTER TABLE answer DROP ordering
SQL); SQL);

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250504101440 extends AbstractMigration final class Version20250504101440 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20250504101440 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_C8B28E445E237E064EC001D1 ON candidate (name, season_id) CREATE UNIQUE INDEX UNIQ_C8B28E445E237E064EC001D1 ON candidate (name, season_id)
SQL); SQL);
@@ -30,7 +26,6 @@ final class Version20250504101440 extends AbstractMigration
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
DROP INDEX UNIQ_A412FA925E237E064EC001D1 DROP INDEX UNIQ_A412FA925E237E064EC001D1
SQL); SQL);

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250606195952 extends AbstractMigration final class Version20250606195952 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250607154730 extends AbstractMigration final class Version20250607154730 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20250607154730 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
ALTER TABLE season DROP CONSTRAINT FK_F0E45BA96706D6B ALTER TABLE season DROP CONSTRAINT FK_F0E45BA96706D6B
SQL); SQL);
@@ -30,7 +26,6 @@ final class Version20250607154730 extends AbstractMigration
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
ALTER TABLE season DROP CONSTRAINT fk_f0e45ba96706d6b ALTER TABLE season DROP CONSTRAINT fk_f0e45ba96706d6b
SQL); SQL);

View File

@@ -7,9 +7,6 @@ namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250607184525 extends AbstractMigration final class Version20250607184525 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
@@ -19,7 +16,6 @@ final class Version20250607184525 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
ALTER TABLE elimination DROP CONSTRAINT FK_5947284F853CD175 ALTER TABLE elimination DROP CONSTRAINT FK_5947284F853CD175
SQL); SQL);
@@ -36,7 +32,6 @@ final class Version20250607184525 extends AbstractMigration
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL' $this->addSql(<<<'SQL'
ALTER TABLE given_answer DROP CONSTRAINT fk_9ac61a30853cd175 ALTER TABLE given_answer DROP CONSTRAINT fk_9ac61a30853cd175
SQL); SQL);

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20251007194241 extends AbstractMigration
{
public function getDescription(): string
{
return 'Change elimination data type to jsonb';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE elimination ALTER data TYPE JSONB');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE elimination ALTER data TYPE JSON');
}
}

View File

@@ -8,3 +8,7 @@ parameters:
- src/ - src/
- tests/ - tests/
treatPhpDocTypesAsCertain: false treatPhpDocTypesAsCertain: false
symfony:
containerXmlPath: var/cache/dev/Tvdt_KernelDevDebugContainer.xml
doctrine:
objectManagerLoader: tests/object-manager.php

View File

@@ -3,6 +3,8 @@
declare(strict_types=1); declare(strict_types=1);
use Rector\Config\RectorConfig; use Rector\Config\RectorConfig;
use Rector\Symfony\Bridge\Symfony\Routing\SymfonyRoutesProvider;
use Rector\Symfony\Contract\Bridge\Symfony\Routing\SymfonyRoutesProviderInterface;
return RectorConfig::configure() return RectorConfig::configure()
->withPaths([ ->withPaths([
@@ -11,7 +13,9 @@ return RectorConfig::configure()
__DIR__.'/src', __DIR__.'/src',
__DIR__.'/tests', __DIR__.'/tests',
]) ])
->withSymfonyContainerXml('var/cache/dev/App_KernelDevDebugContainer.xml') ->withSymfonyContainerXml(__DIR__.'/var/cache/dev/Tvdt_KernelDevDebugContainer.xml')
->withSymfonyContainerPhp(__DIR__.'/tests/symfony-container.php')
->registerService(SymfonyRoutesProvider::class, SymfonyRoutesProviderInterface::class)
->withParallel() ->withParallel()
->withPhpSets() ->withPhpSets()
->withPreparedSets( ->withPreparedSets(

View File

@@ -26,12 +26,12 @@ readonly class AddSettingsCommand
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
foreach ($this->seasonRepository->findAll() as $season) { foreach ($this->seasonRepository->findAll() as $season) {
if (null !== $season->getSettings()) { if (null !== $season->settings) {
continue; continue;
} }
$io->text('Adding settings to season : '.$season->getSeasonCode()); $io->text('Adding settings to season : '.$season->seasonCode);
$season->setSettings(new SeasonSettings()); $season->settings = new SeasonSettings();
} }
$this->entityManager->flush(); $this->entityManager->flush();

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\Answer;
/** @extends AbstractCrudController<Answer> */
class AnswerCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Answer::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\Candidate;
/** @extends AbstractCrudController<Candidate> */
class CandidateCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Candidate::class;
}
}

View File

@@ -1,67 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Attribute\AdminDashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Symfony\Component\HttpFoundation\Response;
use Tvdt\Entity\Answer;
use Tvdt\Entity\Candidate;
use Tvdt\Entity\GivenAnswer;
use Tvdt\Entity\Question;
use Tvdt\Entity\Quiz;
use Tvdt\Entity\QuizCandidate;
use Tvdt\Entity\Season;
use Tvdt\Entity\User;
#[AdminDashboard(routePath: '/admin', routeName: 'admin')]
class DashboardController extends AbstractDashboardController
{
#[\Override]
public function index(): Response
{
// Option 1. You can make your dashboard redirect to some common page of your backend
//
$adminUrlGenerator = $this->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');
}
#[\Override]
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('TijdVoorDeTest');
}
#[\Override]
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', QuizCandidate::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', 'fas fa-sign-out');
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\GivenAnswer;
/** @extends AbstractCrudController<GivenAnswer> */
class GivenAnswerCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return GivenAnswer::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\Question;
/** @extends AbstractCrudController<Question> */
class QuestionCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Question::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\QuizCandidate;
/** @extends AbstractCrudController<QuizCandidate> */
class QuizCorrectionCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return QuizCandidate::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\Quiz;
/** @extends AbstractCrudController<Quiz> */
class QuizCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Quiz::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\Season;
/** @extends AbstractCrudController<Season> */
class SeasonCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Season::class;
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Tvdt\Entity\User;
/** @extends AbstractCrudController<User> */
class UserCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return User::class;
}
}

View File

@@ -61,7 +61,7 @@ final class BackofficeController extends AbstractController
$em->persist($season); $em->persist($season);
$em->flush(); $em->flush();
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]); return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->seasonCode]);
} }
return $this->render('backoffice/season_add.html.twig', ['form' => $form]); return $this->render('backoffice/season_add.html.twig', ['form' => $form]);

View File

@@ -26,7 +26,7 @@ final class PrepareEliminationController extends AbstractController
{ {
$elimination = $eliminationFactory->createEliminationFromQuiz($quiz); $elimination = $eliminationFactory->createEliminationFromQuiz($quiz);
return $this->redirectToRoute('tvdt_prepare_elimination_view', ['elimination' => $elimination->getId()]); return $this->redirectToRoute('tvdt_prepare_elimination_view', ['elimination' => $elimination->id]);
} }
#[Route( #[Route(
@@ -41,7 +41,7 @@ final class PrepareEliminationController extends AbstractController
$em->flush(); $em->flush();
if ($request->request->getBoolean('start')) { if ($request->request->getBoolean('start')) {
return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->getId()]); return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->id]);
} }
$this->addFlash('success', 'Elimination updated'); $this->addFlash('success', 'Elimination updated');

View File

@@ -33,12 +33,12 @@ class QuizController extends AbstractController
private readonly TranslatorInterface $translator, private readonly TranslatorInterface $translator,
) {} ) {}
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route( #[Route(
'/backoffice/season/{seasonCode:season}/quiz/{quiz}', '/backoffice/season/{seasonCode:season}/quiz/{quiz}',
name: 'tvdt_backoffice_quiz', name: 'tvdt_backoffice_quiz',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID], requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID],
)] )]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function index(Season $season, Quiz $quiz): Response public function index(Season $season, Quiz $quiz): Response
{ {
return $this->render('backoffice/quiz.html.twig', [ return $this->render('backoffice/quiz.html.twig', [
@@ -48,30 +48,30 @@ class QuizController extends AbstractController
]); ]);
} }
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route( #[Route(
'/backoffice/season/{seasonCode:season}/quiz/{quiz}/enable', '/backoffice/season/{seasonCode:season}/quiz/{quiz}/enable',
name: 'tvdt_backoffice_enable', name: 'tvdt_backoffice_enable',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID.'|null'], requirements: ['seasonCode' => self::SEASON_CODE_REGEX, 'quiz' => Requirement::UUID.'|null'],
)] )]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function enableQuiz(Season $season, ?Quiz $quiz, EntityManagerInterface $em): RedirectResponse public function enableQuiz(Season $season, ?Quiz $quiz, EntityManagerInterface $em): RedirectResponse
{ {
$season->setActiveQuiz($quiz); $season->activeQuiz = $quiz;
$em->flush(); $em->flush();
if ($quiz instanceof Quiz) { if ($quiz instanceof Quiz) {
return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $season->getSeasonCode(), 'quiz' => $quiz->getId()]); return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $season->seasonCode, 'quiz' => $quiz->id]);
} }
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]); return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->seasonCode]);
} }
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
#[Route( #[Route(
'/backoffice/quiz/{quiz}/clear', '/backoffice/quiz/{quiz}/clear',
name: 'tvdt_backoffice_quiz_clear', name: 'tvdt_backoffice_quiz_clear',
requirements: ['quiz' => Requirement::UUID], requirements: ['quiz' => Requirement::UUID],
)] )]
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
public function clearQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse public function clearQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse
{ {
try { try {
@@ -81,30 +81,30 @@ class QuizController extends AbstractController
$this->addFlash('error', $this->translator->trans('Error clearing quiz')); $this->addFlash('error', $this->translator->trans('Error clearing quiz'));
} }
return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $quiz->getSeason()->getSeasonCode(), 'quiz' => $quiz->getId()]); return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $quiz->season->seasonCode, 'quiz' => $quiz->id]);
} }
#[IsGranted(SeasonVoter::DELETE, subject: 'quiz')]
#[Route( #[Route(
'/backoffice/quiz/{quiz}/delete', '/backoffice/quiz/{quiz}/delete',
name: 'tvdt_backoffice_quiz_delete', name: 'tvdt_backoffice_quiz_delete',
requirements: ['quiz' => Requirement::UUID], requirements: ['quiz' => Requirement::UUID],
)] )]
#[IsGranted(SeasonVoter::DELETE, subject: 'quiz')]
public function deleteQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse public function deleteQuiz(Quiz $quiz, QuizRepository $quizRepository): RedirectResponse
{ {
$quizRepository->deleteQuiz($quiz); $quizRepository->deleteQuiz($quiz);
$this->addFlash('success', $this->translator->trans('Quiz deleted')); $this->addFlash('success', $this->translator->trans('Quiz deleted'));
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $quiz->getSeason()->getSeasonCode()]); return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $quiz->season->seasonCode]);
} }
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
#[Route( #[Route(
'/backoffice/quiz/{quiz}/candidate/{candidate}/modify_correction', '/backoffice/quiz/{quiz}/candidate/{candidate}/modify_correction',
name: 'tvdt_backoffice_modify_correction', name: 'tvdt_backoffice_modify_correction',
requirements: ['quiz' => Requirement::UUID, 'candidate' => Requirement::UUID], requirements: ['quiz' => Requirement::UUID, 'candidate' => Requirement::UUID],
)] )]
#[IsGranted(SeasonVoter::EDIT, subject: 'quiz')]
public function modifyCorrection(Quiz $quiz, Candidate $candidate, QuizCandidateRepository $quizCandidateRepository, Request $request): RedirectResponse public function modifyCorrection(Quiz $quiz, Candidate $candidate, QuizCandidateRepository $quizCandidateRepository, Request $request): RedirectResponse
{ {
if (!$request->isMethod('POST')) { if (!$request->isMethod('POST')) {
@@ -115,6 +115,6 @@ class QuizController extends AbstractController
$quizCandidateRepository->setCorrectionsForCandidate($quiz, $candidate, $corrections); $quizCandidateRepository->setCorrectionsForCandidate($quiz, $candidate, $corrections);
return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $quiz->getSeason()->getSeasonCode(), 'quiz' => $quiz->getId()]); return $this->redirectToRoute('tvdt_backoffice_quiz', ['seasonCode' => $quiz->season->seasonCode, 'quiz' => $quiz->id]);
} }
} }

View File

@@ -32,15 +32,15 @@ class SeasonController extends AbstractController
private readonly EntityManagerInterface $em, private readonly EntityManagerInterface $em,
) {} ) {}
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route( #[Route(
'/backoffice/season/{seasonCode:season}', '/backoffice/season/{seasonCode:season}',
name: 'tvdt_backoffice_season', name: 'tvdt_backoffice_season',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX], requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
)] )]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function index(Season $season, Request $request): Response public function index(Season $season, Request $request): Response
{ {
$form = $this->createForm(SettingsForm::class, $season->getSettings()); $form = $this->createForm(SettingsForm::class, $season->settings);
$form->handleRequest($request); $form->handleRequest($request);
@@ -54,13 +54,13 @@ class SeasonController extends AbstractController
]); ]);
} }
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route( #[Route(
'/backoffice/season/{seasonCode:season}/add-candidate', '/backoffice/season/{seasonCode:season}/add-candidate',
name: 'tvdt_backoffice_add_candidates', name: 'tvdt_backoffice_add_candidates',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX], requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
priority: 10, priority: 10,
)] )]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function addCandidates(Season $season, Request $request): Response public function addCandidates(Season $season, Request $request): Response
{ {
$form = $this->createForm(AddCandidatesFormType::class); $form = $this->createForm(AddCandidatesFormType::class);
@@ -74,19 +74,19 @@ class SeasonController extends AbstractController
$this->em->flush(); $this->em->flush();
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]); return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->seasonCode]);
} }
return $this->render('backoffice/season_add_candidates.html.twig', ['form' => $form]); return $this->render('backoffice/season_add_candidates.html.twig', ['form' => $form]);
} }
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
#[Route( #[Route(
'/backoffice/season/{seasonCode:season}/add-quiz', '/backoffice/season/{seasonCode:season}/add-quiz',
name: 'tvdt_backoffice_quiz_add', name: 'tvdt_backoffice_quiz_add',
requirements: ['seasonCode' => self::SEASON_CODE_REGEX], requirements: ['seasonCode' => self::SEASON_CODE_REGEX],
priority: 10, priority: 10,
)] )]
#[IsGranted(SeasonVoter::EDIT, subject: 'season')]
public function addQuiz(Request $request, Season $season, QuizSpreadsheetService $quizSpreadsheet): Response public function addQuiz(Request $request, Season $season, QuizSpreadsheetService $quizSpreadsheet): Response
{ {
$quiz = new Quiz(); $quiz = new Quiz();
@@ -100,13 +100,13 @@ class SeasonController extends AbstractController
$quizSpreadsheet->xlsxToQuiz($quiz, $sheet); $quizSpreadsheet->xlsxToQuiz($quiz, $sheet);
$quiz->setSeason($season); $quiz->season = $season;
$this->em->persist($quiz); $this->em->persist($quiz);
$this->em->flush(); $this->em->flush();
$this->addFlash(FlashType::Success, $this->translator->trans('Quiz Added!')); $this->addFlash(FlashType::Success, $this->translator->trans('Quiz Added!'));
return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->getSeasonCode()]); return $this->redirectToRoute('tvdt_backoffice_season', ['seasonCode' => $season->seasonCode]);
} }
return $this->render('/backoffice/quiz_add.html.twig', ['form' => $form, 'season' => $season]); return $this->render('/backoffice/quiz_add.html.twig', ['form' => $form, 'season' => $season]);

View File

@@ -28,8 +28,8 @@ final class EliminationController extends AbstractController
{ {
public function __construct(private readonly TranslatorInterface $translator) {} public function __construct(private readonly TranslatorInterface $translator) {}
#[Route('/elimination/{elimination}', name: 'tvdt_elimination', requirements: ['elimination' => Requirement::UUID])]
#[IsGranted(SeasonVoter::ELIMINATION, 'elimination')] #[IsGranted(SeasonVoter::ELIMINATION, 'elimination')]
#[Route('/elimination/{elimination}', name: 'tvdt_elimination', requirements: ['elimination' => Requirement::UUID])]
public function index(#[MapEntity] Elimination $elimination, Request $request): Response public function index(#[MapEntity] Elimination $elimination, Request $request): Response
{ {
$form = $this->createForm(EliminationEnterNameType::class); $form = $this->createForm(EliminationEnterNameType::class);
@@ -39,7 +39,7 @@ final class EliminationController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$name = $form->get('name')->getData(); $name = $form->get('name')->getData();
return $this->redirectToRoute('tvdt_elimination_candidate', ['elimination' => $elimination->getId(), 'candidateHash' => Base64::base64UrlEncode($name)]); return $this->redirectToRoute('tvdt_elimination_candidate', ['elimination' => $elimination->id, 'candidateHash' => Base64::base64UrlEncode($name)]);
} }
return $this->render('quiz/elimination/index.html.twig', [ return $this->render('quiz/elimination/index.html.twig', [
@@ -48,25 +48,25 @@ final class EliminationController extends AbstractController
]); ]);
} }
#[Route('/elimination/{elimination}/{candidateHash}', name: 'tvdt_elimination_candidate', requirements: ['elimination' => Requirement::UUID, 'candidateHash' => self::CANDIDATE_HASH_REGEX])]
#[IsGranted(SeasonVoter::ELIMINATION, 'elimination')] #[IsGranted(SeasonVoter::ELIMINATION, 'elimination')]
#[Route('/elimination/{elimination}/{candidateHash}', name: 'tvdt_elimination_candidate', requirements: ['elimination' => Requirement::UUID, 'candidateHash' => self::CANDIDATE_HASH_REGEX])]
public function candidateScreen(Elimination $elimination, string $candidateHash, CandidateRepository $candidateRepository): Response public function candidateScreen(Elimination $elimination, string $candidateHash, CandidateRepository $candidateRepository): Response
{ {
$candidate = $candidateRepository->getCandidateByHash($elimination->getQuiz()->getSeason(), $candidateHash); $candidate = $candidateRepository->getCandidateByHash($elimination->quiz->season, $candidateHash);
if (!$candidate instanceof Candidate) { if (!$candidate instanceof Candidate) {
$this->addFlash(FlashType::Warning, $this->addFlash(FlashType::Warning,
t('Cound not find candidate with name %name%', ['%name%' => Base64::base64UrlDecode($candidateHash)])->trans($this->translator), t('Cound not find candidate with name %name%', ['%name%' => Base64::base64UrlDecode($candidateHash)])->trans($this->translator),
); );
return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->getId()]); return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->id]);
} }
$screenColour = $elimination->getScreenColour($candidate->getName()); $screenColour = $elimination->getScreenColour($candidate->name);
if (null === $screenColour) { if (null === $screenColour) {
$this->addFlash(FlashType::Warning, $this->translator->trans('Cound not find candidate with name %name% in elimination.', ['%name%' => $candidate->getName()])); $this->addFlash(FlashType::Warning, $this->translator->trans('Cound not find candidate with name %name% in elimination.', ['%name%' => $candidate->name]));
return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->getId()]); return $this->redirectToRoute('tvdt_elimination', ['elimination' => $elimination->id]);
} }
return $this->render('quiz/elimination/candidate.html.twig', [ return $this->render('quiz/elimination/candidate.html.twig', [

View File

@@ -65,7 +65,7 @@ final class QuizController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$name = $form->get('name')->getData(); $name = $form->get('name')->getData();
return $this->redirectToRoute('tvdt_quiz_quiz_page', ['seasonCode' => $season->getSeasonCode(), 'nameHash' => Base64::base64UrlEncode($name)]); return $this->redirectToRoute('tvdt_quiz_quiz_page', ['seasonCode' => $season->seasonCode, 'nameHash' => Base64::base64UrlEncode($name)]);
} }
return $this->render('quiz/enter_name.twig', ['season' => $season, 'form' => $form]); return $this->render('quiz/enter_name.twig', ['season' => $season, 'form' => $form]);
@@ -91,15 +91,15 @@ final class QuizController extends AbstractController
if (!$candidate instanceof Candidate) { if (!$candidate instanceof Candidate) {
$this->addFlash(FlashType::Danger, $this->translator->trans('Candidate not found')); $this->addFlash(FlashType::Danger, $this->translator->trans('Candidate not found'));
return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]); return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->seasonCode]);
} }
$quiz = $season->getActiveQuiz(); $quiz = $season->activeQuiz;
if (!$quiz instanceof Quiz) { if (!$quiz instanceof Quiz) {
$this->addFlash(FlashType::Warning, $this->translator->trans('There is no active quiz')); $this->addFlash(FlashType::Warning, $this->translator->trans('There is no active quiz'));
return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]); return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->seasonCode]);
} }
if ('POST' === $request->getMethod()) { if ('POST' === $request->getMethod()) {
@@ -109,10 +109,10 @@ final class QuizController extends AbstractController
throw new BadRequestHttpException('Invalid Answer ID'); throw new BadRequestHttpException('Invalid Answer ID');
} }
$givenAnswer = new GivenAnswer($candidate, $answer->getQuestion()->getQuiz(), $answer); $givenAnswer = new GivenAnswer($candidate, $answer->question->quiz, $answer);
$givenAnswerRepository->save($givenAnswer); $givenAnswerRepository->save($givenAnswer);
return $this->redirectToRoute('tvdt_quiz_quiz_page', ['seasonCode' => $season->getSeasonCode(), 'nameHash' => $nameHash]); return $this->redirectToRoute('tvdt_quiz_quiz_page', ['seasonCode' => $season->seasonCode, 'nameHash' => $nameHash]);
} }
$question = $questionRepository->findNextQuestionForCandidate($candidate); $question = $questionRepository->findNextQuestionForCandidate($candidate);
@@ -120,7 +120,7 @@ final class QuizController extends AbstractController
if (!$question instanceof Question) { if (!$question instanceof Question) {
$this->addFlash(FlashType::Success, $this->translator->trans('Quiz completed')); $this->addFlash(FlashType::Success, $this->translator->trans('Quiz completed'));
return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->getSeasonCode()]); return $this->redirectToRoute('tvdt_quiz_enter_name', ['seasonCode' => $season->seasonCode]);
} }
$quizCandidateRepository->createIfNotExist($quiz, $candidate); $quizCandidateRepository->createIfNotExist($quiz, $candidate);

View File

@@ -41,7 +41,7 @@ final class RegistrationController extends AbstractController
/** @var string $plainPassword */ /** @var string $plainPassword */
$plainPassword = $form->get('plainPassword')->getData(); $plainPassword = $form->get('plainPassword')->getData();
$user->setPassword($userPasswordHasher->hashPassword($user, $plainPassword)); $user->password = $userPasswordHasher->hashPassword($user, $plainPassword);
$entityManager->persist($user); $entityManager->persist($user);
$entityManager->flush(); $entityManager->flush();
@@ -50,7 +50,7 @@ final class RegistrationController extends AbstractController
// generate a signed url and email it to the user // generate a signed url and email it to the user
$this->emailVerifier->sendEmailConfirmation('tvdt_verify_email', $user, $this->emailVerifier->sendEmailConfirmation('tvdt_verify_email', $user,
new TemplatedEmail() new TemplatedEmail()
->to((string) $user->getEmail()) ->to($user->email)
->subject($this->translator->trans('Please Confirm your Email')) ->subject($this->translator->trans('Please Confirm your Email'))
->htmlTemplate('backoffice/registration/confirmation_email.html.twig'), ->htmlTemplate('backoffice/registration/confirmation_email.html.twig'),
); );

View File

@@ -19,8 +19,9 @@ class KrtekFixtures extends Fixture
$season = new Season(); $season = new Season();
$manager->persist($season); $manager->persist($season);
$season->setName('Krtek Weekend') $season->name = 'Krtek Weekend';
->setSeasonCode('krtek') $season->seasonCode = 'krtek';
$season
->addCandidate(new Candidate('Claudia')) ->addCandidate(new Candidate('Claudia'))
->addCandidate(new Candidate('Eelco')) ->addCandidate(new Candidate('Eelco'))
->addCandidate(new Candidate('Elise')) ->addCandidate(new Candidate('Elise'))
@@ -35,53 +36,54 @@ class KrtekFixtures extends Fixture
->addCandidate(new Candidate('Robbert')) ->addCandidate(new Candidate('Robbert'))
->addCandidate(new Candidate('Tom')); ->addCandidate(new Candidate('Tom'));
$quiz1 = $this->createQuiz1($season); $quiz1 = $this->createQuiz1($season);
$season->addQuiz($quiz1) $season->addQuiz($quiz1);
->setActiveQuiz($quiz1) $season->activeQuiz = $quiz1;
->addQuiz($this->createQuiz2($season)); $season->addQuiz($this->createQuiz2($season));
$manager->flush(); $manager->flush();
} }
private function createQuiz1(Season $season): Quiz private function createQuiz1(Season $season): Quiz
{ {
return new Quiz() $quiz = new Quiz();
->setName('Quiz 1') $quiz->name = 'Quiz 1';
->setSeason($season) $quiz->season = $season;
->addQuestion(new Question() $q = new Question();
->setQuestion('Is de Krtek een man of een vrouw?') $q->question = 'Is de Krtek een man of een vrouw?';
->addAnswer(new Answer('Vrouw', true)) $q->addAnswer(new Answer('Vrouw', true))
->addAnswer(new Answer('Man')) ->addAnswer(new Answer('Man'));
->setOrdering(1), $q->ordering = 1;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Hoeveel broers heeft de Krtek?') $q->question = 'Hoeveel broers heeft de Krtek?';
->addAnswer(new Answer('Geen', true)) $q->addAnswer(new Answer('Geen', true))
->addAnswer(new Answer('1')) ->addAnswer(new Answer('1'))
->addAnswer(new Answer('2')) ->addAnswer(new Answer('2'));
->setOrdering(2), $q->ordering = 2;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Wat is de lievelingsfeestdag van de Krtek?') $q->question = 'Wat is de lievelingsfeestdag van de Krtek?';
->addAnswer(new Answer('Geen')) $q->addAnswer(new Answer('Geen'))
->addAnswer(new Answer('Diens eigen verjaardag')) ->addAnswer(new Answer('Diens eigen verjaardag'))
->addAnswer(new Answer('Koningsdag')) ->addAnswer(new Answer('Koningsdag'))
->addAnswer(new Answer('Kerst', true)) ->addAnswer(new Answer('Kerst', true))
->addAnswer(new Answer('Oud en Nieuw')) ->addAnswer(new Answer('Oud en Nieuw'));
->setOrdering(3), $q->ordering = 3;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Hoe kwam de Krtek naar Kersteren vandaag?') $q->question = 'Hoe kwam de Krtek naar Kersteren vandaag?';
->addAnswer(new Answer('Met het OV', true)) $q->addAnswer(new Answer('Met het OV', true))
->addAnswer(new Answer('Met de auto')) ->addAnswer(new Answer('Met de auto'));
->setOrdering(4), $q->ordering = 4;
) $quiz->addQuestion($q);
->addQuestion(new Question()
->setQuestion('Met wie keek de Krtek video bij binnenkomst?') $q = new Question();
->addAnswer(new Answer('Claudia')) $q->question = 'Met wie keek de Krtek video bij binnenkomst?';
$q->addAnswer(new Answer('Claudia'))
->addAnswer(new Answer('Eelco')) ->addAnswer(new Answer('Eelco'))
->addAnswer(new Answer('Elise')) ->addAnswer(new Answer('Elise'))
->addAnswer(new Answer('Gert-Jan')) ->addAnswer(new Answer('Gert-Jan'))
@@ -93,52 +95,52 @@ class KrtekFixtures extends Fixture
->addAnswer(new Answer('Philine')) ->addAnswer(new Answer('Philine'))
->addAnswer(new Answer('Remy')) ->addAnswer(new Answer('Remy'))
->addAnswer(new Answer('Robbert')) ->addAnswer(new Answer('Robbert'))
->addAnswer(new Answer('Tom', true)) ->addAnswer(new Answer('Tom', true));
->setOrdering(5), $q->ordering = 5;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Welk advies zou de Krtek zichzelf als kind geven?') $q->question = 'Welk advies zou de Krtek zichzelf als kind geven?';
->addAnswer(new Answer('Geef je vader een knuffel.')) $q->addAnswer(new Answer('Geef je vader een knuffel.'))
->addAnswer(new Answer('Trek je wat minder aan van anderen.')) ->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('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('Stel niet alles tot het laatste moment uit.'))
->addAnswer(new Answer('Altijd doorgaan.')) ->addAnswer(new Answer('Altijd doorgaan.'))
->addAnswer(new Answer('Probeer ook eens buiten de lijntjes te kleuren', true)) ->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('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.')) ->addAnswer(new Answer('Trek minder aan van de mening van anderen, het is oké om anders te zijn.'));
->setOrdering(6), $q->ordering = 6;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Wat voor soort schoenen droeg de Krtek bij het diner?') $q->question = 'Wat voor soort schoenen droeg de Krtek bij het diner?';
->addAnswer(new Answer('Sneakers')) $q->addAnswer(new Answer('Sneakers'))
->addAnswer(new Answer('Wandel-/bergschoenen', true)) ->addAnswer(new Answer('Wandel-/bergschoenen', true))
->addAnswer(new Answer('Lederen schoenen')) ->addAnswer(new Answer('Lederen schoenen'))
->addAnswer(new Answer('Pantoffels')) ->addAnswer(new Answer('Pantoffels'))
->addAnswer(new Answer('Hakken')) ->addAnswer(new Answer('Hakken'))
->addAnswer(new Answer('Geen schoenen, alleen sokken')) ->addAnswer(new Answer('Geen schoenen, alleen sokken'));
->setOrdering(7), $q->ordering = 7;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Met welk vervoersmiddel reist de Krtek het liefste?') $q->question = 'Met welk vervoersmiddel reist de Krtek het liefste?';
->addAnswer(new Answer('Fiets', true)) $q->addAnswer(new Answer('Fiets', true))
->addAnswer(new Answer('Auto')) ->addAnswer(new Answer('Auto'))
->addAnswer(new Answer('Trein')) ->addAnswer(new Answer('Trein'));
->setOrdering(8), $q->ordering = 8;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Heeft de Krtek een eigen auto?') $q->question = 'Heeft de Krtek een eigen auto?';
->addAnswer(new Answer('Ja')) $q->addAnswer(new Answer('Ja'))
->addAnswer(new Answer('Nee', true)) ->addAnswer(new Answer('Nee', true));
->setOrdering(9), $q->ordering = 9;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Van wie is de quote die de Krtek gepakt heeft') $q->question = 'Van wie is de quote die de Krtek gepakt heeft';
->addAnswer(new Answer('Karen')) $q->addAnswer(new Answer('Karen'))
->addAnswer(new Answer('Gilles de Coster')) ->addAnswer(new Answer('Gilles de Coster'))
->addAnswer(new Answer('Kees Tol')) ->addAnswer(new Answer('Kees Tol'))
->addAnswer(new Answer('Harry en John')) ->addAnswer(new Answer('Harry en John'))
@@ -152,44 +154,44 @@ class KrtekFixtures extends Fixture
->addAnswer(new Answer('Karin de Groot')) ->addAnswer(new Answer('Karin de Groot'))
->addAnswer(new Answer('Pieter')) ->addAnswer(new Answer('Pieter'))
->addAnswer(new Answer('Renée Fokker')) ->addAnswer(new Answer('Renée Fokker'))
->addAnswer(new Answer('Sam, Davy', true)) ->addAnswer(new Answer('Sam, Davy', true));
->setOrdering(10), $q->ordering = 10;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Zou de Krtek molboekjes, jokers, vrijstellingen of topitos uit iemands rugzak stelen om te kunnen winnen?') $q->question = 'Zou de Krtek molboekjes, jokers, vrijstellingen of topitos uit iemands rugzak stelen om te kunnen winnen?';
->addAnswer(new Answer('Ja')) $q->addAnswer(new Answer('Ja'))
->addAnswer(new Answer('Nee', true)) ->addAnswer(new Answer('Nee', true));
->setOrdering(11), $q->ordering = 11;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('In wat voor bed slaapt de Krtek dit weekend?') $q->question = 'In wat voor bed slaapt de Krtek dit weekend?';
->addAnswer(new Answer('Éénpersoons, losstaand bed')) $q->addAnswer(new Answer('Éénpersoons, losstaand bed'))
->addAnswer(new Answer('Éénpersoonsbed, tegen een ander bed aan', true)) ->addAnswer(new Answer('Éénpersoonsbed, tegen een ander bed aan', true))
->addAnswer(new Answer('Tweepersoons bed')) ->addAnswer(new Answer('Tweepersoons bed'));
->setOrdering(12), $q->ordering = 12;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Hoeveel jaar heeft de Krtek gedaan over de middelbare school?') $q->question = 'Hoeveel jaar heeft de Krtek gedaan over de middelbare school?';
->addAnswer(new Answer('5')) $q->addAnswer(new Answer('5'))
->addAnswer(new Answer('6', true)) ->addAnswer(new Answer('6', true))
->addAnswer(new Answer('7')) ->addAnswer(new Answer('7'))
->addAnswer(new Answer('8')) ->addAnswer(new Answer('8'));
->setOrdering(13), $q->ordering = 13;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Waar zat de Krtek aan tafel bij het diner?') $q->question = 'Waar zat de Krtek aan tafel bij het diner?';
->addAnswer(new Answer('Met de rug naar de accommodatie')) $q->addAnswer(new Answer('Met de rug naar de accommodatie'))
->addAnswer(new Answer('Met de rug naar de buitenmuur', true)) ->addAnswer(new Answer('Met de rug naar de buitenmuur', true));
->setOrdering(14), $q->ordering = 14;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Wie is de Krtek?') $q->question = 'Wie is de Krtek?';
->addAnswer(new Answer('Claudia', true)) $q->addAnswer(new Answer('Claudia', true))
->addAnswer(new Answer('Eelco')) ->addAnswer(new Answer('Eelco'))
->addAnswer(new Answer('Elise')) ->addAnswer(new Answer('Elise'))
->addAnswer(new Answer('Gert-Jan')) ->addAnswer(new Answer('Gert-Jan'))
@@ -201,158 +203,159 @@ class KrtekFixtures extends Fixture
->addAnswer(new Answer('Philine')) ->addAnswer(new Answer('Philine'))
->addAnswer(new Answer('Remy')) ->addAnswer(new Answer('Remy'))
->addAnswer(new Answer('Robbert')) ->addAnswer(new Answer('Robbert'))
->addAnswer(new Answer('Tom')) ->addAnswer(new Answer('Tom'));
->setOrdering(15), $q->ordering = 15;
) $quiz->addQuestion($q);
;
return $quiz;
} }
private function createQuiz2(Season $season): Quiz private function createQuiz2(Season $season): Quiz
{ {
return new Quiz() $quiz = new Quiz();
->setName('Quiz 2') $quiz->name = 'Quiz 2';
->setSeason($season) $quiz->season = $season;
->addQuestion(new Question() $q = new Question();
->setQuestion('Is de Krtek een man of een vrouw?') $q->question = 'Is de Krtek een man of een vrouw?';
->addAnswer(new Answer('Man')) $q->addAnswer(new Answer('Man'))
->addAnswer(new Answer('Vrouw', true)) ->addAnswer(new Answer('Vrouw', true));
->setOrdering(1), $q->ordering = 1;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Heeft de Krtek dieetwensen of allergieën?') $q->question = 'Heeft de Krtek dieetwensen of allergieën?';
->addAnswer(new Answer('nee')) $q->addAnswer(new Answer('nee'))
->addAnswer(new Answer('De Krtek is vegetariër', true)) ->addAnswer(new Answer('De Krtek is vegetariër', true))
->addAnswer(new Answer('De Krtek is flexitariër')) ->addAnswer(new Answer('De Krtek is flexitariër'))
->addAnswer(new Answer('De Krtek heeft een allergie')) ->addAnswer(new Answer('De Krtek heeft een allergie'))
->addAnswer(new Answer('De Krtek heeft een intolerantie')) ->addAnswer(new Answer('De Krtek heeft een intolerantie'))
->addAnswer(new Answer('De Krtek eet geen rundvlees')) ->addAnswer(new Answer('De Krtek eet geen rundvlees'))
->addAnswer(new Answer('De Krtek eet geen waterdieren')) ->addAnswer(new Answer('De Krtek eet geen waterdieren'));
->setOrdering(2), $q->ordering = 2;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Hoe heet het huisdier/de huisdieren van de Krtek?') $q->question = 'Hoe heet het huisdier/de huisdieren van de Krtek?';
->addAnswer(new Answer('Amy, Karel en Floyd')) $q->addAnswer(new Answer('Amy, Karel en Floyd'))
->addAnswer(new Answer('Flip en Majoor')) ->addAnswer(new Answer('Flip en Majoor'))
->addAnswer(new Answer('Benji')) ->addAnswer(new Answer('Benji'))
->addAnswer(new Answer('Sini')) ->addAnswer(new Answer('Sini'))
->addAnswer(new Answer('Tom')) ->addAnswer(new Answer('Tom'))
->addAnswer(new Answer('De huisdieren van de Krtek hebben geen naam')) ->addAnswer(new Answer('De huisdieren van de Krtek hebben geen naam'))
->addAnswer(new Answer('De Krtek heeft geen huisdieren', true)) ->addAnswer(new Answer('De Krtek heeft geen huisdieren', true));
->setOrdering(3), $q->ordering = 3;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Wat dronk de Krtek deze ochtend bij het ontbijt?') $q->question = 'Wat dronk de Krtek deze ochtend bij het ontbijt?';
->addAnswer(new Answer('Koffie')) $q->addAnswer(new Answer('Koffie'))
->addAnswer(new Answer('Thee')) ->addAnswer(new Answer('Thee'))
->addAnswer(new Answer('Water', true)) ->addAnswer(new Answer('Water', true))
->addAnswer(new Answer('Melk')) ->addAnswer(new Answer('Melk'))
->addAnswer(new Answer('Sap')) ->addAnswer(new Answer('Sap'))
->addAnswer(new Answer('Niks')) ->addAnswer(new Answer('Niks'));
->setOrdering(4), $q->ordering = 4;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Waar ging de eerste vakantie die de Krtek zich nog herinnert heen?') $q->question = 'Waar ging de eerste vakantie die de Krtek zich nog herinnert heen?';
->addAnswer(new Answer('Denemarken')) $q->addAnswer(new Answer('Denemarken'))
->addAnswer(new Answer('Drenthe')) ->addAnswer(new Answer('Drenthe'))
->addAnswer(new Answer('Mallorca')) ->addAnswer(new Answer('Mallorca'))
->addAnswer(new Answer('Marokko')) ->addAnswer(new Answer('Marokko'))
->addAnswer(new Answer('Oostenrijk')) ->addAnswer(new Answer('Oostenrijk'))
->addAnswer(new Answer('Turkije')) ->addAnswer(new Answer('Turkije'))
->addAnswer(new Answer('Zweden', true)) ->addAnswer(new Answer('Zweden', true));
->setOrdering(5), $q->ordering = 5;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Met welk groepje ging de Krtek als eerste het Douanespel in?') $q->question = 'Met welk groepje ging de Krtek als eerste het Douanespel in?';
->addAnswer(new Answer('Het eerste groepje', true)) $q->addAnswer(new Answer('Het eerste groepje', true))
->addAnswer(new Answer('Het tweede groepje')) ->addAnswer(new Answer('Het tweede groepje'))
->addAnswer(new Answer('Het derde groepje')) ->addAnswer(new Answer('Het derde groepje'))
->addAnswer(new Answer('Het vierde groepje')) ->addAnswer(new Answer('Het vierde groepje'))
->addAnswer(new Answer('Het vijfde groepje')) ->addAnswer(new Answer('Het vijfde groepje'));
->setOrdering(6), $q->ordering = 6;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Gelooft de Krtek ergens in?') $q->question = 'Gelooft de Krtek ergens in?';
->addAnswer(new Answer('Nee')) $q->addAnswer(new Answer('Nee'))
->addAnswer(new Answer('Het universum', true)) ->addAnswer(new Answer('Het universum', true))
->addAnswer(new Answer('Toeval')) ->addAnswer(new Answer('Toeval'))
->addAnswer(new Answer('De Krtek is hindoeïstisch')) ->addAnswer(new Answer('De Krtek is hindoeïstisch'));
->setOrdering(7), $q->ordering = 7;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('At de Krtek op vrijdagavond heksenkaas tijdens het diner?') $q->question = 'At de Krtek op vrijdagavond heksenkaas tijdens het diner?';
->addAnswer(new Answer('Ja', true)) $q->addAnswer(new Answer('Ja', true))
->addAnswer(new Answer('Nee')) ->addAnswer(new Answer('Nee'));
->setOrdering(8), $q->ordering = 8;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Hoe laat ging de Krtek gisteravond naar bed?') $q->question = 'Hoe laat ging de Krtek gisteravond naar bed?';
->addAnswer(new Answer('Tussen 0:00 en 0:59 uur')) $q->addAnswer(new Answer('Tussen 0:00 en 0:59 uur'))
->addAnswer(new Answer('Tussen 1:00 en 1:59 uur', true)) ->addAnswer(new Answer('Tussen 1:00 en 1:59 uur', true))
->addAnswer(new Answer('Tussen 2:00 en 2:59 uur')) ->addAnswer(new Answer('Tussen 2:00 en 2:59 uur'))
->addAnswer(new Answer('Na 3:00')) ->addAnswer(new Answer('Na 3:00'));
->setOrdering(9), $q->ordering = 9;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Hoeveel batterijen heeft de Krtek naar het bord gebracht bij het douanespel?') $q->question = 'Hoeveel batterijen heeft de Krtek naar het bord gebracht bij het douanespel?';
->addAnswer(new Answer('1')) $q->addAnswer(new Answer('1'))
->addAnswer(new Answer('2')) ->addAnswer(new Answer('2'))
->addAnswer(new Answer('3')) ->addAnswer(new Answer('3'))
->addAnswer(new Answer('geen', true)) ->addAnswer(new Answer('geen', true));
->setOrdering(10), $q->ordering = 10;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Wat keek de Krtek als kind graag op TV?') $q->question = 'Wat keek de Krtek als kind graag op TV?';
->addAnswer(new Answer('Digimon', true)) $q->addAnswer(new Answer('Digimon', true))
->addAnswer(new Answer('Floris')) ->addAnswer(new Answer('Floris'))
->addAnswer(new Answer('Het huis Anubis')) ->addAnswer(new Answer('Het huis Anubis'))
->addAnswer(new Answer('Sesamstraat')) ->addAnswer(new Answer('Sesamstraat'))
->addAnswer(new Answer('Spongebob Squarepants')) ->addAnswer(new Answer('Spongebob Squarepants'))
->addAnswer(new Answer('Teletubbies')) ->addAnswer(new Answer('Teletubbies'));
->setOrdering(11), $q->ordering = 11;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Waarin zat op de heenreis de bagage van de Krtek (voornamelijk)?') $q->question = 'Waarin zat op de heenreis de bagage van de Krtek (voornamelijk)?';
->addAnswer(new Answer('In koffer(s)', true)) $q->addAnswer(new Answer('In koffer(s)', true))
->addAnswer(new Answer('In losse tas(sen)')) ->addAnswer(new Answer('In losse tas(sen)'))
->addAnswer(new Answer('In een rugzak')) ->addAnswer(new Answer('In een rugzak'));
->setOrdering(12), $q->ordering = 12;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Van welk geluid gaan de haren van de Krtek overeind staan?') $q->question = 'Van welk geluid gaan de haren van de Krtek overeind staan?';
->addAnswer(new Answer('Een vork die door een metalen pan krast ')) $q->addAnswer(new Answer('Een vork die door een metalen pan krast '))
->addAnswer(new Answer('Smakkende mensen')) ->addAnswer(new Answer('Smakkende mensen'))
->addAnswer(new Answer('Een vork die over een bord schraapt')) ->addAnswer(new Answer('Een vork die over een bord schraapt'))
->addAnswer(new Answer('Schuren met schuurpapier')) ->addAnswer(new Answer('Schuren met schuurpapier'))
->addAnswer(new Answer('Nagels op een krijtbord')) ->addAnswer(new Answer('Nagels op een krijtbord'))
->addAnswer(new Answer('Servies dat tegen elkaar klettert')) ->addAnswer(new Answer('Servies dat tegen elkaar klettert'))
->addAnswer(new Answer('Het geroekoe van een duif', true)) ->addAnswer(new Answer('Het geroekoe van een duif', true))
->addAnswer(new Answer('Piepschuim')) ->addAnswer(new Answer('Piepschuim'));
->setOrdering(13), $q->ordering = 13;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Wilde de Krtek penningmeester worden?') $q->question = 'Wilde de Krtek penningmeester worden?';
->addAnswer(new Answer('Ja')) $q->addAnswer(new Answer('Ja'))
->addAnswer(new Answer('Nee', true)) ->addAnswer(new Answer('Nee', true));
->setOrdering(14), $q->ordering = 14;
) $quiz->addQuestion($q);
->addQuestion(new Question() $q = new Question();
->setQuestion('Wie is de Krtek?') $q->question = 'Wie is de Krtek?';
->addAnswer(new Answer('Claudia', true)) $q->addAnswer(new Answer('Claudia', true))
->addAnswer(new Answer('Eelco')) ->addAnswer(new Answer('Eelco'))
->addAnswer(new Answer('Elise')) ->addAnswer(new Answer('Elise'))
->addAnswer(new Answer('Gert-Jan')) ->addAnswer(new Answer('Gert-Jan'))
@@ -364,9 +367,10 @@ class KrtekFixtures extends Fixture
->addAnswer(new Answer('Philine')) ->addAnswer(new Answer('Philine'))
->addAnswer(new Answer('Remy')) ->addAnswer(new Answer('Remy'))
->addAnswer(new Answer('Robbert')) ->addAnswer(new Answer('Robbert'))
->addAnswer(new Answer('Tom')) ->addAnswer(new Answer('Tom'));
->setOrdering(15), $q->ordering = 15;
) $quiz->addQuestion($q);
;
return $quiz;
} }
} }

19
src/Dto/Result.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Tvdt\Dto;
use Symfony\Component\Uid\Uuid;
final readonly class Result
{
public function __construct(
public Uuid $id,
public string $name,
public int $correct,
public float $corrections,
public \DateInterval $time,
public float $score,
) {}
}

View File

@@ -8,7 +8,6 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\AnswerRepository; use Tvdt\Repository\AnswerRepository;
@@ -16,115 +15,46 @@ use Tvdt\Repository\AnswerRepository;
#[ORM\Entity(repositoryClass: AnswerRepository::class)] #[ORM\Entity(repositoryClass: AnswerRepository::class)]
class Answer class Answer
{ {
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)] #[ORM\Column(type: UuidType::NAME)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])] #[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])]
private int $ordering = 0; public int $ordering = 0;
#[ORM\ManyToOne(inversedBy: 'answers')]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private Question $question; #[ORM\ManyToOne(inversedBy: 'answers')]
public Question $question;
/** @var Collection<int, Candidate> */ /** @var Collection<int, Candidate> */
#[ORM\ManyToMany(targetEntity: Candidate::class, inversedBy: 'answersOnCandidate')] #[ORM\ManyToMany(targetEntity: Candidate::class, inversedBy: 'answersOnCandidate')]
private Collection $candidates; public private(set) Collection $candidates;
/** @var Collection<int, GivenAnswer> */ /** @var Collection<int, GivenAnswer> */
#[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'answer', orphanRemoval: true)] #[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'answer', orphanRemoval: true)]
private Collection $givenAnswers; public private(set) Collection $givenAnswers;
public function __construct( public function __construct(
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
private string $text, public string $text,
#[ORM\Column] #[ORM\Column]
private bool $isRightAnswer = false, public bool $isRightAnswer = false,
) { ) {
$this->candidates = new ArrayCollection(); $this->candidates = new ArrayCollection();
$this->givenAnswers = new ArrayCollection(); $this->givenAnswers = new ArrayCollection();
} }
public function getId(): Uuid public function addCandidate(Candidate $candidate): void
{
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<int, Candidate> */
public function getCandidates(): Collection
{
return $this->candidates;
}
public function addCandidate(Candidate $candidate): static
{ {
if (!$this->candidates->contains($candidate)) { if (!$this->candidates->contains($candidate)) {
$this->candidates->add($candidate); $this->candidates->add($candidate);
} }
return $this;
} }
public function removeCandidate(Candidate $candidate): static public function removeCandidate(Candidate $candidate): void
{ {
$this->candidates->removeElement($candidate); $this->candidates->removeElement($candidate);
return $this;
}
/** @return Collection<int, GivenAnswer> */
public function getGivenAnswers(): Collection
{
return $this->givenAnswers;
}
public function getOrdering(): int
{
return $this->ordering;
}
public function setOrdering(int $ordering): self
{
$this->ordering = $ordering;
return $this;
} }
} }

View File

@@ -7,7 +7,6 @@ namespace Tvdt\Entity;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Helpers\Base64; use Tvdt\Helpers\Base64;
@@ -17,105 +16,53 @@ use Tvdt\Repository\CandidateRepository;
#[ORM\UniqueConstraint(fields: ['name', 'season'])] #[ORM\UniqueConstraint(fields: ['name', 'season'])]
class Candidate class Candidate
{ {
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)] #[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\ManyToOne(inversedBy: 'candidates')]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private Season $season; #[ORM\ManyToOne(inversedBy: 'candidates')]
public Season $season;
/** @var Collection<int, Answer> */ /** @var Collection<int, Answer> */
#[ORM\ManyToMany(targetEntity: Answer::class, mappedBy: 'candidates')] #[ORM\ManyToMany(targetEntity: Answer::class, mappedBy: 'candidates')]
private Collection $answersOnCandidate; public private(set) Collection $answersOnCandidate;
/** @var Collection<int, GivenAnswer> */ /** @var Collection<int, GivenAnswer> */
#[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'candidate', orphanRemoval: true)] #[ORM\OneToMany(targetEntity: GivenAnswer::class, mappedBy: 'candidate', orphanRemoval: true)]
private Collection $givenAnswers; public private(set) Collection $givenAnswers;
/** @var Collection<int, QuizCandidate> */ /** @var Collection<int, QuizCandidate> */
#[ORM\OneToMany(targetEntity: QuizCandidate::class, mappedBy: 'candidate', orphanRemoval: true)] #[ORM\OneToMany(targetEntity: QuizCandidate::class, mappedBy: 'candidate', orphanRemoval: true)]
private Collection $quizData; public private(set) Collection $quizData;
public string $nameHash {
get => Base64::base64UrlEncode($this->name);
}
public function __construct( public function __construct(
#[ORM\Column(length: 16)] #[ORM\Column(length: 16)]
private string $name, public string $name,
) { ) {
$this->answersOnCandidate = new ArrayCollection(); $this->answersOnCandidate = new ArrayCollection();
$this->givenAnswers = new ArrayCollection(); $this->givenAnswers = new ArrayCollection();
$this->quizData = new ArrayCollection(); $this->quizData = new ArrayCollection();
} }
public function getId(): Uuid public function addAnswersOnCandidate(Answer $answersOnCandidate): void
{
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<int, Answer> */
public function getAnswersOnCandidate(): Collection
{
return $this->answersOnCandidate;
}
public function addAnswersOnCandidate(Answer $answersOnCandidate): static
{ {
if (!$this->answersOnCandidate->contains($answersOnCandidate)) { if (!$this->answersOnCandidate->contains($answersOnCandidate)) {
$this->answersOnCandidate->add($answersOnCandidate); $this->answersOnCandidate->add($answersOnCandidate);
$answersOnCandidate->addCandidate($this); $answersOnCandidate->addCandidate($this);
} }
return $this;
} }
public function removeAnswersOnCandidate(Answer $answersOnCandidate): static public function removeAnswersOnCandidate(Answer $answersOnCandidate): void
{ {
if ($this->answersOnCandidate->removeElement($answersOnCandidate)) { if ($this->answersOnCandidate->removeElement($answersOnCandidate)) {
$answersOnCandidate->removeCandidate($this); $answersOnCandidate->removeCandidate($this);
} }
return $this;
}
/** @return Collection<int, GivenAnswer> */
public function getGivenAnswers(): Collection
{
return $this->givenAnswers;
}
/** @return Collection<int, QuizCandidate> */
public function getQuizData(): Collection
{
return $this->quizData;
}
public function getNameHash(): string
{
return Base64::base64UrlEncode($this->name);
} }
} }

View File

@@ -7,7 +7,6 @@ namespace Tvdt\Entity;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Safe\DateTimeImmutable; use Safe\DateTimeImmutable;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\HttpFoundation\InputBag; use Symfony\Component\HttpFoundation\InputBag;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
@@ -21,49 +20,25 @@ class Elimination
public const string SCREEN_RED = 'red'; public const string SCREEN_RED = 'red';
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)] #[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
/** @var array<string, mixed> */ /** @var array<string, mixed> */
#[ORM\Column(type: Types::JSON)] #[ORM\Column(type: Types::JSONB)]
private array $data = []; public array $data = [];
#[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: false)] #[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: false)]
private \DateTimeImmutable $created; public private(set) \DateTimeImmutable $created;
public function __construct( public function __construct(
#[ORM\ManyToOne(inversedBy: 'eliminations')]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private Quiz $quiz, #[ORM\ManyToOne(inversedBy: 'eliminations')]
public Quiz $quiz,
) {} ) {}
public function getId(): Uuid
{
return $this->id;
}
/** @return array<string, mixed> */
public function getData(): array
{
return $this->data;
}
/** @param array<string, mixed> $data */
public function setData(array $data): self
{
$this->data = $data;
return $this;
}
public function getQuiz(): Quiz
{
return $this->quiz;
}
/** @param InputBag<bool|float|int|string> $inputBag */ /** @param InputBag<bool|float|int|string> $inputBag */
public function updateFromInputBag(InputBag $inputBag): self public function updateFromInputBag(InputBag $inputBag): self
{ {
@@ -87,9 +62,4 @@ class Elimination
{ {
$this->created = new DateTimeImmutable(); $this->created = new DateTimeImmutable();
} }
public function getCreated(): \DateTimeInterface
{
return $this->created;
}
} }

View File

@@ -7,7 +7,6 @@ namespace Tvdt\Entity;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Safe\DateTimeImmutable; use Safe\DateTimeImmutable;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\GivenAnswerRepository; use Tvdt\Repository\GivenAnswerRepository;
@@ -16,54 +15,29 @@ use Tvdt\Repository\GivenAnswerRepository;
#[ORM\HasLifecycleCallbacks] #[ORM\HasLifecycleCallbacks]
class GivenAnswer class GivenAnswer
{ {
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)] #[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: false)] #[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: false)]
private \DateTimeImmutable $created; public private(set) \DateTimeImmutable $created;
public function __construct( public function __construct(
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private Candidate $candidate, #[ORM\ManyToOne(inversedBy: 'givenAnswers')]
private(set) Candidate $candidate,
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private Quiz $quiz, #[ORM\ManyToOne]
private(set) Quiz $quiz,
#[ORM\ManyToOne(inversedBy: 'givenAnswers')]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private Answer $answer, #[ORM\ManyToOne(inversedBy: 'givenAnswers')]
private(set) Answer $answer,
) {} ) {}
public function getId(): Uuid
{
return $this->id;
}
public function getCandidate(): Candidate
{
return $this->candidate;
}
public function getQuiz(): Quiz
{
return $this->quiz;
}
public function getAnswer(): Answer
{
return $this->answer;
}
public function getCreated(): \DateTimeImmutable
{
return $this->created;
}
#[ORM\PrePersist] #[ORM\PrePersist]
public function setCreatedAtValue(): void public function setCreatedAtValue(): void
{ {

View File

@@ -8,7 +8,6 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\QuestionRepository; use Tvdt\Repository\QuestionRepository;
@@ -16,87 +15,40 @@ use Tvdt\Repository\QuestionRepository;
#[ORM\Entity(repositoryClass: QuestionRepository::class)] #[ORM\Entity(repositoryClass: QuestionRepository::class)]
class Question class Question
{ {
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)] #[ORM\Column(type: UuidType::NAME)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])] #[ORM\Column(type: Types::SMALLINT, options: ['default' => 0])]
private int $ordering; public int $ordering;
#[ORM\Column(type: Types::STRING, length: 255)] #[ORM\Column(type: Types::STRING, length: 255)]
private string $question; public string $question;
#[ORM\ManyToOne(inversedBy: 'questions')]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private Quiz $quiz; #[ORM\ManyToOne(inversedBy: 'questions')]
public Quiz $quiz;
#[ORM\Column] #[ORM\Column]
private bool $enabled = true; public bool $enabled = true;
/** @var Collection<int, Answer> */ /** @var Collection<int, Answer> */
#[ORM\OneToMany(targetEntity: Answer::class, mappedBy: 'question', cascade: ['persist'], orphanRemoval: true)] #[ORM\OneToMany(targetEntity: Answer::class, mappedBy: 'question', cascade: ['persist'], orphanRemoval: true)]
#[ORM\OrderBy(['ordering' => 'ASC'])] #[ORM\OrderBy(['ordering' => 'ASC'])]
private Collection $answers; public private(set) Collection $answers;
public function __construct() public function __construct()
{ {
$this->answers = new ArrayCollection(); $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<int, Answer> */
public function getAnswers(): Collection
{
return $this->answers;
}
public function addAnswer(Answer $answer): static public function addAnswer(Answer $answer): static
{ {
if (!$this->answers->contains($answer)) { if (!$this->answers->contains($answer)) {
$this->answers->add($answer); $this->answers->add($answer);
$answer->setQuestion($this); $answer->question = $this;
} }
return $this; return $this;
@@ -108,7 +60,7 @@ class Question
return 'This question has no answers'; return 'This question has no answers';
} }
$correctAnswers = $this->answers->filter(static fn (Answer $answer): bool => $answer->isRightAnswer())->count(); $correctAnswers = $this->answers->filter(static fn (Answer $answer): bool => $answer->isRightAnswer)->count();
if (0 === $correctAnswers) { if (0 === $correctAnswers) {
return 'This question has no correct answers'; return 'This question has no correct answers';
@@ -120,16 +72,4 @@ class Question
return null; return null;
} }
public function getOrdering(): int
{
return $this->ordering;
}
public function setOrdering(int $ordering): static
{
$this->ordering = $ordering;
return $this;
}
} }

View File

@@ -7,7 +7,6 @@ namespace Tvdt\Entity;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\QuizRepository; use Tvdt\Repository\QuizRepository;
@@ -16,35 +15,35 @@ use Tvdt\Repository\QuizRepository;
#[ORM\UniqueConstraint(fields: ['name', 'season'])] #[ORM\UniqueConstraint(fields: ['name', 'season'])]
class Quiz class Quiz
{ {
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)] #[ORM\Column(type: UuidType::NAME)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\Column(length: 64)] #[ORM\Column(length: 64)]
private string $name; public string $name;
#[ORM\ManyToOne(inversedBy: 'quizzes')]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private Season $season; #[ORM\ManyToOne(inversedBy: 'quizzes')]
public Season $season;
/** @var Collection<int, Question> */ /** @var Collection<int, Question> */
#[ORM\OneToMany(targetEntity: Question::class, mappedBy: 'quiz', cascade: ['persist'], orphanRemoval: true)] #[ORM\OneToMany(targetEntity: Question::class, mappedBy: 'quiz', cascade: ['persist'], orphanRemoval: true)]
#[ORM\OrderBy(['ordering' => 'ASC'])] #[ORM\OrderBy(['ordering' => 'ASC'])]
private Collection $questions; public private(set) Collection $questions;
/** @var Collection<int, QuizCandidate> */ /** @var Collection<int, QuizCandidate> */
#[ORM\OneToMany(targetEntity: QuizCandidate::class, mappedBy: 'quiz', orphanRemoval: true)] #[ORM\OneToMany(targetEntity: QuizCandidate::class, mappedBy: 'quiz', orphanRemoval: true)]
private Collection $candidateData; public private(set) Collection $candidateData;
#[ORM\Column(nullable: false, options: ['default' => 1])] #[ORM\Column(nullable: false, options: ['default' => 1])]
private int $dropouts = 1; public int $dropouts = 1;
/** @var Collection<int, Elimination> */ /** @var Collection<int, Elimination> */
#[ORM\OneToMany(targetEntity: Elimination::class, mappedBy: 'quiz', cascade: ['persist'], orphanRemoval: true)] #[ORM\OneToMany(targetEntity: Elimination::class, mappedBy: 'quiz', cascade: ['persist'], orphanRemoval: true)]
#[ORM\OrderBy(['created' => 'DESC'])] #[ORM\OrderBy(['created' => 'DESC'])]
private Collection $eliminations; public private(set) Collection $eliminations;
public function __construct() public function __construct()
{ {
@@ -53,75 +52,16 @@ class Quiz
$this->eliminations = new ArrayCollection(); $this->eliminations = 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<int, Question> */
public function getQuestions(): Collection
{
return $this->questions;
}
public function addQuestion(Question $question): static public function addQuestion(Question $question): static
{ {
if (!$this->questions->contains($question)) { if (!$this->questions->contains($question)) {
$this->questions->add($question); $this->questions->add($question);
$question->setQuiz($this); $question->quiz = $this;
} }
return $this; return $this;
} }
/** @return Collection<int, QuizCandidate> */
public function getCandidateData(): Collection
{
return $this->candidateData;
}
public function getDropouts(): int
{
return $this->dropouts;
}
public function setDropouts(int $dropouts): static
{
$this->dropouts = $dropouts;
return $this;
}
/** @return Collection<int, Elimination> */
public function getEliminations(): Collection
{
return $this->eliminations;
}
public function addElimination(Elimination $elimination): self public function addElimination(Elimination $elimination): self
{ {
$this->eliminations->add($elimination); $this->eliminations->add($elimination);

View File

@@ -7,70 +7,37 @@ namespace Tvdt\Entity;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Safe\DateTimeImmutable; use Safe\DateTimeImmutable;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\QuizCandidateRepository; use Tvdt\Repository\QuizCandidateRepository;
#[ORM\Entity(repositoryClass: QuizCandidateRepository::class)] #[ORM\Entity(repositoryClass: QuizCandidateRepository::class)]
#[ORM\UniqueConstraint(columns: ['candidate_id', 'quiz_id'])]
#[ORM\HasLifecycleCallbacks] #[ORM\HasLifecycleCallbacks]
#[ORM\UniqueConstraint(columns: ['candidate_id', 'quiz_id'])]
class QuizCandidate class QuizCandidate
{ {
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)] #[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\Column] #[ORM\Column]
private float $corrections = 0; public float $corrections = 0;
#[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE)] #[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE)]
private \DateTimeImmutable $created; public private(set) \DateTimeImmutable $created;
public function __construct( public function __construct(
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'candidateData')] #[ORM\ManyToOne(inversedBy: 'candidateData')]
#[ORM\JoinColumn(nullable: false)] public Quiz $quiz,
private Quiz $quiz,
#[ORM\JoinColumn(nullable: false)]
#[ORM\ManyToOne(inversedBy: 'quizData')] #[ORM\ManyToOne(inversedBy: 'quizData')]
#[ORM\JoinColumn(nullable: false)] public Candidate $candidate,
private Candidate $candidate,
) {} ) {}
public function getId(): Uuid
{
return $this->id;
}
public function getCandidate(): Candidate
{
return $this->candidate;
}
public function getQuiz(): Quiz
{
return $this->quiz;
}
public function getCorrections(): ?float
{
return $this->corrections;
}
public function setCorrections(float $corrections): static
{
$this->corrections = $corrections;
return $this;
}
public function getCreated(): \DateTimeImmutable
{
return $this->created;
}
#[ORM\PrePersist] #[ORM\PrePersist]
public function setCreatedAtValue(): void public function setCreatedAtValue(): void
{ {

View File

@@ -7,7 +7,6 @@ namespace Tvdt\Entity;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\SeasonRepository; use Tvdt\Repository\SeasonRepository;
@@ -17,38 +16,38 @@ class Season
{ {
private const string SEASON_CODE_CHARACTERS = 'bcdfghjklmnpqrstvwxz'; private const string SEASON_CODE_CHARACTERS = 'bcdfghjklmnpqrstvwxz';
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME)] #[ORM\Column(type: UuidType::NAME)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\Column(length: 64)] #[ORM\Column(length: 64)]
private string $name; public string $name;
#[ORM\Column(length: 5)] #[ORM\Column(length: 5)]
private string $seasonCode; public string $seasonCode;
/** @var Collection<int, Quiz> */ /** @var Collection<int, Quiz> */
#[ORM\OneToMany(targetEntity: Quiz::class, mappedBy: 'season', cascade: ['persist'], orphanRemoval: true)] #[ORM\OneToMany(targetEntity: Quiz::class, mappedBy: 'season', cascade: ['persist'], orphanRemoval: true)]
private Collection $quizzes; public private(set) Collection $quizzes;
/** @var Collection<int, Candidate> */ /** @var Collection<int, Candidate> */
#[ORM\OneToMany(targetEntity: Candidate::class, mappedBy: 'season', cascade: ['persist'], orphanRemoval: true)] #[ORM\OneToMany(targetEntity: Candidate::class, mappedBy: 'season', cascade: ['persist'], orphanRemoval: true)]
#[ORM\OrderBy(['name' => 'ASC'])] #[ORM\OrderBy(['name' => 'ASC'])]
private Collection $candidates; public private(set) Collection $candidates;
/** @var Collection<int, User> */ /** @var Collection<int, User> */
#[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'seasons')] #[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'seasons')]
private Collection $owners; public private(set) Collection $owners;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')] #[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
private ?Quiz $ActiveQuiz = null; #[ORM\ManyToOne]
public ?Quiz $activeQuiz = null;
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
#[ORM\JoinColumn(nullable: true)] #[ORM\JoinColumn(nullable: true)]
private ?SeasonSettings $settings = null; #[ORM\OneToOne(cascade: ['persist', 'remove'])]
public ?SeasonSettings $settings = null;
public function __construct() public function __construct()
{ {
@@ -58,73 +57,26 @@ class Season
$this->owners = 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;
}
/** @return Collection<int, Quiz> */
public function getQuizzes(): Collection
{
return $this->quizzes;
}
public function addQuiz(Quiz $quiz): static public function addQuiz(Quiz $quiz): static
{ {
if (!$this->quizzes->contains($quiz)) { if (!$this->quizzes->contains($quiz)) {
$this->quizzes->add($quiz); $this->quizzes->add($quiz);
$quiz->setSeason($this); $quiz->season = $this;
} }
return $this; return $this;
} }
/** @return Collection<int, Candidate> */
public function getCandidates(): Collection
{
return $this->candidates;
}
public function addCandidate(Candidate $candidate): static public function addCandidate(Candidate $candidate): static
{ {
if (!$this->candidates->contains($candidate)) { if (!$this->candidates->contains($candidate)) {
$this->candidates->add($candidate); $this->candidates->add($candidate);
$candidate->setSeason($this); $candidate->season = $this;
} }
return $this; return $this;
} }
/** @return Collection<int, User> */
public function getOwners(): Collection
{
return $this->owners;
}
public function addOwner(User $owner): static public function addOwner(User $owner): static
{ {
if (!$this->owners->contains($owner)) { if (!$this->owners->contains($owner)) {
@@ -141,18 +93,6 @@ class Season
return $this; return $this;
} }
public function getActiveQuiz(): ?Quiz
{
return $this->ActiveQuiz;
}
public function setActiveQuiz(?Quiz $ActiveQuiz): static
{
$this->ActiveQuiz = $ActiveQuiz;
return $this;
}
public function isOwner(User $user): bool public function isOwner(User $user): bool
{ {
return $this->owners->contains($user); return $this->owners->contains($user);
@@ -171,16 +111,4 @@ class Season
return $this; return $this;
} }
public function getSettings(): ?SeasonSettings
{
return $this->settings;
}
public function setSettings(SeasonSettings $settings): static
{
$this->settings = $settings;
return $this;
}
} }

View File

@@ -6,7 +6,6 @@ namespace Tvdt\Entity;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Tvdt\Repository\SeasonSettingsRepository; use Tvdt\Repository\SeasonSettingsRepository;
@@ -14,44 +13,15 @@ use Tvdt\Repository\SeasonSettingsRepository;
#[ORM\Entity(repositoryClass: SeasonSettingsRepository::class)] #[ORM\Entity(repositoryClass: SeasonSettingsRepository::class)]
class SeasonSettings class SeasonSettings
{ {
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Column(type: UuidType::NAME)] #[ORM\Column(type: UuidType::NAME)]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private Uuid $id; #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\Id]
public private(set) Uuid $id;
#[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])] #[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])]
private bool $showNumbers = false; public bool $showNumbers = false;
#[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])] #[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])]
private bool $confirmAnswers = false; public bool $confirmAnswers = false;
public function getId(): Uuid
{
return $this->id;
}
public function isShowNumbers(): bool
{
return $this->showNumbers;
}
public function setShowNumbers(bool $showNumbers): self
{
$this->showNumbers = $showNumbers;
return $this;
}
public function isConfirmAnswers(): bool
{
return $this->confirmAnswers;
}
public function setConfirmAnswers(bool $confirmAnswers): self
{
$this->confirmAnswers = $confirmAnswers;
return $this;
}
} }

View File

@@ -8,7 +8,6 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
@@ -22,52 +21,39 @@ use Tvdt\Repository\UserRepository;
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')] #[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface class User implements UserInterface, PasswordAuthenticatedUserInterface
{ {
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)] #[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
#[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)] #[ORM\Id]
private Uuid $id; public private(set) Uuid $id;
#[ORM\Column(length: 180)] #[ORM\Column(length: 180)]
private string $email; public string $email;
/** @var list<string> The user roles */ /** @var list<string> The user roles */
#[ORM\Column(type: Types::JSON)] #[ORM\Column(type: Types::JSON)]
private array $roles = []; public array $roles = [];
/** @var string The hashed password */ /** @var string The hashed password */
#[ORM\Column] #[ORM\Column]
private string $password; public string $password;
/** @var Collection<int, Season> */ /** @var Collection<int, Season> */
#[ORM\ManyToMany(targetEntity: Season::class, mappedBy: 'owners')] #[ORM\ManyToMany(targetEntity: Season::class, mappedBy: 'owners')]
private Collection $seasons; public private(set) Collection $seasons;
#[ORM\Column] #[ORM\Column]
private bool $isVerified = false; public bool $isVerified = false;
public bool $isAdmin {
get => \in_array('ROLE_ADMIN', $this->getRoles(), true);
}
public function __construct() public function __construct()
{ {
$this->seasons = new ArrayCollection(); $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. * A visual identifier that represents this user.
* *
@@ -97,27 +83,12 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return array_unique($roles); return array_unique($roles);
} }
/** @param list<string> $roles */
public function setRoles(array $roles): static
{
$this->roles = $roles;
return $this;
}
/** @see PasswordAuthenticatedUserInterface */ /** @see PasswordAuthenticatedUserInterface */
public function getPassword(): ?string public function getPassword(): ?string
{ {
return $this->password; return $this->password;
} }
public function setPassword(string $password): static
{
$this->password = $password;
return $this;
}
/** @see UserInterface */ /** @see UserInterface */
public function eraseCredentials(): void public function eraseCredentials(): void
{ {
@@ -125,12 +96,6 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
// $this->plainPassword = null; // $this->plainPassword = null;
} }
/** @return Collection<int, Season> */
public function getSeasons(): Collection
{
return $this->seasons;
}
public function addSeason(Season $season): static public function addSeason(Season $season): static
{ {
if (!$this->seasons->contains($season)) { if (!$this->seasons->contains($season)) {
@@ -149,21 +114,4 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
public function isVerified(): bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): static
{
$this->isVerified = $isVerified;
return $this;
}
public function isAdmin(): bool
{
return \in_array('ROLE_ADMIN', $this->getRoles(), true);
}
} }

View File

@@ -26,10 +26,10 @@ final readonly class EliminationFactory
$simpleScores = []; $simpleScores = [];
foreach (array_reverse($scores) as $i => $score) { foreach (array_reverse($scores) as $i => $score) {
$simpleScores[$score['name']] = $i < $quiz->getDropouts() ? Elimination::SCREEN_RED : Elimination::SCREEN_GREEN; $simpleScores[$score->name] = $i < $quiz->dropouts ? Elimination::SCREEN_RED : Elimination::SCREEN_GREEN;
} }
$elimination->setData($simpleScores); $elimination->data = $simpleScores;
$this->em->flush(); $this->em->flush();

View File

@@ -6,8 +6,10 @@ namespace Tvdt\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
use Safe\DateTimeImmutable;
use Safe\Exceptions\DatetimeException;
use Safe\Exceptions\UrlException; use Safe\Exceptions\UrlException;
use Symfony\Component\Uid\Uuid; use Tvdt\Dto\Result;
use Tvdt\Entity\Candidate; use Tvdt\Entity\Candidate;
use Tvdt\Entity\Quiz; use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season; use Tvdt\Entity\Season;
@@ -15,9 +17,6 @@ use Tvdt\Helpers\Base64;
/** /**
* @extends ServiceEntityRepository<Candidate> * @extends ServiceEntityRepository<Candidate>
*
* @phpstan-type Result array{id: Uuid, name: string, correct: int, time: \DateInterval, corrections: float, score: float}
* @phpstan-type ResultList list<Result>
*/ */
class CandidateRepository extends ServiceEntityRepository class CandidateRepository extends ServiceEntityRepository
{ {
@@ -53,16 +52,21 @@ class CandidateRepository extends ServiceEntityRepository
} }
} }
/** @return ResultList */ /**
* @throws DatetimeException
*
* @return list<Result>
*/
public function getScores(Quiz $quiz): array public function getScores(Quiz $quiz): array
{ {
return $this->getEntityManager()->createQuery(<<<DQL $result = $this->getEntityManager()->createQuery(<<<DQL
select select
c.id, c.id,
c.name, c.name,
sum(case when a.isRightAnswer = true then 1 else 0 end) as correct, sum(case when a.isRightAnswer = true then 1 else 0 end) as correct,
qc.corrections, qc.corrections,
max(ga.created) - qc.created as time, max(ga.created) as end_time,
qc.created as start_time,
(sum(case when a.isRightAnswer = true then 1 else 0 end) + qc.corrections) as score (sum(case when a.isRightAnswer = true then 1 else 0 end) + qc.corrections) as score
from Tvdt\Entity\Candidate c from Tvdt\Entity\Candidate c
join c.givenAnswers ga join c.givenAnswers ga
@@ -70,8 +74,17 @@ class CandidateRepository extends ServiceEntityRepository
join c.quizData qc join c.quizData qc
where qc.quiz = :quiz and ga.quiz = :quiz where qc.quiz = :quiz and ga.quiz = :quiz
group by ga.quiz, c.id, qc.id group by ga.quiz, c.id, qc.id
order by score desc, time asc order by score desc, max(ga.created) - qc.created asc
DQL DQL
)->setParameter('quiz', $quiz)->getResult(); )->setParameter('quiz', $quiz)->getResult();
return array_map(static fn (array $row): Result => new Result(
id: $row['id'],
name: $row['name'],
correct: (int) $row['correct'],
corrections: $row['corrections'],
time: new DateTimeImmutable($row['end_time'])->diff($row['start_time']),
score: $row['score'],
), $result);
} }
} }

View File

@@ -35,7 +35,7 @@ class QuestionRepository extends ServiceEntityRepository
DQL) DQL)
->setMaxResults(1) ->setMaxResults(1)
->setParameter('candidate', $candidate) ->setParameter('candidate', $candidate)
->setParameter('quiz', $candidate->getSeason()->getActiveQuiz()) ->setParameter('quiz', $candidate->season->activeQuiz)
->getOneOrNullResult(); ->getOneOrNullResult();
} }
} }

View File

@@ -41,7 +41,7 @@ class QuizCandidateRepository extends ServiceEntityRepository
throw new \InvalidArgumentException('Quiz candidate not found'); throw new \InvalidArgumentException('Quiz candidate not found');
} }
$quizCandidate->setCorrections($corrections); $quizCandidate->corrections = $corrections;
$this->getEntityManager()->flush(); $this->getEntityManager()->flush();
} }
} }

View File

@@ -23,7 +23,7 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
* */ * */
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{ {
$user->setPassword($newHashedPassword); $user->password = $newHashedPassword;
$this->getEntityManager()->persist($user); $this->getEntityManager()->persist($user);
$this->getEntityManager()->flush(); $this->getEntityManager()->flush();
} }
@@ -35,7 +35,7 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
throw new \InvalidArgumentException('User not found'); throw new \InvalidArgumentException('User not found');
} }
$user->setRoles(['ROLE_ADMIN']); $user->roles = ['ROLE_ADMIN'];
$this->getEntityManager()->flush(); $this->getEntityManager()->flush();
} }
} }

View File

@@ -25,9 +25,9 @@ readonly class EmailVerifier
{ {
$signatureComponents = $this->verifyEmailHelper->generateSignature( $signatureComponents = $this->verifyEmailHelper->generateSignature(
$verifyEmailRouteName, $verifyEmailRouteName,
(string) $user->getId(), $user->id->toRfc4122(),
(string) $user->getEmail(), $user->email,
['id' => $user->getId()], ['id' => $user->id],
); );
$context = $email->getContext(); $context = $email->getContext();
@@ -42,9 +42,9 @@ readonly class EmailVerifier
public function handleEmailConfirmation(Request $request, User $user): void public function handleEmailConfirmation(Request $request, User $user): void
{ {
$this->verifyEmailHelper->validateEmailConfirmationFromRequest($request, (string) $user->getId(), (string) $user->getEmail()); $this->verifyEmailHelper->validateEmailConfirmationFromRequest($request, $user->id->toRfc4122(), $user->email);
$user->setIsVerified(true); $user->isVerified = true;
$this->entityManager->persist($user); $this->entityManager->persist($user);
$this->entityManager->flush(); $this->entityManager->flush();

View File

@@ -15,7 +15,7 @@ use Tvdt\Entity\Quiz;
use Tvdt\Entity\Season; use Tvdt\Entity\Season;
use Tvdt\Entity\User; use Tvdt\Entity\User;
/** @extends Voter<string, Season> */ /** @extends Voter<string, Season|Elimination|Quiz|Candidate|Answer|Question> */
final class SeasonVoter extends Voter final class SeasonVoter extends Voter
{ {
public const string EDIT = 'SEASON_EDIT'; public const string EDIT = 'SEASON_EDIT';
@@ -28,16 +28,15 @@ final class SeasonVoter extends Voter
{ {
return \in_array($attribute, [self::EDIT, self::DELETE, self::ELIMINATION], true) return \in_array($attribute, [self::EDIT, self::DELETE, self::ELIMINATION], true)
&& ( && (
$subject instanceof Season $subject instanceof Answer
|| $subject instanceof Elimination
|| $subject instanceof Quiz
|| $subject instanceof Candidate || $subject instanceof Candidate
|| $subject instanceof Answer || $subject instanceof Elimination
|| $subject instanceof Season
|| $subject instanceof Question || $subject instanceof Question
|| $subject instanceof Quiz
); );
} }
/** @param Season|Elimination|Quiz|Candidate|Answer|Question $subject */
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
{ {
$user = $token->getUser(); $user = $token->getUser();
@@ -45,21 +44,21 @@ final class SeasonVoter extends Voter
return false; return false;
} }
if ($user->isAdmin()) { if ($user->isAdmin) {
return true; return true;
} }
switch (true) { switch (true) {
case $subject instanceof Answer: case $subject instanceof Answer:
$season = $subject->getQuestion()->getQuiz()->getSeason(); $season = $subject->question->quiz->season;
break; break;
case $subject instanceof Elimination: case $subject instanceof Elimination:
case $subject instanceof Question: case $subject instanceof Question:
$season = $subject->getQuiz()->getSeason(); $season = $subject->quiz->season;
break; break;
case $subject instanceof Candidate: case $subject instanceof Candidate:
case $subject instanceof Quiz: case $subject instanceof Quiz:
$season = $subject->getSeason(); $season = $subject->season;
break; break;
case $subject instanceof Season: case $subject instanceof Season:
$season = $subject; $season = $subject;

View File

@@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
namespace Tvdt\Service;
use Tvdt\Repository\CandidateRepository;
/**
* @phpstan-import-type ResultList from CandidateRepository
*/
class EliminationService
{
/** @phpstan-param ResultList $result */
public function createEliminationFromResult(array $result): void {}
}

View File

@@ -84,8 +84,8 @@ class QuizSpreadsheetService
} }
$question = new Question(); $question = new Question();
$question->setQuestion((string) $questionArr[0]); $question->question = (string) $questionArr[0];
$question->setOrdering($questionCounter++); $question->ordering = $questionCounter++;
$answerCounter = 1; $answerCounter = 1;
$arrCounter = 1; $arrCounter = 1;
@@ -100,7 +100,7 @@ class QuizSpreadsheetService
} }
$answer = new Answer((string) $questionArr[$arrCounter++], (bool) $questionArr[$arrCounter++]); $answer = new Answer((string) $questionArr[$arrCounter++], (bool) $questionArr[$arrCounter++]);
$answer->setOrdering($answerCounter++); $answer->ordering = $answerCounter++;
$question->addAnswer($answer); $question->addAnswer($answer);
} }

View File

@@ -47,15 +47,6 @@
"migrations/.gitignore" "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": { "friendsofphp/php-cs-fixer": {
"version": "3.65", "version": "3.65",
"recipe": { "recipe": {
@@ -276,12 +267,12 @@
] ]
}, },
"symfony/translation": { "symfony/translation": {
"version": "7.2", "version": "7.3",
"recipe": { "recipe": {
"repo": "github.com/symfony/recipes", "repo": "github.com/symfony/recipes",
"branch": "main", "branch": "main",
"version": "6.3", "version": "6.3",
"ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b" "ref": "620a1b84865ceb2ba304c8f8bf2a185fbf32a843"
}, },
"files": [ "files": [
"config/packages/translation.yaml", "config/packages/translation.yaml",
@@ -319,20 +310,8 @@
"ref": "c85ff94da66841d7ff087c19cbcd97a2df744ef9" "ref": "c85ff94da66841d7ff087c19cbcd97a2df744ef9"
} }
}, },
"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": { "symfony/validator": {
"version": "7.2", "version": "7.3",
"recipe": { "recipe": {
"repo": "github.com/symfony/recipes", "repo": "github.com/symfony/recipes",
"branch": "main", "branch": "main",

View File

@@ -109,7 +109,7 @@
</form> </form>
</td> </td>
<td>{{ candidate.score|default('x') }}</td> <td>{{ candidate.score|default('x') }}</td>
<td>{{ candidate.time }}</td> <td>{{ candidate.time.format('%i:%S') }}</td>
</tr> </tr>
{% else %} {% else %}
<tr> <tr>

View File

@@ -53,19 +53,19 @@ final class SeasonVoterTest extends TestCase
$season->method('isOwner')->willReturn(true); $season->method('isOwner')->willReturn(true);
$quiz = self::createStub(Quiz::class); $quiz = self::createStub(Quiz::class);
$quiz->method('getSeason')->willReturn($season); $quiz->season = $season;
$elimination = self::createStub(Elimination::class); $elimination = self::createStub(Elimination::class);
$elimination->method('getQuiz')->willReturn($quiz); $elimination->quiz = $quiz;
$candidate = self::createStub(Candidate::class); $candidate = self::createStub(Candidate::class);
$candidate->method('getSeason')->willReturn($season); $candidate->season = $season;
$question = self::createStub(Question::class); $question = self::createStub(Question::class);
$question->method('getQuiz')->willReturn($quiz); $question->quiz = $quiz;
$answer = self::createStub(Answer::class); $answer = self::createStub(Answer::class);
$answer->method('getQuestion')->willReturn($question); $answer->question = $question;
yield 'Season' => [$season]; yield 'Season' => [$season];
yield 'Elimination' => [$elimination]; yield 'Elimination' => [$elimination];

15
tests/object-manager.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
use Symfony\Component\Dotenv\Dotenv;
use Tvdt\Kernel;
require __DIR__.'/../vendor/autoload.php';
new Dotenv()->bootEnv(__DIR__.'/../.env');
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$kernel->boot();
return $kernel->getContainer()->get('doctrine')->getManager();

View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
use Tvdt\Kernel;
require __DIR__.'/bootstrap.php';
$appKernel = new Kernel('test', false);
$appKernel->boot();
return $appKernel->getContainer();