gnu-social/docs/developer/src/database.md

109 lines
88 KiB
Markdown
Raw Normal View History

2021-07-31 01:46:54 +01:00
Database
========
GNU social has to store a large collection of data for
rapid search and retrieval.
GNU social can use different Relational Database
Management Systems, namely PostgreSQL and MariaDB.
The storage is interfaced using an [Object-Relational
Mapper (ORM)](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping)
paradigm.
As the term ORM already hints at, this allows to
simplify the translation between database rows and the
PHP object model.
[_images/mapping_single_entity.png]: data:image/png;base64,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
Transactions
------------
An _EntityManager_ and the underlying _UnitOfWork_
employ a strategy called [transactional write-behind](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/architecture.html#transactional-write-behind)
that delays the execution of SQL statements in order to
execute them in the most efficient way and at the end
of a transaction so that all write locks are quickly
released. You should see Doctrine as a tool to
synchronize your in-memory objects with the database
in well defined [units of work](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/architecture.html#the-unit-of-work).
Work with your objects and modify them as usual. For
the most part, Doctrine ORM already takes care of proper [transaction demarcation](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/transactions-and-concurrency.html#transaction-demarcation)
for you: All the write operations (INSERT/UPDATE/DELETE)
are queued until `EntityManager#flush()` is invoked which
2021-07-31 01:46:54 +01:00
wraps all of these changes in a single transaction.
Declaring an Entity
-------------------
```php
<?php
namespace Plugin\Embed\Entity;
use App\Core\Entity;
use DateTimeInterface;
class AttachmentEmbed extends Entity
{
// These tags are meant to be literally included and will be populated with the appropriate fields, setters and getters by `bin/generate_entity_fields`
// {{{ Autocode
// }}} Autocode
2021-07-31 01:46:54 +01:00
public static function schemaDef()
{
return [
'name' => 'attachment_embed',
'fields' => [
'attachment_id' => ['type' => 'int', 'not null' => true, 'foreign key' => true, 'target' => 'Attachment.id', 'multiplicity' => 'one to one', 'description' => 'Embed for that URL/file'],
2021-07-31 01:46:54 +01:00
'mimetype' => ['type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'],
'filename' => ['type' => 'varchar', 'length' => 191, 'description' => 'file name of resource when available'],
'media_url' => ['type' => 'text', 'description' => 'URL for this Embed resource when applicable (photo, link)'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'],
],
'primary key' => ['attachment_id'],
];
}
}
```
Retrieving an entity
--------------------
```php
use App\Core\DB\DB;
use App\Util\Exception\NotFoundException;
use App\Util\Exception\DuplicateFoundException;
/// ...
try {
$object = DB::findOneBy('attachment_embed', ['attachment_id' => $attachment->getId()]);
} catch (NotFoundException) {
// Not found
} catch (DuplicateFoundException) {
// Integrety compromised
2021-07-31 01:46:54 +01:00
}
2021-07-31 01:46:54 +01:00
```
Deleting an Entity
------------------
```php
DB::delete($object);
2021-07-31 01:46:54 +01:00
```
Creating an Entity
-----------------
```php
$embed_data['attachment_id'] = $attachment->getId();
DB::persist(Entity\AttachmentEmbed::create($embed_data));
DB::flush();
```
Querying the database --------------------- When the ORM isn't
powerful enough to satisfy your needs, you can resort to
[Doctrine Query Language](https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/dql-doctrine-query-language.html),
which is preferred and has been extended so you can use table names
rather than class names, or
[Doctrine QueryBuilder](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/query-builder.html#the-querybuilder).