44
55namespace Fhp ;
66
7+ use Fhp \Model \PollingInfo ;
78use Fhp \Model \TanRequest ;
9+ use Fhp \Model \VopConfirmationRequest ;
810use Fhp \Protocol \ActionIncompleteException ;
11+ use Fhp \Protocol \ActionPendingException ;
912use Fhp \Protocol \BPD ;
1013use Fhp \Protocol \Message ;
1114use Fhp \Protocol \TanRequiredException ;
1215use Fhp \Protocol \UnexpectedResponseException ;
1316use Fhp \Protocol \UPD ;
17+ use Fhp \Protocol \VopConfirmationRequiredException ;
1418use Fhp \Segment \BaseSegment ;
1519use Fhp \Segment \HIRMS \Rueckmeldung ;
1620use Fhp \Segment \HIRMS \Rueckmeldungscode ;
@@ -48,6 +52,12 @@ abstract class BaseAction implements \Serializable
4852 /** If set, the last response from the server regarding this action asked for a TAN from the user. */
4953 protected ?TanRequest $ tanRequest = null ;
5054
55+ /** If set, this action is currently waiting for a long-running operation on the server to complete. */
56+ protected ?PollingInfo $ pollingInfo = null ;
57+
58+ /** If set, this action needs the user's confirmation to be completed. */
59+ protected ?VopConfirmationRequest $ vopConfirmationRequest = null ;
60+
5161 protected bool $ isDone = false ;
5262
5363 /**
@@ -61,8 +71,7 @@ abstract class BaseAction implements \Serializable
6171 *
6272 * NOTE: A common mistake is to call this function directly. Instead, you probably want `serialize($instance)`.
6373 *
64- * An action can only be serialized *after* it has been executed in case it needs a TAN, i.e. when the result is not
65- * present yet.
74+ * An action can only be serialized before it was completed.
6675 * If a sub-class overrides this, it should call the parent function and include it in its result.
6776 * @return string The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
6877 */
@@ -72,22 +81,23 @@ public function serialize(): string
7281 }
7382
7483 /**
75- * An action can only be serialized *after* it has been executed in case it needs a TAN, i.e. when the result is not
76- * present yet.
84+ * An action can only be serialized before it was completed.
7785 * If a sub-class overrides this, it should call the parent function and include it in its result.
7886 *
7987 * @return array The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
8088 * Note that this is not necessarily valid UTF-8, so you should store it as a BLOB column or raw bytes.
8189 */
8290 public function __serialize (): array
8391 {
84- if (! $ this ->needsTan ()) {
85- throw new \RuntimeException ('Cannot serialize this action, because it is not waiting for a TAN . ' );
92+ if ($ this ->isDone ()) {
93+ throw new \RuntimeException ('Completed actions cannot be serialized . ' );
8694 }
8795 return [
8896 $ this ->requestSegmentNumbers ,
8997 $ this ->tanRequest ,
9098 $ this ->needTanForSegment ,
99+ $ this ->pollingInfo ,
100+ $ this ->vopConfirmationRequest ,
91101 ];
92102 }
93103
@@ -108,7 +118,9 @@ public function __unserialize(array $serialized): void
108118 $ this ->requestSegmentNumbers ,
109119 $ this ->tanRequest ,
110120 $ this ->needTanForSegment ,
111- ) = $ serialized ;
121+ $ this ->pollingInfo ,
122+ $ this ->vopConfirmationRequest ,
123+ ) = array_pad ($ serialized , 5 , null );
112124 }
113125
114126 /**
@@ -140,25 +152,54 @@ public function getTanRequest(): ?TanRequest
140152 return $ this ->tanRequest ;
141153 }
142154
155+ public function needsPollingWait (): bool
156+ {
157+ return !$ this ->isDone () && $ this ->pollingInfo !== null ;
158+ }
159+
160+ public function getPollingInfo (): ?PollingInfo
161+ {
162+ return $ this ->pollingInfo ;
163+ }
164+
165+ public function needsVopConfirmation (): bool
166+ {
167+ return !$ this ->isDone () && $ this ->vopConfirmationRequest !== null ;
168+ }
169+
170+ public function getVopConfirmationRequest (): ?VopConfirmationRequest
171+ {
172+ return $ this ->vopConfirmationRequest ;
173+ }
174+
143175 /**
144176 * Throws an exception unless this action has been successfully executed, i.e. in the following cases:
145177 * - the action has not been {@link FinTs::execute()}-d at all or the {@link FinTs::execute()} call for it threw an
146178 * exception,
147- * - the action is awaiting a TAN/confirmation (as per {@link BaseAction::needsTan()}.
179+ * - the action is awaiting a TAN/confirmation (as per {@link BaseAction::needsTan()},
180+ * - the action is pending a long-running operation on the bank server ({@link BaseAction::needsPollingWait()}),
181+ * - the action is awaiting the user's confirmation of the Verification of Payee result (as per
182+ * {@link BaseAction::needsVopConfirmation()}).
148183 *
149184 * After executing an action, you can use this function to make sure that it succeeded. This is especially useful
150185 * for actions that don't have any results (as each result getter would call {@link ensureDone()} internally).
151186 * On the other hand, you do not need to call this function if you make sure that (1) you called
152- * {@link FinTs::execute()} and (2) you checked {@link needsTan()} and, if it returned true, supplied a TAN by
153- * calling {@ink FinTs::submitTan()}. Note that both exception types thrown from this method are sub-classes of
154- * {@link \RuntimeException}, so you shouldn't need a try-catch block at the call site for this.
187+ * {@link FinTs::execute()} and (2) you checked and resolved all other special outcome states documented there.
188+ * Note that both exception types thrown from this method are sub-classes of {@link \RuntimeException}, so you
189+ * shouldn't need a try-catch block at the call site for this.
155190 * @throws ActionIncompleteException If the action hasn't even been executed.
191+ * @throws ActionPendingException If the action is pending a long-running server operation that needs polling.
192+ * @throws VopConfirmationRequiredException If the action requires the user's confirmation for VOP.
156193 * @throws TanRequiredException If the action needs a TAN.
157194 */
158- public function ensureDone ()
195+ public function ensureDone (): void
159196 {
160197 if ($ this ->tanRequest !== null ) {
161198 throw new TanRequiredException ($ this ->tanRequest );
199+ } elseif ($ this ->pollingInfo !== null ) {
200+ throw new ActionPendingException ($ this ->pollingInfo );
201+ } elseif ($ this ->vopConfirmationRequest !== null ) {
202+ throw new VopConfirmationRequiredException ($ this ->vopConfirmationRequest );
162203 } elseif (!$ this ->isDone ()) {
163204 throw new ActionIncompleteException ();
164205 }
@@ -249,4 +290,16 @@ final public function setTanRequest(?TanRequest $tanRequest): void
249290 {
250291 $ this ->tanRequest = $ tanRequest ;
251292 }
293+
294+ /** To be called only by the FinTs instance that executes this action. */
295+ final public function setPollingInfo (?PollingInfo $ pollingInfo ): void
296+ {
297+ $ this ->pollingInfo = $ pollingInfo ;
298+ }
299+
300+ /** To be called only by the FinTs instance that executes this action. */
301+ final public function setVopConfirmationRequest (?VopConfirmationRequest $ vopConfirmationRequest ): void
302+ {
303+ $ this ->vopConfirmationRequest = $ vopConfirmationRequest ;
304+ }
252305}
0 commit comments