PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 8.5.72
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v8.5.72
9.1.3 9.1.2 9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 8.5.38 8.5.39 All 222 releases
wpvr / vendor / linno / telemetry / src / EventDispatcher.php

EventDispatcher.php in WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress 8.5.72, at vendor/linno/telemetry/src/EventDispatcher.php

282 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * EventDispatcher Class
4 *
5 * Orchestrates event sending by normalizing payloads, adding system information,
6 * validating data, and delegating transmission to the appropriate driver.
7 *
8 * @package LinnoSDK\Telemetry
9 * @since 1.0.0
10 */
11
12 namespace LinnoSDK\Telemetry;
13
14 use LinnoSDK\Telemetry\Drivers\DriverInterface;
15 use LinnoSDK\Telemetry\Helpers\Utils;
16
17 /**
18 * EventDispatcher class
19 *
20 * Acts as an abstraction layer between the Client and the analytics platform.
21 *
22 * @since 1.0.0
23 */
24 class EventDispatcher {
25 /**
26 * Driver instance for sending events
27 *
28 * @var DriverInterface
29 */
30 private $driver;
31
32 /**
33 * Plugin name
34 *
35 * @var string
36 */
37 private $plugin_name;
38
39 /**
40 * Plugin version
41 *
42 * @var string
43 */
44 private $plugin_version;
45
46 /**
47 * Unique identifier for the site
48 *
49 * @var string
50 */
51 private $unique_id;
52
53 /**
54 * Configuration data
55 *
56 * @var array
57 */
58 private $config;
59
60 /**
61 * Constructor
62 *
63 * @param DriverInterface $driver Driver instance for sending events.
64 * @param array $config Configuration data.
65 *
66 * @since 1.0.0
67 */
68 public function __construct(DriverInterface $driver, array $config)
69 {
70 $this->driver = $driver;
71 $this->config = $config;
72 $this->plugin_name = $config['pluginName'] ?? '';
73 $this->plugin_version = $config['version'] ?? $config['pluginVersion'] ?? '';
74 $this->unique_id = $config['unique_id'] ?? '';
75 }
76
77 public function getDriver(): DriverInterface
78 {
79 return $this->driver;
80 }
81
82 /**
83 * Dispatch an event to the analytics platform
84 *
85 * Orchestrates the event sending process by normalizing the payload,
86 * adding system information, validating, and sending via the driver.
87 *
88 * @param string $event Event name.
89 * @param array $properties Event properties (optional).
90 *
91 * @return bool True on success, false on failure.
92 * @since 1.0.0
93 */
94 public function dispatch( string $event, array $properties = array() ): bool {
95 // Normalize the payload
96 $payload = $this->normalizePayload( $event, $properties );
97
98 // Add system info to the payload
99 $payload = $this->addSystemInfo( $payload );
100
101 // Validate the payload
102 if ( ! $this->validatePayload( $payload ) ) {
103 return false;
104 }
105 // Send via driver
106 $result = $this->driver->send( $payload['event'], $payload['properties'] );
107
108 if ( ! $result ) {
109 $error = $this->driver->getLastError();
110 error_log( sprintf(
111 '[Linno Telemetry] Failed to send event "%s": %s',
112 $payload['event'],
113 $error ?? 'unknown error'
114 ) );
115 return false;
116 }
117
118 return true;
119 }
120
121 /**
122 * Dispatch a minimal event payload without automatic metadata enrichment.
123 *
124 * This is used for lifecycle events that must not include personal data
125 * or consent-gated context.
126 *
127 * @param string $event Event name.
128 * @param array $properties Event properties.
129 *
130 * @return bool True on success, false on failure.
131 * @since 1.0.0
132 */
133 public function dispatch_minimal( string $event, array $properties = array() ): bool {
134 $sanitized_event = Utils::sanitizeEventName( $event );
135 $sanitized_properties = Utils::sanitizeProperties( $properties );
136
137 if ( empty( $sanitized_event ) ) {
138 return false;
139 }
140
141 $result = $this->driver->send( $sanitized_event, $sanitized_properties );
142
143 if ( ! $result ) {
144 $error = $this->driver->getLastError();
145 error_log( sprintf(
146 '[Linno Telemetry] Failed to send event "%s": %s',
147 $sanitized_event,
148 $error ?? 'unknown error'
149 ) );
150 return false;
151 }
152
153 return true;
154 }
155
156 /**
157 * Normalize payload to create consistent event structure
158 *
159 * Creates a standardized structure with event and properties keys,
160 * and adds required fields like site_url, plugin_name, plugin_version, and timestamp.
161 *
162 * @param string $event Event name.
163 * @param array $properties Event properties.
164 *
165 * @return array Normalized payload with event and properties keys.
166 * @since 1.0.0
167 */
168 private function normalizePayload( string $event, array $properties ): array {
169 // Sanitize event name
170 $sanitized_event = Utils::sanitizeEventName( $event );
171
172 // Sanitize properties
173 $sanitized_properties = Utils::sanitizeProperties( $properties );
174
175 // Add required fields with proper sanitization
176 $sanitized_properties['site_url'] = esc_url_raw( Utils::getSiteUrl() );
177 $sanitized_properties['unique_id'] = $sanitized_properties['unique_id'] ?? $this->unique_id;
178 $sanitized_properties['plugin_name'] = $this->plugin_name;
179 $sanitized_properties['plugin_version'] = $this->plugin_version;
180 $sanitized_properties['timestamp'] = $sanitized_properties['timestamp'] ?? Utils::getCurrentTimestamp();
181
182 // Automatically add profile identification with current user info
183 if ( ! isset( $sanitized_properties['__identify'] ) ) {
184 // No __identify provided - create one with site profile ID and current user info
185 $sanitized_properties['__identify'] = array(
186 'profileId' => Utils::getSiteProfileId(),
187 );
188
189 // Add current user information if available
190 if ( function_exists( 'wp_get_current_user' ) ) {
191 $current_user = wp_get_current_user();
192 if ( $current_user && $current_user->ID > 0 ) {
193 $sanitized_properties['__identify']['email'] = $current_user->user_email;
194 $sanitized_properties['__identify']['firstName'] = $current_user->first_name ?: 'User';
195 $sanitized_properties['__identify']['lastName'] = $current_user->last_name ?: '';
196 if ( function_exists( 'get_avatar_url' ) ) {
197 $sanitized_properties['__identify']['avatar'] = get_avatar_url( $current_user->ID );
198 }
199 }
200 }
201 } elseif ( is_array( $sanitized_properties['__identify'] ) ) {
202 if ( empty( $sanitized_properties['__identify']['profileId'] ) ) {
203 // Add site profile ID while preserving other fields
204 $sanitized_properties['__identify']['profileId'] = Utils::getSiteProfileId();
205 }
206
207 // Fill in missing user info if not provided
208 if ( function_exists( 'wp_get_current_user' ) ) {
209 $current_user = wp_get_current_user();
210 if ( $current_user && $current_user->ID > 0 ) {
211 if ( empty( $sanitized_properties['__identify']['email'] ) ) {
212 $sanitized_properties['__identify']['email'] = $current_user->user_email;
213 }
214 if ( empty( $sanitized_properties['__identify']['firstName'] ) ) {
215 $sanitized_properties['__identify']['firstName'] = $current_user->first_name ?: 'User';
216 }
217 if ( empty( $sanitized_properties['__identify']['lastName'] ) ) {
218 $sanitized_properties['__identify']['lastName'] = $current_user->last_name ?: '';
219 }
220 if ( empty( $sanitized_properties['__identify']['avatar'] ) && function_exists( 'get_avatar_url' ) ) {
221 $sanitized_properties['__identify']['avatar'] = get_avatar_url( $current_user->ID );
222 }
223 }
224 }
225 }
226 return array(
227 'event' => $sanitized_event,
228 'properties' => $sanitized_properties,
229 );
230 }
231
232 /**
233 * Add system information to the payload
234 *
235 * Adds minimal system information to the event properties.
236 *
237 * @param array $payload Event payload.
238 *
239 * @return array Payload with system information added.
240 * @since 1.0.0
241 */
242 private function addSystemInfo( array $payload ): array {
243 return $payload;
244 }
245
246 /**
247 * Validate payload structure and required fields
248 *
249 * Checks that all required fields are present: event, site_url,
250 * plugin_name, plugin_version, and timestamp.
251 *
252 * @param array $payload Event payload to validate.
253 *
254 * @return bool True if valid, false otherwise.
255 * @since 1.0.0
256 */
257 private function validatePayload( array $payload ): bool {
258 // Check event key exists and is not empty
259 if ( empty( $payload['event'] ) || ! is_string( $payload['event'] ) ) {
260 return false;
261 }
262
263 // Check properties key exists and is an array
264 if ( ! isset( $payload['properties'] ) || ! is_array( $payload['properties'] ) ) {
265 return false;
266 }
267
268 $properties = $payload['properties'];
269
270 // Check required fields in properties
271 $required_fields = array( 'site_url', 'unique_id', 'plugin_name', 'plugin_version', 'timestamp' );
272
273 foreach ( $required_fields as $field ) {
274 if ( empty( $properties[ $field ] ) || ! is_string( $properties[ $field ] ) ) {
275 return false;
276 }
277 }
278
279 return true;
280 }
281 }
282