PluginProbe
Texty – SMS Notification for WordPress, WooCommerce, Dokan and more / trunk
Texty – SMS Notification for WordPress, WooCommerce, Dokan and more vtrunk
2.0.2 trunk 0.2 1.0 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 2.0.0 2.0.1
texty / includes / Dispatcher.php

Dispatcher.php in Texty – SMS Notification for WordPress, WooCommerce, Dokan and more trunk, at includes/Dispatcher.php

198 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Texty;
4
5 use Texty\Integrations\Dokan;
6 use Texty\Integrations\WooCommerce;
7 use Texty\Models\SmsStat;
8 use Texty\Dependencies\WeDevs\WPKit\DataLayer\DataLayerFactory;
9 use Texty\Gateways\GatewayInterface;
10 use WP_Comment;
11
12 /**
13 * Dispatcher Class
14 */
15 class Dispatcher {
16
17 /**
18 * Initialize
19 */
20 public function __construct() {
21
22 // WordPress Events
23 add_action( 'user_register', [ $this, 'user_register' ] );
24 add_action( 'comment_post', [ $this, 'new_comment' ] );
25
26 // SMS Logging via gateway hooks
27 add_action( 'texty_after_send_sms', [ $this, 'log_sms' ], 10, 4 );
28
29 // Load integrations
30 $this->register_integrations();
31 }
32
33 /**
34 * Register integrations via hook for extensibility.
35 *
36 * @return void
37 */
38 private function register_integrations() {
39 /**
40 * Fires to allow registration of custom integrations.
41 *
42 * Default handler loads WooCommerce and Dokan integrations
43 * when their respective plugins are active.
44 */
45 do_action( 'texty_register_integrations' );
46
47 // Load built-in integrations conditionally
48 if ( class_exists( 'WooCommerce' ) ) {
49 new WooCommerce();
50 }
51
52 if ( class_exists( 'WeDevs_Dokan' ) ) {
53 new Dokan();
54 }
55 }
56
57 /**
58 * Send message upon user registration
59 *
60 * @param int $user_id
61 *
62 * @return void
63 */
64 public function user_register( $user_id ) {
65 $class = texty()->notifications()->get( 'registration' );
66 $notifier = new $class();
67
68 $notifier->set_user( $user_id );
69 $notifier->send();
70 }
71
72 /**
73 * Send message upon a new comment
74 *
75 * @param int $comment_id
76 *
77 * @return void
78 */
79 public function new_comment( $comment_id ) {
80 // The comment may have been deleted, trashed, or flagged as spam
81 // (e.g. by an anti-spam plugin hooked on `comment_post`) before this
82 // runs. Bail so we don't render and bill an SMS for a comment that no
83 // longer exists.
84 if ( ! get_comment( $comment_id ) instanceof WP_Comment ) {
85 return;
86 }
87
88 $class = texty()->notifications()->get( 'comment' );
89 $notifier = new $class();
90
91 $notifier->set_comment( $comment_id );
92 $notifier->send();
93 }
94
95 /**
96 * Log SMS message to database via gateway hook
97 *
98 * Uses DataLayer for type-safe, cached, and hookable SMS logging.
99 *
100 * @param mixed $result The send result (bool, array, or WP_Error)
101 * @param string $to Recipient phone number
102 * @param string $message The message body
103 * @param GatewayInterface|false $gateway The gateway instance or false
104 *
105 * @return void
106 */
107 public function log_sms( $result, $to, $message, $gateway ) {
108 $store = DataLayerFactory::make_store( SmsStat::class );
109
110 if ( null === $store ) {
111 return;
112 }
113
114 $gateway_name = $gateway ? $gateway->name() : texty()->settings()->gateway();
115
116 // Determine status based on result
117 $status = is_wp_error( $result ) ? 'failed' : 'sent';
118
119 // Extract reference_id from gateway response
120 $reference_id = $this->extract_reference_id( $result );
121 if ( null === $reference_id ) {
122 $reference_id = '';
123 }
124
125 // Pull notification context off the registry — set by
126 // `Notification::send()` around its `$gateway->send()` loop.
127 $notification = texty()->notifications()->get_active();
128 $notification_id = $notification ? (string) $notification->get_id() : '';
129 $notification_group = $notification ? (string) $notification->get_group() : '';
130
131 // Create and save SMS record using DataLayer.
132 // `set_receiver` is typed `string`; coerce defensively so a failed
133 // send with a null/missing recipient still logs instead of fatalling.
134 $sms = new SmsStat();
135 $sms->set_props(
136 [
137 'receiver' => is_string( $to ) ? $to : '',
138 'gateway' => $gateway_name ? $gateway_name : '',
139 'status' => $status,
140 'notification_id' => $notification_id,
141 'notification_group' => $notification_group,
142 'message' => is_string( $message ) ? $message : '',
143 'response' => $this->encode_response( $result ),
144 'reference_id' => is_scalar( $reference_id ) ? (string) $reference_id : '',
145 'created_at' => current_time( 'mysql' ),
146 'updated_at' => current_time( 'mysql' ),
147 ]
148 );
149
150 $store->create( $sms );
151 }
152
153 /**
154 * Normalize the gateway result into a JSON-friendly payload for the
155 * `response` column. WP_Error gets unpacked into code/message/data so
156 * the failure is human-readable; arrays/objects are passed through;
157 * scalars are JSON-encoded as-is.
158 *
159 * @param mixed $result The send result (bool, array, or WP_Error).
160 *
161 * @return array|string|null
162 */
163 private function encode_response( $result ) {
164 if ( is_wp_error( $result ) ) {
165 return [
166 'code' => $result->get_error_code(),
167 'message' => $result->get_error_message(),
168 'data' => $result->get_error_data(),
169 ];
170 }
171
172 return $result;
173 }
174
175 private function extract_reference_id( $result ) {
176 if ( ! is_array( $result ) ) {
177 return null;
178 }
179
180 $id_keys = [ 'sid', 'message-id', 'message_uuid', 'apiMsgId', 'reference_id' ];
181
182 foreach ( $id_keys as $key ) {
183 if ( ! empty( $result[ $key ] ) ) {
184 $value = $result[ $key ];
185
186 // Plivo wraps message_uuid in an array — flatten to the first id.
187 if ( is_array( $value ) ) {
188 $value = reset( $value );
189 }
190
191 return $value;
192 }
193 }
194
195 return null;
196 }
197 }
198