PluginProbe
Stream – Activity Log & Audit Trail / 3.0.6
Stream – Activity Log & Audit Trail v3.0.6
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.0.6, at classes/class-connector.php

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