first commit
This commit is contained in:
142
README.md
Normal file
142
README.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Database (PocketMine-MP)
|
||||
|
||||
Плагин для PMMP 5.36+ с поддержкой PostgreSQL/MySQL через PDO, пулом соединений, миграциями, ORM на атрибутах и кэшем сущностей.
|
||||
|
||||
## Требования
|
||||
- PHP 8.1+ (как у PMMP 5.x).
|
||||
- Расширения: `pdo` + `pdo_pgsql` (PostgreSQL) или `pdo_mysql` (MySQL). Проверяется при запуске.
|
||||
|
||||
## Установка
|
||||
1. Соберите плагин (zip папку `pmmp/Database` или сборка через DevTools).
|
||||
2. Поместите архив/папку в `plugins/`.
|
||||
3. Запустите сервер один раз для генерации `config.yml`.
|
||||
4. Заполните `config.yml`, перезапустите сервер.
|
||||
|
||||
## Конфигурация (`config.yml`)
|
||||
```yaml
|
||||
driver: "postgres" # postgres | mysql
|
||||
host: "127.0.0.1"
|
||||
port: 5432 # 3306 для mysql по умолчанию
|
||||
database: "server"
|
||||
username: "postgres"
|
||||
password: ""
|
||||
options:
|
||||
persistent: false # persistent соединения PDO
|
||||
timeoutSeconds: 10
|
||||
pool:
|
||||
size: 4 # размер пула PDO
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
writeBehind: true
|
||||
flushIntervalSeconds: 10
|
||||
maxDirty: 100
|
||||
ttlSeconds: 0
|
||||
maxEntries: 0
|
||||
preloadBatchSize: 20
|
||||
preloadDelayTicks: 20
|
||||
preloadAsync: true
|
||||
|
||||
migrations:
|
||||
enabled: true
|
||||
table: "db_migrations"
|
||||
```
|
||||
|
||||
## Быстрый старт
|
||||
```php
|
||||
use andrewkydev\Database\DatabaseProvider;
|
||||
use andrewkydev\Database\ORM\Attributes as ORM;
|
||||
use andrewkydev\Database\ORM\Conditions;
|
||||
|
||||
$db = DatabaseProvider::get();
|
||||
|
||||
// Raw SQL
|
||||
$db->query()->execute("UPDATE players SET level = level + 1 WHERE username = ?", ["Steve"]);
|
||||
|
||||
// ORM-модель
|
||||
#[ORM\Entity(table: "players")]
|
||||
final class Player {
|
||||
#[ORM\Id(autoIncrement: true)]
|
||||
#[ORM\Column(name: "id")]
|
||||
public int $id;
|
||||
|
||||
#[ORM\Column(unique: true, length: 32)]
|
||||
#[andrewkydev\Database\ORM\Attributes\CacheKey]
|
||||
public string $username;
|
||||
|
||||
#[ORM\Column]
|
||||
public int $level;
|
||||
}
|
||||
|
||||
$orm = $db->orm();
|
||||
$orm->enableCache(Player::class, preload: true);
|
||||
|
||||
$player = $orm->findOneWhere(Player::class, "username = ?", ["Steve"]);
|
||||
$top = $orm->query(Player::class)
|
||||
->where(Conditions::gt("level", 10))
|
||||
->orderBy("level DESC")
|
||||
->limit(10)
|
||||
->list();
|
||||
```
|
||||
|
||||
## Компоненты API
|
||||
- `DatabaseApi` (через `DatabaseProvider::get()`):
|
||||
- `config()` — текущий `DatabaseConfig`.
|
||||
- `schema()` — `SchemaManager` (DDL: create/drop db/table, колонки, индексы).
|
||||
- `query()` — `QueryRunner` (сырой SQL sync/async).
|
||||
- `orm()` — `EntityManager` (ORM, кэш, QueryBuilder).
|
||||
- `migrations()` — `MigrationManager`.
|
||||
|
||||
### Сырые запросы (`QueryRunner`)
|
||||
- `execute($sql, $params=[])` — `rowCount()`.
|
||||
- `query($sql, $params=[], $mapper=null)` — массив строк или маппер.
|
||||
- `executeAsync/queryAsync($sql, $params, $onSuccess, $onError=null)` — выполняется в async-пуле PMMP, создаёт отдельный PDO.
|
||||
|
||||
### ORM и атрибуты
|
||||
- Основные атрибуты: `Entity`, `Id(autoIncrement)`, `Column(name, nullable, length, unique, type)`, `Json`, `CacheKey`, `Transient`.
|
||||
- Связи: `OneToOne`, `ManyToOne`, `OneToMany`, `ManyToMany` (`target`, `mappedBy`, `joinColumn`, `referencedColumn`, `joinTable`, `inverseJoinColumn`, `cascadePersist/remove`, `lazy`).
|
||||
- Ленивая загрузка свойств: `LazyRelationsTrait`.
|
||||
|
||||
### Операции ORM (`EntityManager`)
|
||||
- CRUD: `insert/update/delete/save` + async аналоги.
|
||||
- Поиск: `findById/findAll/findOneWhere/findWhere/count/exists/deleteWhere` (+ async).
|
||||
- Построитель: `query(Class)::QueryBuilder` (select/where/and/or/group/having/order/limit, `joinFetch` для manyToOne/oneToOne, `withRelations` для загрузки связей, async `listAsync/oneAsync/countAsync/existsAsync/deleteAsync`).
|
||||
- Загрузка связей: `loadRelation(s)` и батч `loadRelationsFor`.
|
||||
|
||||
### Условия (`Conditions`)
|
||||
`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `like`, `in`, `isNull`, `isNotNull`, `raw`. Комбинации через `Condition->and()/or()`.
|
||||
|
||||
### Кэш сущностей
|
||||
- Включается `cache.enabled`.
|
||||
- Регистрация: `$orm->enableCache(Model::class, ['id','username'], preload: true);`
|
||||
- Ключи по умолчанию: Id, поля с `CacheKey`, уникальные колонки.
|
||||
- `writeBehind=true`: `update/delete` складываются в очередь (`CacheManager`) и сбрасываются периодически (`CacheFlushTask`) или при достижении `maxDirty`.
|
||||
- `ttlSeconds` и `maxEntries` контролируют размер/старение. Прогрев — `CachePreloadTask`/`CachePreloadAsyncTask`.
|
||||
|
||||
### Миграции
|
||||
- Интерфейс `Migration { version(): int; up(SchemaManager $schema, QueryRunner $query): void; }`
|
||||
- Регистрация: `$db->migrations()->register(new class implements Migration {...});`
|
||||
- Запуск: `$db->migrations()->runPending();` (создаёт таблицу `migrations.table` при необходимости).
|
||||
- Генерация схемы по модели: `OrmSchema::fromEntity(Model::class, SqlDialect::POSTGRES|MYSQL)` → `SchemaManager::createTable(...)`.
|
||||
|
||||
### DDL (`SchemaManager`)
|
||||
- `createDatabase/dropDatabase`
|
||||
- `createTable(TableSpec)`, `dropTable`
|
||||
- `addColumn/updateColumn/dropColumn`
|
||||
- `addIndex/dropIndex` (учитывает синтаксис Postgres/MySQL).
|
||||
|
||||
## Асинхронность
|
||||
- Все async методы используют `Server::getInstance()->getAsyncPool()` и собственный PDO, не блокируя main thread.
|
||||
- Колбэки: `onSuccess($rows|$entity|$count)` и опциональный `onError($message)`.
|
||||
|
||||
## Практические советы
|
||||
- Всегда задавайте `#[Id]` и уникальные поля — это улучшает кэш и генерацию схемы.
|
||||
- Для критичных данных можно отключить `writeBehind`, чтобы обновления уходили сразу.
|
||||
- `joinFetch` используйте для `manyToOne/oneToOne`, а большие коллекции грузите через `withRelations` или отдельные запросы.
|
||||
- Postgres: автоинкремент переводится в `SERIAL/BIGSERIAL`; MySQL — `AUTO_INCREMENT`.
|
||||
|
||||
## Отладка и проблемы
|
||||
- Ошибка о расширениях — установите/включите `pdo`, `pdo_pgsql` или `pdo_mysql`.
|
||||
- `DatabaseApi is not initialized` — плагин ещё не загрузился; обращайтесь к `DatabaseProvider::get()` после `onEnable`.
|
||||
- Пустой пул — проверьте доступ к БД и креды в конфиге.
|
||||
|
||||
Reference in New Issue
Block a user