Skip to content

Commit 29a57c9

Browse files
authored
Merge pull request #512 from Philipp91/vop-minor
#477 Polish code for easier reuse in VoP implementation
2 parents e1dc068 + 0b1af44 commit 29a57c9

File tree

6 files changed

+55
-40
lines changed

6 files changed

+55
-40
lines changed

lib/Fhp/BaseAction.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,8 @@ final public function setRequestSegmentNumbers(array $requestSegmentNumbers)
243243
$this->requestSegmentNumbers = $requestSegmentNumbers;
244244
}
245245

246-
/**
247-
* To be called only by the FinTs instance that executes this action.
248-
*/
249-
final public function setTanRequest(?TanRequest $tanRequest)
246+
/** To be called only by the FinTs instance that executes this action. */
247+
final public function setTanRequest(?TanRequest $tanRequest): void
250248
{
251249
$this->tanRequest = $tanRequest;
252250
}

lib/Fhp/FinTs.php

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ public function __unserialize(array $data): void
201201
*
202202
* @throws \InvalidArgumentException
203203
*/
204-
public function loadPersistedInstance(string $persistedInstance)
204+
public function loadPersistedInstance(string $persistedInstance): void
205205
{
206206
$unserialized = unserialize($persistedInstance);
207207
if (!is_array($unserialized) || count($unserialized) === 0) {
@@ -216,7 +216,7 @@ public function loadPersistedInstance(string $persistedInstance)
216216
}
217217
}
218218

219-
private function loadPersistedInstanceVersion2(array $data)
219+
private function loadPersistedInstanceVersion2(array $data): void
220220
{
221221
list( // This should match persist().
222222
$this->bpd,
@@ -254,7 +254,7 @@ public function setLogger(LoggerInterface $logger): void
254254
* @param int $responseTimeout The number of seconds to wait before aborting a request to the bank server.
255255
* @noinspection PhpUnused
256256
*/
257-
public function setTimeouts(int $connectTimeout, int $responseTimeout)
257+
public function setTimeouts(int $connectTimeout, int $responseTimeout): void
258258
{
259259
$this->options->timeoutConnect = $connectTimeout;
260260
$this->options->timeoutResponse = $responseTimeout;
@@ -304,34 +304,51 @@ public function login(): DialogInitialization
304304
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
305305
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
306306
*/
307-
public function execute(BaseAction $action)
307+
public function execute(BaseAction $action): void
308308
{
309309
if ($this->dialogId === null && !($action instanceof DialogInitialization)) {
310310
throw new \RuntimeException('Need to login (DialogInitialization) before executing other actions');
311311
}
312312

313+
// Add the action's main request segments.
313314
$requestSegments = $action->getNextRequest($this->bpd, $this->upd);
314-
315315
if (count($requestSegments) === 0) {
316316
return; // No request needed.
317317
}
318+
$message = MessageBuilder::create()->add($requestSegments);
318319

319-
// Construct the full request message.
320-
$message = MessageBuilder::create()->add($requestSegments); // This fills in the segment numbers.
320+
// Add HKTAN for authentication if necessary.
321321
if (!($this->getSelectedTanMode() instanceof NoPsd2TanMode)) {
322322
if (($needTanForSegment = $action->getNeedTanForSegment()) !== null) {
323323
$message->add(HKTANFactory::createProzessvariante2Step1(
324324
$this->requireTanMode(), $this->selectedTanMedium, $needTanForSegment));
325325
}
326326
}
327-
$request = $this->buildMessage($message, $this->getSelectedTanMode());
327+
328+
// Construct the request and tell the action about the segment numbers that were assigned.
329+
$request = $this->buildMessage($message, $this->getSelectedTanMode()); // This fills in the segment numbers.
328330
$action->setRequestSegmentNumbers(array_map(function ($segment) {
329331
/* @var BaseSegment $segment */
330332
return $segment->getSegmentNumber();
331333
}, $requestSegments));
332334

333335
// Execute the request.
334336
$response = $this->sendMessage($request);
337+
$this->processServerResponse($action, $response);
338+
}
339+
340+
/**
341+
* Updates the state of this FinTs instance and of the `$action` based on the server's response.
342+
* See {@link execute()} for more documentation on the possible outcomes.
343+
* @param BaseAction $action The action for which the request was sent.
344+
* @param Message $response The response we just got from the server.
345+
* @throws CurlException When the connection fails in a layer below the FinTS protocol.
346+
* @throws UnexpectedResponseException When the server responds with a valid but unexpected message.
347+
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
348+
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
349+
*/
350+
private function processServerResponse(BaseAction $action, Message $response): void
351+
{
335352
$this->readBPD($response);
336353

337354
// Detect if the bank wants a TAN.
@@ -379,7 +396,7 @@ public function execute(BaseAction $action)
379396
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
380397
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
381398
*/
382-
public function submitTan(BaseAction $action, string $tan)
399+
public function submitTan(BaseAction $action, string $tan): void
383400
{
384401
// Check the action's state.
385402
$tanRequest = $action->getTanRequest();
@@ -538,7 +555,7 @@ public function checkDecoupledSubmission(BaseAction $action): bool
538555
* from cached BPD/UPD upon the next {@link login()}, for instance.
539556
* @throws ServerException When closing the dialog fails.
540557
*/
541-
public function close()
558+
public function close(): void
542559
{
543560
if ($this->dialogId !== null) {
544561
$this->endDialog();
@@ -552,7 +569,7 @@ public function close()
552569
* This can be called by the application using this library when it just restored this FinTs instance from the
553570
* persisted format after a long time, during which the session/dialog has most likely expired on the server side.
554571
*/
555-
public function forgetDialog()
572+
public function forgetDialog(): void
556573
{
557574
$this->dialogId = null;
558575
}
@@ -573,7 +590,9 @@ public function getTanModes(): array
573590
$this->ensureTanModesAvailable();
574591
$result = [];
575592
foreach ($this->allowedTanModes as $tanModeId) {
576-
if (!array_key_exists($tanModeId, $this->bpd->allTanModes)) continue;
593+
if (!array_key_exists($tanModeId, $this->bpd->allTanModes)) {
594+
continue;
595+
}
577596
$result[$tanModeId] = $this->bpd->allTanModes[$tanModeId];
578597
}
579598
return $result;
@@ -624,7 +643,7 @@ public function getTanMedia($tanMode): array
624643
* must be the value returned from {@link TanMedium::getName()} for one of the TAN media supported with that TAN
625644
* mode. Use {@link getTanMedia()} to obtain a list of possible TAN media options.
626645
*/
627-
public function selectTanMode($tanMode, $tanMedium = null)
646+
public function selectTanMode($tanMode, $tanMedium = null): void
628647
{
629648
if (!is_int($tanMode) && !($tanMode instanceof TanMode)) {
630649
throw new \InvalidArgumentException('tanMode must be an int or a TanMode');
@@ -664,7 +683,7 @@ public function getBpd(): BPD
664683
* @throws UnexpectedResponseException When the server does not send the BPD or close the dialog properly.
665684
* @throws ServerException When the server resopnds with an error.
666685
*/
667-
private function ensureBpdAvailable()
686+
private function ensureBpdAvailable(): void
668687
{
669688
if ($this->bpd !== null) {
670689
return; // Nothing to do.
@@ -711,7 +730,7 @@ private function requireCredentials(): Credentials
711730
* like it should according to the protocol, or when the dialog is not closed properly.
712731
* @throws ServerException When the server responds with an error.
713732
*/
714-
private function ensureTanModesAvailable()
733+
private function ensureTanModesAvailable(): void
715734
{
716735
if ($this->allowedTanModes === null) {
717736
$this->ensureBpdAvailable();
@@ -730,7 +749,7 @@ private function ensureTanModesAvailable()
730749
* dialog is not closed properly.
731750
* @throws ServerException When the server responds with an error.
732751
*/
733-
private function ensureSynchronized()
752+
private function ensureSynchronized(): void
734753
{
735754
if ($this->kundensystemId === null) {
736755
$this->ensureBpdAvailable();
@@ -820,7 +839,7 @@ protected function newConnection(): Connection
820839
/**
821840
* Closes the physical connection, if necessary.
822841
*/
823-
private function disconnect()
842+
private function disconnect(): void
824843
{
825844
if ($this->connection !== null) {
826845
$this->connection->disconnect();
@@ -834,7 +853,7 @@ private function disconnect()
834853
* @param Message $fakeResponseMessage A messsage that contains the response segments for this action.
835854
* @throws UnexpectedResponseException When the server responded with a valid but unexpected message.
836855
*/
837-
private function processActionResponse(BaseAction $action, Message $fakeResponseMessage)
856+
private function processActionResponse(BaseAction $action, Message $fakeResponseMessage): void
838857
{
839858
$action->processResponse($fakeResponseMessage);
840859
if ($action instanceof DialogInitialization) {
@@ -864,7 +883,7 @@ private function processActionResponse(BaseAction $action, Message $fakeResponse
864883
* properly.
865884
* @throws ServerException When the server responds with an error.
866885
*/
867-
private function executeWeakDialogInitialization(?string $hktanRef)
886+
private function executeWeakDialogInitialization(?string $hktanRef): void
868887
{
869888
if ($this->dialogId !== null) {
870889
throw new \RuntimeException('Cannot init another dialog.');
@@ -905,7 +924,7 @@ private function readBPD(Message $response): bool
905924
* @throws ServerException When the server responds with an error instead of closing the dialog. This means that
906925
* the connection is tainted and can probably not be used for another dialog.
907926
*/
908-
protected function endDialog(bool $isAnonymous = false)
927+
protected function endDialog(bool $isAnonymous = false): void
909928
{
910929
if ($this->connection === null) {
911930
$this->dialogId = null;
@@ -943,7 +962,7 @@ protected function endDialog(bool $isAnonymous = false)
943962
* @param MessageBuilder $message The message to be built.
944963
* @param TanMode|null $tanMode Optionally a TAN mode that will be used when sending this message, defaults to 999
945964
* (single step).
946-
* @param string|null Optionally a TAN to sign this message with.
965+
* @param string|null $tan Optionally a TAN to sign this message with.
947966
* @return Message The built message.
948967
*/
949968
private function buildMessage(MessageBuilder $message, ?TanMode $tanMode = null, ?string $tan = null): Message

lib/Fhp/PaginateableAction.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use Fhp\Protocol\Message;
77
use Fhp\Protocol\UnexpectedResponseException;
88
use Fhp\Protocol\UPD;
9-
use Fhp\Segment\BaseSegment;
109
use Fhp\Segment\HIRMS\Rueckmeldungscode;
1110
use Fhp\Segment\Paginateable;
1211

@@ -79,7 +78,7 @@ public function hasMorePages(): bool
7978

8079
public function processResponse(Message $response)
8180
{
82-
if (($pagination = $response->findRueckmeldung(Rueckmeldungscode::PAGINATION)) !== null) {
81+
if (($pagination = $response->findRueckmeldung(Rueckmeldungscode::AUFSETZPUNKT)) !== null) {
8382
if (count($pagination->rueckmeldungsparameter) !== 1) {
8483
throw new UnexpectedResponseException("Unexpected pagination request: $pagination");
8584
}

lib/Fhp/Protocol/Message.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,16 @@ public static function parse(string $rawMessage): Message
300300
$segments = Parser::parseSegments($rawMessage);
301301

302302
// Message header and footer must always be there, or something went badly wrong.
303-
if (!($segments[0] instanceof HNHBKv3)) {
304-
throw new \InvalidArgumentException("Expected first segment to be HNHBK: $rawMessage");
305-
}
306-
if (!($segments[count($segments) - 1] instanceof HNHBSv1)) {
307-
throw new \InvalidArgumentException("Expected last segment to be HNHBS: $rawMessage");
308-
}
309303
$result->header = $segments[0];
310304
$result->footer = $segments[count($segments) - 1];
305+
if (!($result->header instanceof HNHBKv3)) {
306+
$actual = $result->header->getName();
307+
throw new \InvalidArgumentException("Expected first segment to be HNHBK, but got $actual: $rawMessage");
308+
}
309+
if (!($result->footer instanceof HNHBSv1)) {
310+
$actual = $result->footer->getName();
311+
throw new \InvalidArgumentException("Expected last segment to be HNHBS, but got $actual: $rawMessage");
312+
}
311313

312314
// Check if there's an encryption header and "encrypted" data.
313315
// Section B.8 specifies that there are exactly 4 segments: HNHBK, HNVSK, HNVSD, HNHBS.

lib/Fhp/Segment/HIRMS/Rueckmeldungscode.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public static function isError(int $code): bool
7777
* Tells the client that the response is incomplete and the request needs to be re-sent with the pagination token
7878
* ("Aufsetzpunkt") that is contained in the Rueckmeldung parameters.
7979
*/
80-
public const PAGINATION = 3040;
80+
public const AUFSETZPUNKT = 3040;
8181

8282
public const VOP_KEINE_NAMENSABWEICHUNG = 25;
8383

lib/Tests/Fhp/FinTsPeer.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@
1313
*/
1414
class FinTsPeer extends FinTs
1515
{
16-
/**
17-
* @var Connection
18-
*/
19-
public static $mockConnection;
16+
public static ?Connection $mockConnection = null;
2017

2118
public function __construct(FinTsOptions $options, ?Credentials $credentials)
2219
{
@@ -31,12 +28,12 @@ protected function newConnection(): Connection
3128
/**
3229
* @throws ServerException
3330
*/
34-
public function endDialog(bool $isAnonymous = false) // parent::endDialog() is protected
31+
public function endDialog(bool $isAnonymous = false): void // parent::endDialog() is protected
3532
{
3633
parent::endDialog($isAnonymous);
3734
}
3835

39-
public function getDialogId()
36+
public function getDialogId(): ?string
4037
{
4138
return $this->dialogId;
4239
}

0 commit comments

Comments
 (0)