Completed
Push — master ( d18f01...4301df )
by Cesar
56s queued 20s
created

IndexV2::getRedirectUrl()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 36
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 23
dl 0
loc 36
rs 8.4444
c 0
b 0
f 0
cc 8
nc 9
nop 0
1
<?php
2
3
namespace DigitalOrigin\Pmt\Controller\Notify;
4
5
use Magento\Quote\Model\QuoteManagement;
6
use Magento\Quote\Api\Data\PaymentInterface;
7
use Magento\Sales\Api\Data\OrderInterface;
8
use Magento\Sales\Api\OrderRepositoryInterface;
9
use Magento\Quote\Model\Quote;
10
use Magento\Quote\Model\QuoteRepository;
11
use Magento\Framework\App\Action\Context;
12
use Magento\Framework\App\Action\Action;
13
use PagaMasTarde\ModuleUtils\Exception\MerchantOrderNotFoundException;
14
use PagaMasTarde\OrdersApiClient\Client;
15
use DigitalOrigin\Pmt\Helper\Config;
16
use DigitalOrigin\Pmt\Helper\ExtraConfig;
17
use Magento\Framework\App\ResourceConnection;
18
use Magento\Checkout\Model\Session;
19
use Magento\Framework\DB\Ddl\Table;
20
use PagaMasTarde\ModuleUtils\Exception\AmountMismatchException;
21
use PagaMasTarde\ModuleUtils\Exception\ConcurrencyException;
22
use PagaMasTarde\ModuleUtils\Exception\NoIdentificationException;
23
use PagaMasTarde\ModuleUtils\Exception\OrderNotFoundException;
24
use PagaMasTarde\ModuleUtils\Exception\QuoteNotFoundException;
25
use PagaMasTarde\ModuleUtils\Exception\UnknownException;
26
use PagaMasTarde\ModuleUtils\Exception\WrongStatusException;
27
use PagaMasTarde\ModuleUtils\Model\Response\JsonSuccessResponse;
28
use PagaMasTarde\ModuleUtils\Model\Response\JsonExceptionResponse;
29
use PagaMasTarde\ModuleUtils\Exception\AlreadyProcessedException;
30
use PagaMasTarde\ModuleUtils\Model\Log\LogEntry;
31
use Magento\Framework\App\CsrfAwareActionInterface;
32
use Magento\Framework\App\RequestInterface;
33
use Magento\Framework\App\Request\InvalidRequestException;
34
35
/**
36
 * Class Index
37
 * @package DigitalOrigin\Pmt\Controller\Notify
38
 */
39
class IndexV2 extends Action implements CsrfAwareActionInterface
40
{
41
    /** Orders tablename */
42
    const ORDERS_TABLE = 'cart_process';
43
44
    /** Concurrency tablename */
45
    const CONCURRENCY_TABLE = 'pmt_orders';
46
47
    /** Concurrency tablename */
48
    const LOGS_TABLE = 'pmt_logs';
49
50
    /** Payment code */
51
    const PAYMENT_METHOD = 'paylater';
52
53
    /**
54
     * EXCEPTION RESPONSES
55
     */
56
    const CPO_ERR_MSG = 'Order not confirmed';
57
    const CPO_OK_MSG = 'Order confirmed';
58
59
    /** @var QuoteManagement */
60
    protected $quoteManagement;
61
62
    /** @var PaymentInterface $paymentInterface */
63
    protected $paymentInterface;
64
65
    /** @var OrderRepositoryInterface $orderRepositoryInterface */
66
    protected $orderRepositoryInterface;
67
68
    /** @var Quote $quote */
69
    protected $quote;
70
71
    /** @var QuoteRepository $quoteRepository */
72
    protected $quoteRepository;
73
74
    /** @var mixed $config */
75
    protected $config;
76
77
    /** @var mixed $quoteId */
78
    protected $quoteId;
79
80
    /** @var array $notifyResult */
81
    protected $notifyResult;
82
83
    /** @var mixed $magentoOrderId */
84
    protected $magentoOrderId;
85
86
    /** @var mixed $pmtOrder */
87
    protected $pmtOrder;
88
89
    /** @var ResourceConnection $dbObject */
90
    protected $dbObject;
91
92
    /** @var Session $checkoutSession */
93
    protected $checkoutSession;
94
95
    /** @var Client $orderClient */
96
    protected $orderClient;
97
98
    /** @var mixed $pmtOrderId */
99
    protected $pmtOrderId;
100
101
    /** @var  OrderInterface $magentoOrder */
102
    protected $magentoOrder;
103
104
    /** @var ExtraConfig $extraConfig */
105
    protected $extraConfig;
106
107
    /**
108
     * Index constructor.
109
     *
110
     * @param Context                  $context
111
     * @param Quote                    $quote
112
     * @param QuoteManagement          $quoteManagement
113
     * @param PaymentInterface         $paymentInterface
114
     * @param Config                   $config
115
     * @param QuoteRepository          $quoteRepository
116
     * @param OrderRepositoryInterface $orderRepositoryInterface
117
     * @param ResourceConnection       $dbObject
118
     * @param Session                  $checkoutSession
119
     * @param ExtraConfig              $extraConfig
120
     */
121
    public function __construct(
122
        Context $context,
123
        Quote $quote,
124
        QuoteManagement $quoteManagement,
125
        PaymentInterface $paymentInterface,
126
        Config $config,
127
        QuoteRepository $quoteRepository,
128
        OrderRepositoryInterface $orderRepositoryInterface,
129
        ResourceConnection $dbObject,
130
        Session $checkoutSession,
131
        ExtraConfig $extraConfig
132
    ) {
133
        parent::__construct($context);
134
        $this->quote = $quote;
135
        $this->quoteManagement = $quoteManagement;
136
        $this->paymentInterface = $paymentInterface;
137
        $this->extraConfig = $extraConfig->getExtraConfig();
0 ignored issues
show
Documentation Bug introduced by
It seems like $extraConfig->getExtraConfig() of type array or array is incompatible with the declared type DigitalOrigin\Pmt\Helper\ExtraConfig of property $extraConfig.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
138
        $this->config = $config->getConfig();
139
        $this->quoteRepository = $quoteRepository;
140
        $this->orderRepositoryInterface = $orderRepositoryInterface;
141
        $this->dbObject = $dbObject;
142
        $this->checkoutSession = $checkoutSession;
143
    }
144
145
    /**
146
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface|void
147
     * @throws UnknownException
148
     */
149
    public function execute()
150
    {
151
        try {
152
            $this->checkConcurrency();
153
            $this->getMerchantOrder();
154
            $this->getPmtOrderId();
155
            $this->getPmtOrder();
156
            $this->checkOrderStatus();
157
            $this->checkMerchantOrderStatus();
158
            $this->validateAmount();
159
            $this->processMerchantOrder();
160
        } catch (\Exception $exception) {
161
            $jsonResponse = new JsonExceptionResponse();
162
            $jsonResponse->setMerchantOrderId($this->magentoOrderId);
163
            $jsonResponse->setPmtOrderId($this->pmtOrderId);
164
            $jsonResponse->setException($exception);
165
            $response = $jsonResponse->toJson();
166
            $this->insertLog($exception);
167
        }
168
169
        try {
170
            if (!isset($response)) {
171
                $this->confirmPmtOrder();
172
                $jsonResponse = new JsonSuccessResponse();
173
                $jsonResponse->setMerchantOrderId($this->magentoOrderId);
174
                $jsonResponse->setPmtOrderId($this->pmtOrderId);
175
            }
176
        } catch (\Exception $exception) {
177
            $this->rollbackMerchantOrder();
178
            $jsonResponse = new JsonExceptionResponse();
179
            $jsonResponse->setMerchantOrderId($this->magentoOrderId);
180
            $jsonResponse->setPmtOrderId($this->pmtOrderId);
181
            $jsonResponse->setException($exception);
182
            $jsonResponse->toJson();
183
            $this->insertLog($exception);
184
        }
185
186
        $this->unblockConcurrency(true);
187
188
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
189
            $jsonResponse->printResponse();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $jsonResponse does not seem to be defined for all execution paths leading up to this point.
Loading history...
190
        } else {
191
            $returnUrl = $this->getRedirectUrl();
192
            $this->_redirect($returnUrl);
193
        }
194
    }
195
196
    /**
197
     * COMMON FUNCTIONS
198
     */
199
200
    /**
201
     * @throws QuoteNotFoundException
202
     * @throws UnknownException
203
     */
204
    private function checkConcurrency()
205
    {
206
        $this->getQuoteId();
207
        $this->checkDbTable();
208
        $this->unblockConcurrency();
209
        $this->blockConcurrency();
210
    }
211
212
    /**
213
     * @throws MerchantOrderNotFoundException
214
     */
215
    private function getMerchantOrder()
216
    {
217
        try {
218
            /** @var Quote quote */
219
            $this->quote = $this->quoteRepository->get($this->quoteId);
220
        } catch (\Exception $e) {
221
            throw new MerchantOrderNotFoundException();
222
        }
223
    }
224
225
    /**
226
     * @throws UnknownException
227
     */
228
    private function getPmtOrderId()
229
    {
230
        try {
231
            /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
232
            $dbConnection     = $this->dbObject->getConnection();
233
            $tableName        = $this->dbObject->getTableName(self::ORDERS_TABLE);
234
            $query            = "select order_id from $tableName where id='$this->quoteId'";
235
            $queryResult      = $dbConnection->fetchRow($query);
236
            $this->pmtOrderId = $queryResult['order_id'];
237
            if ($this->pmtOrderId == '') {
238
                throw new NoIdentificationException();
239
            }
240
        } catch (\Exception $e) {
241
            throw new UnknownException($e->getMessage());
242
        }
243
    }
244
245
    /**
246
     * @throws OrderNotFoundException
247
     */
248
    private function getPmtOrder()
249
    {
250
        try {
251
            $this->orderClient = new Client($this->config['pmt_public_key'], $this->config['pmt_private_key']);
252
            $this->pmtOrder = $this->orderClient->getOrder($this->pmtOrderId);
253
        } catch (\Exception $e) {
254
            throw new OrderNotFoundException();
255
        }
256
    }
257
258
    /**
259
     * @throws AlreadyProcessedException
260
     * @throws WrongStatusException
261
     */
262
    private function checkOrderStatus()
263
    {
264
        try {
265
            $this->checkPmtStatus(array('AUTHORIZED'));
266
        } catch (\Exception $e) {
267
            $this->getMagentoOrderId();
268
            if ($this->magentoOrderId!='') {
269
                throw new AlreadyProcessedException();
270
            } else {
271
                throw new WrongStatusException($this->pmtOrder->getStatus());
272
            }
273
        }
274
    }
275
276
    /**
277
     * @throws AlreadyProcessedException
278
     */
279
    private function checkMerchantOrderStatus()
280
    {
281
        if ($this->quote->getIsActive()=='0') {
282
            $this->getMagentoOrderId();
283
            throw new AlreadyProcessedException();
284
        }
285
    }
286
287
    /**
288
     * @throws AmountMismatchException
289
     */
290
    private function validateAmount()
291
    {
292
        $pmtAmount = $this->pmtOrder->getShoppingCart()->getTotalAmount();
293
        $merchantAmount = intval(strval(100 * $this->quote->getGrandTotal()));
294
        if ($pmtAmount != $merchantAmount) {
295
            throw new AmountMismatchException($pmtAmount, $merchantAmount);
296
        }
297
    }
298
299
    /**
300
     * @throws UnknownException
301
     */
302
    private function processMerchantOrder()
303
    {
304
        try {
305
            $this->saveOrder();
306
            $this->updateBdInfo();
307
        } catch (\Exception $e) {
308
            throw new UnknownException($e->getMessage());
309
        }
310
    }
311
312
    /**
313
     * @return false|string
314
     * @throws UnknownException
315
     */
316
    private function confirmPmtOrder()
317
    {
318
        try {
319
            $this->pmtOrder = $this->orderClient->confirmOrder($this->pmtOrderId);
320
        } catch (\Exception $e) {
321
            throw new UnknownException($e->getMessage());
322
        }
323
324
        $jsonResponse = new JsonSuccessResponse();
325
        $jsonResponse->setStatusCode(200);
326
        $jsonResponse->setMerchantOrderId($this->magentoOrderId);
327
        $jsonResponse->setPmtOrderId($this->pmtOrderId);
328
        $jsonResponse->setResult(self::CPO_OK_MSG);
329
        return $jsonResponse->toJson();
330
    }
331
332
    /**
333
     * UTILS FUNCTIONS
334
     */
335
336
    /** STEP 1 CC - Check concurrency
337
     * @throws QuoteNotFoundException
338
     */
339
    private function getQuoteId()
340
    {
341
        $this->quoteId = $this->getRequest()->getParam('quoteId');
342
        if ($this->quoteId == '') {
343
            throw new QuoteNotFoundException();
344
        }
345
    }
346
347
    /**
348
     * @return \Zend_Db_Statement_Interface
349
     * @throws UnknownException
350
     */
351
    private function checkDbTable()
352
    {
353
        try {
354
            /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
355
            $dbConnection = $this->dbObject->getConnection();
356
            $tableName    = $this->dbObject->getTableName(self::CONCURRENCY_TABLE);
357
            $query        = "CREATE TABLE IF NOT EXISTS $tableName(`id` int not null,`timestamp` int not null,PRIMARY KEY (`id`))";
358
359
            return $dbConnection->query($query);
360
        } catch (\Exception $e) {
361
            throw new UnknownException($e->getMessage());
362
        }
363
    }
364
365
    /**
366
     * @return void|\Zend_Db_Statement_Interface
367
     * @throws UnknownException
368
     */
369
    private function checkDbLogTable()
370
    {
371
        try {
372
            /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
373
            $dbConnection = $this->dbObject->getConnection();
374
            $tableName = $this->dbObject->getTableName(self::LOGS_TABLE);
375
            if (!$dbConnection->isTableExists($tableName)) {
376
                $table = $dbConnection
377
                    ->newTable($tableName)
378
                    ->addColumn('id', Table::TYPE_SMALLINT, null, array('nullable'=>false, 'auto_increment'=>true, 'primary'=>true))
379
                    ->addColumn('log', Table::TYPE_TEXT, null, array('nullable'=>false))
380
                    ->addColumn('createdAt', Table::TYPE_TIMESTAMP, null, array('nullable'=>false, 'default'=>Table::TIMESTAMP_INIT));
381
                return $dbConnection->createTable($table);
382
            }
383
384
            return;
385
        } catch (\Exception $e) {
386
            throw new UnknownException($e->getMessage());
387
        }
388
    }
389
390
    /**
391
     * @param bool $mode
392
     *
393
     * @throws \Exception
394
     */
395
    private function unblockConcurrency($mode = false)
396
    {
397
        try {
398
            /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
399
            $dbConnection = $this->dbObject->getConnection();
400
            $tableName    = $this->dbObject->getTableName(self::CONCURRENCY_TABLE);
401
            if ($mode == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
402
                $dbConnection->delete($tableName, "timestamp<".(time() - 5));
403
            } elseif ($this->quoteId!='') {
404
                $dbConnection->delete($tableName, "id=".$this->quoteId);
405
            }
406
        } catch (Exception $exception) {
0 ignored issues
show
Bug introduced by
The type DigitalOrigin\Pmt\Controller\Notify\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
407
            throw new ConcurrencyException();
408
        }
409
    }
410
411
    /**
412
     * @throws \Exception
413
     */
414
    private function blockConcurrency()
415
    {
416
        try {
417
            /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
418
            $dbConnection = $this->dbObject->getConnection();
419
            $tableName    = $this->dbObject->getTableName(self::CONCURRENCY_TABLE);
420
            $dbConnection->insert($tableName, array('id'=>$this->quoteId, 'timestamp'=>time()));
421
        } catch (Exception $exception) {
422
            throw new ConcurrencyException();
423
        }
424
    }
425
426
    /** STEP 2 GMO - Get Merchant Order */
427
    /** STEP 3 GPOI - Get Pmt OrderId */
428
    /** STEP 4 GPO - Get Pmt Order */
429
    /** STEP 5 COS - Check Order Status */
430
    /**
431
     * @param $statusArray
432
     *
433
     * @throws \Exception
434
     */
435
    private function checkPmtStatus($statusArray)
436
    {
437
        $pmtStatus = array();
438
        foreach ($statusArray as $status) {
439
            $pmtStatus[] = constant("\PagaMasTarde\OrdersApiClient\Model\Order::STATUS_$status");
440
        }
441
442
        $payed = in_array($this->pmtOrder->getStatus(), $pmtStatus);
443
        if (!$payed) {
444
            throw new WrongStatusException($this->pmtOrder->getStatus());
445
        }
446
    }
447
448
    /** STEP 6 CMOS - Check Merchant Order Status */
449
    /**
450
     * @throws \Exception
451
     */
452
    private function getMagentoOrderId()
453
    {
454
        try {
455
            /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
456
            $dbConnection = $this->dbObject->getConnection();
457
            $tableName    = $this->dbObject->getTableName(self::ORDERS_TABLE);
458
            $pmtOrderId   = $this->pmtOrderId;
459
460
            $query        = "select mg_order_id from $tableName where id='$this->quoteId' and order_id='$pmtOrderId'";
461
            $queryResult  = $dbConnection->fetchRow($query);
462
            $this->magentoOrderId = $queryResult['mg_order_id'];
463
        } catch (\Exception $e) {
464
            throw new UnknownException($e->getMessage());
465
        }
466
    }
467
468
    /** STEP 7 VA - Validate Amount */
469
    /** STEP 8 PMO - Process Merchant Order */
470
    /**
471
     * @throws UnknownException
472
     */
473
    private function saveOrder()
474
    {
475
        try {
476
            $this->paymentInterface->setMethod(self::PAYMENT_METHOD);
477
            $this->magentoOrderId = $this->quoteManagement->placeOrder($this->quoteId, $this->paymentInterface);
478
            /** @var \Magento\Sales\Api\Data\OrderInterface magentoOrder */
479
            $this->magentoOrder = $this->orderRepositoryInterface->get($this->magentoOrderId);
480
481
            if ($this->magentoOrderId == '') {
482
                throw new UnknownException('Order can not be saved');
483
            }
484
        } catch (\Exception $e) {
485
            throw new UnknownException($e->getMessage());
486
        }
487
    }
488
489
    /**
490
     * @throws UnknownException
491
     */
492
    private function updateBdInfo()
493
    {
494
        try {
495
            /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
496
            $dbConnection = $this->dbObject->getConnection();
497
            $tableName    = $this->dbObject->getTableName(self::ORDERS_TABLE);
498
            $pmtOrderId   = $this->pmtOrder->getId();
499
            $dbConnection->update(
500
                $tableName,
501
                array('mg_order_id' => $this->magentoOrderId),
502
                "order_id='$pmtOrderId' and id='$this->quoteId'"
503
            );
504
        } catch (\Exception $e) {
505
            throw new UnknownException($e->getMessage());
506
        }
507
    }
508
509
    /** STEP 9 CPO - Confirmation Pmt Order */
510
    /**
511
     * @throws UnknownException
512
     */
513
    private function rollbackMerchantOrder()
514
    {
515
        try {
516
            $this->magentoOrder->setState(\Magento\Sales\Model\Order::STATE_PENDING_PAYMENT, true);
0 ignored issues
show
Unused Code introduced by
The call to Magento\Sales\Api\Data\OrderInterface::setState() has too many arguments starting with true. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

516
            $this->magentoOrder->/** @scrutinizer ignore-call */ 
517
                                 setState(\Magento\Sales\Model\Order::STATE_PENDING_PAYMENT, true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
517
            $this->magentoOrder->setStatus(\Magento\Sales\Model\Order::STATE_PENDING_PAYMENT);
518
            $this->magentoOrder->save();
519
        } catch (\Exception $e) {
520
            throw new UnknownException($e->getMessage());
521
        }
522
    }
523
524
    /**
525
     * @return string
526
     */
527
    private function getRedirectUrl()
528
    {
529
        //$returnUrl = 'checkout/#payment';
530
        $returnUrl = $this->_url->getUrl('checkout', ['_fragment' => 'payment']);
531
        if ($this->magentoOrderId!='') {
532
            /** @var Order $this->magentoOrder */
533
            $this->magentoOrder = $this->orderRepositoryInterface->get($this->magentoOrderId);
534
            if (!$this->_objectManager->get(\Magento\Checkout\Model\Session\SuccessValidator::class)->isValid()) {
535
                $this->checkoutSession
536
                    ->setLastOrderId($this->magentoOrderId)
537
                    ->setLastRealOrderId($this->magentoOrder->getIncrementId())
538
                    ->setLastQuoteId($this->quoteId)
539
                    ->setLastSuccessQuoteId($this->quoteId)
540
                    ->setLastOrderStatus($this->magentoOrder->getStatus());
541
            }
542
543
            //Magento status flow => https://docs.magento.com/m2/ce/user_guide/sales/order-status-workflow.html
544
            //Order Workflow => https://docs.magento.com/m2/ce/user_guide/sales/order-workflow.html
545
            $orderStatus    = strtolower($this->magentoOrder->getStatus());
546
            $acceptedStatus = array('processing', 'completed');
547
            if (in_array($orderStatus, $acceptedStatus)) {
548
                if (isset($this->extraConfig['PMT_OK_URL']) &&  $this->extraConfig['PMT_OK_URL']!= '') {
549
                    $returnUrl = $this->extraConfig['PMT_OK_URL'];
550
                } else {
551
                    $returnUrl = 'checkout/onepage/success';
552
                }
553
            } else {
554
                if (isset($this->extraConfig['PMT_KO_URL']) && $this->extraConfig['PMT_KO_URL'] != '') {
555
                    $returnUrl = $this->extraConfig['PMT_KO_URL'];
556
                } else {
557
                    //$returnUrl = 'checkout/#payment';
558
                    $returnUrl = $this->_url->getUrl('checkout', ['_fragment' => 'payment']);
559
                }
560
            }
561
        }
562
        return $returnUrl;
563
    }
564
565
    /**
566
     * @param $exceptionMessage
567
     *
568
     * @throws UnknownException
569
     */
570
    private function insertLog($exceptionMessage)
571
    {
572
        try {
573
            if ($exceptionMessage instanceof \Exception) {
574
                $this->checkDbLogTable();
575
                $logEntry = new LogEntry();
576
                $logEntryJson = $logEntry->error($exceptionMessage)->toJson();
577
578
                /** @var \Magento\Framework\DB\Adapter\AdapterInterface $dbConnection */
579
                $dbConnection = $this->dbObject->getConnection();
580
                $tableName    = $this->dbObject->getTableName(self::LOGS_TABLE);
581
                $dbConnection->insert($tableName, array('log' => $logEntryJson));
582
            }
583
        } catch (\Exception $e) {
584
            throw new UnknownException($e->getMessage());
585
        }
586
    }
587
588
    /**
589
     * @param RequestInterface $request
590
     *
591
     * @return InvalidRequestException|null
592
     */
593
    public function createCsrfValidationException(RequestInterface $request): ? InvalidRequestException
594
    {
595
        return null;
596
    }
597
598
    /**
599
     * @param RequestInterface $request
600
     *
601
     * @return bool|null
602
     */
603
    public function validateForCsrf(RequestInterface $request): ? bool
604
    {
605
        return true;
606
    }
607
}
608