PluginProbe
ActivityPub / 4.0.2
ActivityPub v4.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-base-object.php

class-base-object.php in ActivityPub 4.0.2, at includes/activity/class-base-object.php

747 lines 17.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Inspired by the PHP ActivityPub Library by @Landrok
4 *
5 * @link https://github.com/landrok/activitypub
6 *
7 * @package Activitypub
8 */
9
10 namespace Activitypub\Activity;
11
12 use WP_Error;
13 use ReflectionClass;
14 use DateTime;
15
16 use function Activitypub\camel_to_snake_case;
17 use function Activitypub\snake_to_camel_case;
18
19 /**
20 * Base_Object is an implementation of one of the
21 * Activity Streams Core Types.
22 *
23 * The Object is the primary base type for the Activity Streams
24 * vocabulary.
25 *
26 * Note: Object is a reserved keyword in PHP. It has been suffixed with
27 * 'Base_' for this reason.
28 *
29 * @see https://www.w3.org/TR/activitystreams-core/#object
30 */
31 class Base_Object {
32 const JSON_LD_CONTEXT = array(
33 'https://www.w3.org/ns/activitystreams',
34 array(
35 'Hashtag' => 'as:Hashtag',
36 'sensitive' => 'as:sensitive',
37 ),
38 );
39
40 /**
41 * The object's unique global identifier
42 *
43 * @see https://www.w3.org/TR/activitypub/#obj-id
44 *
45 * @var string
46 */
47 protected $id;
48
49 /**
50 * The type of the object.
51 *
52 * @var string
53 */
54 protected $type = 'Object';
55
56 /**
57 * A resource attached or related to an object that potentially
58 * requires special handling.
59 * The intent is to provide a model that is at least semantically
60 * similar to attachments in email.
61 *
62 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attachment
63 *
64 * @var string
65 * | ObjectType
66 * | Link
67 * | array<ObjectType>
68 * | array<Link>
69 * | null
70 */
71 protected $attachment;
72
73 /**
74 * One or more entities to which this object is attributed.
75 * The attributed entities might not be Actors. For instance, an
76 * object might be attributed to the completion of another activity.
77 *
78 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attributedto
79 *
80 * @var string
81 * | ObjectType
82 * | Link
83 * | array<ObjectType>
84 * | array<Link>
85 * | null
86 */
87 protected $attributed_to;
88
89 /**
90 * One or more entities that represent the total population of
91 * entities for which the object can considered to be relevant.
92 *
93 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audience
94 *
95 * @var string
96 * | ObjectType
97 * | Link
98 * | array<ObjectType>
99 * | array<Link>
100 * | null
101 */
102 protected $audience;
103
104 /**
105 * The content or textual representation of the Object encoded as a
106 * JSON string. By default, the value of content is HTML.
107 * The mediaType property can be used in the object to indicate a
108 * different content type.
109 *
110 * The content MAY be expressed using multiple language-tagged
111 * values.
112 *
113 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-content
114 *
115 * @var string|null
116 */
117 protected $content;
118
119 /**
120 * The context within which the object exists or an activity was
121 * performed.
122 * The notion of "context" used is intentionally vague.
123 * The intended function is to serve as a means of grouping objects
124 * and activities that share a common originating context or
125 * purpose. An example could be all activities relating to a common
126 * project or event.
127 *
128 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-context
129 *
130 * @var string
131 * | ObjectType
132 * | Link
133 * | null
134 */
135 protected $context;
136
137 /**
138 * The content MAY be expressed using multiple language-tagged
139 * values.
140 *
141 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-content
142 *
143 * @var array|null
144 */
145 protected $content_map;
146
147 /**
148 * A simple, human-readable, plain-text name for the object.
149 * HTML markup MUST NOT be included.
150 *
151 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name
152 *
153 * @var string|null xsd:string
154 */
155 protected $name;
156
157 /**
158 * The name MAY be expressed using multiple language-tagged values.
159 *
160 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name
161 *
162 * @var array|null rdf:langString
163 */
164 protected $name_map;
165
166 /**
167 * The date and time describing the actual or expected ending time
168 * of the object.
169 * When used with an Activity object, for instance, the endTime
170 * property specifies the moment the activity concluded or
171 * is expected to conclude.
172 *
173 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-endtime
174 *
175 * @var string|null
176 */
177 protected $end_time;
178
179 /**
180 * The entity (e.g. an application) that generated the object.
181 *
182 * @var string|null
183 */
184 protected $generator;
185
186 /**
187 * An entity that describes an icon for this object.
188 * The image should have an aspect ratio of one (horizontal)
189 * to one (vertical) and should be suitable for presentation
190 * at a small size.
191 *
192 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-icon
193 *
194 * @var string
195 * | Image
196 * | Link
197 * | array<Image>
198 * | array<Link>
199 * | null
200 */
201 protected $icon;
202
203 /**
204 * An entity that describes an image for this object.
205 * Unlike the icon property, there are no aspect ratio
206 * or display size limitations assumed.
207 *
208 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image-term
209 *
210 * @var string
211 * | Image
212 * | Link
213 * | array<Image>
214 * | array<Link>
215 * | null
216 */
217 protected $image;
218
219 /**
220 * One or more entities for which this object is considered a
221 * response.
222 *
223 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-inreplyto
224 *
225 * @var string
226 * | ObjectType
227 * | Link
228 * | array<ObjectType>
229 * | array<Link>
230 * | null
231 */
232 protected $in_reply_to;
233
234 /**
235 * One or more physical or logical locations associated with the
236 * object.
237 *
238 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-location
239 *
240 * @var string
241 * | ObjectType
242 * | Link
243 * | array<ObjectType>
244 * | array<Link>
245 * | null
246 */
247 protected $location;
248
249 /**
250 * An entity that provides a preview of this object.
251 *
252 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-preview
253 *
254 * @var string
255 * | ObjectType
256 * | Link
257 * | null
258 */
259 protected $preview;
260
261 /**
262 * The date and time at which the object was published
263 *
264 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-published
265 *
266 * @var string|null xsd:dateTime
267 */
268 protected $published;
269
270 /**
271 * The date and time describing the actual or expected starting time
272 * of the object.
273 * When used with an Activity object, for instance, the startTime
274 * property specifies the moment the activity began
275 * or is scheduled to begin.
276 *
277 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-starttime
278 *
279 * @var string|null xsd:dateTime
280 */
281 protected $start_time;
282
283 /**
284 * A natural language summarization of the object encoded as HTML.
285 * Multiple language tagged summaries MAY be provided.
286 *
287 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-summary
288 *
289 * @var string
290 * | ObjectType
291 * | Link
292 * | null
293 */
294 protected $summary;
295
296 /**
297 * The content MAY be expressed using multiple language-tagged
298 * values.
299 *
300 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-summary
301 *
302 * @var array<string>|null
303 */
304 protected $summary_map;
305
306 /**
307 * One or more "tags" that have been associated with an objects.
308 * A tag can be any kind of Object.
309 * The key difference between attachment and tag is that the former
310 * implies association by inclusion, while the latter implies
311 * associated by reference.
312 *
313 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tag
314 *
315 * @var string
316 * | ObjectType
317 * | Link
318 * | array<ObjectType>
319 * | array<Link>
320 * | null
321 */
322 protected $tag;
323
324 /**
325 * The date and time at which the object was updated
326 *
327 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-updated
328 *
329 * @var string|null xsd:dateTime
330 */
331 protected $updated;
332
333 /**
334 * One or more links to representations of the object.
335 *
336 * @var string
337 * | array<string>
338 * | Link
339 * | array<Link>
340 * | null
341 */
342 protected $url;
343
344 /**
345 * An entity considered to be part of the public primary audience
346 * of an Object
347 *
348 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-to
349 *
350 * @var string
351 * | ObjectType
352 * | Link
353 * | array<ObjectType>
354 * | array<Link>
355 * | null
356 */
357 protected $to;
358
359 /**
360 * An Object that is part of the private primary audience of this
361 * Object.
362 *
363 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-bto
364 *
365 * @var string
366 * | ObjectType
367 * | Link
368 * | array<ObjectType>
369 * | array<Link>
370 * | null
371 */
372 protected $bto;
373
374 /**
375 * An Object that is part of the public secondary audience of this
376 * Object.
377 *
378 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-cc
379 *
380 * @var string
381 * | ObjectType
382 * | Link
383 * | array<ObjectType>
384 * | array<Link>
385 * | null
386 */
387 protected $cc;
388
389 /**
390 * One or more Objects that are part of the private secondary
391 * audience of this Object.
392 *
393 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-bcc
394 *
395 * @var string
396 * | ObjectType
397 * | Link
398 * | array<ObjectType>
399 * | array<Link>
400 * | null
401 */
402 protected $bcc;
403
404 /**
405 * The MIME media type of the value of the content property.
406 * If not specified, the content property is assumed to contain
407 * text/html content.
408 *
409 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-mediatype
410 *
411 * @var string|null
412 */
413 protected $media_type;
414
415 /**
416 * When the object describes a time-bound resource, such as an audio
417 * or video, a meeting, etc, the duration property indicates the
418 * object's approximate duration.
419 * The value MUST be expressed as an xsd:duration as defined by
420 * xmlschema11-2, section 3.3.6 (e.g. a period of 5 seconds is
421 * represented as "PT5S").
422 *
423 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
424 *
425 * @var string|null
426 */
427 protected $duration;
428
429 /**
430 * Intended to convey some sort of source from which the content
431 * markup was derived, as a form of provenance, or to support
432 * future editing by clients.
433 *
434 * @see https://www.w3.org/TR/activitypub/#source-property
435 *
436 * @var array
437 */
438 protected $source;
439
440 /**
441 * A Collection containing objects considered to be responses to
442 * this object.
443 *
444 * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-replies
445 *
446 * @var string
447 * | Collection
448 * | Link
449 * | null
450 */
451 protected $replies;
452
453 /**
454 * Used to mark an object as containing sensitive content.
455 * Mastodon displays a content warning, requiring users to click
456 * through to view the content.
457 *
458 * @see https://docs.joinmastodon.org/spec/activitypub/#sensitive
459 *
460 * @var boolean
461 */
462 protected $sensitive = false;
463
464 /**
465 * Magic function to implement getter and setter.
466 *
467 * @param string $method The method name.
468 * @param string $params The method params.
469 */
470 public function __call( $method, $params ) {
471 $var = \strtolower( \substr( $method, 4 ) );
472
473 if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
474 if ( ! $this->has( $var ) ) {
475 return new WP_Error( 'invalid_key', __( 'Invalid key', 'activitypub' ), array( 'status' => 404 ) );
476 }
477
478 return $this->$var;
479 }
480
481 if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
482 return $this->set( $var, $params[0] );
483 }
484
485 if ( \strncasecmp( $method, 'add', 3 ) === 0 ) {
486 $this->add( $var, $params[0] );
487 }
488 }
489
490 /**
491 * Magic function, to transform the object to string.
492 *
493 * @return string The object id.
494 */
495 public function __toString() {
496 return $this->to_string();
497 }
498
499 /**
500 * Function to transform the object to string.
501 *
502 * @return string The object id.
503 */
504 public function to_string() {
505 return $this->get_id();
506 }
507
508 /**
509 * Generic getter.
510 *
511 * @param string $key The key to get.
512 *
513 * @return mixed The value.
514 */
515 public function get( $key ) {
516 if ( ! $this->has( $key ) ) {
517 return new WP_Error( 'invalid_key', __( 'Invalid key', 'activitypub' ), array( 'status' => 404 ) );
518 }
519
520 return call_user_func( array( $this, 'get_' . $key ) );
521 }
522
523 /**
524 * Check if the object has a key
525 *
526 * @param string $key The key to check.
527 *
528 * @return boolean True if the object has the key.
529 */
530 public function has( $key ) {
531 return property_exists( $this, $key );
532 }
533
534 /**
535 * Generic setter.
536 *
537 * @param string $key The key to set.
538 * @param string $value The value to set.
539 *
540 * @return mixed The value.
541 */
542 public function set( $key, $value ) {
543 if ( ! $this->has( $key ) ) {
544 return new WP_Error( 'invalid_key', __( 'Invalid key', 'activitypub' ), array( 'status' => 404 ) );
545 }
546
547 $this->$key = $value;
548
549 return $this;
550 }
551
552 /**
553 * Generic adder.
554 *
555 * @param string $key The key to set.
556 * @param mixed $value The value to add.
557 *
558 * @return mixed The value.
559 */
560 public function add( $key, $value ) {
561 if ( ! $this->has( $key ) ) {
562 return new WP_Error( 'invalid_key', __( 'Invalid key', 'activitypub' ), array( 'status' => 404 ) );
563 }
564
565 if ( ! isset( $this->$key ) ) {
566 $this->$key = array();
567 }
568
569 $attributes = $this->$key;
570 $attributes[] = $value;
571
572 $this->$key = $attributes;
573
574 return $this->$key;
575 }
576
577 /**
578 * Convert JSON input to an array.
579 *
580 * @param string $json The JSON string.
581 *
582 * @return Base_Object An Object built from the JSON string.
583 */
584 public static function init_from_json( $json ) {
585 $array = \json_decode( $json, true );
586
587 if ( ! is_array( $array ) ) {
588 $array = array();
589 }
590
591 return self::init_from_array( $array );
592 }
593
594 /**
595 * Convert input array to a Base_Object.
596 *
597 * @param array $data The object array.
598 *
599 * @return Base_Object|WP_Error An Object built from the input array or WP_Error when it's not an array.
600 */
601 public static function init_from_array( $data ) {
602 if ( ! is_array( $data ) ) {
603 return new WP_Error( 'invalid_array', __( 'Invalid array', 'activitypub' ), array( 'status' => 404 ) );
604 }
605
606 $object = new static();
607
608 foreach ( $data as $key => $value ) {
609 $key = camel_to_snake_case( $key );
610 call_user_func( array( $object, 'set_' . $key ), $value );
611 }
612
613 return $object;
614 }
615
616 /**
617 * Convert JSON input to an array and pre-fill the object.
618 *
619 * @param string $json The JSON string.
620 */
621 public function from_json( $json ) {
622 $array = \json_decode( $json, true );
623
624 $this->from_array( $array );
625 }
626
627 /**
628 * Convert JSON input to an array and pre-fill the object.
629 *
630 * @param array $data The array.
631 */
632 public function from_array( $data ) {
633 foreach ( $data as $key => $value ) {
634 if ( $value ) {
635 $key = camel_to_snake_case( $key );
636 call_user_func( array( $this, 'set_' . $key ), $value );
637 }
638 }
639 }
640
641 /**
642 * Convert Object to an array.
643 *
644 * It tries to get the object attributes if they exist
645 * and falls back to the getters. Empty values are ignored.
646 *
647 * @param bool $include_json_ld_context Whether to include the JSON-LD context. Default true.
648 *
649 * @return array An array built from the Object.
650 */
651 public function to_array( $include_json_ld_context = true ) {
652 $array = array();
653 $vars = get_object_vars( $this );
654
655 foreach ( $vars as $key => $value ) {
656 // Ignore all _prefixed keys.
657 if ( '_' === substr( $key, 0, 1 ) ) {
658 continue;
659 }
660
661 // If value is empty, try to get it from a getter.
662 if ( ! $value ) {
663 $value = call_user_func( array( $this, 'get_' . $key ) );
664 }
665
666 if ( is_object( $value ) ) {
667 $value = $value->to_array( false );
668 }
669
670 // If value is still empty, ignore it for the array and continue.
671 if ( isset( $value ) ) {
672 $array[ snake_to_camel_case( $key ) ] = $value;
673 }
674 }
675
676 if ( $include_json_ld_context ) {
677 // Get JsonLD context and move it to '@context' at the top.
678 $array = array_merge( array( '@context' => $this->get_json_ld_context() ), $array );
679 }
680
681 $class = new ReflectionClass( $this );
682 $class = strtolower( $class->getShortName() );
683
684 /**
685 * Filter the array of the ActivityPub object.
686 *
687 * @param array $array The array of the ActivityPub object.
688 * @param string $class The class of the ActivityPub object.
689 * @param int $id The ID of the ActivityPub object.
690 * @param Base_Object $object The ActivityPub object.
691 *
692 * @return array The filtered array of the ActivityPub object.
693 */
694 $array = \apply_filters( 'activitypub_activity_object_array', $array, $class, $this->id, $this );
695
696 /**
697 * Filter the array of the ActivityPub object by class.
698 *
699 * @param array $array The array of the ActivityPub object.
700 * @param int $id The ID of the ActivityPub object.
701 * @param Base_Object $object The ActivityPub object.
702 *
703 * @return array The filtered array of the ActivityPub object.
704 */
705 return \apply_filters( "activitypub_activity_{$class}_object_array", $array, $this->id, $this );
706 }
707
708 /**
709 * Convert Object to JSON.
710 *
711 * @param bool $include_json_ld_context Whether to include the JSON-LD context. Default true.
712 *
713 * @return string The JSON string.
714 */
715 public function to_json( $include_json_ld_context = true ) {
716 $array = $this->to_array( $include_json_ld_context );
717 $options = \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT;
718
719 /**
720 * Options to be passed to json_encode()
721 *
722 * @param int $options The current options flags.
723 */
724 $options = \apply_filters( 'activitypub_json_encode_options', $options );
725
726 return \wp_json_encode( $array, $options );
727 }
728
729 /**
730 * Returns the keys of the object vars.
731 *
732 * @return array The keys of the object vars.
733 */
734 public function get_object_var_keys() {
735 return \array_keys( \get_object_vars( $this ) );
736 }
737
738 /**
739 * Returns the JSON-LD context of this object.
740 *
741 * @return array $context A compacted JSON-LD context for the ActivityPub object.
742 */
743 public function get_json_ld_context() {
744 return static::JSON_LD_CONTEXT;
745 }
746 }
747