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
$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 (
id INTEGER PRIMARY KEY,
target TEXT NOT NULL,
source TEXT NOT NULL,
type TEXT NOT NULL,
content TEXT,
author INTEGER
author INTEGER,
FOREIGN KEY(author) REFERENCES authors(id)
);
SQL;
@ -36,7 +45,22 @@ class SqliteGateway extends WebmentionGatewayInterface
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->execute(["id" => $id]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
@ -49,7 +73,7 @@ class SqliteGateway extends WebmentionGatewayInterface
$row["source"],
MentionType::from($row["type"]),
$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
{
$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->execute(["post" => $post]);
@ -81,8 +119,10 @@ class SqliteGateway extends WebmentionGatewayInterface
public function save(Webmention $webmention): ?int
{
$author = $this->saveAuthor($webmention->author);
$sql = <<< SQL
INSERT INTO webmentions
REPLACE INTO webmentions
(id, target, source, type, content, author)
VALUES
(:id, :target, :source, :type, :content, :author);
@ -95,13 +135,65 @@ class SqliteGateway extends WebmentionGatewayInterface
"source" => $webmention->source,
"type" => $webmention->type->toString(),
"content" => $webmention->content,
"author" => $webmention->author->id,
"author" => $author,
]);
$statement->closeCursor();
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
{
$sql = "DELETE FROM webmentions WHERE id=:id;";
@ -116,7 +208,18 @@ class SqliteGateway extends WebmentionGatewayInterface
return "$v=:$v";
}, array_keys($values)));
$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}
SQL;

View File

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

View File

@ -43,7 +43,7 @@ class SqliteGatewayTest extends TestCase
"https://a-source.url",
MentionType::Like,
"No content",
new \Lewisdale\Webmentions\Models\Author(),
new \Lewisdale\Webmentions\Models\Author(null, null, null, null),
);
$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);
}
}