Database
Dokumentacja jest stale rozwijana i aktualizowana wraz z postępem projektu. Ponieważ powstaje ona równolegle z kodem, niektóre sekcje mogą tymczasowo odnosić się do wcześniejszych wersji systemu - są one sukcesywnie dostosowywane do bieżącego stanu aplikacji. Jeśli zauważysz nieaktualne informacje, zgłoś to lub załóż Issue / Pull Request.
Dokumentacja
# Database
Moduł Database dla DbM Framework Obsługa baz danych przy pomocy PDO lub Doctrine DBAL (wymienne, konfigurowalne, transparentne dla aplikacji).
# Moduł został zaprojektowany, aby:
- działał w trybie PDO lub Doctrine,
- był wymienny - kod aplikacji działa tak samo z obydwoma driverami,
- posiadał własny Query Builder dla PDO,
- wspierał w pełni Doctrine QueryBuilder gdy driver = DOCTRINE,
- był łatwo rozbudowywalny i izolowany od reszty systemu.
# Instalacja i konfiguracja
Plik .env - parametry.
# Database driver: 'PDO|pdo_mysql' (default) / pdo_pgsql, opcjonalnie DOCTRINE - requires Composer installation
DB_DRIVER=PDO|pdo_mysql
# Podstawowa konfiguracja bazy
DB_HOST=127.0.0.1
DB_NAME=test
DB_USER=root
DB_PASSWORD=
# Zmiana drivera:
DB_DRIVER=PDO # klasyczny szybki adapter, brak zależności
DB_DRIVER=DOCTRINE # wymaga doctrine/dbal - composer install
# Adaptery PDO i Doctrine
PdoDatabaseAdapter
- używa natywnego PDO
- posiada własny Query Builder (PdoQueryBuilder)
- minimalne zależności
- szybki, lekki
# DoctrineDatabaseAdapter
- wykorzystuje Doctrine\DBAL\Connection
- daje dostęp do: QueryBuilder, ExpressionBuilder, platform (MySQL, PostgreSQL itd.), typy danych Doctrine
- pełna zgodność z wersją 4.3
# Przełączenie drivera: DB_DRIVER=PDO / DOCTRINE
Po zmianie .env:
DB_DRIVER=DOCTRINE
Twoje repositories i services działają identycznie - bez zmian w kodzie.
# INFO
Doctrine DBAL wymaga kilku dodatkowych bibliotek. Minimalny zestaw: doctrine/dbal, doctrine/deprecations, doctrine/event-manager
W autoloadzie musiałbyś dodać każdą z nich, dlatego dla Doctrine DBAL zalecamy:
- korzystać z vendor/autoload.php
- nie próbować ręcznie ładować DBAL, bo zależności są rozproszone
Uruchamiane za pomocą polecenia "composer install".
# Query Builder
W zależności od drivera używany jest:
1) PdoQueryBuilder - własna implementacja:
Metody:
buildInsertQuery(array $data, string $table): array
buildUpdateQuery(array $data, string $table, string $where, array $params = []): array
buildDeleteQuery(string $table, string $where, array $params = []): array
2) Doctrine QueryBuilder
Pełny QueryBuilder:
$qb = $database->createQueryBuilder();
$qb->select('u.*')->from('users', 'u')->where('id = :id');
# AbstractRepository - API ujednolicające
namespace Dbm\Database\Repository;
use Dbm\Database\Interfaces\MainDatabaseInterface;
abstract class AbstractRepository
{
protected MainDatabaseInterface $database;
protected string $table;
public function __construct(MainDatabaseInterface $database)
{
$this->database = $database;
}
public function find(int $id): ?object
{
$sql = "SELECT * FROM {$this->table} WHERE id = :id";
$this->database->queryExecute($sql, ['id' => $id]);
return $this->database->fetchObject() ?: null;
}
public function insert(array $data): bool
{
[$sql, $params] = $this->database
->builder()
->buildInsertQuery($data, $this->table);
return $this->database->queryExecute($sql, $params);
}
public function update(array $data, string $where, array $extra = []): bool
{
[$sql, $params] = $this->database
->builder()
->buildUpdateQuery($data, $this->table, $where, $extra);
return $this->database->queryExecute($sql, $params);
}
public function delete(string $where, array $params = []): bool
{
[$sql, $bind] = $this->database
->builder()
->buildDeleteQuery($this->table, $where, $params);
return $this->database->queryExecute($sql, $bind);
}
}
# Przykłady repozytoriów
1) Repozytorium używające wyłącznie adaptera PDO (zalecany styl uniwersalny):
namespace Mod\Account\Repository;
use Dbm\Database\Repository\AbstractRepository;
class AccountRepository extends AbstractRepository
{
protected string $table = 'accounts';
public function getByEmail(string $email): ?object
{
$sql = "SELECT * FROM accounts WHERE email = :email";
$this->database->queryExecute($sql, ['email' => $email]);
return $this->database->fetchObject();
}
public function createAccount(array $data): bool
{
return $this->insert($data);
}
public function updateAccount(int $id, array $data): bool
{
return $this->update($data, "id = :id", ['id' => $id]);
}
}
- działa zarówno z PDO, jak i z Doctrine
- korzysta z ujednoliconego API
2) Przykład z użyciem specjalnych funkcji Doctrine (opcjonalnie)
Ten kod zadziała tylko gdy DB_DRIVER=DOCTRINE:
public function searchAdvanced(string $emailPart): array
{
$qb = $this->database->createQueryBuilder();
$qb->select('a.*')
->from('accounts', 'a')
->where('a.email LIKE :email')
->setParameter('email', '%' . $emailPart . '%')
->orderBy('a.id', 'DESC');
return $this->database->fetchAll(
$qb->getSQL(),
$qb->getParameters()
);
}
3) Przykład update poprzez PdoQueryBuilder
public function updateLastLogin(int $id): bool
{
$data = [
'last_login' => date('Y-m-d H:i:s'),
];
return $this->update(
$data,
'id = :id',
['id' => $id]
);
}
Generuje SQL:
UPDATE accounts SET last_login = :last_login WHERE id = :id
# Kiedy używać którego stylu?
Uniwersalny styl - działa ZAWSZE:
- queryExecute
- fetch / fetchObject
- builder()->buildInsertQuery()
- builder()->buildUpdateQuery()
- builder()->buildDeleteQuery()
Tylko gdy DB_DRIVER = DOCTRINE:
- createQueryBuilder()
- ExpressionBuilder
- zaawansowane platformy / typy Doctrine
# Podsumowanie
Moduł Database oferuje:
- pełną wymienność PDO <=> Doctrine
- pełną kompatybilność repozytoriów
- szybki własny QueryBuilder dla PDO
- możliwość korzystania z potężnego QueryBuildera Doctrine
- bezpieczną abstrakcję poprzez MainDatabaseInterface
- wspólne metody (queryExecute, fetch, fetchObject, fetchAll)