aboutsummaryrefslogtreecommitdiffhomepage
path: root/WpfTest/Model
diff options
context:
space:
mode:
Diffstat (limited to 'WpfTest/Model')
-rw-r--r--WpfTest/Model/Actor.php16
-rw-r--r--WpfTest/Model/ActorEndpoints.php12
-rw-r--r--WpfTest/Model/FetchableModel.php78
-rw-r--r--WpfTest/Model/Note.php22
-rw-r--r--WpfTest/Model/NoteAttachment.php12
-rw-r--r--WpfTest/Model/NotePrivacy.php31
-rw-r--r--WpfTest/Model/NotePrivacyInteractors.php10
-rw-r--r--WpfTest/Model/NotePrivacyScope.php10
8 files changed, 164 insertions, 27 deletions
diff --git a/WpfTest/Model/Actor.php b/WpfTest/Model/Actor.php
index eaef99c..0b0e729 100644
--- a/WpfTest/Model/Actor.php
+++ b/WpfTest/Model/Actor.php
@@ -1,9 +1,9 @@
<?php
namespace WpfTest\Model;
-use WpfTest\Model;
+use WpfTest\RemoteFetchable;
-class Actor extends Model implements \JsonSerializable {
+class Actor extends FetchableModel implements \JsonSerializable {
public ?int $id;
public string $uri;
public bool $isLocal = false;
@@ -20,6 +20,14 @@ class Actor extends Model implements \JsonSerializable {
public ActorEndpoints $endpoints;
public array $extensions = [];
+ protected function getUpdateWhereClause(\PDO $db): ?string {
+ if (self::findWhere('uri = ?', [$this->uri]) != null)
+ return 'uri = ' . $db->quote($this->uri);
+ if (self::findWhere('id = ?', [$this->id]) != null)
+ return "id = $this->id";
+ return null;
+ }
+
public static function findLocalByHandle(string $handle): ?self {
return self::findWhere('is_local = true AND handle = ?', [$handle]);
}
@@ -42,4 +50,8 @@ class Actor extends Model implements \JsonSerializable {
]
];
}
+
+ public function hydrate() {
+ $this->endpoints = ActorEndpoints::findWhere('actor_id = ?', [$this->id]);
+ }
} \ No newline at end of file
diff --git a/WpfTest/Model/ActorEndpoints.php b/WpfTest/Model/ActorEndpoints.php
index 03dab9e..f6120d3 100644
--- a/WpfTest/Model/ActorEndpoints.php
+++ b/WpfTest/Model/ActorEndpoints.php
@@ -4,6 +4,7 @@ namespace WpfTest\Model;
use WpfTest\Model;
class ActorEndpoints extends Model {
+ public ?int $actorId;
public string $basicFeed;
public ?string $fullFeed;
public ?string $follow;
@@ -12,4 +13,15 @@ class ActorEndpoints extends Model {
public ?string $unblock;
public ?string $subscribe;
public ?string $unsubscribe;
+
+ protected function setOwnerId(int $id) {
+ $this->actorId = $id;
+ }
+
+ protected function getUpdateWhereClause($db): ?string {
+ if (self::findWhere('actor_id = ?', [$this->actorId]) != null) {
+ return "actor_id = $this->actorId";
+ }
+ return null;
+ }
} \ No newline at end of file
diff --git a/WpfTest/Model/FetchableModel.php b/WpfTest/Model/FetchableModel.php
new file mode 100644
index 0000000..44106d4
--- /dev/null
+++ b/WpfTest/Model/FetchableModel.php
@@ -0,0 +1,78 @@
+<?php
+namespace WpfTest\Model;
+
+use WpfTest\Model;
+use WpfTest\RemoteFetchable;
+
+abstract class FetchableModel extends Model implements RemoteFetchable {
+ private static \JsonMapper $mapper;
+
+ public static function __initStatic() {
+ self::$mapper = new \JsonMapper();
+ // this is unfortunately necessary to parse DateTime(Immutable)s properly
+ self::$mapper->bStrictObjectTypeChecking = false;
+ }
+
+ private static function fetchFromRemote(string $uri, bool $autoSave): ?static {
+ // fetch the object
+ $data = @file_get_contents($uri, context: stream_context_create(['http' => [
+ 'header' => 'Accept: application/json'
+ ]]));
+ if ($data === false)
+ return null;
+ $data = json_decode($data);
+ if ($data === false)
+ return null;
+ // default everything nullable to null
+ $obj = new static();
+ $reflProps = (new \ReflectionClass(static::class))->getProperties();
+ foreach ($reflProps as $reflProp) {
+ assert($reflProp instanceof \ReflectionProperty); // for intellisense lmao
+ if ($reflProp->getType()->allowsNull()) {
+ $obj->{$reflProp->getName()} = null;
+ }
+ }
+ // rename 'self' to 'uri' because of reasons
+ if (property_exists($data, 'self')) {
+ $data->uri = $data->self;
+ unset($data->self);
+ }
+ // map all present fields
+ self::$mapper->map($data, $obj);
+ // (hopefully) recursively fetch any other fetchable models contained in this one
+ foreach ($reflProps as $reflProp) {
+ assert($reflProp instanceof \ReflectionProperty);
+ $reflType = $reflProp->getType();
+ $propName = $reflProp->getName();
+ if (!($reflType instanceof \ReflectionNamedType))
+ continue;
+ $type = $reflType->getName();
+ if (is_subclass_of($type, FetchableModel::class) && is_string($data->{$propName})) {
+ // try to avoid recursion
+ // TODO: make a better effort at avoiding recursion (e.g. when it's more than one step nested)
+ if ($data->{$propName} == $uri) {
+ $obj->{$propName} = $obj;
+ } else {
+ $obj->{$propName} = $type::findByUri($data->{$propName}, $autoSave);
+ }
+ }
+ }
+
+ if ($autoSave) {
+ $obj->save();
+ }
+
+ return $obj;
+ }
+
+ public static function findByUri(string $uri, bool $autoSave = true, bool $forceRefetch = false): ?static {
+ if (!$forceRefetch) {
+ $obj = static::findWhere('uri = ?', [$uri]);
+ if ($obj != null)
+ return $obj;
+ }
+ return static::fetchFromRemote($uri, $autoSave);
+ }
+}
+
+FetchableModel::__initStatic(); \ No newline at end of file
diff --git a/WpfTest/Model/Note.php b/WpfTest/Model/Note.php
index 85b3567..af2d2aa 100644
--- a/WpfTest/Model/Note.php
+++ b/WpfTest/Model/Note.php
@@ -2,9 +2,8 @@
namespace WpfTest\Model;
use WpfTest\Db;
-use WpfTest\Model;
-class Note extends Model implements \JsonSerializable {
+class Note extends FetchableModel implements \JsonSerializable {
public ?int $id;
public string $uri;
public \DateTimeImmutable $created;
@@ -30,7 +29,15 @@ class Note extends Model implements \JsonSerializable {
public array $attachments = [];
public array $extensions = [];
- protected function hydrate(array $row) {
+ protected function getUpdateWhereClause(\PDO $db): ?string {
+ if (self::findWhere('uri = ?', [$this->uri]) != null)
+ return 'uri = ' . $db->quote($this->uri);
+ if (self::findWhere('id = ?', [$this->id]) != null)
+ return "id = $this->id";
+ return null;
+ }
+
+ protected function hydrate() {
$this->privacy = NotePrivacy::findWhere('note_id = ?', [$this->id]);
$this->formattedContent = $this->findFormattedContents();
$this->mentions = $this->findMentions();
@@ -74,14 +81,7 @@ class Note extends Model implements \JsonSerializable {
}, $this->mentions),
'inReplyTo' => $this->inReplyTo?->uri,
'threadApex' => $this->threadApex?->uri,
- 'privacy' => [
- 'scope' => $this->privacy->scope->name,
- 'alsoVisibleTo' => $this->privacy->alsoVisibleTo,
- 'indexable' => $this->privacy->indexable,
- 'canReshare' => $this->privacy->canReshare->name,
- 'canReply' => $this->privacy->canReply->name,
- 'canOtherInteract' => $this->privacy->canOtherInteract->name
- ],
+ 'privacy' => $this->privacy,
'attachments' => array_map(function (NoteAttachment $attachment) {
return [
'type' => $attachment->type,
diff --git a/WpfTest/Model/NoteAttachment.php b/WpfTest/Model/NoteAttachment.php
index b07d595..16947c5 100644
--- a/WpfTest/Model/NoteAttachment.php
+++ b/WpfTest/Model/NoteAttachment.php
@@ -4,8 +4,20 @@ namespace WpfTest\Model;
use WpfTest\Model;
class NoteAttachment extends Model {
+ public ?int $noteId;
public int $index;
public string $type;
public string $href;
public ?string $description;
+
+ protected function setOwnerId(int $id) {
+ $this->noteId = $id;
+ }
+
+ protected function getUpdateWhereClause($db): ?string {
+ if (self::findWhere('note_id = ?', [$this->noteId]) != null) {
+ return "note_id = $this->noteId";
+ }
+ return null;
+ }
} \ No newline at end of file
diff --git a/WpfTest/Model/NotePrivacy.php b/WpfTest/Model/NotePrivacy.php
index b7ed58a..b955447 100644
--- a/WpfTest/Model/NotePrivacy.php
+++ b/WpfTest/Model/NotePrivacy.php
@@ -3,14 +3,37 @@ namespace WpfTest\Model;
use WpfTest\Model;
-class NotePrivacy extends Model {
+class NotePrivacy extends Model implements \JsonSerializable {
+ public ?int $noteId;
public NotePrivacyScope $scope;
/**
* @var Actor[]
*/
public array $alsoVisibleTo = [];
public bool $indexable;
- public NotePrivacyInteractors $canReshare = NotePrivacyInteractors::all;
- public NotePrivacyInteractors $canReply = NotePrivacyInteractors::all;
- public NotePrivacyInteractors $canOtherInteract = NotePrivacyInteractors::all;
+ public NotePrivacyInteractors $canReshare = NotePrivacyInteractors::ALL;
+ public NotePrivacyInteractors $canReply = NotePrivacyInteractors::ALL;
+ public NotePrivacyInteractors $canOtherInteract = NotePrivacyInteractors::ALL;
+
+ protected function setOwnerId(int $id) {
+ $this->noteId = $id;
+ }
+
+ protected function getUpdateWhereClause($db): ?string {
+ if (self::findWhere('note_id = ?', [$this->noteId]) != null) {
+ return "note_id = $this->noteId";
+ }
+ return null;
+ }
+
+ public function jsonSerialize(): array {
+ return [
+ 'scope' => $this->scope->value,
+ 'alsoVisibleTo' => $this->alsoVisibleTo,
+ 'indexable' => $this->indexable,
+ 'canReshare' => $this->canReshare->value,
+ 'canReply' => $this->canReply->value,
+ 'canOtherInteract' => $this->canOtherInteract->value
+ ];
+ }
} \ No newline at end of file
diff --git a/WpfTest/Model/NotePrivacyInteractors.php b/WpfTest/Model/NotePrivacyInteractors.php
index ff4d7fa..917d90a 100644
--- a/WpfTest/Model/NotePrivacyInteractors.php
+++ b/WpfTest/Model/NotePrivacyInteractors.php
@@ -1,9 +1,9 @@
<?php
namespace WpfTest\Model;
-enum NotePrivacyInteractors {
- case all;
- case followers;
- case mutuals;
- case none;
+enum NotePrivacyInteractors: string {
+ case ALL = 'all';
+ case FOLLOWERS = 'followers';
+ case MUTUALS = 'mutuals';
+ case NONE = 'none';
} \ No newline at end of file
diff --git a/WpfTest/Model/NotePrivacyScope.php b/WpfTest/Model/NotePrivacyScope.php
index 3134c26..44c9344 100644
--- a/WpfTest/Model/NotePrivacyScope.php
+++ b/WpfTest/Model/NotePrivacyScope.php
@@ -1,9 +1,9 @@
<?php
namespace WpfTest\Model;
-enum NotePrivacyScope {
- case public;
- case followers;
- case mutuals;
- case none;
+enum NotePrivacyScope: string {
+ case PUBLIC = 'public';
+ case FOLLOWERS = 'followers';
+ case MUTUALS = 'mutuals';
+ case NONE = 'none';
} \ No newline at end of file