276 lines
6.1 KiB
PHP
276 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace Framework\Database;
|
|
|
|
use Pagerfanta\Pagerfanta;
|
|
use Traversable;
|
|
|
|
class Query implements \IteratorAggregate
|
|
{
|
|
|
|
private $select;
|
|
|
|
private $from;
|
|
|
|
private $where = [];
|
|
|
|
private $entity;
|
|
|
|
private $order = [];
|
|
|
|
private $limit;
|
|
|
|
private $joins;
|
|
|
|
private $pdo;
|
|
|
|
private $params = [];
|
|
|
|
public function __construct(?\PDO $pdo = null)
|
|
{
|
|
$this->pdo = $pdo;
|
|
}
|
|
|
|
/**
|
|
* Definit le FROM
|
|
* @param string $table
|
|
* @param null|string $alias
|
|
* @return Query
|
|
*/
|
|
public function from(string $table, ?string $alias = null): self
|
|
{
|
|
if ($alias) {
|
|
$this->from[$table] = $alias;
|
|
} else {
|
|
$this->from[] = $table;
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Spécifie les champs à récupérer
|
|
* @param string[] ...$fields
|
|
* @return Query
|
|
*/
|
|
public function select(string ...$fields): self
|
|
{
|
|
$this->select = $fields;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Spécifie la limite
|
|
* @param int $length
|
|
* @param int $offset
|
|
* @return Query
|
|
*/
|
|
public function limit(int $length, int $offset = 0): self
|
|
{
|
|
$this->limit = "$offset, $length";
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Spécifie l'ordre de récupération
|
|
* @param string $order
|
|
* @return Query
|
|
*/
|
|
public function order(string $order): self
|
|
{
|
|
$this->order[] = $order;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Ajoute une liaison
|
|
* @param string $table
|
|
* @param string $condition
|
|
* @param string $type
|
|
* @return Query
|
|
*/
|
|
public function join(string $table, string $condition, string $type = "left"): self
|
|
{
|
|
$this->joins[$type][] = [$table, $condition];
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Définit la condition de récupération
|
|
* @param string[] ...$condition
|
|
* @return Query
|
|
*/
|
|
public function where(string ...$condition): self
|
|
{
|
|
$this->where = array_merge($this->where, $condition);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Execute un COUNT() et renvoie la colonne
|
|
* @return int
|
|
*/
|
|
public function count(): int
|
|
{
|
|
$query = clone $this;
|
|
$table = current($this->from);
|
|
return $query->select("COUNT($table.id)")->execute()->fetchColumn();
|
|
}
|
|
|
|
/**
|
|
* Définit les paramètre pour la requête
|
|
* @param array $params
|
|
* @return Query
|
|
*/
|
|
public function params(array $params): self
|
|
{
|
|
$this->params = array_merge($this->params, $params);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Spécifie l'entité à utiliser
|
|
* @param string $entity
|
|
* @return Query
|
|
*/
|
|
public function into(string $entity): self
|
|
{
|
|
$this->entity = $entity;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Récupère un résultat
|
|
*/
|
|
public function fetch()
|
|
{
|
|
$record = $this->execute()->fetch(\PDO::FETCH_ASSOC);
|
|
if ($record === false) {
|
|
return false;
|
|
}
|
|
if ($this->entity) {
|
|
return Hydrator::hydrate($record, $this->entity);
|
|
}
|
|
return $record;
|
|
}
|
|
|
|
/**
|
|
* Récupère un résultat
|
|
* @param int $columnNumber
|
|
* @return mixed
|
|
*/
|
|
public function fetchColumn(int $columnNumber = 0)
|
|
{
|
|
return $this->execute()->fetchColumn($columnNumber);
|
|
}
|
|
|
|
/**
|
|
* Retournera un résultat ou renvoie une exception
|
|
* @return bool|mixed
|
|
* @throws NoRecordException
|
|
*/
|
|
public function fetchOrFail()
|
|
{
|
|
$record = $this->fetch();
|
|
if ($record === false) {
|
|
// throw new NoRecordException();
|
|
}
|
|
return $record;
|
|
}
|
|
|
|
/**
|
|
* Lance la requête
|
|
* @return QueryResult
|
|
*/
|
|
public function fetchAll(): QueryResult
|
|
{
|
|
return new QueryResult(
|
|
$this->execute()->fetchAll(\PDO::FETCH_ASSOC),
|
|
$this->entity
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Pagine les résultats
|
|
* @param int $perPage
|
|
* @param int $currentPage
|
|
* @return Pagerfanta
|
|
*/
|
|
public function paginate(int $perPage, int $currentPage = 1): Pagerfanta
|
|
{
|
|
$paginator = new PaginatedQuery($this);
|
|
return (new Pagerfanta($paginator))->setMaxPerPage($perPage)->setCurrentPage($currentPage);
|
|
}
|
|
|
|
/**
|
|
* Génère la requête SQL
|
|
* @return string
|
|
*/
|
|
public function __toString()
|
|
{
|
|
$parts = ['SELECT'];
|
|
if ($this->select) {
|
|
$parts[] = join(', ', $this->select);
|
|
} else {
|
|
$parts[] = '*';
|
|
}
|
|
$parts[] = 'FROM';
|
|
$parts[] = $this->buildFrom();
|
|
if (!empty($this->joins)) {
|
|
foreach ($this->joins as $type => $joins) {
|
|
foreach ($joins as [$table, $condition]) {
|
|
$parts[] = strtoupper($type) . " JOIN $table ON $condition";
|
|
}
|
|
}
|
|
}
|
|
if (!empty($this->where)) {
|
|
$parts[] = "WHERE";
|
|
$parts[] = "(" . join(') AND (', $this->where) . ')';
|
|
}
|
|
if (!empty($this->order)) {
|
|
$parts[] = 'ORDER BY';
|
|
$parts[] = join(', ', $this->order);
|
|
}
|
|
if ($this->limit) {
|
|
$parts[] = 'LIMIT ' . $this->limit;
|
|
}
|
|
return join(' ', $parts);
|
|
}
|
|
|
|
/**
|
|
* Construit le FROM a as b ....
|
|
* @return string
|
|
*/
|
|
private function buildFrom(): string
|
|
{
|
|
$from = [];
|
|
foreach ($this->from as $key => $value) {
|
|
if (is_string($key)) {
|
|
$from[] = "$key as $value";
|
|
} else {
|
|
$from[] = $value;
|
|
}
|
|
}
|
|
return join(', ', $from);
|
|
}
|
|
|
|
/**
|
|
* Exécute la requête
|
|
* @return \PDOStatement
|
|
*/
|
|
private function execute()
|
|
{
|
|
$query = $this->__toString();
|
|
if (!empty($this->params)) {
|
|
$statement = $this->pdo->prepare($query);
|
|
$statement->execute($this->params);
|
|
return $statement;
|
|
}
|
|
return $this->pdo->query($query);
|
|
}
|
|
|
|
public function getIterator()
|
|
{
|
|
return $this->fetchAll();
|
|
}
|
|
}
|