PluginProbe
Stream – Activity Log & Audit Trail / 3.2.0
Stream – Activity Log & Audit Trail v3.2.0
4.4.0 4.3.0 4.2.2 4.2.1 trunk 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1 3.1.1 3.10.0 3.2.0 3.2.1 3.2.2 3.2.3 All 50 releases
stream / classes / class-connector.php

class-connector.php in Stream – Activity Log & Audit Trail 3.2.0, at classes/class-connector.php

248 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WP_Stream;
3
4 abstract class Connector {
5 /**
6 * Connector slug
7 *
8 * @var string
9 */
10 public $name = null;
11
12 /**
13 * Actions registered for this connector
14 *
15 * @var array
16 */
17 public $actions = array();
18
19 /**
20 * Store delayed logs
21 *
22 * @var array
23 */
24 public $delayed = array();
25
26 /**
27 * Previous Stream entry in same request
28 *
29 * @var int
30 */
31 public $prev_stream = null;
32
33 /**
34 * Register connector in the WP Admin
35 *
36 * @var bool
37 */
38 public $register_admin = true;
39
40 /**
41 * Register connector in the WP Frontend
42 *
43 * @var bool
44 */
45 public $register_frontend = true;
46
47 /**
48 * Register all context hooks
49 */
50 public function register() {
51 foreach ( $this->actions as $action ) {
52 add_action( $action, array( $this, 'callback' ), 10, 99 );
53 }
54
55 add_filter( 'wp_stream_action_links_' . $this->name, array( $this, 'action_links' ), 10, 2 );
56 }
57
58 /**
59 * Callback for all registered hooks throughout Stream
60 * Looks for a class method with the convention: "callback_{action name}"
61 */
62 public function callback() {
63 $action = current_filter();
64 $callback = array( $this, 'callback_' . preg_replace( '/[^a-z0-9_\-]/', '_', $action ) );
65
66 // For the sake of testing, trigger an action with the name of the callback
67 if ( defined( 'WP_STREAM_TESTS' ) && WP_STREAM_TESTS ) {
68 /**
69 * Action fires during testing to test the current callback
70 *
71 * @param array $callback Callback name
72 */
73 do_action( 'wp_stream_test_' . $callback[1] );
74 }
75
76 // Call the real function
77 if ( is_callable( $callback ) ) {
78 return call_user_func_array( $callback, func_get_args() );
79 }
80 }
81
82 /**
83 * Add action links to Stream drop row in admin list screen
84 *
85 * @param array $links Previous links registered
86 * @param object $record Stream record
87 *
88 * @filter wp_stream_action_links_{connector}
89 *
90 * @return array Action links
91 */
92 public function action_links( $links, $record ) {
93 unset( $record );
94 return $links;
95 }
96
97 /**
98 * Log handler
99 *
100 * @param string $message sprintf-ready error message string
101 * @param array $args sprintf (and extra) arguments to use
102 * @param int $object_id Target object id
103 * @param string $context Context of the event
104 * @param string $action Action of the event
105 * @param int $user_id User responsible for the event
106 *
107 * @return bool
108 */
109 public function log( $message, $args, $object_id, $context, $action, $user_id = null ) {
110 $connector = $this->name;
111
112 $data = apply_filters(
113 'wp_stream_log_data',
114 compact( 'connector', 'message', 'args', 'object_id', 'context', 'action', 'user_id' )
115 );
116
117 if ( ! $data ) {
118 return false;
119 } else {
120 $connector = $data['connector'];
121 $message = $data['message'];
122 $args = $data['args'];
123 $object_id = $data['object_id'];
124 $context = $data['context'];
125 $action = $data['action'];
126 $user_id = $data['user_id'];
127 }
128
129 return call_user_func_array( array( wp_stream_get_instance()->log, 'log' ), compact( 'connector', 'message', 'args', 'object_id', 'context', 'action', 'user_id' ) );
130 }
131
132 /**
133 * Save log data till shutdown, so other callbacks would be able to override
134 *
135 * @param string $handle Special slug to be shared with other actions
136 * @note param mixed $arg1 Extra arguments to sent to log()
137 * @note param param mixed $arg2, etc..
138 */
139 public function delayed_log( $handle ) {
140 $args = func_get_args();
141
142 array_shift( $args );
143
144 $this->delayed[ $handle ] = $args;
145
146 add_action( 'shutdown', array( $this, 'delayed_log_commit' ) );
147 }
148
149 /**
150 * Commit delayed logs saved by @delayed_log
151 */
152 public function delayed_log_commit() {
153 foreach ( $this->delayed as $handle => $args ) {
154 call_user_func_array( array( $this, 'log' ), $args );
155 }
156 }
157
158 /**
159 * Compare two values and return changed keys if they are arrays
160 *
161 * @param mixed $old_value Value before change
162 * @param mixed $new_value Value after change
163 * @param bool|int $deep Get array children changes keys as well, not just parents
164 *
165 * @return array
166 */
167 public function get_changed_keys( $old_value, $new_value, $deep = false ) {
168 if ( ! is_array( $old_value ) && ! is_array( $new_value ) ) {
169 return array();
170 }
171
172 if ( ! is_array( $old_value ) ) {
173 return array_keys( $new_value );
174 }
175
176 if ( ! is_array( $new_value ) ) {
177 return array_keys( $old_value );
178 }
179
180 $diff = array_udiff_assoc(
181 $old_value,
182 $new_value,
183 function( $value1, $value2 ) {
184 return maybe_serialize( $value1 ) !== maybe_serialize( $value2 );
185 }
186 );
187
188 $result = array_keys( $diff );
189
190 // find unexisting keys in old or new value
191 $common_keys = array_keys( array_intersect_key( $old_value, $new_value ) );
192 $unique_keys_old = array_values( array_diff( array_keys( $old_value ), $common_keys ) );
193 $unique_keys_new = array_values( array_diff( array_keys( $new_value ), $common_keys ) );
194
195 $result = array_merge( $result, $unique_keys_old, $unique_keys_new );
196
197 // remove numeric indexes
198 $result = array_filter(
199 $result,
200 function( $value ) {
201 // @codingStandardsIgnoreStart
202 // check if is not valid number (is_int, is_numeric and ctype_digit are not enough)
203 return (string) (int) $value !== (string) $value;
204 // @codingStandardsIgnoreEnd
205 }
206 );
207
208 $result = array_values( array_unique( $result ) );
209
210 if ( false === $deep ) {
211 return $result; // Return an numerical based array with changed TOP PARENT keys only
212 }
213
214 $result = array_fill_keys( $result, null );
215
216 foreach ( $result as $key => $val ) {
217 if ( in_array( $key, $unique_keys_old, true ) ) {
218 $result[ $key ] = false; // Removed
219 } elseif ( in_array( $key, $unique_keys_new, true ) ) {
220 $result[ $key ] = true; // Added
221 } elseif ( $deep ) { // Changed, find what changed, only if we're allowed to explore a new level
222 if ( is_array( $old_value[ $key ] ) && is_array( $new_value[ $key ] ) ) {
223 $inner = array();
224 $parent = $key;
225 $deep--;
226 $changed = $this->get_changed_keys( $old_value[ $key ], $new_value[ $key ], $deep );
227 foreach ( $changed as $child => $change ) {
228 $inner[ $parent . '::' . $child ] = $change;
229 }
230 $result[ $key ] = 0; // Changed parent which has a changed children
231 $result = array_merge( $result, $inner );
232 }
233 }
234 }
235
236 return $result;
237 }
238
239 /**
240 * Allow connectors to determine if their dependencies is satisfied or not
241 *
242 * @return bool
243 */
244 public function is_dependency_satisfied() {
245 return true;
246 }
247 }
248