PluginProbe
ActivityPub / 8.0.2
ActivityPub v8.0.2
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / includes / activity / class-generic-object.php

class-generic-object.php in ActivityPub 8.0.2, at includes/activity/class-generic-object.php

360 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Generic Object.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Activity;
9
10 use function Activitypub\camel_to_snake_case;
11 use function Activitypub\snake_to_camel_case;
12
13 /**
14 * Generic Object.
15 *
16 * This class is used to create Generic Objects.
17 * It is used to create objects that might be unknown by the plugin but
18 * conform to the ActivityStreams vocabulary.
19 *
20 * Provides generic magic methods for getting, setting, and adding properties
21 * through __call(). Specific property documentation is in the classes where
22 * the properties are actually defined.
23 *
24 * @since 5.3.0
25 */
26 #[\AllowDynamicProperties]
27 class Generic_Object {
28 /**
29 * The JSON-LD context for the object.
30 *
31 * @var array
32 */
33 const JSON_LD_CONTEXT = array(
34 'https://www.w3.org/ns/activitystreams',
35 );
36
37 /**
38 * The object's unique global identifier
39 *
40 * @see https://www.w3.org/TR/activitypub/#obj-id
41 *
42 * @var string
43 */
44 protected $id;
45
46 /**
47 * Magic function, to transform the object to string.
48 *
49 * @return string The object id.
50 */
51 public function __toString() {
52 return $this->to_string();
53 }
54
55 /**
56 * Function to transform the object to string.
57 *
58 * @return string The object id.
59 */
60 public function to_string() {
61 return $this->get_id();
62 }
63
64 /**
65 * Magic function to implement getter and setter.
66 *
67 * @param string $method The method name.
68 * @param string $params The method params.
69 *
70 * @return mixed
71 */
72 public function __call( $method, $params ) {
73 $var = \strtolower( \substr( $method, 4 ) );
74
75 if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
76 if ( ! $this->has( $var ) ) {
77 return null;
78 }
79
80 return $this->$var;
81 }
82
83 if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
84 return $this->set( $var, $params[0] );
85 }
86
87 if ( \strncasecmp( $method, 'add', 3 ) === 0 ) {
88 return $this->add( $var, $params[0] );
89 }
90
91 return null;
92 }
93
94 /**
95 * Generic getter.
96 *
97 * @param string $key The key to get.
98 *
99 * @return mixed The value.
100 */
101 public function get( $key ) {
102 return call_user_func( array( $this, 'get_' . $key ) );
103 }
104
105 /**
106 * Generic setter.
107 *
108 * @param string $key The key to set.
109 * @param string $value The value to set.
110 *
111 * @return mixed The value.
112 */
113 public function set( $key, $value ) {
114 $this->$key = $value;
115
116 return $this;
117 }
118
119 /**
120 * Generic adder.
121 *
122 * @param string $key The key to set.
123 * @param mixed $value The value to add.
124 *
125 * @return mixed|void The value.
126 */
127 public function add( $key, $value ) {
128 if ( empty( $value ) ) {
129 return;
130 }
131
132 if ( ! isset( $this->$key ) ) {
133 $this->$key = array();
134 }
135
136 if ( is_string( $this->$key ) ) {
137 $this->$key = array( $this->$key );
138 }
139
140 $attributes = $this->$key;
141
142 if ( is_array( $value ) ) {
143 $attributes = array_merge( $attributes, $value );
144 } else {
145 $attributes[] = $value;
146 }
147
148 $this->$key = array_unique( $attributes );
149
150 return $this->$key;
151 }
152
153 /**
154 * Check if the object has a key
155 *
156 * @param string $key The key to check.
157 *
158 * @return boolean True if the object has the key.
159 */
160 public function has( $key ) {
161 return property_exists( $this, $key );
162 }
163
164 /**
165 * Convert JSON input to an array.
166 *
167 * @param string $json The JSON string.
168 *
169 * @return static|\WP_Error An Object built from the JSON string or WP_Error when it's not a JSON string.
170 */
171 public static function init_from_json( $json ) {
172 $array = \json_decode( $json, true );
173
174 if ( ! is_array( $array ) ) {
175 return new \WP_Error( 'invalid_json', __( 'Invalid JSON', 'activitypub' ), array( 'status' => 400 ) );
176 }
177
178 return self::init_from_array( $array );
179 }
180
181 /**
182 * Convert input array to a Base_Object.
183 *
184 * @param array $data The object array.
185 *
186 * @return static|\WP_Error An Object built from the input array or WP_Error when it's not an array.
187 */
188 public static function init_from_array( $data ) {
189 if ( ! is_array( $data ) ) {
190 return new \WP_Error( 'invalid_array', __( 'Invalid array', 'activitypub' ), array( 'status' => 400 ) );
191 }
192
193 $object = new static();
194 $object->from_array( $data );
195
196 return $object;
197 }
198
199 /**
200 * Convert JSON input to an array and pre-fill the object.
201 *
202 * @param array $data The array.
203 */
204 public function from_array( $data ) {
205 foreach ( $data as $key => $value ) {
206 if ( null !== $value ) {
207 // Convert camelCase to snake_case if not prefixed with '_'.
208 if ( ! \str_starts_with( $key, '_' ) ) {
209 $key = camel_to_snake_case( $key );
210 }
211
212 call_user_func( array( $this, 'set_' . $key ), $value );
213 }
214 }
215 }
216
217 /**
218 * Convert JSON input to an array and pre-fill the object.
219 *
220 * @param string $json The JSON string.
221 */
222 public function from_json( $json ) {
223 $array = \json_decode( $json, true );
224
225 $this->from_array( $array );
226 }
227
228 /**
229 * Convert Object to an array.
230 *
231 * It tries to get the object attributes if they exist
232 * and falls back to the getters. Empty values are ignored.
233 *
234 * @param bool $include_json_ld_context Whether to include the JSON-LD context. Default true.
235 *
236 * @return array An array built from the Object.
237 */
238 public function to_array( $include_json_ld_context = true ) {
239 $array = array();
240 $vars = get_object_vars( $this );
241
242 foreach ( $vars as $key => $value ) {
243 if ( \is_wp_error( $value ) ) {
244 continue;
245 }
246
247 // Ignore all _prefixed keys.
248 if ( '_' === substr( $key, 0, 1 ) ) {
249 continue;
250 }
251
252 // If value is empty, try to get it from a getter.
253 if ( ! $value ) {
254 $value = call_user_func( array( $this, 'get_' . $key ) );
255 }
256
257 if ( is_object( $value ) ) {
258 $value = $value->to_array( false );
259 }
260
261 if ( is_array( $value ) && $this->is_namespaced( $key ) ) {
262 foreach ( $value as $sub_key => $sub_value ) {
263 $array[ snake_to_camel_case( $key ) . ':' . snake_to_camel_case( $sub_key ) ] = $sub_value;
264 }
265 } elseif ( isset( $value ) ) {
266 $array[ snake_to_camel_case( $key ) ] = $value;
267 }
268 }
269
270 if ( $include_json_ld_context ) {
271 // Get JsonLD context and move it to '@context' at the top.
272 $array = array_merge( array( '@context' => $this->get_json_ld_context() ), $array );
273 }
274
275 $class = new \ReflectionClass( $this );
276 $class = strtolower( $class->getShortName() );
277
278 /**
279 * Filter the array of the ActivityPub object.
280 *
281 * @param array $array The array of the ActivityPub object.
282 * @param string $class The class of the ActivityPub object.
283 * @param string $id The ID of the ActivityPub object.
284 * @param Generic_Object $object The ActivityPub object.
285 *
286 * @return array The filtered array of the ActivityPub object.
287 */
288 $array = \apply_filters( 'activitypub_activity_object_array', $array, $class, $this->id, $this );
289
290 /**
291 * Filter the array of the ActivityPub object by class.
292 *
293 * @param array $array The array of the ActivityPub object.
294 * @param string $id The ID of the ActivityPub object.
295 * @param Generic_Object $object The ActivityPub object.
296 *
297 * @return array The filtered array of the ActivityPub object.
298 */
299 return \apply_filters( "activitypub_activity_{$class}_object_array", $array, $this->id, $this );
300 }
301
302 /**
303 * Convert Object to JSON.
304 *
305 * @param bool $include_json_ld_context Whether to include the JSON-LD context. Default true.
306 *
307 * @return string The JSON string.
308 */
309 public function to_json( $include_json_ld_context = true ) {
310 $array = $this->to_array( $include_json_ld_context );
311 $options = \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT | \JSON_UNESCAPED_SLASHES;
312
313 /**
314 * Options to be passed to json_encode().
315 *
316 * @param int $options The current options flags.
317 */
318 $options = \apply_filters( 'activitypub_json_encode_options', $options );
319
320 return \wp_json_encode( $array, $options );
321 }
322
323 /**
324 * Returns the keys of the object vars.
325 *
326 * @return array The keys of the object vars.
327 */
328 public function get_object_var_keys() {
329 return \array_keys( \get_object_vars( $this ) );
330 }
331
332 /**
333 * Returns the JSON-LD context of this object.
334 *
335 * @return array $context A compacted JSON-LD context for the ActivityPub object.
336 */
337 public function get_json_ld_context() {
338 return static::JSON_LD_CONTEXT;
339 }
340
341 /**
342 * Checks if an attribute is in a namespace.
343 *
344 * @param string $attribute The attribute to check.
345 *
346 * @return bool Whether the attribute is namespaced.
347 */
348 private function is_namespaced( $attribute ) {
349 $namespaces = array();
350
351 foreach ( static::JSON_LD_CONTEXT as $context ) {
352 if ( is_array( $context ) ) {
353 $namespaces = \array_merge( $namespaces, $context );
354 }
355 }
356
357 return isset( $namespaces[ $attribute ] ) && \wp_http_validate_url( $namespaces[ $attribute ] );
358 }
359 }
360