Passed
Push — master ( df9557...e5317d )
by Jan
04:48 queued 11s
created

PaymentOrderController::new()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 48
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 27
nc 6
nop 4
dl 0
loc 48
rs 8.8657
c 2
b 0
f 0
1
<?php
2
/*
3
 * Copyright (C) 2020  Jan Böhmer
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Affero General Public License as published
7
 * by the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU Affero General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Affero General Public License
16
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace App\Controller;
20
21
use App\Entity\PaymentOrder;
22
use App\Event\PaymentOrderSubmittedEvent;
23
use App\Form\PaymentOrderConfirmationType;
24
use App\Form\PaymentOrderType;
25
use App\Services\PaymentReferenceGenerator;
26
use DateTime;
27
use Doctrine\ORM\EntityManagerInterface;
28
use InvalidArgumentException;
29
use RuntimeException;
30
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
31
use Symfony\Component\Form\Form;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\HttpFoundation\Response;
34
use Symfony\Component\Routing\Annotation\Route;
35
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
36
37
/**
38
 * This controller handles the payment order submit form.
39
 *
40
 * @Route("/payment_order")
41
 */
42
class PaymentOrderController extends AbstractController
43
{
44
    /**
45
     * @Route("/new", name="payment_order_new")
46
     */
47
    public function new(Request $request, EntityManagerInterface $entityManager, EventDispatcherInterface $dispatcher, PaymentReferenceGenerator $paymentReferenceGenerator): Response
48
    {
49
        $new_order = new PaymentOrder();
50
51
        $form = $this->createForm(PaymentOrderType::class, $new_order);
52
53
        if (!$form instanceof Form) {
54
            throw new InvalidArgumentException('$form must be a Form object!');
55
        }
56
57
        $form->handleRequest($request);
58
59
        if ($form->isSubmitted()) {
60
            if ($form->isValid()) {
61
                $entityManager->persist($new_order);
62
                $entityManager->flush();
63
64
                //We have to do this after the first flush, as we need to know the ID
65
                $paymentReferenceGenerator->setPaymentReference($new_order);
66
                $entityManager->flush();
67
68
                $this->addFlash('success', 'flash.saved_successfully');
69
70
                //Dispatch event so an email can be sent
71
                $event = new PaymentOrderSubmittedEvent($new_order);
72
                $dispatcher->dispatch($event, $event::NAME);
73
74
                //Redirect to homepage, if no further paymentOrders should be submitted
75
                //Otherwise create a new form for further ones
76
                if ('submit' === $form->getClickedButton()->getName()) {
77
                    return $this->redirectToRoute('homepage');
78
                }
79
80
                if ('submit_new' === $form->getClickedButton()->getName()) {
81
                    $old_order = $new_order;
82
                    $new_order = new PaymentOrder();
83
                    $this->copyProperties($old_order, $new_order);
84
85
                    $form = $this->createForm(PaymentOrderType::class, $new_order);
86
                }
87
            } else {
88
                $this->addFlash('error', 'flash.error.check_input');
89
            }
90
        }
91
92
        return $this->render('PaymentOrder/form.html.twig', [
93
            'form' => $form->createView(),
94
            'entity' => $new_order,
95
        ]);
96
    }
97
98
    private function copyProperties(PaymentOrder $source, PaymentOrder $target): void
99
    {
100
        $target->setFirstName($source->getFirstName());
101
        $target->setLastName($source->getLastName());
102
        $target->setContactEmail($source->getContactEmail());
103
        $target->setDepartment($source->getDepartment());
104
        $target->setBankInfo($source->getBankInfo());
105
    }
106
107
    /**
108
     * @Route("/{id}/confirm", name="payment_order_confirm")
109
     */
110
    public function confirmation(PaymentOrder $paymentOrder, Request $request, EntityManagerInterface $em): Response
111
    {
112
        //Check if we have one of the valid confirm numbers
113
        $confirm_step = $request->query->getInt('confirm');
114
        if (1 !== $confirm_step && 2 !== $confirm_step) {
115
            //$this->createNotFoundException('Invalid confirmation step! Only 1 or 2 are allowed.');
116
            $this->addFlash('error', 'payment_order.confirmation.invalid_step');
117
118
            return $this->redirectToRoute('homepage');
119
        }
120
121
        //Check if given token is correct for this step
122
        $correct_token = (1 === $confirm_step) ? $paymentOrder->getConfirm1Token() : $paymentOrder->getConfirm2Token();
123
        if (null === $correct_token) {
124
            throw new RuntimeException('This payment_order can not be confirmed! No token is set.');
125
        }
126
127
        $given_token = (string) $request->query->get('token');
128
        if (!password_verify($given_token, $correct_token)) {
129
            $this->addFlash('error', 'payment_order.confirmation.invalid_token');
130
131
            return $this->redirectToRoute('homepage');
132
        }
133
134
        //Check if it was already confirmed from this side and disable form if needed
135
        $confirm_timestamp = (1 === $confirm_step) ? $paymentOrder->getConfirm1Timestamp() : $paymentOrder->getConfirm2Timestamp();
136
        if (null !== $confirm_timestamp) {
137
            $this->addFlash('info', 'payment_order.confirmation.already_confirmed');
138
        }
139
        $form = $this->createForm(PaymentOrderConfirmationType::class, null, [
140
            'disabled' => null !== $confirm_timestamp,
141
        ]);
142
143
        $form->handleRequest($request);
144
        if ($form->isSubmitted() && $form->isValid()) {
145
            $this->addFlash('success', 'payment_order.confirmation.success');
146
            //Write confirmation to DB
147
            if (1 === $confirm_step) {
148
                $paymentOrder->setConfirm1Timestamp(new DateTime());
149
            } elseif (2 === $confirm_step) {
150
                $paymentOrder->setConfirm2Timestamp(new DateTime());
151
            }
152
            $em->flush();
153
154
            //Rerender form if it was confirmed, to apply the disabled state
155
            $form = $this->createForm(PaymentOrderConfirmationType::class, null, [
156
                'disabled' => true,
157
            ]);
158
            $this->addFlash('info', 'payment_order.confirmation.already_confirmed');
159
        }
160
161
        return $this->render('PaymentOrder/confirm/confirm.html.twig', [
162
            'entity' => $paymentOrder,
163
            'confirmation_nr' => $confirm_step,
164
            'form' => $form->createView(),
165
        ]);
166
    }
167
}
168