Store authors alongside webmentions

This commit is contained in:
Lewis Dale 2023-03-16 09:34:57 +00:00
parent 3cafc5238e
commit 51f1269600
4 changed files with 210 additions and 19 deletions

View File

@ -21,13 +21,22 @@ class SqliteGateway extends WebmentionGatewayInterface
{ {
// Create Webmention table // Create Webmention table
$sql = <<<SQL $sql = <<<SQL
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS authors (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
url TEXT,
photo TEXT,
UNIQUE(name, url)
);
CREATE TABLE IF NOT EXISTS webmentions ( CREATE TABLE IF NOT EXISTS webmentions (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
target TEXT NOT NULL, target TEXT NOT NULL,
source TEXT NOT NULL, source TEXT NOT NULL,
type TEXT NOT NULL, type TEXT NOT NULL,
content TEXT, content TEXT,
author INTEGER author INTEGER,
FOREIGN KEY(author) REFERENCES authors(id)
); );
SQL; SQL;
@ -36,7 +45,22 @@ class SqliteGateway extends WebmentionGatewayInterface
public function get(int $id): ?Webmention public function get(int $id): ?Webmention
{ {
$sql = "SELECT * FROM webmentions WHERE id=:id LIMIT 1;"; $sql = <<<SQL
SELECT webmentions.id as id,
webmentions.source as source,
webmentions.target as target,
webmentions.type as type,
webmentions.content as content,
authors.id as author,
authors.name as author_name,
authors.url as author_url,
authors.photo as author_photo
FROM webmentions
LEFT JOIN
authors ON webmentions.author=authors.id
WHERE webmentions.id=:id
LIMIT 1;
SQL;
$statement = $this->connection->prepare($sql); $statement = $this->connection->prepare($sql);
$statement->execute(["id" => $id]); $statement->execute(["id" => $id]);
$row = $statement->fetch(PDO::FETCH_ASSOC); $row = $statement->fetch(PDO::FETCH_ASSOC);
@ -49,7 +73,7 @@ class SqliteGateway extends WebmentionGatewayInterface
$row["source"], $row["source"],
MentionType::from($row["type"]), MentionType::from($row["type"]),
$row["content"], $row["content"],
new Author((int)$row["author"]) new Author((int)$row["author"], $row["author_name"], $row["author_url"], $row["author_photo"])
); );
} }
@ -58,7 +82,21 @@ class SqliteGateway extends WebmentionGatewayInterface
public function getByPost(string $post): array public function getByPost(string $post): array
{ {
$sql = "SELECT * FROM webmentions WHERE target=:post"; $sql = <<<SQL
SELECT webmentions.id as id,
webmentions.source as source,
webmentions.target as target,
webmentions.type as type,
webmentions.content as content,
authors.id as author,
authors.name as author_name,
authors.url as author_url,
authors.photo as author_photo
FROM webmentions
LEFT JOIN
authors ON webmentions.author=authors.id
WHERE target=:post;
SQL;
$statement = $this->connection->prepare($sql); $statement = $this->connection->prepare($sql);
$statement->execute(["post" => $post]); $statement->execute(["post" => $post]);
@ -81,8 +119,10 @@ class SqliteGateway extends WebmentionGatewayInterface
public function save(Webmention $webmention): ?int public function save(Webmention $webmention): ?int
{ {
$author = $this->saveAuthor($webmention->author);
$sql = <<< SQL $sql = <<< SQL
INSERT INTO webmentions REPLACE INTO webmentions
(id, target, source, type, content, author) (id, target, source, type, content, author)
VALUES VALUES
(:id, :target, :source, :type, :content, :author); (:id, :target, :source, :type, :content, :author);
@ -95,13 +135,65 @@ class SqliteGateway extends WebmentionGatewayInterface
"source" => $webmention->source, "source" => $webmention->source,
"type" => $webmention->type->toString(), "type" => $webmention->type->toString(),
"content" => $webmention->content, "content" => $webmention->content,
"author" => $webmention->author->id, "author" => $author,
]); ]);
$statement->closeCursor(); $statement->closeCursor();
return $success ? (int)$this->connection->lastInsertId() : null; return $success ? (int)$this->connection->lastInsertId() : null;
} }
protected function saveAuthor(Author $author): ?int
{
if (!$author->name || !$author->url) {
return null;
}
$sql = <<< SQL
INSERT OR IGNORE INTO authors
(id, name, url, photo)
VALUES
(:id, :name, :url, :photo);
SQL;
$statement = $this->connection->prepare($sql);
$success = $statement->execute([
"id" => $author->id,
"name" => $author->name,
"url" => $author->url,
"photo" => $author->photo,
]);
$statement->closeCursor();
return $this->findAuthor($author->name, $author->url)?->id;
}
protected function findAuthor(string $name, string $url): ?Author
{
$sql = "SELECT id, name, url, photo FROM authors WHERE url=:url AND name=:name";
$statement = $this->connection->prepare($sql);
$success = $statement->execute([
"url" => $url,
"name" => $name,
]);
if (!$success) {
return null;
}
$row = $statement->fetch(PDO::FETCH_ASSOC);
$statement->closeCursor();
return $row ? new Author(
(int)$row['id'],
$row['name'],
$row['url'],
$row['photo']
) : null;
}
public function delete(Webmention $webmention): void public function delete(Webmention $webmention): void
{ {
$sql = "DELETE FROM webmentions WHERE id=:id;"; $sql = "DELETE FROM webmentions WHERE id=:id;";
@ -116,7 +208,18 @@ class SqliteGateway extends WebmentionGatewayInterface
return "$v=:$v"; return "$v=:$v";
}, array_keys($values))); }, array_keys($values)));
$sql = <<<SQL $sql = <<<SQL
SELECT * FROM webmentions SELECT webmentions.id as id,
webmentions.source as source,
webmentions.target as target,
webmentions.type as type,
webmentions.content as content,
authors.id as author,
authors.name as author_name,
authors.url as author_url,
authors.photo as author_photo
FROM webmentions
LEFT JOIN
authors ON webmentions.author=authors.id
WHERE {$keys} WHERE {$keys}
SQL; SQL;

View File

@ -4,13 +4,17 @@ namespace Lewisdale\Webmentions\Gateways;
use Lewisdale\Webmentions\Models\Webmention; use Lewisdale\Webmentions\Models\Webmention;
abstract class WebmentionGatewayInterface { abstract class WebmentionGatewayInterface
{
abstract protected function up(): void; abstract protected function up(): void;
abstract public function getByPost(string $post): array; abstract public function getByPost(string $post): array;
abstract public function save(Webmention $webmention): ?int; abstract public function save(Webmention $webmention): ?int;
abstract public function delete(Webmention $webmention): void; abstract public function delete(Webmention $webmention): void;
abstract public function get(int $id): ?Webmention; abstract public function get(int $id): ?Webmention;
abstract public function find(array $values): array; abstract public function find(array $values): array;
} }
?>

View File

@ -20,5 +20,3 @@ class Webmention
return "Webmention (id: {$this->id}, target: {$this->target}, source: {$this->source}, content: {$this->content}, author: {$this->author->name})"; return "Webmention (id: {$this->id}, target: {$this->target}, source: {$this->source}, content: {$this->content}, author: {$this->author->name})";
} }
} }
?>

View File

@ -43,7 +43,7 @@ class SqliteGatewayTest extends TestCase
"https://a-source.url", "https://a-source.url",
MentionType::Like, MentionType::Like,
"No content", "No content",
new \Lewisdale\Webmentions\Models\Author(), new \Lewisdale\Webmentions\Models\Author(null, null, null, null),
); );
$webmention->id = $this->gateway->save($webmention); $webmention->id = $this->gateway->save($webmention);
@ -155,4 +155,90 @@ class SqliteGatewayTest extends TestCase
]) ])
); );
} }
public function testItSavesAnAuthorWithTheWebmention()
{
$webmention = new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Like,
"Liked this post",
new \Lewisdale\Webmentions\Models\Author(
null,
"Doreen Mifah",
"https://my-homepage.com",
"https://cdn.imgserver.com/400/400"
)
);
$webmention->id = $this->gateway->save($webmention);
$retrieved = $this->gateway->get($webmention->id)?->author;
$expected = $webmention->author;
$this->assertEquals($expected->name, $retrieved?->name);
$this->assertEquals($expected->url, $retrieved?->url);
$this->assertEquals($expected->photo, $retrieved?->photo);
}
public function testItLooksUpWebmentionsByAuthorName()
{
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Like,
"Liked this post",
new \Lewisdale\Webmentions\Models\Author(
null,
"Doreen Mifah",
"https://my-homepage.com",
"https://cdn.imgserver.com/400/400"
)
));
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Like,
"Liked this post",
new \Lewisdale\Webmentions\Models\Author(
null,
"Carl Weathers",
"https://carl-weathers.com",
"https://cdn.imgserver.com/400/400"
)
));
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Like,
"Liked this post",
new \Lewisdale\Webmentions\Models\Author(
null,
"Barry White",
"https://barry.white.com",
"https://cdn.imgserver.com/400/400"
)
));
$this->gateway->save(new Webmention(
null,
"https://a-target-url.com",
"https://a-source-url.com",
MentionType::Reply,
"This was a cool post!",
new \Lewisdale\Webmentions\Models\Author(
null,
"Carl Weathers",
"https://carl-weathers.com",
"https://cdn.imgserver.com/400/400"
)
));
$retrieved = $this->gateway->find(["author_name" => "Carl Weathers"]);
$this->assertCount(2, $retrieved);
}
} }