PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.2
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / myyoast-client / application / callback-outcome.php

callback-outcome.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.2, at src/myyoast-client/application/callback-outcome.php

193 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
3
4 namespace Yoast\WP\SEO\MyYoast_Client\Application;
5
6 /**
7 * Immutable result of handling an OAuth authorization-code callback.
8 *
9 * Describes the outcome in OAuth terms: a success, a no-op (the request was not
10 * a real callback), a provider error (the authorization endpoint redirected back
11 * with an `error`), or an exchange error (the token endpoint rejected the code).
12 * It invents no severity vocabulary of its own — it passes through whichever
13 * native OAuth error code was reported and records which OAuth phase produced
14 * it, leaving each consumer to translate that onto its own surface (a
15 * notification, a REST error response, CLI output, ...).
16 *
17 * The phase matters because the same absence of a recognised code means
18 * different things per phase: an unrecognised provider error is unexpected,
19 * whereas an unrecognised token-endpoint error is a generic token failure.
20 */
21 final class Callback_Outcome {
22
23 public const PHASE_NONE = 'none';
24 public const PHASE_PROVIDER = 'provider';
25 public const PHASE_EXCHANGE = 'exchange';
26
27 /**
28 * Whether the callback completed successfully.
29 *
30 * @var bool
31 */
32 private $is_success;
33
34 /**
35 * Whether the request carried no actionable callback parameters.
36 *
37 * @var bool
38 */
39 private $is_no_op;
40
41 /**
42 * The OAuth phase that produced a failure (a PHASE_* constant).
43 *
44 * @var string
45 */
46 private $error_phase;
47
48 /**
49 * The native OAuth error code on failure, or null when there is none
50 * (a success, a no-op, or a failure with no OAuth response at all).
51 *
52 * @var string|null
53 */
54 private $error_code;
55
56 /**
57 * Callback_Outcome constructor.
58 *
59 * @param bool $is_success Whether the callback succeeded.
60 * @param bool $is_no_op Whether the request was not a real callback.
61 * @param string $error_phase The OAuth phase that produced a failure.
62 * @param string|null $error_code The native OAuth error code on failure.
63 */
64 private function __construct( bool $is_success, bool $is_no_op, string $error_phase, ?string $error_code ) {
65 $this->is_success = $is_success;
66 $this->is_no_op = $is_no_op;
67 $this->error_phase = $error_phase;
68 $this->error_code = $error_code;
69 }
70
71 /**
72 * Creates a successful outcome (the code was exchanged and tokens stored).
73 *
74 * @return self
75 */
76 public static function success(): self {
77 return new self( true, false, self::PHASE_NONE, null );
78 }
79
80 /**
81 * Creates a no-op outcome (empty code/state — not a real callback).
82 *
83 * @return self
84 */
85 public static function no_op(): self {
86 return new self( false, true, self::PHASE_NONE, null );
87 }
88
89 /**
90 * Creates an outcome for an error reported by the authorization endpoint
91 * redirect (the `error` query parameter on the callback).
92 *
93 * @param string $oauth_error_code The native OAuth error code.
94 *
95 * @return self
96 */
97 public static function provider_error( string $oauth_error_code ): self {
98 return new self( false, false, self::PHASE_PROVIDER, $oauth_error_code );
99 }
100
101 /**
102 * Creates an outcome for a failure while exchanging the code at the token
103 * endpoint.
104 *
105 * @param string|null $oauth_error_code The native OAuth error code, or null
106 * when the failure produced no OAuth
107 * response at all.
108 *
109 * @return self
110 */
111 public static function exchange_error( ?string $oauth_error_code ): self {
112 return new self( false, false, self::PHASE_EXCHANGE, $oauth_error_code );
113 }
114
115 /**
116 * Whether the callback completed successfully.
117 *
118 * @return bool
119 */
120 public function is_success(): bool {
121 return $this->is_success;
122 }
123
124 /**
125 * Whether the request carried no actionable callback parameters.
126 *
127 * @return bool
128 */
129 public function is_no_op(): bool {
130 return $this->is_no_op;
131 }
132
133 /**
134 * Whether the callback failed.
135 *
136 * @return bool
137 */
138 public function is_failure(): bool {
139 return ! $this->is_success && ! $this->is_no_op;
140 }
141
142 /**
143 * Returns the OAuth phase that produced a failure.
144 *
145 * @return string A PHASE_* constant.
146 */
147 public function get_error_phase(): string {
148 return $this->error_phase;
149 }
150
151 /**
152 * Returns the native OAuth error code on failure.
153 *
154 * @return string|null The OAuth error code, or null when there is none.
155 */
156 public function get_error_code(): ?string {
157 return $this->error_code;
158 }
159
160 /**
161 * Converts the outcome to an associative array for storage.
162 *
163 * @return array{is_success: bool, is_no_op: bool, error_phase: string, error_code: string|null}
164 */
165 public function to_array(): array {
166 return [
167 'is_success' => $this->is_success,
168 'is_no_op' => $this->is_no_op,
169 'error_phase' => $this->error_phase,
170 'error_code' => $this->error_code,
171 ];
172 }
173
174 /**
175 * Creates a Callback_Outcome from a stored array.
176 *
177 * @param array<string, bool|string|null> $data The stored array data.
178 *
179 * @return self
180 */
181 public static function from_array( array $data ): self {
182 $error_phase = ( isset( $data['error_phase'] ) && \is_string( $data['error_phase'] ) ) ? $data['error_phase'] : self::PHASE_NONE;
183 $error_code = ( isset( $data['error_code'] ) && \is_string( $data['error_code'] ) ) ? $data['error_code'] : null;
184
185 return new self(
186 ! empty( $data['is_success'] ),
187 ! empty( $data['is_no_op'] ),
188 $error_phase,
189 $error_code,
190 );
191 }
192 }
193