diff --git a/assets/controllers.json b/assets/controllers.json index 103b202..29ea244 100644 --- a/assets/controllers.json +++ b/assets/controllers.json @@ -1,15 +1,15 @@ { - "controllers": { - "@symfony/ux-turbo": { - "turbo-core": { - "enabled": true, - "fetch": "eager" - }, - "mercure-turbo-stream": { - "enabled": false, - "fetch": "eager" - } - } - }, - "entrypoints": [] + "controllers": { + "@symfony/ux-turbo": { + "turbo-core": { + "enabled": true, + "fetch": "eager" + }, + "mercure-turbo-stream": { + "enabled": false, + "fetch": "eager" + } + } + }, + "entrypoints": [] } diff --git a/assets/controllers/form_controller.js b/assets/controllers/form_controller.js index 5397de6..d9e1e33 100644 --- a/assets/controllers/form_controller.js +++ b/assets/controllers/form_controller.js @@ -2,7 +2,7 @@ import { Controller } from "@hotwired/stimulus"; import {loadStripe} from "@stripe/stripe-js"; export default class extends Controller { - static targets = ['key', 'submit']; + static targets = ['key', 'submit', 'firstname', 'lastname', 'email', 'phone']; stripe; @@ -40,7 +40,13 @@ export default class extends Controller { this.submitTarget.querySelector('svg').classList.remove('hidden'); const forms = document.querySelectorAll("form"); - const formData = this.getFormData(forms); + const personalData = this.getPersonalData(); + const ticketData = this.getTicketData(forms); + + const formData = { + personal: personalData, + tickets: ticketData, + } fetch("/ticket/submit", { method: "POST", @@ -61,12 +67,29 @@ export default class extends Controller { }); } - getFormData(forms) { + getTicketData(forms) { const formData = []; forms.forEach((form) => { - formData.push(Object.fromEntries(new FormData(form).entries())); + formData.push(this.extractFormData(form)); }); return formData; } + + getPersonalData() { + return { + firstname: this.firstnameTarget.value, + lastname: this.lastnameTarget.value, + email: this.emailTarget.value, + phone: this.phoneTarget.value, + }; + } + + extractFormData(form) { + return { + ticket: parseInt(form.querySelector('select[name="ticket"]').value), + food: parseInt(form.querySelector('select[name="food"]').value), + note: form.querySelector('input[name="note"]').value, + } + } } diff --git a/assets/styles/app.css b/assets/styles/app.css index b5c61c9..09771a7 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -1,3 +1,7 @@ @tailwind base; @tailwind components; @tailwind utilities; + +.text-input { + @apply border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 outline-orange-500 focus:border-orange-500 transition-colors; +} \ No newline at end of file diff --git a/composer.json b/composer.json index 885348b..d1506a7 100644 --- a/composer.json +++ b/composer.json @@ -7,11 +7,13 @@ "php": ">=8.2", "ext-ctype": "*", "ext-iconv": "*", + "doctrine/annotations": "^2.0", "doctrine/dbal": "^3", "doctrine/doctrine-bundle": "^2.13", "doctrine/doctrine-migrations-bundle": "^3.4", "doctrine/orm": "^3.3", "php-flasher/flasher-noty-symfony": "^2.1", + "phpdocumentor/reflection-docblock": "^5.6", "stripe/stripe-php": "^16.4", "symfony/asset": "7.2.*", "symfony/asset-mapper": "7.2.*", @@ -21,6 +23,8 @@ "symfony/form": "7.2.*", "symfony/framework-bundle": "7.2.*", "symfony/mailer": "7.2.*", + "symfony/property-access": "7.2.*", + "symfony/property-info": "7.2.*", "symfony/runtime": "7.2.*", "symfony/serializer": "7.2.*", "symfony/twig-bundle": "7.2.*", diff --git a/composer.lock b/composer.lock index c083e45..61a72ee 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "51f020bf0346145a2eaa666b7a83d36b", + "content-hash": "8dc2a9d9e624cf61b3c68d2678e9d53c", "packages": [ { "name": "composer/semver", @@ -87,6 +87,82 @@ ], "time": "2024-09-19T14:15:21+00:00" }, + { + "name": "doctrine/annotations", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2 || ^3", + "ext-tokenizer": "*", + "php": "^7.2 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^2.0", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.10.28", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^5.4 || ^6.4 || ^7", + "vimeo/psalm": "^4.30 || ^5.14" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/2.0.2" + }, + "time": "2024-09-05T10:17:24+00:00" + }, { "name": "doctrine/cache", "version": "2.2.0", @@ -1645,6 +1721,228 @@ ], "time": "2025-01-18T10:26:31+00:00" }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", + "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1" + }, + "time": "2024-12-07T09:39:29+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.18|^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" + }, + "time": "2024-11-09T15:12:26+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "c00d78fb6b29658347f9d37ebe104bffadf36299" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/c00d78fb6b29658347f9d37ebe104bffadf36299", + "reference": "c00d78fb6b29658347f9d37ebe104bffadf36299", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.0.0" + }, + "time": "2024-10-13T11:29:49+00:00" + }, { "name": "psr/cache", "version": "3.0.0", @@ -4543,16 +4841,16 @@ }, { "name": "symfony/property-access", - "version": "v7.2.0", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "3ae42efba01e45aaedecf5c93c8d6a3ab3a82276" + "reference": "b28732e315d81fbec787f838034de7d6c9b2b902" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/3ae42efba01e45aaedecf5c93c8d6a3ab3a82276", - "reference": "3ae42efba01e45aaedecf5c93c8d6a3ab3a82276", + "url": "https://api.github.com/repos/symfony/property-access/zipball/b28732e315d81fbec787f838034de7d6c9b2b902", + "reference": "b28732e315d81fbec787f838034de7d6c9b2b902", "shasum": "" }, "require": { @@ -4599,7 +4897,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v7.2.0" + "source": "https://github.com/symfony/property-access/tree/v7.2.3" }, "funding": [ { @@ -4615,20 +4913,20 @@ "type": "tidelift" } ], - "time": "2024-09-26T12:28:35+00:00" + "time": "2025-01-17T10:56:55+00:00" }, { "name": "symfony/property-info", - "version": "v7.2.2", + "version": "v7.2.3", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "1dfeb0dac7a99f7b3be42db9ccc299c5a6483fcf" + "reference": "dedb118fd588a92f226b390250b384d25f4192fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/1dfeb0dac7a99f7b3be42db9ccc299c5a6483fcf", - "reference": "1dfeb0dac7a99f7b3be42db9ccc299c5a6483fcf", + "url": "https://api.github.com/repos/symfony/property-info/zipball/dedb118fd588a92f226b390250b384d25f4192fe", + "reference": "dedb118fd588a92f226b390250b384d25f4192fe", "shasum": "" }, "require": { @@ -4639,7 +4937,9 @@ "conflict": { "phpdocumentor/reflection-docblock": "<5.2", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/dependency-injection": "<6.4" + "symfony/cache": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" }, "require-dev": { "phpdocumentor/reflection-docblock": "^5.2", @@ -4682,7 +4982,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v7.2.2" + "source": "https://github.com/symfony/property-info/tree/v7.2.3" }, "funding": [ { @@ -4698,7 +4998,7 @@ "type": "tidelift" } ], - "time": "2024-12-31T11:04:50+00:00" + "time": "2025-01-27T11:08:17+00:00" }, { "name": "symfony/routing", @@ -6412,6 +6712,64 @@ } ], "time": "2024-12-29T10:51:50+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" } ], "packages-dev": [ diff --git a/src/Controller/TicketController.php b/src/Controller/TicketController.php index a4cdaaa..d426959 100644 --- a/src/Controller/TicketController.php +++ b/src/Controller/TicketController.php @@ -2,8 +2,8 @@ namespace App\Controller; -use App\DataObjects\TicketData; -use App\Form\TicketForm; +use App\DataObjects\TicketFormData; +use App\Repository\PaymentRepository; use App\Service\TicketService; use Stripe\Stripe; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -17,15 +17,14 @@ final class TicketController extends AbstractController public function __construct( private TicketService $service, private SerializerInterface $serializer, + private PaymentRepository $repository, ) { } #[Route('/ticket', name: 'app_ticket')] public function index(): Response { - return $this->render('ticket/index.html.twig', [ - 'form' => $this->createForm(TicketForm::class)->createView(), - ]); + return $this->render('ticket/index.html.twig'); } #[Route(path: '/ticket/submit', name: 'app_submit', methods: Request::METHOD_POST)] @@ -33,21 +32,15 @@ final class TicketController extends AbstractController { Stripe::setApiKey($_ENV['STRIPE_SECRET_KEY']); - /** @var TicketData[] $ticketData */ - $ticketData = $this->serializer->deserialize( - $request->getContent(), - TicketData::class.'[]', - 'json', - ['disable_type_enforcement' => true] - ); + $ticketData = $this->serializer->deserialize($request->getContent(), TicketFormData::class, 'json'); return $this->json(['id' => $this->service->handleTicketData($ticketData)->id]); } #[Route(path: '/success', name: 'app_success', methods: Request::METHOD_GET)] - public function success(): Response + public function success(Request $request): Response { - $this->service->saveTicketData(); + $payment = $this->repository->findOneBy(['sessionId' => $request->query->get('session_id')]); return $this->render('ticket/success.html.twig'); } diff --git a/src/DataObjects/PersonalData.php b/src/DataObjects/PersonalData.php new file mode 100644 index 0000000..f201c80 --- /dev/null +++ b/src/DataObjects/PersonalData.php @@ -0,0 +1,14 @@ + + */ + #[ORM\OneToMany(targetEntity: Ticket::class, mappedBy: 'customer', cascade: ['persist'], fetch: 'EAGER', orphanRemoval: true)] + private Collection $tickets; + + #[ORM\OneToOne(mappedBy: 'customer', cascade: ['persist', 'remove'])] + private ?Payment $payment = null; + + public function __construct() + { + $this->tickets = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function setEmail(string $email): static + { + $this->email = $email; + + return $this; + } + + public function getPhone(): ?string + { + return $this->phone; + } + + public function setPhone(?string $phone): static + { + $this->phone = $phone; + + return $this; + } + + public function getFirstname(): ?string + { + return $this->firstname; + } + + public function setFirstname(string $firstname): static + { + $this->firstname = $firstname; + + return $this; + } + + public function getLastname(): ?string + { + return $this->lastname; + } + + public function setLastname(string $lastname): static + { + $this->lastname = $lastname; + + return $this; + } + + /** + * @return Collection + */ + public function getTickets(): Collection + { + return $this->tickets; + } + + public function addTicket(Ticket $ticket): static + { + if (!$this->tickets->contains($ticket)) { + $this->tickets->add($ticket); + $ticket->setCustomer($this); + } + + return $this; + } + + public function removeTicket(Ticket $ticket): static + { + if ($this->tickets->removeElement($ticket)) { + // set the owning side to null (unless already changed) + if ($ticket->getCustomer() === $this) { + $ticket->setCustomer(null); + } + } + + return $this; + } + + public function addTickets(array $tickets): static + { + foreach ($tickets as $ticket) { + $this->addTicket($ticket); + } + + return $this; + } + + public function getPayment(): ?Payment + { + return $this->payment; + } + + public function setPayment(Payment $payment): static + { + // set the owning side of the relation if necessary + if ($payment->getCustomer() !== $this) { + $payment->setCustomer($this); + } + + $this->payment = $payment; + + return $this; + } +} diff --git a/src/Entity/Payment.php b/src/Entity/Payment.php new file mode 100644 index 0000000..0e788af --- /dev/null +++ b/src/Entity/Payment.php @@ -0,0 +1,66 @@ +id; + } + + public function getSessionId(): ?string + { + return $this->sessionId; + } + + public function setSessionId(string $sessionId): static + { + $this->sessionId = $sessionId; + + return $this; + } + + public function isCompleted(): ?bool + { + return $this->completed; + } + + public function setCompleted(bool $completed): static + { + $this->completed = $completed; + + return $this; + } + + public function getCustomer(): ?Customer + { + return $this->customer; + } + + public function setCustomer(Customer $customer): static + { + $this->customer = $customer; + + return $this; + } +} diff --git a/src/Entity/Ticket.php b/src/Entity/Ticket.php index 9803a90..1bb91de 100644 --- a/src/Entity/Ticket.php +++ b/src/Entity/Ticket.php @@ -13,82 +13,68 @@ class Ticket #[ORM\Column] private ?int $id = null; - #[ORM\Column(length: 255)] - private ?string $email = null; - - #[ORM\Column(length: 255, nullable: true)] - private ?string $phone = null; - - #[ORM\Column(length: 255)] - private ?string $firstname = null; - - #[ORM\Column(length: 255)] - private ?string $lastname = null; + #[ORM\Column] + private ?int $type = null; #[ORM\Column] - private int $quantity = 0; + private ?int $foodType = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $note = null; + + #[ORM\ManyToOne(inversedBy: 'tickets')] + #[ORM\JoinColumn(nullable: false)] + private ?Customer $customer = null; public function getId(): ?int { return $this->id; } - public function getEmail(): ?string + public function getType(): ?int { - return $this->email; + return $this->type; } - public function setEmail(string $email): static + public function setType(int $type): static { - $this->email = $email; + $this->type = $type; return $this; } - public function getPhone(): ?string + public function getFoodType(): ?int { - return $this->phone; + return $this->foodType; } - public function setPhone(?string $phone): static + public function setFoodType(int $foodType): static { - $this->phone = $phone; + $this->foodType = $foodType; return $this; } - public function getFirstname(): ?string + public function getNote(): ?string { - return $this->firstname; + return $this->note; } - public function setFirstname(string $firstname): static + public function setNote(?string $note): static { - $this->firstname = $firstname; + $this->note = $note; return $this; } - public function getLastname(): ?string + public function getCustomer(): ?Customer { - return $this->lastname; + return $this->customer; } - public function setLastname(string $lastname): static + public function setCustomer(?Customer $customer): static { - $this->lastname = $lastname; - - return $this; - } - - public function getQuantity(): int - { - return $this->quantity; - } - - public function setQuantity(int $quantity): static - { - $this->quantity = $quantity; + $this->customer = $customer; return $this; } diff --git a/src/Enum/TicketData.php b/src/Enum/TicketData.php index a8a5ee3..3e7eb04 100644 --- a/src/Enum/TicketData.php +++ b/src/Enum/TicketData.php @@ -5,19 +5,19 @@ namespace App\Enum; class TicketData { public const TICKET_DATA = [ - 0 => [ + 1 => [ 'name' => 'Ticket', 'price' => 50, ], - 1 => [ + 2 => [ 'name' => 'After-Show Ticket', 'price' => 20, ], - 2 => [ + 3 => [ 'name' => 'Kind (6-12 Jahre)', 'price' => 0, ], - 3 => [ + 4 => [ 'name' => 'Kind (0-6 Jahre)', 'price' => 0, ], diff --git a/src/Form/TicketForm.php b/src/Form/TicketForm.php deleted file mode 100644 index 3d33704..0000000 --- a/src/Form/TicketForm.php +++ /dev/null @@ -1,14 +0,0 @@ - + */ +class CustomerRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Customer::class); + } +} diff --git a/src/Repository/PaymentRepository.php b/src/Repository/PaymentRepository.php new file mode 100644 index 0000000..bf97e4b --- /dev/null +++ b/src/Repository/PaymentRepository.php @@ -0,0 +1,18 @@ + + */ +class PaymentRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Payment::class); + } +} diff --git a/src/Repository/TicketRepository.php b/src/Repository/TicketRepository.php index f3c0786..fce3bff 100644 --- a/src/Repository/TicketRepository.php +++ b/src/Repository/TicketRepository.php @@ -15,29 +15,4 @@ class TicketRepository extends ServiceEntityRepository { parent::__construct($registry, Ticket::class); } - -// /** -// * @return Ticket[] Returns an array of Ticket objects -// */ -// public function findByExampleField($value): array -// { -// return $this->createQueryBuilder('t') -// ->andWhere('t.exampleField = :val') -// ->setParameter('val', $value) -// ->orderBy('t.id', 'ASC') -// ->setMaxResults(10) -// ->getQuery() -// ->getResult() -// ; -// } - -// public function findOneBySomeField($value): ?Ticket -// { -// return $this->createQueryBuilder('t') -// ->andWhere('t.exampleField = :val') -// ->setParameter('val', $value) -// ->getQuery() -// ->getOneOrNullResult() -// ; -// } } diff --git a/src/Service/TicketService.php b/src/Service/TicketService.php index ad8f653..c02b0aa 100644 --- a/src/Service/TicketService.php +++ b/src/Service/TicketService.php @@ -3,29 +3,50 @@ namespace App\Service; use App\DataObjects\TicketData; +use App\DataObjects\TicketFormData; +use App\Entity\Customer; +use App\Entity\Payment; +use App\Entity\Ticket; use App\Enum\TicketData as TicketEnum; +use Cassandra\Custom; +use Doctrine\ORM\EntityManagerInterface; use Stripe\Checkout\Session; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class TicketService { public function __construct( private readonly UrlGeneratorInterface $generator, - private readonly RequestStack $requestStack, + private readonly EntityManagerInterface $em, ) { } - /** - * @param TicketData[] $data - */ - public function handleTicketData(array $data): Session + public function handleTicketData(TicketFormData $data): Session { - $this->requestStack->getSession()->set('ticketData', $data); + $session = $this->createSession($this->getLineItems($data->tickets), $data->personal->email); + $this->saveTicketData($data, $session->id); + + return $session; + } + + public function saveTicketData(TicketFormData $data, string $sessionId): void + { + $payment = (new Payment()) + ->setSessionId($sessionId) + ->setCompleted(false) + ->setCustomer($this->createEntityFromData($data)); + + $this->em->persist($payment); + $this->em->flush(); + } + + + private function getLineItems(array $tickets): array + { $lineItems = []; - foreach ($data as $ticket) { + foreach ($tickets as $ticket) { $ticketData = TicketEnum::TICKET_DATA[$ticket->ticketType]; $lineItems[] = [ 'price_data' => [ @@ -39,18 +60,52 @@ class TicketService ]; } + return $lineItems; + } + + private function createSession(array $lineItems, string $email): Session + { return Session::create([ 'line_items' => $lineItems, 'mode' => 'payment', - 'success_url' => $this->generator->generate('app_success', [], 0), + 'customer_email' => $email, + 'success_url' => $this->generator->generate('app_success', [], 0) . '?session_id={CHECKOUT_SESSION_ID}', 'cancel_url' => $this->generator->generate('app_cancelled', [], 0), ]); } - public function saveTicketData() + private function createEntityFromData(TicketFormData $ticketData): Customer { - $ticketData = $this->requestStack->getSession()->get('ticketData'); + $personalData = $ticketData->personal; + $entity = (new Customer()) + ->setFirstname($personalData->firstname) + ->setLastname($personalData->lastname) + ->setEmail($personalData->email) + ->setPhone($personalData->phone); + $entity->addTickets($this->createTicketEntities($ticketData->tickets)); + + $this->em->persist($entity); + $this->em->flush(); + + return $entity; + } + + /** + * @param TicketData[] $tickets + */ + private function createTicketEntities(array $tickets): array + { + $entities = []; + + foreach ($tickets as $ticket) { + $entities[] = (new Ticket()) + ->setType($ticket->ticketType) + ->setFoodType($ticket->foodType) + ->setNote($ticket->note); + } + + return $entities; } } \ No newline at end of file diff --git a/symfony.lock b/symfony.lock index ede50e2..8377651 100644 --- a/symfony.lock +++ b/symfony.lock @@ -1,4 +1,13 @@ { + "doctrine/annotations": { + "version": "2.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.10", + "ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05" + } + }, "doctrine/doctrine-bundle": { "version": "2.13", "recipe": { diff --git a/templates/ticket/_partials/_form.html.twig b/templates/ticket/_partials/_form.html.twig index 1d15a80..fe6f243 100644 --- a/templates/ticket/_partials/_form.html.twig +++ b/templates/ticket/_partials/_form.html.twig @@ -11,7 +11,7 @@ - + diff --git a/templates/ticket/index.html.twig b/templates/ticket/index.html.twig index 2e0ad19..9832568 100644 --- a/templates/ticket/index.html.twig +++ b/templates/ticket/index.html.twig @@ -23,6 +23,24 @@
+ +

Persönliche Daten

+ +
+
+ + +
+
+ + +
+
+ +
+ +

Tickets

+
Ticket
Ernährung
@@ -30,7 +48,7 @@
- {% include 'ticket/_partials/_form.html.twig' with {form: form} %} + {% include 'ticket/_partials/_form.html.twig' %}